Hello, I played a bit with our shiny new json interface in aa-logprof.
While doing that, I learned that grabbing stdout and simulating stdin isn't easy and/or underdocumented. I finally found http://www.python-course.eu/pipes.php It has a very nice and working "Bidirectional Pipes" example which I used as a base for the code below. The next thing I noticed out is that aa-logprof simply ends - there isn't any "end" message, so for now, I have to catch EOFError. Is this acceptable, or should we introduce a formal "end" message in json? Note that such an "end" message could be slightly tricky because there's more than one way how aa-logprof finishes (no events, aborting, all events handled and logs saved, crashing with an exception, ...) That said - here is a proof of concept for testing the aa-logprof json interface. I tested it with file events, and I'm quite sure it will break when an exec event appears ;-) Also note that I only tested with py3. import os, sys def do_logprof(): import apparmor.aa as apparmor import apparmor.ui as aaui aaui.set_json_mode() # apparmor.profile_dir = apparmor.get_full_path(profiledir) apparmor.set_logfile('./audit.log') apparmor.init_aa() apparmor.loadincludes() apparmor.do_logprof_pass('') def logprof_driver(): if not 'raw_input' in dir(__builtins__): raw_input = input fh = open("guesser.log","w") while True: try: res = raw_input() fh.write(res + "\n") except EOFError: return if 'promptuser' in res: if "Changed Local Profiles" in res: print('{"dialog": "promptuser", "selected": 0, "response_key": "r"}') fh.write('*** logprof_driver printed r (abort)\n') else: print('{"dialog": "promptuser", "selected": 0, "response_key": "a"}') fh.write('*** logprof_driver printed a\n') elif 'yesno' in res: print('{"dialog": "yesno", "response_key": "y"}') sys.stdout.flush() stdin = sys.stdin.fileno() # usually 0 stdout = sys.stdout.fileno() # usually 1 parentStdin, childStdout = os.pipe() childStdin, parentStdout = os.pipe() pid = os.fork() if pid: # parent process os.close(parentStdin) os.close(parentStdout) os.dup2(childStdin, stdin) os.dup2(childStdout, stdout) logprof_driver() else: # child process os.close(childStdout) os.close(childStdin) os.dup2(parentStdin, stdin) os.dup2(parentStdout, stdout) do_logprof() You probably noticed that the answer selection is, well, quite limited ;-) The final version will have a list of expected input and output. I'm also thinking about implementing a "json log" in aa-logprof because writing these lists of expected input and output manually is probably an annoying task. Just running aa-logprof normally and having all the input and output as json afterwards would be easier ;-) Note: you'll need an utils/test/.coveragerc - otherwise you'll end up with a "Can't combine arc data with line data" error when trying to create a coverage report (from what I found, coverage options given on the commandline don't survive the fork()). # cat .coveragerc [run] branch = True parallel = True concurrency = multiprocessing Speaking about coverage - running _only_ the above proof of concept results in: - 29% coverage of aa.py (that means more than 1000 lines are covered!) - 51% coverage of ui.py I also compared "make coverage html" with and without the above POC: - aa.py: 40% -> 48% - ui.py: 11% -> 52% As always - feedback and better code are welcome ;-) Regards, Christian Boltz -- Lass es mich so ausdrücken, Du hast einem mutmaßlichen Anfänger auf die Frage "Wie lasse ich ein Auto an?", mit einer Erklärung wie er die Zündung kurzschließt geantwortet :-) [Ralf Corsepius in suse-programming]
signature.asc
Description: This is a digitally signed message part.
-- AppArmor mailing list AppArmor@lists.ubuntu.com Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/apparmor