2014-11-06 12:32:49 -08:00
|
|
|
#!/usr/bin/env python
|
2013-09-28 20:43:06 +05:30
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
|
2014-11-06 12:32:49 -08:00
|
|
|
# Copyright (C) 2014 Canonical, Ltd.
|
2013-09-28 20:43:06 +05:30
|
|
|
#
|
|
|
|
# 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.
|
|
|
|
#
|
|
|
|
# ----------------------------------------------------------------------
|
2013-08-31 04:08:26 +05:30
|
|
|
import os
|
2013-08-30 03:54:31 +05:30
|
|
|
import shutil
|
2014-11-06 12:32:49 -08:00
|
|
|
import tempfile
|
2013-06-21 20:08:32 +05:30
|
|
|
import unittest
|
2013-06-25 04:46:59 +05:30
|
|
|
|
2013-07-06 18:57:06 +05:30
|
|
|
import apparmor.severity as severity
|
|
|
|
from apparmor.common import AppArmorException
|
2014-11-06 12:32:49 -08:00
|
|
|
from common_test import write_file
|
2013-07-19 00:44:55 +05:30
|
|
|
|
2014-11-06 12:32:49 -08:00
|
|
|
class SeverityBaseTest(unittest.TestCase):
|
2013-09-22 22:51:30 +05:30
|
|
|
|
2013-08-30 03:54:31 +05:30
|
|
|
def setUp(self):
|
2014-11-06 12:32:49 -08:00
|
|
|
self.sev_db = severity.Severity('severity.db')
|
2013-09-22 22:51:30 +05:30
|
|
|
|
2013-08-31 04:08:26 +05:30
|
|
|
def tearDown(self):
|
2014-11-06 12:32:49 -08:00
|
|
|
pass
|
2013-09-22 22:51:30 +05:30
|
|
|
|
2014-11-06 12:32:49 -08:00
|
|
|
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))
|
2013-09-22 22:51:30 +05:30
|
|
|
|
2014-11-06 12:32:49 -08:00
|
|
|
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))
|
|
|
|
|
|
|
|
class SeverityTest(SeverityBaseTest):
|
|
|
|
def test_perm_x(self):
|
|
|
|
self._simple_severity_w_perm('/usr/bin/whatis', 'x', 5)
|
|
|
|
|
|
|
|
def test_perm_etc_x(self):
|
|
|
|
self._simple_severity_w_perm('/etc', 'x', 10)
|
|
|
|
|
|
|
|
def test_perm_dev_x(self):
|
|
|
|
self._simple_severity_w_perm('/dev/doublehit', 'x', 0)
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
2014-11-14 02:27:33 +01:00
|
|
|
def test_cap_setpcap_lowercase(self):
|
|
|
|
self._simple_severity_test('CAP_setpcap', 9)
|
|
|
|
|
2014-11-06 12:32:49 -08:00
|
|
|
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):
|
2014-11-13 10:58:50 -08:00
|
|
|
self._test_db('''
|
2014-11-06 12:32:49 -08:00
|
|
|
CAP_LEASE 8
|
|
|
|
/etc/passwd* 4 8 0
|
|
|
|
''')
|
|
|
|
|
|
|
|
def test_cap_val_max_range(self):
|
2014-11-13 10:58:50 -08:00
|
|
|
self._test_db("CAP_LEASE 10\n")
|
2014-11-06 12:32:49 -08:00
|
|
|
|
|
|
|
def test_cap_val_min_range(self):
|
2014-11-13 10:58:50 -08:00
|
|
|
self._test_db("CAP_LEASE 0\n")
|
2014-11-06 12:32:49 -08:00
|
|
|
|
2014-11-13 10:58:50 -08:00
|
|
|
def test_cap_val_out_of_range_1(self):
|
2014-11-06 12:32:49 -08:00
|
|
|
with self.assertRaises(AppArmorException):
|
2014-11-13 10:58:50 -08:00
|
|
|
self._test_db("CAP_LEASE 18\n")
|
2014-11-06 12:32:49 -08:00
|
|
|
|
2014-11-13 10:58:50 -08:00
|
|
|
def test_cap_val_out_of_range_2(self):
|
2014-11-06 12:32:49 -08:00
|
|
|
with self.assertRaises(AppArmorException):
|
2014-11-13 10:58:50 -08:00
|
|
|
self._test_db("CAP_LEASE -1\n")
|
2014-11-06 12:32:49 -08:00
|
|
|
|
|
|
|
def test_path_insufficient_vals(self):
|
|
|
|
with self.assertRaises(AppArmorException):
|
2014-11-13 10:58:50 -08:00
|
|
|
self._test_db("/etc/passwd* 0 4\n")
|
2014-11-06 12:32:49 -08:00
|
|
|
|
|
|
|
def test_path_too_many_vals(self):
|
|
|
|
with self.assertRaises(AppArmorException):
|
2014-11-13 10:58:50 -08:00
|
|
|
self._test_db("/etc/passwd* 0 4 5 6\n")
|
2014-11-06 12:32:49 -08:00
|
|
|
|
|
|
|
def test_path_outside_range_1(self):
|
|
|
|
with self.assertRaises(AppArmorException):
|
2014-11-13 10:58:50 -08:00
|
|
|
self._test_db("/etc/passwd* -2 4 6\n")
|
2014-11-06 12:32:49 -08:00
|
|
|
|
|
|
|
def test_path_outside_range_2(self):
|
|
|
|
with self.assertRaises(AppArmorException):
|
2014-11-13 10:58:50 -08:00
|
|
|
self._test_db("/etc/passwd* 12 4 6\n")
|
2014-11-06 12:32:49 -08:00
|
|
|
|
|
|
|
def test_path_outside_range_3(self):
|
|
|
|
with self.assertRaises(AppArmorException):
|
2014-11-13 10:58:50 -08:00
|
|
|
self._test_db("/etc/passwd* 2 -4 6\n")
|
2014-11-06 12:32:49 -08:00
|
|
|
|
|
|
|
def test_path_outside_range_4(self):
|
|
|
|
with self.assertRaises(AppArmorException):
|
2014-11-13 10:58:50 -08:00
|
|
|
self._test_db("/etc/passwd 2 14 6\n")
|
2014-11-06 12:32:49 -08:00
|
|
|
|
|
|
|
def test_path_outside_range_5(self):
|
|
|
|
with self.assertRaises(AppArmorException):
|
2014-11-13 10:58:50 -08:00
|
|
|
self._test_db("/etc/passwd 2 4 -12\n")
|
2014-11-06 12:32:49 -08:00
|
|
|
|
|
|
|
def test_path_outside_range_6(self):
|
|
|
|
with self.assertRaises(AppArmorException):
|
2014-11-13 10:58:50 -08:00
|
|
|
self._test_db("/etc/passwd 2 4 4294967297\n")
|
2014-11-06 12:32:49 -08:00
|
|
|
|
|
|
|
def test_garbage_line(self):
|
|
|
|
with self.assertRaises(AppArmorException):
|
2014-11-13 10:58:50 -08:00
|
|
|
self._test_db("garbage line\n")
|
2014-11-06 12:32:49 -08:00
|
|
|
|
|
|
|
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):
|
2014-11-06 12:37:02 -08:00
|
|
|
with self.assertRaises(AppArmorException):
|
|
|
|
severity.Severity()
|
2013-06-21 20:08:32 +05:30
|
|
|
|
|
|
|
if __name__ == "__main__":
|
2014-11-06 12:32:49 -08:00
|
|
|
unittest.main(verbosity=2)
|