2
0
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:
Steve Beattie
2014-11-06 12:32:49 -08:00
parent c35a4c412d
commit e26f139025
2 changed files with 187 additions and 55 deletions

View File

@@ -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()

View File

@@ -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)