apparmor/utils/test/test-severity.py
Christian Boltz 5eb796044b Change test-severity.py to use 'unknown' as default rank, and fix the bugs it found
To be able to distinguish between severity 10 and unknown severity,
change AASetup to specify 'unknown' as default rank, and change the
expected result to 'unknown' where it's expected.

Also change the "expected rank %d" to "%s" because it can be a string
now, and add a test that contains directories with different severity
in one variable.

After these changes, handle_variable_rank() errors out with
    TypeError: unorderable types: str() > int()
so fix it by
- initializing rank with the default rank (instead of none)
- explicitely check that rank and rank_new are != the default rank before
  doing a comparison

A side effect is another bugfix - '@{HOME}/sys/@{PROC}/overcommit_memory'
is severity 4, not 10 or unknown (confirmed by reading severity.db).


Acked-by: Steve Beattie <steve@nxnw.org>
2015-05-29 23:39:14 +02:00

177 lines
6.5 KiB
Python
Executable file

#!/usr/bin/env python
# ----------------------------------------------------------------------
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
# Copyright (C) 2014 Canonical, Ltd.
# Copyright (C) 2015 Christian Boltz <apparmor@cboltz.de>
#
# 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 as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# ----------------------------------------------------------------------
import unittest
from common_test import AATest, setup_all_loops
import apparmor.severity as severity
from apparmor.common import AppArmorException
class SeverityBaseTest(AATest):
def AASetup(self):
self.sev_db = severity.Severity('severity.db', 'unknown')
def _simple_severity_test(self, path, expected_rank):
rank = self.sev_db.rank(path)
self.assertEqual(rank, expected_rank,
'expected rank %s, got %s' % (expected_rank, 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 %s, got %s' % (expected_rank, rank))
class SeverityTest(SeverityBaseTest):
tests = [
(['/usr/bin/whatis', 'x' ], 5),
(['/etc', 'x' ], 'unknown'),
(['/dev/doublehit', 'x' ], 0),
(['/dev/doublehit', 'rx' ], 4),
(['/dev/doublehit', 'rwx' ], 8),
(['/dev/tty10', 'rwx' ], 9),
(['/var/adm/foo/**', 'rx' ], 3),
(['/etc/apparmor/**', 'r' ], 6),
(['/etc/**', 'r' ], 'unknown'),
(['/usr/foo@bar', 'r' ], 'unknown'), ## filename containing @
(['/home/foo@bar', 'rw' ], 6), ## filename containing @
]
def _run_test(self, params, expected):
self._simple_severity_w_perm(params[0], params[1], expected) ## filename containing @
def test_invalid_rank(self):
with self.assertRaises(AppArmorException):
self._simple_severity_w_perm('unexpected_unput', 'rw', 6)
class SeverityTestCap(SeverityBaseTest):
tests = [
('KILL', 8),
('SETPCAP', 9),
('setpcap', 9),
('UNKNOWN', 'unknown'),
('K*', 'unknown'),
]
def _run_test(self, params, expected):
cap_with_prefix = 'CAP_%s' % params
self._simple_severity_test(cap_with_prefix, expected)
rank = self.sev_db.rank_capability(params)
self.assertEqual(rank, expected, 'expected rank %s, got %s' % (expected, rank))
class SeverityVarsTest(SeverityBaseTest):
VARIABLE_DEFINITIONS = '''
@{HOME}=@{HOMEDIRS}/*/ /root/
@{HOMEDIRS}=/home/
# add another path to @{HOMEDIRS}
@{HOMEDIRS}+=/storage/
@{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}
@{somepaths}=/home/foo/downloads @{HOMEDIRS}/foo/.ssh/
'''
def _init_tunables(self, content=''):
if not content:
content = self.VARIABLE_DEFINITIONS
self.rules_file = self.writeTmpfile('tunables', content)
self.sev_db.load_variables(self.rules_file)
def AATeardown(self):
self.sev_db.unload_variables()
tests = [
(['@{PROC}/sys/vm/overcommit_memory', 'r'], 6),
(['@{HOME}/sys/@{PROC}/overcommit_memory', 'r'], 4),
(['/overco@{multiarch}mmit_memory', 'r'], 'unknown'),
(['@{PROC}/sys/@{TFTP_DIR}/overcommit_memory', 'r'], 6),
(['@{somepaths}/somefile', 'r'], 7),
]
def _run_test(self, params, expected):
self._init_tunables()
self._simple_severity_w_perm(params[0], params[1], expected)
def test_include(self):
self._init_tunables('#include <file/not/found>') # including non-existing files doesn't raise an exception
self.assertTrue(True) # this test only makes sure that loading the tunables file works
def test_invalid_variable_add(self):
with self.assertRaises(AppArmorException):
self._init_tunables('@{invalid} += /home/')
def test_invalid_variable_double_definition(self):
with self.assertRaises(AppArmorException):
self._init_tunables('@{foo} = /home/\n@{foo} = /root/')
class SeverityDBTest(AATest):
def _test_db(self, contents):
self.db_file = self.writeTmpfile('severity.db', contents)
self.sev_db = severity.Severity(self.db_file)
return self.sev_db
tests = [
("CAP_LEASE 18\n" , AppArmorException), # out of range
("CAP_LEASE -1\n" , AppArmorException), # out of range
("/etc/passwd* 0 4\n" , AppArmorException), # insufficient vals
("/etc/passwd* 0 4 5 6\n" , AppArmorException), # too many vals
("/etc/passwd* -2 4 6\n" , AppArmorException), # out of range
("/etc/passwd* 12 4 6\n" , AppArmorException), # out of range
("/etc/passwd* 2 -4 6\n" , AppArmorException), # out of range
("/etc/passwd 2 14 6\n" , AppArmorException), # out of range
("/etc/passwd 2 4 -12\n" , AppArmorException), # out of range
("/etc/passwd 2 4 4294967297\n" , AppArmorException), # out of range
("garbage line\n" , AppArmorException),
]
def _run_test(self, params, expected):
with self.assertRaises(expected):
self._test_db(params)
def test_simple_db(self):
self._test_db('''
CAP_LEASE 8
/etc/passwd* 4 8 0
''')
def test_cap_val_max_range(self):
self._test_db("CAP_LEASE 10\n")
def test_cap_val_min_range(self):
self._test_db("CAP_LEASE 0\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):
with self.assertRaises(AppArmorException):
severity.Severity()
setup_all_loops(__name__)
if __name__ == '__main__':
unittest.main(verbosity=2)