[apparmor] [POC] testing the json interface
Christian Boltz
apparmor at cboltz.de
Sat Jun 24 22:09:32 UTC 2017
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]
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: This is a digitally signed message part.
URL: <https://lists.ubuntu.com/archives/apparmor/attachments/20170625/684c4da3/attachment.pgp>
More information about the AppArmor
mailing list