1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
|
#! /usr/bin/python3
# ------------------------------------------------------------------
#
# Copyright (C) 2011-2012 Canonical Ltd.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 of the GNU General Public
# License published by the Free Software Foundation.
#
# ------------------------------------------------------------------
import os
import signal
import subprocess
import unittest
from tempfile import NamedTemporaryFile
# The location of the aa-decode utility can be overridden by setting
# the APPARMOR_DECODE environment variable; this is useful for running
# these tests in an installed environment
aadecode_bin = "../aa-decode"
# http://www.chiark.greenend.org.uk/ucgi/~cjwatson/blosxom/2009-07-02-python-sigpipe.html
# This is needed so that the subprocesses that produce endless output
# actually quit when the reader goes away.
def subprocess_setup():
# Python installs a SIGPIPE handler by default. This is usually not what
# non-Python subprocesses expect.
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
# Define only arguments that are actually ever used: command and stdin
def cmd(command, stdin=None):
"""Try to execute given command (array) and return its stdout, or return
a textual error if it failed."""
try:
sp = subprocess.Popen(
command,
stdin=stdin,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
close_fds=True,
preexec_fn=subprocess_setup
)
except OSError as e:
return 127, str(e)
stdout, stderr = sp.communicate(input)
# If there was some error output, show that instead of stdout to ensure
# test fails and does not mask potentially major warnings and errors.
if stderr:
out = stderr
else:
out = stdout
return sp.returncode, out.decode('utf-8')
class AADecodeTest(unittest.TestCase):
def test_help(self):
"""Test --help argument"""
expected = 0
rc, report = cmd((aadecode_bin, "--help"))
result = 'Got exit code {}, expected {}\n'.format(rc, expected)
self.assertEqual(expected, rc, result + report)
def _run_file_test(self, content, expected):
"""test case helper function; takes log content and a list of
expected strings as arguments"""
expected_return_code = 0
with NamedTemporaryFile("w+", prefix='tst-aadecode-') as temp_file:
self.tmpfile = temp_file.name
temp_file.write(content)
temp_file.flush()
temp_file.seek(0)
rc, report = cmd((aadecode_bin,), stdin=temp_file)
result = 'Got exit code {}, expected {}\n'.format(rc, expected_return_code)
self.assertEqual(expected_return_code, rc, result + report)
for expected_string in expected:
result = 'could not find expected {} in output:\n'.format(expected_string)
self.assertIn(expected_string, report, result + report)
def test_simple_decode(self):
"""Test simple decode on command line"""
expected = 0
expected_output = 'Decoded: /tmp/foo bar'
test_code = '2F746D702F666F6F20626172'
rc, report = cmd((aadecode_bin, test_code))
result = 'Got exit code {}, expected {}\n'.format(rc, expected)
self.assertEqual(expected, rc, result + report)
result = 'Got output "{}", expected "{}"\n'.format(report, expected_output)
self.assertIn(expected_output, report, result + report)
def test_simple_filter(self):
"""test simple decoding of the name argument"""
expected_string = 'name="/tmp/foo bar"'
content = \
'''type=AVC msg=audit(1348982151.183:2934): apparmor="DENIED" operation="open" parent=30751 profile="/usr/lib/firefox/firefox{,*[^s] [^h]}" name=2F746D702F666F6F20626172 pid=30833 comm="plugin-containe" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
''' # noqa: E128
self._run_file_test(content, (expected_string,))
def test_simple_multiline(self):
"""test simple multiline decoding of the name argument"""
expected_strings = (
'ses=4294967295 new ses=2762',
'name="/tmp/foo bar"',
'name="/home/steve/tmp/my test file"',
)
content = \
''' type=LOGIN msg=audit(1348980001.155:2925): login pid=17875 uid=0 old auid=4294967295 new auid=0 old ses=4294967295 new ses=2762
type=AVC msg=audit(1348982151.183:2934): apparmor="DENIED" operation="open" parent=30751 profile="/usr/lib/firefox/firefox{,*[^s] [^h]}" name=2F746D702F666F6F20626172 pid=30833 comm="plugin-containe" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
type=AVC msg=audit(1348982148.195:2933): apparmor="DENIED" operation="file_lock" parent=5490 profile="/usr/lib/firefox/firefox{,*[^s][^h]}" name=2F686F6D652F73746576652F746D702F6D7920746573742066696C65 pid=30737 comm="firefox" requested_mask="k" denied_mask="k" fsuid=1000 ouid=1000
''' # noqa: E128
self._run_file_test(content, expected_strings)
def test_simple_profile(self):
"""test simple decoding of the profile argument"""
# Example take from LP: #897957
expected_strings = (
'name="/lib/x86_64-linux-gnu/libdl-2.13.so"', 'profile="/test space"')
content = \
'''[289763.843292] type=1400 audit(1322614912.304:857): apparmor="ALLOWED" operation="getattr" parent=16001 profile=2F74657374207370616365 name="/lib/x86_64-linux-gnu/libdl-2.13.so" pid=17011 comm="bash" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
''' # noqa: E128
self._run_file_test(content, expected_strings)
def test_simple_profile2(self):
"""test simple decoding of name and profile argument"""
# Example take from LP: #897957
expected_strings = ('name="/home/steve/tmp/my test file"',
'profile="/home/steve/tmp/my prog.sh"')
content = \
'''type=AVC msg=audit(1349805073.402:6857): apparmor="DENIED" operation="mknod" parent=5890 profile=2F686F6D652F73746576652F746D702F6D792070726F672E7368 name=2F686F6D652F73746576652F746D702F6D7920746573742066696C65 pid=5891 comm="touch" requested_mask="c" denied_mask="c" fsuid=1000 ouid=1000
''' # noqa: E128
self._run_file_test(content, expected_strings)
def test_simple_embedded_carat(self):
"""test simple decoding of embedded ^ in files"""
expected_strings = ('name="/home/steve/tmp/my test ^file"',)
content = \
'''type=AVC msg=audit(1349805073.402:6857): apparmor="DENIED" operation="mknod" parent=5890 profile="/usr/bin/test_profile" name=2F686F6D652F73746576652F746D702F6D792074657374205E66696C65 pid=5891 comm="touch" requested_mask="c" denied_mask="c" fsuid=1000 ouid=1000
''' # noqa: E128
self._run_file_test(content, expected_strings)
def test_simple_embedded_backslash_carat(self):
r"""test simple decoding of embedded \^ in files"""
expected_strings = (r'name="/home/steve/tmp/my test \^file"',)
content = \
'''type=AVC msg=audit(1349805073.402:6857): apparmor="DENIED" operation="mknod" parent=5890 profile="/usr/bin/test_profile" name=2F686F6D652F73746576652F746D702F6D792074657374205C5E66696C65 pid=5891 comm="touch" requested_mask="c" denied_mask="c" fsuid=1000 ouid=1000
''' # noqa: E128
self._run_file_test(content, expected_strings)
def test_simple_embedded_singlequote(self):
"""test simple decoding of embedded \' in files"""
expected_strings = ('name="/home/steve/tmp/my test \'file"',)
content = \
'''type=AVC msg=audit(1349805073.402:6857): apparmor="DENIED" operation="mknod" parent=5890 profile="/usr/bin/test_profile" name=2F686F6D652F73746576652F746D702F6D792074657374202766696C65 pid=5891 comm="touch" requested_mask="c" denied_mask="c" fsuid=1000 ouid=1000
''' # noqa: E128
self._run_file_test(content, expected_strings)
def test_simple_encoded_nonpath_profiles(self):
"""test simple decoding of nonpath profiles"""
expected_strings = ('name="/lib/x86_64-linux-gnu/libdl-2.13.so"', 'profile="test space"')
content = \
'''[289763.843292] type=1400 audit(1322614912.304:857): apparmor="ALLOWED" operation="getattr" parent=16001 profile=74657374207370616365 name="/lib/x86_64-linux-gnu/libdl-2.13.so" pid=17011 comm="bash" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
''' # noqa: E128
self._run_file_test(content, expected_strings)
#
# Main
#
if __name__ == '__main__':
if 'APPARMOR_DECODE' in os.environ:
aadecode_bin = os.environ['APPARMOR_DECODE']
unittest.main(verbosity=1)
|