mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 08:24:42 +01:00
573 lines
26 KiB
Python
573 lines
26 KiB
Python
![]() |
#!/usr/bin/python3
|
||
|
# ----------------------------------------------------------------------
|
||
|
# 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 collections import namedtuple
|
||
|
|
||
|
from apparmor.common import AppArmorBug, AppArmorException
|
||
|
from apparmor.logparser import ReadLog
|
||
|
from apparmor.aare import AARE
|
||
|
from apparmor.rule.pivot_root import PivotRootRule, PivotRootRuleset
|
||
|
from apparmor.translations import init_translation
|
||
|
from common_test import AATest, setup_all_loops
|
||
|
|
||
|
_ = init_translation()
|
||
|
|
||
|
exp = namedtuple(
|
||
|
'exp', ('audit', 'allow_keyword', 'deny', 'comment', 'oldroot', 'all_oldroots', 'newroot',
|
||
|
'all_newroots', 'profile_name', 'all_profile_names'),
|
||
|
)
|
||
|
|
||
|
|
||
|
# # --- tests for single PivotRootRule --- #
|
||
|
|
||
|
class PivotRootTest(AATest):
|
||
|
def _compare_obj(self, obj, expected):
|
||
|
self.assertEqual(expected.audit, obj.audit)
|
||
|
self.assertEqual(expected.allow_keyword, obj.allow_keyword)
|
||
|
self.assertEqual(expected.deny, obj.deny)
|
||
|
self.assertEqual(expected.comment, obj.comment)
|
||
|
|
||
|
if type(obj.oldroot) is AARE:
|
||
|
self.assertEqual(expected.oldroot, obj.oldroot.regex)
|
||
|
else:
|
||
|
self.assertEqual(expected.oldroot, obj.oldroot)
|
||
|
|
||
|
self.assertEqual(expected.all_oldroots, obj.all_oldroots)
|
||
|
|
||
|
if type(obj.newroot) is AARE:
|
||
|
self.assertEqual(expected.newroot, obj.newroot.regex)
|
||
|
else:
|
||
|
self.assertEqual(expected.newroot, obj.newroot)
|
||
|
|
||
|
self.assertEqual(expected.all_newroots, obj.all_newroots)
|
||
|
|
||
|
if type(obj.profile_name) is AARE:
|
||
|
self.assertEqual(expected.profile_name, obj.profile_name.regex)
|
||
|
else:
|
||
|
self.assertEqual(expected.profile_name, obj.profile_name)
|
||
|
|
||
|
self.assertEqual(expected.all_profile_names, obj.all_profile_names)
|
||
|
|
||
|
|
||
|
class PivotRootTestParse(PivotRootTest):
|
||
|
tests = (
|
||
|
# PivotRootRule object audit allow deny comment oldroot all? newroot all? profile_name all?
|
||
|
('pivot_root,', exp(False, False, False, '', None, True, None, True, None, True)),
|
||
|
('pivot_root oldroot=/oldroot, # cmt', exp(False, False, False, ' # cmt', '/oldroot', False, None, True, None, True)),
|
||
|
('pivot_root oldroot=/oldroot /new/root, # cmt', exp(False, False, False, ' # cmt', '/oldroot', False, '/new/root', False, None, True)),
|
||
|
('pivot_root oldroot=/oldroot /new/root -> targetprof, # cmt', exp(False, False, False, ' # cmt', '/oldroot', False, '/new/root', False, 'targetprof', False)),
|
||
|
('pivot_root oldroot=/oldroot -> targetprof, # cmt', exp(False, False, False, ' # cmt', '/oldroot', False, None, True, 'targetprof', False)),
|
||
|
('pivot_root /new/root, # cmt', exp(False, False, False, ' # cmt', None, True, '/new/root', False, None, True)),
|
||
|
('pivot_root /new/root -> targetprof, # cmt', exp(False, False, False, ' # cmt', None, True, '/new/root', False, 'targetprof', False)),
|
||
|
('pivot_root -> targetprof, # cmt', exp(False, False, False, ' # cmt', None, True, None, True, 'targetprof', False)),
|
||
|
('pivot_root oldroot="/oldroot", # cmt', exp(False, False, False, ' # cmt', '/oldroot', False, None, True, None, True)),
|
||
|
('pivot_root "/new/root", # cmt', exp(False, False, False, ' # cmt', None, True, '/new/root', False, None, True)),
|
||
|
('pivot_root -> "targetprof", # cmt', exp(False, False, False, ' # cmt', None, True, None, True, 'targetprof', False)),
|
||
|
)
|
||
|
|
||
|
def _run_test(self, rawrule, expected):
|
||
|
self.assertTrue(PivotRootRule.match(rawrule))
|
||
|
obj = PivotRootRule.create_instance(rawrule)
|
||
|
self.assertEqual(rawrule.strip(), obj.raw_rule)
|
||
|
self._compare_obj(obj, expected)
|
||
|
|
||
|
|
||
|
class PivotRootTestParseInvalid(PivotRootTest):
|
||
|
tests = (
|
||
|
('pivot_root foo,', AppArmorException),
|
||
|
('pivot_root foo bar,', AppArmorException),
|
||
|
('pivot_root oldroot= ,', AppArmorException),
|
||
|
('pivot_root -> ,', AppArmorException),
|
||
|
)
|
||
|
|
||
|
def _run_test(self, rawrule, expected):
|
||
|
self.assertTrue(PivotRootRule.match(rawrule)) # the above invalid rules still match the main regex!
|
||
|
with self.assertRaises(expected):
|
||
|
PivotRootRule.create_instance(rawrule)
|
||
|
|
||
|
def test_invalid_rule_name(self):
|
||
|
self.assertFalse(PivotRootRule.match('pivot_rootbeer,'))
|
||
|
with self.assertRaises(AppArmorException):
|
||
|
PivotRootRule.create_instance('pivot_rootbeer,')
|
||
|
|
||
|
|
||
|
class PivotRootTestParseFromLog(PivotRootTest):
|
||
|
def test_pivot_root_from_log(self):
|
||
|
parser = ReadLog('', '', '')
|
||
|
event = 'type=AVC msg=audit(1409700678.384:547594): apparmor="DENIED" operation="pivotroot" profile="/home/ubuntu/bzr/apparmor/tests/regression/apparmor/pivot_root" name="/tmp/sdtest.21082-7446-EeefO6/new_root/" pid=21162 comm="pivot_root" srcname="/tmp/sdtest.21082-7446-EeefO6/new_root/put_old/"'
|
||
|
|
||
|
parsed_event = parser.parse_event(event)
|
||
|
|
||
|
self.assertEqual(parsed_event, {
|
||
|
'request_mask': None,
|
||
|
'denied_mask': None,
|
||
|
'error_code': 0,
|
||
|
'magic_token': 0,
|
||
|
'parent': 0,
|
||
|
'profile': '/home/ubuntu/bzr/apparmor/tests/regression/apparmor/pivot_root',
|
||
|
'operation': 'pivotroot',
|
||
|
'resource': None,
|
||
|
'info': None,
|
||
|
'aamode': 'REJECTING',
|
||
|
'time': 1409700678,
|
||
|
'active_hat': None,
|
||
|
'pid': 21162,
|
||
|
'task': 0,
|
||
|
'attr': None,
|
||
|
'name2': None,
|
||
|
'src_name': '/tmp/sdtest.21082-7446-EeefO6/new_root/put_old/',
|
||
|
'name': '/tmp/sdtest.21082-7446-EeefO6/new_root/',
|
||
|
'family': None,
|
||
|
'protocol': None,
|
||
|
'sock_type': None,
|
||
|
'class': None,
|
||
|
})
|
||
|
|
||
|
obj = PivotRootRule(parsed_event['src_name'], parsed_event['name'], PivotRootRule.ALL, log_event=parsed_event)
|
||
|
|
||
|
# audit allow deny comment oldroot all? newroot all? target all?
|
||
|
expected = exp(False, False, False, '', '/tmp/sdtest.21082-7446-EeefO6/new_root/put_old/', False, '/tmp/sdtest.21082-7446-EeefO6/new_root/', False, None, True)
|
||
|
|
||
|
self._compare_obj(obj, expected)
|
||
|
|
||
|
self.assertEqual(
|
||
|
obj.get_raw(1),
|
||
|
' pivot_root oldroot=/tmp/sdtest.21082-7446-EeefO6/new_root/put_old/ /tmp/sdtest.21082-7446-EeefO6/new_root/,')
|
||
|
|
||
|
|
||
|
class PivotRootFromInit(PivotRootTest):
|
||
|
tests = (
|
||
|
# PivotRootRule object audit allow deny comment oldroot all? newroot all? profile_name all?
|
||
|
(PivotRootRule('/oldroot', '/new/root', 'some_profile', deny=True), exp(False, False, True, '', '/oldroot', False, '/new/root', False, 'some_profile', False)),
|
||
|
(PivotRootRule('/oldroot', '/new/root', PivotRootRule.ALL, deny=True), exp(False, False, True, '', '/oldroot', False, '/new/root', False, None, True)),
|
||
|
(PivotRootRule('/oldroot', PivotRootRule.ALL, '/someprofile', deny=True), exp(False, False, True, '', '/oldroot', False, None, True, '/someprofile', False)),
|
||
|
(PivotRootRule(PivotRootRule.ALL, '/new/root', '/someprofile', deny=True), exp(False, False, True, '', None, True, '/new/root', False, '/someprofile', False)),
|
||
|
(PivotRootRule('/oldroot', PivotRootRule.ALL, PivotRootRule.ALL, deny=True), exp(False, False, True, '', '/oldroot', False, None, True, None, True)),
|
||
|
(PivotRootRule(PivotRootRule.ALL, '/new/root', PivotRootRule.ALL, deny=True), exp(False, False, True, '', None, True, '/new/root', False, None, True)),
|
||
|
(PivotRootRule(PivotRootRule.ALL, PivotRootRule.ALL, 'some_profile', deny=True), exp(False, False, True, '', None, True, None, True, 'some_profile', False)),
|
||
|
(PivotRootRule(PivotRootRule.ALL, PivotRootRule.ALL, PivotRootRule.ALL, deny=True), exp(False, False, True, '', None, True, None, True, None, True)),
|
||
|
)
|
||
|
|
||
|
def _run_test(self, obj, expected):
|
||
|
self._compare_obj(obj, expected)
|
||
|
|
||
|
|
||
|
class InvalidPivotRootInit(AATest):
|
||
|
tests = (
|
||
|
# (init params, expected exception)
|
||
|
(('', '/foo', 'bar'), AppArmorBug), # empty oldroot
|
||
|
(('/old', '', 'bar'), AppArmorBug), # empty newroot
|
||
|
(('/old', '/foo', '' ), AppArmorBug), # empty targetprof # noqa: E202
|
||
|
|
||
|
(('old', '/foo', 'bar'), AppArmorException), # oldroot is not a path
|
||
|
(('/old', 'foo', 'bar'), AppArmorException), # newroot is not a path
|
||
|
|
||
|
|
||
|
((None, '/foo', 'bar'), AppArmorBug), # wrong type
|
||
|
(('/old', None, 'bar'), AppArmorBug), #
|
||
|
(('/old', '/foo', None ), AppArmorBug), # noqa: E202
|
||
|
|
||
|
((dict(), '/foo', 'bar'), AppArmorBug), # wrong type
|
||
|
(('/old', dict(), 'bar'), AppArmorBug), #
|
||
|
(('/old', '/foo', dict()), AppArmorBug), #
|
||
|
)
|
||
|
|
||
|
def _run_test(self, params, expected):
|
||
|
with self.assertRaises(expected):
|
||
|
PivotRootRule(*params)
|
||
|
|
||
|
def test_missing_params_1(self):
|
||
|
with self.assertRaises(TypeError):
|
||
|
PivotRootRule()
|
||
|
|
||
|
def test_missing_params_2(self):
|
||
|
with self.assertRaises(TypeError):
|
||
|
PivotRootRule('/foo')
|
||
|
|
||
|
def test_missing_params_3(self):
|
||
|
with self.assertRaises(TypeError):
|
||
|
PivotRootRule('/foo', '/bar')
|
||
|
|
||
|
|
||
|
class InvalidPivotRootTest(AATest):
|
||
|
def _check_invalid_rawrule(self, rawrule):
|
||
|
obj = None
|
||
|
self.assertFalse(PivotRootRule.match(rawrule))
|
||
|
with self.assertRaises(AppArmorException):
|
||
|
obj = PivotRootRule.create_instance(rawrule)
|
||
|
|
||
|
self.assertIsNone(obj, 'PivotRootRule handed back an object unexpectedly')
|
||
|
|
||
|
def test_invalid_pivot_root_missing_comma(self):
|
||
|
self._check_invalid_rawrule('pivot_root') # missing comma
|
||
|
|
||
|
def test_invalid_non_PivotRootRule(self):
|
||
|
self._check_invalid_rawrule('dbus,') # not a pivot_root rule
|
||
|
|
||
|
def test_empty_data_1(self):
|
||
|
obj = PivotRootRule('/foo', '/bar', 'prof')
|
||
|
obj.oldroot = ''
|
||
|
# no oldroot set, and ALL not set
|
||
|
with self.assertRaises(AppArmorBug):
|
||
|
obj.get_clean(1)
|
||
|
|
||
|
def test_empty_data_2(self):
|
||
|
obj = PivotRootRule('/foo', '/bar', 'prof')
|
||
|
obj.newroot = ''
|
||
|
# no newroot set, and ALL not set
|
||
|
with self.assertRaises(AppArmorBug):
|
||
|
obj.get_clean(1)
|
||
|
|
||
|
def test_empty_data_3(self):
|
||
|
obj = PivotRootRule('/foo', '/bar', 'prof')
|
||
|
obj.profile_name = ''
|
||
|
# no profile_name set, and ALL not set
|
||
|
with self.assertRaises(AppArmorBug):
|
||
|
obj.get_clean(1)
|
||
|
|
||
|
|
||
|
class WritePivotRootTestAATest(AATest):
|
||
|
def _run_test(self, rawrule, expected):
|
||
|
self.assertTrue(PivotRootRule.match(rawrule))
|
||
|
obj = PivotRootRule.create_instance(rawrule)
|
||
|
clean = obj.get_clean()
|
||
|
raw = obj.get_raw()
|
||
|
|
||
|
self.assertEqual(expected.strip(), clean, 'unexpected clean rule')
|
||
|
self.assertEqual(rawrule.strip(), raw, 'unexpected raw rule')
|
||
|
|
||
|
tests = (
|
||
|
# raw rule clean rule
|
||
|
('pivot_root,', 'pivot_root,'),
|
||
|
(' pivot_root , # foo ', 'pivot_root, # foo'),
|
||
|
(' audit pivot_root /foo,', 'audit pivot_root /foo,'),
|
||
|
(' deny pivot_root /foo ,# foo bar', 'deny pivot_root /foo, # foo bar'),
|
||
|
(' deny pivot_root "/foo" ,# foo bar', 'deny pivot_root /foo, # foo bar'),
|
||
|
(' allow pivot_root ,# foo bar', 'allow pivot_root, # foo bar'),
|
||
|
(' pivot_root oldroot=/old , # foo ', 'pivot_root oldroot=/old, # foo'),
|
||
|
(' pivot_root oldroot="/old" , # foo ', 'pivot_root oldroot=/old, # foo'),
|
||
|
(' pivot_root oldroot=/old -> some_profile , ', 'pivot_root oldroot=/old -> some_profile,'),
|
||
|
(' pivot_root oldroot=/old /new -> some_profile , ', 'pivot_root oldroot=/old /new -> some_profile,'),
|
||
|
)
|
||
|
|
||
|
def test_write_manually(self):
|
||
|
obj = PivotRootRule('/old', '/new', 'target', allow_keyword=True)
|
||
|
|
||
|
expected = ' allow pivot_root oldroot=/old /new -> target,'
|
||
|
|
||
|
self.assertEqual(expected, obj.get_clean(2), 'unexpected clean rule')
|
||
|
self.assertEqual(expected, obj.get_raw(2), 'unexpected raw rule')
|
||
|
|
||
|
|
||
|
class PivotRootCoveredTest(AATest):
|
||
|
def _run_test(self, param, expected):
|
||
|
obj = PivotRootRule.create_instance(self.rule)
|
||
|
check_obj = PivotRootRule.create_instance(param)
|
||
|
|
||
|
self.assertTrue(PivotRootRule.match(param))
|
||
|
|
||
|
self.assertEqual(obj.is_equal(check_obj), expected[0], 'Mismatch in is_equal, expected {}'.format(expected[0]))
|
||
|
self.assertEqual(obj.is_equal(check_obj, True), expected[1], 'Mismatch in is_equal/strict, expected {}'.format(expected[1]))
|
||
|
|
||
|
self.assertEqual(obj.is_covered(check_obj), expected[2], 'Mismatch in is_covered, expected {}'.format(expected[2]))
|
||
|
self.assertEqual(obj.is_covered(check_obj, True, True), expected[3], 'Mismatch in is_covered/exact, expected {}'.format(expected[3]))
|
||
|
|
||
|
|
||
|
class PivotRootCoveredTest_01(PivotRootCoveredTest):
|
||
|
rule = 'pivot_root /new,'
|
||
|
|
||
|
tests = (
|
||
|
# rule equal strict equal covered covered exact
|
||
|
('pivot_root,', (False, False, False, False)),
|
||
|
('pivot_root /n*,', (False, False, False, False)),
|
||
|
('pivot_root oldroot=/old,', (False, False, False, False)),
|
||
|
('pivot_root /new,', (True, False, True, True)),
|
||
|
('pivot_root -> target,', (False, False, False, False)),
|
||
|
('pivot_root oldroot=/old /new,', (False, False, True, True)),
|
||
|
('pivot_root /new -> target,', (False, False, True, True)),
|
||
|
('pivot_root oldroot=/old -> target,', (False, False, False, False)),
|
||
|
('pivot_root oldroot=/old /new -> target,', (False, False, True, True)),
|
||
|
)
|
||
|
|
||
|
|
||
|
class PivotRootCoveredTest_02(PivotRootCoveredTest):
|
||
|
rule = 'audit pivot_root oldroot=/ol*,'
|
||
|
|
||
|
tests = (
|
||
|
# rule equal strict equal covered covered exact
|
||
|
('audit pivot_root,', (False, False, False, False)),
|
||
|
('audit pivot_root oldroot=/ol*,', (True, True, True, True)),
|
||
|
('audit pivot_root oldroot=/old,', (False, False, True, True)),
|
||
|
('audit pivot_root /new,', (False, False, False, False)),
|
||
|
('audit pivot_root -> target,', (False, False, False, False)),
|
||
|
('audit pivot_root oldroot=/old /new,', (False, False, True, True)),
|
||
|
('audit pivot_root /new -> target,', (False, False, False, False)),
|
||
|
('audit pivot_root oldroot=/old -> target,', (False, False, True, True)), # covered exact - really?
|
||
|
('audit pivot_root oldroot=/old /new -> target,', (False, False, True, True)), # covered exact - really?
|
||
|
)
|
||
|
|
||
|
|
||
|
class PivotRootCoveredTest_03(PivotRootCoveredTest):
|
||
|
rule = 'pivot_root -> target,'
|
||
|
|
||
|
tests = (
|
||
|
# rule equal strict equal covered covered exact
|
||
|
('pivot_root,', (False, False, False, False)),
|
||
|
('pivot_root oldroot=/ol*,', (False, False, False, False)),
|
||
|
('pivot_root oldroot=/old,', (False, False, False, False)),
|
||
|
('pivot_root /new,', (False, False, False, False)),
|
||
|
('pivot_root -> target,', (True, False, True, True)),
|
||
|
('pivot_root oldroot=/old /new,', (False, False, False, False)),
|
||
|
('pivot_root /new -> target,', (False, False, True, True)),
|
||
|
('pivot_root oldroot=/old -> target,', (False, False, True, True)),
|
||
|
('pivot_root oldroot=/old /new -> target,', (False, False, True, True)),
|
||
|
)
|
||
|
|
||
|
|
||
|
class PivotRootCoveredTest_04(PivotRootCoveredTest):
|
||
|
rule = 'deny pivot_root /foo,'
|
||
|
|
||
|
tests = (
|
||
|
# rule equal strict equal covered covered exact
|
||
|
(' deny pivot_root /foo,', (True, True, True, True)),
|
||
|
('audit deny pivot_root /foo,', (False, False, False, False)),
|
||
|
(' pivot_root /foo,', (False, False, False, False)), # XXX should covered be true here?
|
||
|
(' deny pivot_root /bar,', (False, False, False, False)),
|
||
|
(' deny pivot_root,', (False, False, False, False)),
|
||
|
)
|
||
|
|
||
|
|
||
|
class PivotRootCoveredTest_Invalid(AATest):
|
||
|
# TODO: should this be detected?
|
||
|
# def test_borked_obj_is_covered_1(self):
|
||
|
# obj = PivotRootRule.create_instance('pivot_root oldroot=/old /new -> target,')
|
||
|
|
||
|
# testobj = PivotRootRule('/old', '/foo', 'targetprof')
|
||
|
# testobj.oldrooot = None
|
||
|
|
||
|
# with self.assertRaises(AppArmorBug):
|
||
|
# obj.is_covered(testobj)
|
||
|
|
||
|
def test_borked_obj_is_covered_2(self):
|
||
|
obj = PivotRootRule.create_instance('pivot_root oldroot=/old /new -> target,')
|
||
|
|
||
|
testobj = PivotRootRule('/old', '/foo', 'targetprof')
|
||
|
testobj.newroot = ''
|
||
|
|
||
|
with self.assertRaises(AppArmorBug):
|
||
|
obj.is_covered(testobj)
|
||
|
|
||
|
# def test_borked_obj_is_covered_3(self):
|
||
|
# TODO: should this be detected?
|
||
|
# obj = PivotRootRule.create_instance('pivot_root oldroot=/old /new -> target,')
|
||
|
|
||
|
# testobj = PivotRootRule('/old', '/foo', 'targetprof')
|
||
|
# testobj.profile_name = ''
|
||
|
|
||
|
# with self.assertRaises(AppArmorBug):
|
||
|
# obj.is_covered(testobj)
|
||
|
|
||
|
def test_invalid_is_covered(self):
|
||
|
raw_rule = 'pivot_root oldroot=/old /new -> target,'
|
||
|
|
||
|
class SomeOtherClass(PivotRootRule):
|
||
|
pass
|
||
|
|
||
|
obj = PivotRootRule.create_instance(raw_rule)
|
||
|
testobj = SomeOtherClass.create_instance(raw_rule) # different type
|
||
|
with self.assertRaises(AppArmorBug):
|
||
|
obj.is_covered(testobj)
|
||
|
|
||
|
def test_invalid_is_equal_1(self):
|
||
|
raw_rule = 'pivot_root oldroot=/old /new -> target,'
|
||
|
|
||
|
class SomeOtherClass(PivotRootRule):
|
||
|
pass
|
||
|
|
||
|
obj = PivotRootRule.create_instance(raw_rule)
|
||
|
testobj = SomeOtherClass.create_instance(raw_rule) # different type
|
||
|
with self.assertRaises(AppArmorBug):
|
||
|
obj.is_equal(testobj)
|
||
|
|
||
|
# def test_invalid_is_equal_2(self):
|
||
|
# TODO: should this be detected?
|
||
|
# obj = PivotRootRule.create_instance('pivot_root oldroot=/old /new -> target,')
|
||
|
|
||
|
# testobj = PivotRootRule.create_instance('pivot_root oldroot=/old /new -> target,')
|
||
|
# testobj.all_oldroots = False # make testobj invalid (should trigger exception in _is_equal_aare())
|
||
|
|
||
|
# with self.assertRaises(AppArmorBug):
|
||
|
# obj.is_equal(testobj)
|
||
|
|
||
|
|
||
|
class PivotRootLogprofHeaderTest(AATest):
|
||
|
tests = (
|
||
|
('pivot_root,', [ _('Old root'), _('ALL'), _('New root'), _('ALL'), _('Target profile'), _('ALL')]), # noqa: E201
|
||
|
('pivot_root oldroot=/old,', [ _('Old root'), '/old', _('New root'), _('ALL'), _('Target profile'), _('ALL')]), # noqa: E201
|
||
|
('deny pivot_root,', [_('Qualifier'), 'deny', _('Old root'), _('ALL'), _('New root'), _('ALL'), _('Target profile'), _('ALL')]),
|
||
|
('allow pivot_root oldroot=/old,', [_('Qualifier'), 'allow', _('Old root'), '/old', _('New root'), _('ALL'), _('Target profile'), _('ALL')]),
|
||
|
('audit pivot_root /new,', [_('Qualifier'), 'audit', _('Old root'), _('ALL'), _('New root'), '/new', _('Target profile'), _('ALL')]),
|
||
|
('audit deny pivot_root /new -> target,', [_('Qualifier'), 'audit deny', _('Old root'), _('ALL'), _('New root'), '/new', _('Target profile'), 'target']),
|
||
|
('pivot_root oldroot=/old /new -> target,', [ _('Old root'), '/old', _('New root'), '/new', _('Target profile'), 'target']), # noqa: E201
|
||
|
)
|
||
|
|
||
|
def _run_test(self, params, expected):
|
||
|
obj = PivotRootRule.create_instance(params)
|
||
|
self.assertEqual(obj.logprof_header(), expected)
|
||
|
|
||
|
|
||
|
class PivotRootEditHeaderTest(AATest):
|
||
|
def _run_test(self, params, expected):
|
||
|
rule_obj = PivotRootRule.create_instance(params)
|
||
|
self.assertEqual(rule_obj.can_edit, True)
|
||
|
prompt, path_to_edit = rule_obj.edit_header()
|
||
|
self.assertEqual(path_to_edit, expected)
|
||
|
|
||
|
tests = (
|
||
|
('pivot_root oldroot=/old /foo/bar/baz -> target,', '/foo/bar/baz'),
|
||
|
('pivot_root /foo/**/baz,', '/foo/**/baz'),
|
||
|
('pivot_root /foo/** -> /bar,', '/foo/**'),
|
||
|
)
|
||
|
|
||
|
def test_edit_header_bare_pivot_root(self):
|
||
|
rule_obj = PivotRootRule.create_instance('pivot_root,')
|
||
|
self.assertEqual(rule_obj.can_edit, False)
|
||
|
with self.assertRaises(AppArmorBug):
|
||
|
rule_obj.edit_header()
|
||
|
|
||
|
|
||
|
class PivotRootValidateAndStoreEditTest(AATest):
|
||
|
def _run_test(self, params, expected):
|
||
|
rule_obj = PivotRootRule('/old/', '/foo/bar/baz', 'target', log_event=True)
|
||
|
|
||
|
self.assertEqual(rule_obj.validate_edit(params), expected)
|
||
|
|
||
|
rule_obj.store_edit(params)
|
||
|
self.assertEqual(rule_obj.get_raw(), 'pivot_root oldroot=/old/ ' + params + ' -> target,')
|
||
|
|
||
|
tests = (
|
||
|
# edited path match
|
||
|
('/foo/bar/baz', True),
|
||
|
('/foo/bar/*', True),
|
||
|
('/foo/bar/???', True),
|
||
|
('/foo/xy**', False),
|
||
|
('/foo/bar/baz/', False),
|
||
|
)
|
||
|
|
||
|
def test_validate_not_a_path(self):
|
||
|
rule_obj = PivotRootRule.create_instance('pivot_root /foo/bar/baz,')
|
||
|
|
||
|
with self.assertRaises(AppArmorException):
|
||
|
rule_obj.validate_edit('foo/bar/baz')
|
||
|
|
||
|
with self.assertRaises(AppArmorException):
|
||
|
rule_obj.store_edit('foo/bar/baz')
|
||
|
|
||
|
def test_validate_edit_bare_pivot_root(self):
|
||
|
rule_obj = PivotRootRule.create_instance('pivot_root,')
|
||
|
self.assertEqual(rule_obj.can_edit, False)
|
||
|
|
||
|
with self.assertRaises(AppArmorBug):
|
||
|
rule_obj.validate_edit('/foo/bar')
|
||
|
|
||
|
with self.assertRaises(AppArmorBug):
|
||
|
rule_obj.store_edit('/foo/bar')
|
||
|
|
||
|
|
||
|
# --- tests for PivotRootRuleset --- #
|
||
|
|
||
|
class PivotRootRulesTest(AATest):
|
||
|
def test_empty_ruleset(self):
|
||
|
ruleset = PivotRootRuleset()
|
||
|
ruleset_2 = PivotRootRuleset()
|
||
|
self.assertEqual([], ruleset.get_raw(2))
|
||
|
self.assertEqual([], ruleset.get_clean(2))
|
||
|
self.assertEqual([], ruleset_2.get_raw(2))
|
||
|
self.assertEqual([], ruleset_2.get_clean(2))
|
||
|
|
||
|
# test __repr__() for empty ruleset
|
||
|
self.assertEqual(str(ruleset), '<PivotRootRuleset (empty) />')
|
||
|
|
||
|
def test_ruleset_1(self):
|
||
|
ruleset = PivotRootRuleset()
|
||
|
rules = (
|
||
|
'pivot_root oldroot=/foo,',
|
||
|
'pivot_root /new,',
|
||
|
)
|
||
|
|
||
|
expected_raw = [
|
||
|
'pivot_root oldroot=/foo,',
|
||
|
'pivot_root /new,',
|
||
|
'',
|
||
|
]
|
||
|
|
||
|
expected_clean = [
|
||
|
'pivot_root /new,',
|
||
|
'pivot_root oldroot=/foo,',
|
||
|
'',
|
||
|
]
|
||
|
|
||
|
for rule in rules:
|
||
|
ruleset.add(PivotRootRule.create_instance(rule))
|
||
|
|
||
|
self.assertEqual(expected_raw, ruleset.get_raw())
|
||
|
self.assertEqual(expected_clean, ruleset.get_clean())
|
||
|
|
||
|
# test __repr__() for non-empty ruleset
|
||
|
self.assertEqual(
|
||
|
str(ruleset), '<PivotRootRuleset>\n pivot_root oldroot=/foo,\n pivot_root /new,\n</PivotRootRuleset>')
|
||
|
|
||
|
|
||
|
class PivotRootGlobTestAATest(AATest):
|
||
|
def test_glob(self):
|
||
|
glob_list = [(
|
||
|
'pivot_root /foo/bar,',
|
||
|
'pivot_root /foo/*,',
|
||
|
'pivot_root /**,',
|
||
|
)]
|
||
|
for globs in glob_list:
|
||
|
for i in range(len(globs) - 1):
|
||
|
rule = PivotRootRule.create_instance(globs[i])
|
||
|
rule.glob()
|
||
|
self.assertEqual(rule.get_clean(), globs[i + 1])
|
||
|
|
||
|
def test_glob_all(self):
|
||
|
glob_list = [(
|
||
|
'pivot_root,',
|
||
|
'pivot_root,',
|
||
|
)]
|
||
|
for globs in glob_list:
|
||
|
for i in range(len(globs) - 1):
|
||
|
rule = PivotRootRule.create_instance(globs[i])
|
||
|
rule.glob()
|
||
|
self.assertEqual(rule.get_clean(), globs[i + 1])
|
||
|
|
||
|
|
||
|
# def test_glob_ext(self):
|
||
|
# # rule = PivotRootRule.create_instance('pivot_root /foo/bar,')
|
||
|
# with self.assertRaises(NotImplementedError):
|
||
|
# # get_glob_ext is not available for pivot_root rules
|
||
|
# self.ruleset.get_glob_ext('pivot_root /foo,')
|
||
|
|
||
|
|
||
|
# class PivotRootDeleteTestAATest(AATest):
|
||
|
# pass
|
||
|
|
||
|
|
||
|
setup_all_loops(__name__)
|
||
|
if __name__ == '__main__':
|
||
|
unittest.main(verbosity=1)
|