mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-30 13:58:22 +00:00
utils: re-work the severity.db unit tests
This patch is a re-work of the severity_test.py tests, to break them up into individual unit tests, and to add coverage for detecting an invalid severity database (it does reduce the coverage for walking profiles to find variable declarations, but that should be pulled out of the severity handling code anyway). Note that the last test case will fail, because even though the code path in Severity.__init__() looks like it will return None if no path is given, a Severity object in a half-state of initialization will actually be returned. Signed-off-by: Steve Beattie <steve@nxnw.org> Acked-by: Christian Boltz <apparmor@cboltz.de>
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#
|
||||
# ----------------------------------------------------------------------
|
||||
import unittest
|
||||
import os
|
||||
import re
|
||||
|
||||
import apparmor.common
|
||||
@@ -55,6 +56,13 @@ def setup_regex_tests(test_class):
|
||||
stub_test.__doc__ = "test '%s': %s" % (line, desc)
|
||||
setattr(test_class, 'test_%d' % (i), stub_test)
|
||||
|
||||
def write_file(directory, file, contents):
|
||||
'''construct path, write contents to it, and return the constructed path'''
|
||||
path = os.path.join(directory, file)
|
||||
with open(path, 'w+') as f:
|
||||
f.write(contents)
|
||||
return path
|
||||
|
||||
if __name__ == "__main__":
|
||||
#import sys;sys.argv = ['', 'Test.test_RegexParser']
|
||||
unittest.main()
|
||||
|
@@ -1,5 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
|
||||
# Copyright (C) 2014 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
|
||||
@@ -13,77 +15,199 @@
|
||||
# ----------------------------------------------------------------------
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
import apparmor.severity as severity
|
||||
from apparmor.common import AppArmorException
|
||||
from common_test import write_file
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
class SeverityBaseTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
#copy the local profiles to the test directory
|
||||
if os.path.exists('./profiles'):
|
||||
shutil.rmtree('./profiles')
|
||||
shutil.copytree('../../profiles/apparmor.d/', './profiles/', symlinks=True)
|
||||
self.sev_db = severity.Severity('severity.db')
|
||||
|
||||
def tearDown(self):
|
||||
#Wipe the local profiles from the test directory
|
||||
shutil.rmtree('./profiles')
|
||||
pass
|
||||
|
||||
def testRank_Test(self):
|
||||
sev_db = severity.Severity('severity.db')
|
||||
rank = sev_db.rank('/usr/bin/whatis', 'x')
|
||||
self.assertEqual(rank, 5, 'Wrong rank')
|
||||
rank = sev_db.rank('/etc', 'x')
|
||||
self.assertEqual(rank, 10, 'Wrong rank')
|
||||
rank = sev_db.rank('/dev/doublehit', 'x')
|
||||
self.assertEqual(rank, 0, 'Wrong rank')
|
||||
rank = sev_db.rank('/dev/doublehit', 'rx')
|
||||
self.assertEqual(rank, 4, 'Wrong rank')
|
||||
rank = sev_db.rank('/dev/doublehit', 'rwx')
|
||||
self.assertEqual(rank, 8, 'Wrong rank')
|
||||
rank = sev_db.rank('/dev/tty10', 'rwx')
|
||||
self.assertEqual(rank, 9, 'Wrong rank')
|
||||
rank = sev_db.rank('/var/adm/foo/**', 'rx')
|
||||
self.assertEqual(rank, 3, 'Wrong rank')
|
||||
rank = sev_db.rank('CAP_KILL')
|
||||
self.assertEqual(rank, 8, 'Wrong rank')
|
||||
rank = sev_db.rank('CAP_SETPCAP')
|
||||
self.assertEqual(rank, 9, 'Wrong rank')
|
||||
self.assertEqual(sev_db.rank('/etc/apparmor/**', 'r') , 6, 'Invalid Rank')
|
||||
self.assertEqual(sev_db.rank('/etc/**', 'r') , 10, 'Invalid Rank')
|
||||
self.assertEqual(sev_db.rank('/usr/foo@bar', 'r') , 10, 'Invalid Rank') ## filename containing @
|
||||
self.assertEqual(sev_db.rank('/home/foo@bar', 'rw') , 6, 'Invalid Rank') ## filename containing @
|
||||
def _simple_severity_test(self, path, expected_rank):
|
||||
rank = self.sev_db.rank(path)
|
||||
self.assertEqual(rank, expected_rank,
|
||||
'expected rank %d, got %d' % (expected_rank, rank))
|
||||
|
||||
# Load all variables for /sbin/klogd and test them
|
||||
sev_db.load_variables('profiles/sbin.klogd')
|
||||
self.assertEqual(sev_db.rank('@{PROC}/sys/vm/overcommit_memory', 'r'), 6, 'Invalid Rank')
|
||||
self.assertEqual(sev_db.rank('@{HOME}/sys/@{PROC}/overcommit_memory', 'r'), 10, 'Invalid Rank')
|
||||
self.assertEqual(sev_db.rank('/overco@{multiarch}mmit_memory', 'r'), 10, 'Invalid Rank')
|
||||
def _simple_severity_w_perm(self, path, perm, expected_rank):
|
||||
rank = self.sev_db.rank(path, perm)
|
||||
self.assertEqual(rank, expected_rank,
|
||||
'expected rank %d, got %d' % (expected_rank, rank))
|
||||
|
||||
sev_db.unload_variables()
|
||||
class SeverityTest(SeverityBaseTest):
|
||||
def test_perm_x(self):
|
||||
self._simple_severity_w_perm('/usr/bin/whatis', 'x', 5)
|
||||
|
||||
sev_db.load_variables('profiles/usr.sbin.dnsmasq')
|
||||
self.assertEqual(sev_db.rank('@{PROC}/sys/@{TFTP_DIR}/overcommit_memory', 'r'), 6, 'Invalid Rank')
|
||||
self.assertEqual(sev_db.rank('@{PROC}/sys/vm/overcommit_memory', 'r'), 6, 'Invalid Rank')
|
||||
self.assertEqual(sev_db.rank('@{HOME}/sys/@{PROC}/overcommit_memory', 'r'), 10, 'Invalid Rank')
|
||||
self.assertEqual(sev_db.rank('/overco@{multiarch}mmit_memory', 'r'), 10, 'Invalid Rank')
|
||||
def test_perm_etc_x(self):
|
||||
self._simple_severity_w_perm('/etc', 'x', 10)
|
||||
|
||||
#self.assertEqual(sev_db.rank('/proc/@{PID}/maps', 'rw'), 9, 'Invalid Rank')
|
||||
def test_perm_dev_x(self):
|
||||
self._simple_severity_w_perm('/dev/doublehit', 'x', 0)
|
||||
|
||||
def testInvalid(self):
|
||||
sev_db = severity.Severity('severity.db')
|
||||
rank = sev_db.rank('/dev/doublehit', 'i')
|
||||
self.assertEqual(rank, 10, 'Wrong')
|
||||
try:
|
||||
severity.Severity('severity_broken.db')
|
||||
except AppArmorException:
|
||||
pass
|
||||
rank = sev_db.rank('CAP_UNKOWN')
|
||||
rank = sev_db.rank('CAP_K*')
|
||||
def test_perm_dev_rx(self):
|
||||
self._simple_severity_w_perm('/dev/doublehit', 'rx', 4)
|
||||
|
||||
def test_perm_dev_rwx(self):
|
||||
self._simple_severity_w_perm('/dev/doublehit', 'rwx', 8)
|
||||
|
||||
def test_perm_tty_rwx(self):
|
||||
self._simple_severity_w_perm('/dev/tty10', 'rwx', 9)
|
||||
|
||||
def test_perm_glob_1(self):
|
||||
self._simple_severity_w_perm('/var/adm/foo/**', 'rx', 3)
|
||||
|
||||
def test_cap_kill(self):
|
||||
self._simple_severity_test('CAP_KILL', 8)
|
||||
|
||||
def test_cap_setpcap(self):
|
||||
self._simple_severity_test('CAP_SETPCAP', 9)
|
||||
|
||||
def test_cap_unknown_1(self):
|
||||
self._simple_severity_test('CAP_UNKNOWN', 10)
|
||||
|
||||
def test_cap_unknown_2(self):
|
||||
self._simple_severity_test('CAP_K*', 10)
|
||||
|
||||
def test_perm_apparmor_glob(self):
|
||||
self._simple_severity_w_perm('/etc/apparmor/**', 'r' , 6)
|
||||
|
||||
def test_perm_etc_glob(self):
|
||||
self._simple_severity_w_perm('/etc/**', 'r' , 10)
|
||||
|
||||
def test_perm_filename_w_at_r(self):
|
||||
self._simple_severity_w_perm('/usr/foo@bar', 'r' , 10) ## filename containing @
|
||||
|
||||
def test_perm_filename_w_at_rw(self):
|
||||
self._simple_severity_w_perm('/home/foo@bar', 'rw', 6) ## filename containing @
|
||||
|
||||
def test_invalid_rank(self):
|
||||
with self.assertRaises(AppArmorException):
|
||||
self._simple_severity_w_perm('unexpected_unput', 'rw', 6)
|
||||
|
||||
class SeverityVarsTest(SeverityBaseTest):
|
||||
|
||||
VARIABLE_DEFINITIONS = '''
|
||||
@{HOME}=@{HOMEDIRS}/*/ /root/
|
||||
@{HOMEDIRS}=/home/
|
||||
@{multiarch}=*-linux-gnu*
|
||||
@{TFTP_DIR}=/var/tftp /srv/tftpboot
|
||||
@{PROC}=/proc/
|
||||
@{pid}={[1-9],[1-9][0-9],[1-9][0-9][0-9],[1-9][0-9][0-9][0-9],[1-9][0-9][0-9][0-9][0-9],[1-9][0-9][0-9][0-9][0-9][0-9]}
|
||||
@{tid}=@{pid}
|
||||
@{pids}=@{pid}
|
||||
'''
|
||||
|
||||
def setUp(self):
|
||||
super(SeverityVarsTest, self).setUp()
|
||||
self.tmpdir = tempfile.mkdtemp(prefix='aa-severity-')
|
||||
rules_file = write_file(self.tmpdir, 'tunables', self.VARIABLE_DEFINITIONS)
|
||||
|
||||
self.sev_db.load_variables(rules_file)
|
||||
|
||||
def tearDown(self):
|
||||
self.sev_db.unload_variables()
|
||||
if os.path.exists(self.tmpdir):
|
||||
shutil.rmtree(self.tmpdir)
|
||||
|
||||
super(SeverityVarsTest, self).tearDown()
|
||||
|
||||
def test_proc_var(self):
|
||||
self._simple_severity_w_perm('@{PROC}/sys/vm/overcommit_memory', 'r', 6)
|
||||
|
||||
def test_home_var(self):
|
||||
self._simple_severity_w_perm('@{HOME}/sys/@{PROC}/overcommit_memory', 'r', 10)
|
||||
|
||||
def test_multiarch_var(self):
|
||||
self._simple_severity_w_perm('/overco@{multiarch}mmit_memory', 'r', 10)
|
||||
|
||||
def test_proc_tftp_vars(self):
|
||||
self._simple_severity_w_perm('@{PROC}/sys/@{TFTP_DIR}/overcommit_memory', 'r', 6)
|
||||
|
||||
class SeverityDBTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.tmpdir = tempfile.mkdtemp(prefix='aa-severity-db-')
|
||||
|
||||
def tearDown(self):
|
||||
if os.path.exists(self.tmpdir):
|
||||
shutil.rmtree(self.tmpdir)
|
||||
|
||||
def _test_db(self, contents):
|
||||
self.db_file = write_file(self.tmpdir, 'severity.db', contents)
|
||||
self.sev_db = severity.Severity(self.db_file)
|
||||
return self.sev_db
|
||||
|
||||
def test_simple_db(self):
|
||||
db = self._test_db('''
|
||||
CAP_LEASE 8
|
||||
/etc/passwd* 4 8 0
|
||||
''')
|
||||
|
||||
def test_cap_val_max_range(self):
|
||||
db = self._test_db("CAP_LEASE 10\n")
|
||||
|
||||
def test_cap_val_min_range(self):
|
||||
db = self._test_db("CAP_LEASE 0\n")
|
||||
|
||||
def test_cap_val_out_of_range(self):
|
||||
with self.assertRaises(AppArmorException):
|
||||
db = self._test_db("CAP_LEASE 18\n")
|
||||
|
||||
def test_cap_val_out_of_range(self):
|
||||
with self.assertRaises(AppArmorException):
|
||||
db = self._test_db("CAP_LEASE -1\n")
|
||||
|
||||
def test_path_insufficient_vals(self):
|
||||
with self.assertRaises(AppArmorException):
|
||||
db = self._test_db("/etc/passwd* 0 4\n")
|
||||
|
||||
def test_path_too_many_vals(self):
|
||||
with self.assertRaises(AppArmorException):
|
||||
db = self._test_db("/etc/passwd* 0 4 5 6\n")
|
||||
|
||||
def test_path_outside_range_1(self):
|
||||
with self.assertRaises(AppArmorException):
|
||||
db = self._test_db("/etc/passwd* -2 4 6\n")
|
||||
|
||||
def test_path_outside_range_2(self):
|
||||
with self.assertRaises(AppArmorException):
|
||||
db = self._test_db("/etc/passwd* 12 4 6\n")
|
||||
|
||||
def test_path_outside_range_3(self):
|
||||
with self.assertRaises(AppArmorException):
|
||||
db = self._test_db("/etc/passwd* 2 -4 6\n")
|
||||
|
||||
def test_path_outside_range_4(self):
|
||||
with self.assertRaises(AppArmorException):
|
||||
db = self._test_db("/etc/passwd 2 14 6\n")
|
||||
|
||||
def test_path_outside_range_5(self):
|
||||
with self.assertRaises(AppArmorException):
|
||||
db = self._test_db("/etc/passwd 2 4 -12\n")
|
||||
|
||||
def test_path_outside_range_6(self):
|
||||
with self.assertRaises(AppArmorException):
|
||||
db = self._test_db("/etc/passwd 2 4 4294967297\n")
|
||||
|
||||
def test_garbage_line(self):
|
||||
with self.assertRaises(AppArmorException):
|
||||
db = self._test_db("garbage line\n")
|
||||
|
||||
def test_invalid_db(self):
|
||||
self.assertRaises(AppArmorException, severity.Severity, 'severity_broken.db')
|
||||
|
||||
def test_nonexistent_db(self):
|
||||
self.assertRaises(IOError, severity.Severity, 'severity.db.does.not.exist')
|
||||
|
||||
def test_no_arg_to_severity(self):
|
||||
sev_db = severity.Severity()
|
||||
self.assertIsNone(sev_db, 'expected None, got %s' % (sev_db))
|
||||
|
||||
if __name__ == "__main__":
|
||||
#import sys;sys.argv = ['', 'Test.testName']
|
||||
unittest.main()
|
||||
unittest.main(verbosity=2)
|
||||
|
Reference in New Issue
Block a user