2016-10-01 20:57:09 +02:00
|
|
|
#!/usr/bin/python3
|
2015-05-28 22:23:32 +02:00
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
# 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 common_test import AATest, setup_all_loops
|
|
|
|
|
|
|
|
from apparmor.rule.change_profile import ChangeProfileRule, ChangeProfileRuleset
|
|
|
|
from apparmor.rule import BaseRule
|
|
|
|
from apparmor.common import AppArmorException, AppArmorBug
|
|
|
|
from apparmor.logparser import ReadLog
|
2015-06-06 14:19:09 +02:00
|
|
|
from apparmor.translations import init_translation
|
|
|
|
_ = init_translation()
|
2015-05-28 22:23:32 +02:00
|
|
|
|
|
|
|
exp = namedtuple('exp', ['audit', 'allow_keyword', 'deny', 'comment',
|
2016-07-20 17:24:11 -05:00
|
|
|
'execmode', 'execcond', 'all_execconds', 'targetprofile', 'all_targetprofiles'])
|
2015-05-28 22:23:32 +02:00
|
|
|
|
|
|
|
# --- tests for single ChangeProfileRule --- #
|
|
|
|
|
|
|
|
class ChangeProfileTest(AATest):
|
|
|
|
def _compare_obj(self, obj, expected):
|
|
|
|
self.assertEqual(expected.allow_keyword, obj.allow_keyword)
|
|
|
|
self.assertEqual(expected.audit, obj.audit)
|
2016-07-20 17:24:11 -05:00
|
|
|
self.assertEqual(expected.execmode, obj.execmode)
|
2015-05-28 22:23:32 +02:00
|
|
|
self.assertEqual(expected.execcond, obj.execcond)
|
|
|
|
self.assertEqual(expected.targetprofile, obj.targetprofile)
|
|
|
|
self.assertEqual(expected.all_execconds, obj.all_execconds)
|
|
|
|
self.assertEqual(expected.all_targetprofiles, obj.all_targetprofiles)
|
|
|
|
self.assertEqual(expected.deny, obj.deny)
|
|
|
|
self.assertEqual(expected.comment, obj.comment)
|
|
|
|
|
|
|
|
class ChangeProfileTestParse(ChangeProfileTest):
|
|
|
|
tests = [
|
2016-07-20 17:24:11 -05:00
|
|
|
# rawrule audit allow deny comment execmode execcond all? targetprof all?
|
|
|
|
('change_profile,' , exp(False, False, False, '' , None , None , True , None , True )),
|
|
|
|
('change_profile /foo,' , exp(False, False, False, '' , None , '/foo', False, None , True )),
|
|
|
|
('change_profile safe /foo,' , exp(False, False, False, '' , 'safe' , '/foo', False, None , True )),
|
|
|
|
('change_profile unsafe /foo,' , exp(False, False, False, '' , 'unsafe' , '/foo', False, None , True )),
|
|
|
|
('change_profile /foo -> /bar,' , exp(False, False, False, '' , None , '/foo', False, '/bar' , False)),
|
|
|
|
('change_profile safe /foo -> /bar,' , exp(False, False, False, '' , 'safe' , '/foo', False, '/bar' , False)),
|
|
|
|
('change_profile unsafe /foo -> /bar,' , exp(False, False, False, '' , 'unsafe' , '/foo', False, '/bar' , False)),
|
|
|
|
('deny change_profile /foo -> /bar, # comment' , exp(False, False, True , ' # comment' , None , '/foo', False, '/bar' , False)),
|
|
|
|
('audit allow change_profile safe /foo,' , exp(True , True , False, '' , 'safe' , '/foo', False, None , True )),
|
|
|
|
('change_profile -> /bar,' , exp(False, False, False, '' , None , None , True , '/bar' , False)),
|
|
|
|
('audit allow change_profile -> /bar,' , exp(True , True , False, '' , None , None , True , '/bar' , False)),
|
2015-05-28 22:23:32 +02:00
|
|
|
# quoted versions
|
2016-07-20 17:24:11 -05:00
|
|
|
('change_profile "/foo",' , exp(False, False, False, '' , None , '/foo', False, None , True )),
|
|
|
|
('change_profile "/foo" -> "/bar",' , exp(False, False, False, '' , None , '/foo', False, '/bar' , False)),
|
|
|
|
('deny change_profile "/foo" -> "/bar", # cmt' , exp(False, False, True, ' # cmt' , None , '/foo', False, '/bar' , False)),
|
|
|
|
('audit allow change_profile "/foo",' , exp(True , True , False, '' , None , '/foo', False, None , True )),
|
|
|
|
('change_profile -> "/bar",' , exp(False, False, False, '' , None , None , True , '/bar' , False)),
|
|
|
|
('audit allow change_profile -> "/bar",' , exp(True , True , False, '' , None , None , True , '/bar' , False)),
|
2015-05-28 22:23:32 +02:00
|
|
|
# with globbing and/or named profiles
|
2016-07-20 17:24:11 -05:00
|
|
|
('change_profile,' , exp(False, False, False, '' , None , None , True , None , True )),
|
|
|
|
('change_profile /*,' , exp(False, False, False, '' , None , '/*' , False, None , True )),
|
|
|
|
('change_profile /* -> bar,' , exp(False, False, False, '' , None , '/*' , False, 'bar' , False)),
|
|
|
|
('deny change_profile /** -> bar, # comment' , exp(False, False, True , ' # comment' , None , '/**' , False, 'bar' , False)),
|
|
|
|
('audit allow change_profile /**,' , exp(True , True , False, '' , None , '/**' , False, None , True )),
|
|
|
|
('change_profile -> "ba r",' , exp(False, False, False, '' , None , None , True , 'ba r' , False)),
|
|
|
|
('audit allow change_profile -> "ba r",' , exp(True , True , False, '' , None , None , True , 'ba r' , False)),
|
2015-05-28 22:23:32 +02:00
|
|
|
]
|
|
|
|
|
|
|
|
def _run_test(self, rawrule, expected):
|
|
|
|
self.assertTrue(ChangeProfileRule.match(rawrule))
|
|
|
|
obj = ChangeProfileRule.parse(rawrule)
|
|
|
|
self.assertEqual(rawrule.strip(), obj.raw_rule)
|
|
|
|
self._compare_obj(obj, expected)
|
|
|
|
|
|
|
|
class ChangeProfileTestParseInvalid(ChangeProfileTest):
|
|
|
|
tests = [
|
|
|
|
('change_profile -> ,' , AppArmorException),
|
|
|
|
('change_profile foo -> ,' , AppArmorException),
|
2016-07-20 17:24:11 -05:00
|
|
|
('change_profile notsafe,' , AppArmorException),
|
|
|
|
('change_profile safety -> /bar,' , AppArmorException),
|
2015-05-28 22:23:32 +02:00
|
|
|
]
|
|
|
|
|
|
|
|
def _run_test(self, rawrule, expected):
|
|
|
|
self.assertFalse(ChangeProfileRule.match(rawrule))
|
|
|
|
with self.assertRaises(expected):
|
|
|
|
ChangeProfileRule.parse(rawrule)
|
|
|
|
|
|
|
|
class ChangeProfileTestParseFromLog(ChangeProfileTest):
|
2016-11-19 10:55:03 +01:00
|
|
|
def test_change_profile_from_log(self):
|
2017-08-28 23:15:51 +02:00
|
|
|
parser = ReadLog('', '', '', '')
|
2015-05-28 22:23:32 +02:00
|
|
|
|
|
|
|
event = 'type=AVC msg=audit(1428699242.551:386): apparmor="DENIED" operation="change_profile" profile="/foo/changeprofile" pid=3459 comm="changeprofile" target="/foo/rename"'
|
|
|
|
|
|
|
|
# libapparmor doesn't understand this log format (from JJ)
|
|
|
|
# event = '[ 97.492562] audit: type=1400 audit(1431116353.523:77): apparmor="DENIED" operation="change_profile" profile="/foo/changeprofile" pid=3459 comm="changeprofile" target="/foo/rename"'
|
|
|
|
|
|
|
|
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': '/foo/changeprofile',
|
|
|
|
'operation': 'change_profile',
|
|
|
|
'resource': None,
|
|
|
|
'info': None,
|
|
|
|
'aamode': 'REJECTING',
|
|
|
|
'time': 1428699242,
|
|
|
|
'active_hat': None,
|
|
|
|
'pid': 3459,
|
|
|
|
'task': 0,
|
|
|
|
'attr': None,
|
|
|
|
'name2': '/foo/rename', # target
|
|
|
|
'name': None,
|
2016-11-19 10:55:03 +01:00
|
|
|
'family': None,
|
|
|
|
'protocol': None,
|
|
|
|
'sock_type': None,
|
2015-05-28 22:23:32 +02:00
|
|
|
})
|
|
|
|
|
2016-07-20 17:24:11 -05:00
|
|
|
obj = ChangeProfileRule(None, ChangeProfileRule.ALL, parsed_event['name2'], log_event=parsed_event)
|
2015-05-28 22:23:32 +02:00
|
|
|
|
2016-07-20 17:24:11 -05:00
|
|
|
# audit allow deny comment execmode execcond all? targetprof all?
|
|
|
|
expected = exp(False, False, False, '' , None, None, True, '/foo/rename', False)
|
2015-05-28 22:23:32 +02:00
|
|
|
|
|
|
|
self._compare_obj(obj, expected)
|
|
|
|
|
|
|
|
self.assertEqual(obj.get_raw(1), ' change_profile -> /foo/rename,')
|
|
|
|
|
|
|
|
|
|
|
|
class ChangeProfileFromInit(ChangeProfileTest):
|
|
|
|
tests = [
|
2016-07-20 17:24:11 -05:00
|
|
|
# ChangeProfileRule object audit allow deny comment execmode execcond all? targetprof all?
|
|
|
|
(ChangeProfileRule(None , '/foo', '/bar', deny=True) , exp(False, False, True , '' , None , '/foo', False, '/bar' , False)),
|
|
|
|
(ChangeProfileRule(None , '/foo', '/bar') , exp(False, False, False, '' , None , '/foo', False, '/bar' , False)),
|
|
|
|
(ChangeProfileRule('safe' , '/foo', '/bar') , exp(False, False, False, '' , 'safe' , '/foo', False, '/bar' , False)),
|
|
|
|
(ChangeProfileRule('unsafe', '/foo', '/bar') , exp(False, False, False, '' , 'unsafe', '/foo', False, '/bar' , False)),
|
|
|
|
(ChangeProfileRule(None , '/foo', ChangeProfileRule.ALL) , exp(False, False, False, '' , None , '/foo', False, None , True )),
|
|
|
|
(ChangeProfileRule(None , ChangeProfileRule.ALL, '/bar') , exp(False, False, False, '' , None , None , True , '/bar' , False)),
|
|
|
|
(ChangeProfileRule(None , ChangeProfileRule.ALL,
|
|
|
|
ChangeProfileRule.ALL) , exp(False, False, False, '' , None, None , True , None , True )),
|
2015-05-28 22:23:32 +02:00
|
|
|
]
|
|
|
|
|
|
|
|
def _run_test(self, obj, expected):
|
|
|
|
self._compare_obj(obj, expected)
|
|
|
|
|
|
|
|
|
|
|
|
class InvalidChangeProfileInit(AATest):
|
|
|
|
tests = [
|
|
|
|
# init params expected exception
|
2016-07-20 17:24:11 -05:00
|
|
|
([None , '/foo', '' ] , AppArmorBug), # empty targetprofile
|
|
|
|
([None , '' , '/bar' ] , AppArmorBug), # empty execcond
|
|
|
|
([None , ' ', '/bar' ] , AppArmorBug), # whitespace execcond
|
|
|
|
([None , '/foo', ' ' ] , AppArmorBug), # whitespace targetprofile
|
|
|
|
([None , 'xyxy', '/bar' ] , AppArmorException), # invalid execcond
|
|
|
|
([None , dict(), '/bar' ] , AppArmorBug), # wrong type for execcond
|
|
|
|
([None , None , '/bar' ] , AppArmorBug), # wrong type for execcond
|
|
|
|
([None , '/foo', dict() ] , AppArmorBug), # wrong type for targetprofile
|
|
|
|
([None , '/foo', None ] , AppArmorBug), # wrong type for targetprofile
|
|
|
|
(['maybe' , '/foo', '/bar' ] , AppArmorBug), # invalid keyword for execmode
|
2015-05-28 22:23:32 +02:00
|
|
|
]
|
|
|
|
|
|
|
|
def _run_test(self, params, expected):
|
|
|
|
with self.assertRaises(expected):
|
2016-07-20 17:24:11 -05:00
|
|
|
ChangeProfileRule(params[0], params[1], params[2])
|
2015-05-28 22:23:32 +02:00
|
|
|
|
|
|
|
def test_missing_params_1(self):
|
|
|
|
with self.assertRaises(TypeError):
|
|
|
|
ChangeProfileRule()
|
|
|
|
|
|
|
|
def test_missing_params_2(self):
|
|
|
|
with self.assertRaises(TypeError):
|
|
|
|
ChangeProfileRule('inet')
|
|
|
|
|
|
|
|
|
|
|
|
class InvalidChangeProfileTest(AATest):
|
|
|
|
def _check_invalid_rawrule(self, rawrule):
|
|
|
|
obj = None
|
|
|
|
self.assertFalse(ChangeProfileRule.match(rawrule))
|
|
|
|
with self.assertRaises(AppArmorException):
|
|
|
|
obj = ChangeProfileRule(ChangeProfileRule.parse(rawrule))
|
|
|
|
|
|
|
|
self.assertIsNone(obj, 'ChangeProfileRule handed back an object unexpectedly')
|
|
|
|
|
|
|
|
def test_invalid_net_missing_comma(self):
|
|
|
|
self._check_invalid_rawrule('change_profile') # missing comma
|
|
|
|
|
|
|
|
def test_invalid_net_non_ChangeProfileRule(self):
|
|
|
|
self._check_invalid_rawrule('dbus,') # not a change_profile rule
|
|
|
|
|
|
|
|
def test_empty_net_data_1(self):
|
2016-07-20 17:24:11 -05:00
|
|
|
obj = ChangeProfileRule(None, '/foo', '/bar')
|
2015-05-28 22:23:32 +02:00
|
|
|
obj.execcond = ''
|
|
|
|
# no execcond set, and ALL not set
|
|
|
|
with self.assertRaises(AppArmorBug):
|
|
|
|
obj.get_clean(1)
|
|
|
|
|
|
|
|
def test_empty_net_data_2(self):
|
2016-07-20 17:24:11 -05:00
|
|
|
obj = ChangeProfileRule(None, '/foo', '/bar')
|
2015-05-28 22:23:32 +02:00
|
|
|
obj.targetprofile = ''
|
|
|
|
# no targetprofile set, and ALL not set
|
|
|
|
with self.assertRaises(AppArmorBug):
|
|
|
|
obj.get_clean(1)
|
|
|
|
|
|
|
|
|
|
|
|
class WriteChangeProfileTestAATest(AATest):
|
|
|
|
tests = [
|
|
|
|
# raw rule clean rule
|
|
|
|
(' change_profile , # foo ' , 'change_profile, # foo'),
|
|
|
|
(' audit change_profile /foo,' , 'audit change_profile /foo,'),
|
|
|
|
(' deny change_profile /foo -> bar,# foo bar' , 'deny change_profile /foo -> bar, # foo bar'),
|
|
|
|
(' deny change_profile /foo ,# foo bar' , 'deny change_profile /foo, # foo bar'),
|
|
|
|
(' allow change_profile -> /bar ,# foo bar' , 'allow change_profile -> /bar, # foo bar'),
|
2016-07-20 17:24:11 -05:00
|
|
|
(' allow change_profile unsafe /** -> /bar ,# foo bar' , 'allow change_profile unsafe /** -> /bar, # foo bar'),
|
2015-05-28 22:23:32 +02:00
|
|
|
(' allow change_profile "/fo o" -> "/b ar",' , 'allow change_profile "/fo o" -> "/b ar",'),
|
|
|
|
]
|
|
|
|
|
|
|
|
def _run_test(self, rawrule, expected):
|
|
|
|
self.assertTrue(ChangeProfileRule.match(rawrule))
|
|
|
|
obj = ChangeProfileRule.parse(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')
|
|
|
|
|
|
|
|
def test_write_manually(self):
|
2016-07-20 17:24:11 -05:00
|
|
|
obj = ChangeProfileRule(None, '/foo', 'bar', allow_keyword=True)
|
2015-05-28 22:23:32 +02:00
|
|
|
|
|
|
|
expected = ' allow change_profile /foo -> bar,'
|
|
|
|
|
|
|
|
self.assertEqual(expected, obj.get_clean(2), 'unexpected clean rule')
|
|
|
|
self.assertEqual(expected, obj.get_raw(2), 'unexpected raw rule')
|
|
|
|
|
|
|
|
|
|
|
|
class ChangeProfileCoveredTest(AATest):
|
|
|
|
def _run_test(self, param, expected):
|
|
|
|
obj = ChangeProfileRule.parse(self.rule)
|
|
|
|
check_obj = ChangeProfileRule.parse(param)
|
|
|
|
|
|
|
|
self.assertTrue(ChangeProfileRule.match(param))
|
|
|
|
|
|
|
|
self.assertEqual(obj.is_equal(check_obj), expected[0], 'Mismatch in is_equal, expected %s' % expected[0])
|
|
|
|
self.assertEqual(obj.is_equal(check_obj, True), expected[1], 'Mismatch in is_equal/strict, expected %s' % expected[1])
|
|
|
|
|
|
|
|
self.assertEqual(obj.is_covered(check_obj), expected[2], 'Mismatch in is_covered, expected %s' % expected[2])
|
|
|
|
self.assertEqual(obj.is_covered(check_obj, True, True), expected[3], 'Mismatch in is_covered/exact, expected %s' % expected[3])
|
|
|
|
|
|
|
|
class ChangeProfileCoveredTest_01(ChangeProfileCoveredTest):
|
|
|
|
rule = 'change_profile /foo,'
|
|
|
|
|
|
|
|
tests = [
|
|
|
|
# rule equal strict equal covered covered exact
|
|
|
|
(' change_profile,' , [ False , False , False , False ]),
|
|
|
|
(' change_profile /foo,' , [ True , True , True , True ]),
|
2016-07-20 17:24:11 -05:00
|
|
|
(' change_profile safe /foo,' , [ True , False , True , True ]),
|
|
|
|
(' change_profile unsafe /foo,' , [ False , False , False , False ]),
|
2015-05-28 22:23:32 +02:00
|
|
|
(' change_profile /foo, # comment', [ True , False , True , True ]),
|
|
|
|
(' allow change_profile /foo,' , [ True , False , True , True ]),
|
|
|
|
(' change_profile /foo,' , [ True , False , True , True ]),
|
|
|
|
(' change_profile /foo -> /bar,' , [ False , False , True , True ]),
|
|
|
|
(' change_profile /foo -> bar,' , [ False , False , True , True ]),
|
|
|
|
('audit change_profile /foo,' , [ False , False , False , False ]),
|
|
|
|
('audit change_profile,' , [ False , False , False , False ]),
|
|
|
|
(' change_profile /asdf,' , [ False , False , False , False ]),
|
|
|
|
(' change_profile -> /bar,' , [ False , False , False , False ]),
|
|
|
|
('audit deny change_profile /foo,' , [ False , False , False , False ]),
|
|
|
|
(' deny change_profile /foo,' , [ False , False , False , False ]),
|
|
|
|
]
|
|
|
|
|
|
|
|
class ChangeProfileCoveredTest_02(ChangeProfileCoveredTest):
|
|
|
|
rule = 'audit change_profile /foo,'
|
|
|
|
|
|
|
|
tests = [
|
|
|
|
# rule equal strict equal covered covered exact
|
|
|
|
( 'change_profile /foo,' , [ False , False , True , False ]),
|
|
|
|
('audit change_profile /foo,' , [ True , True , True , True ]),
|
|
|
|
( 'change_profile /foo -> /bar,' , [ False , False , True , False ]),
|
2016-07-20 17:24:11 -05:00
|
|
|
( 'change_profile safe /foo -> /bar,' , [ False , False , True , False ]),
|
2015-05-28 22:23:32 +02:00
|
|
|
('audit change_profile /foo -> /bar,' , [ False , False , True , True ]), # XXX is "covered exact" correct here?
|
|
|
|
( 'change_profile,' , [ False , False , False , False ]),
|
|
|
|
('audit change_profile,' , [ False , False , False , False ]),
|
|
|
|
(' change_profile -> /bar,' , [ False , False , False , False ]),
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
class ChangeProfileCoveredTest_03(ChangeProfileCoveredTest):
|
|
|
|
rule = 'change_profile /foo -> /bar,'
|
|
|
|
|
|
|
|
tests = [
|
|
|
|
# rule equal strict equal covered covered exact
|
|
|
|
( 'change_profile /foo -> /bar,' , [ True , True , True , True ]),
|
|
|
|
('allow change_profile /foo -> /bar,' , [ True , False , True , True ]),
|
|
|
|
( 'change_profile /foo,' , [ False , False , False , False ]),
|
|
|
|
( 'change_profile,' , [ False , False , False , False ]),
|
|
|
|
( 'change_profile /foo -> /xyz,' , [ False , False , False , False ]),
|
|
|
|
('audit change_profile,' , [ False , False , False , False ]),
|
|
|
|
('audit change_profile /foo -> /bar,' , [ False , False , False , False ]),
|
|
|
|
( 'change_profile -> /bar,' , [ False , False , False , False ]),
|
|
|
|
( 'change_profile,' , [ False , False , False , False ]),
|
|
|
|
]
|
|
|
|
|
|
|
|
class ChangeProfileCoveredTest_04(ChangeProfileCoveredTest):
|
|
|
|
rule = 'change_profile,'
|
|
|
|
|
|
|
|
tests = [
|
|
|
|
# rule equal strict equal covered covered exact
|
|
|
|
( 'change_profile,' , [ True , True , True , True ]),
|
|
|
|
('allow change_profile,' , [ True , False , True , True ]),
|
|
|
|
( 'change_profile /foo,' , [ False , False , True , True ]),
|
|
|
|
( 'change_profile /xyz -> bar,' , [ False , False , True , True ]),
|
|
|
|
( 'change_profile -> /bar,' , [ False , False , True , True ]),
|
|
|
|
( 'change_profile /foo -> /bar,' , [ False , False , True , True ]),
|
|
|
|
('audit change_profile,' , [ False , False , False , False ]),
|
|
|
|
('deny change_profile,' , [ False , False , False , False ]),
|
|
|
|
]
|
|
|
|
|
|
|
|
class ChangeProfileCoveredTest_05(ChangeProfileCoveredTest):
|
|
|
|
rule = 'deny change_profile /foo,'
|
|
|
|
|
|
|
|
tests = [
|
|
|
|
# rule equal strict equal covered covered exact
|
|
|
|
( 'deny change_profile /foo,' , [ True , True , True , True ]),
|
|
|
|
('audit deny change_profile /foo,' , [ False , False , False , False ]),
|
|
|
|
( 'change_profile /foo,' , [ False , False , False , False ]), # XXX should covered be true here?
|
|
|
|
( 'deny change_profile /bar,' , [ False , False , False , False ]),
|
|
|
|
( 'deny change_profile,' , [ False , False , False , False ]),
|
|
|
|
]
|
|
|
|
|
2016-07-20 17:24:11 -05:00
|
|
|
class ChangeProfileCoveredTest_06(ChangeProfileCoveredTest):
|
|
|
|
rule = 'change_profile safe /foo,'
|
|
|
|
|
|
|
|
tests = [
|
|
|
|
# rule equal strict equal covered covered exact
|
|
|
|
( 'deny change_profile /foo,' , [ False , False , False , False ]),
|
|
|
|
('audit deny change_profile /foo,' , [ False , False , False , False ]),
|
|
|
|
( 'change_profile /foo,' , [ True , False , True , True ]),
|
|
|
|
( 'deny change_profile /bar,' , [ False , False , False , False ]),
|
|
|
|
( 'deny change_profile,' , [ False , False , False , False ]),
|
|
|
|
]
|
2015-05-28 22:23:32 +02:00
|
|
|
|
|
|
|
class ChangeProfileCoveredTest_Invalid(AATest):
|
|
|
|
def test_borked_obj_is_covered_1(self):
|
|
|
|
obj = ChangeProfileRule.parse('change_profile /foo,')
|
|
|
|
|
2016-07-20 17:24:11 -05:00
|
|
|
testobj = ChangeProfileRule(None, '/foo', '/bar')
|
2015-05-28 22:23:32 +02:00
|
|
|
testobj.execcond = ''
|
|
|
|
|
|
|
|
with self.assertRaises(AppArmorBug):
|
|
|
|
obj.is_covered(testobj)
|
|
|
|
|
|
|
|
def test_borked_obj_is_covered_2(self):
|
|
|
|
obj = ChangeProfileRule.parse('change_profile /foo,')
|
|
|
|
|
2016-07-20 17:24:11 -05:00
|
|
|
testobj = ChangeProfileRule(None, '/foo', '/bar')
|
2015-05-28 22:23:32 +02:00
|
|
|
testobj.targetprofile = ''
|
|
|
|
|
|
|
|
with self.assertRaises(AppArmorBug):
|
|
|
|
obj.is_covered(testobj)
|
|
|
|
|
|
|
|
def test_invalid_is_covered(self):
|
|
|
|
obj = ChangeProfileRule.parse('change_profile /foo,')
|
|
|
|
|
|
|
|
testobj = BaseRule() # different type
|
|
|
|
|
|
|
|
with self.assertRaises(AppArmorBug):
|
|
|
|
obj.is_covered(testobj)
|
|
|
|
|
|
|
|
def test_invalid_is_equal(self):
|
|
|
|
obj = ChangeProfileRule.parse('change_profile -> /bar,')
|
|
|
|
|
|
|
|
testobj = BaseRule() # different type
|
|
|
|
|
|
|
|
with self.assertRaises(AppArmorBug):
|
|
|
|
obj.is_equal(testobj)
|
|
|
|
|
2015-06-06 14:19:09 +02:00
|
|
|
class ChangeProfileLogprofHeaderTest(AATest):
|
|
|
|
tests = [
|
2016-07-20 17:24:11 -05:00
|
|
|
('change_profile,', [ _('Exec Condition'), _('ALL'), _('Target Profile'), _('ALL'), ]),
|
|
|
|
('change_profile -> /bin/ping,', [ _('Exec Condition'), _('ALL'), _('Target Profile'), '/bin/ping',]),
|
|
|
|
('change_profile /bar -> /bin/bar,', [ _('Exec Condition'), '/bar', _('Target Profile'), '/bin/bar', ]),
|
|
|
|
('change_profile safe /foo,', [ _('Exec Mode'), 'safe', _('Exec Condition'), '/foo', _('Target Profile'), _('ALL'), ]),
|
|
|
|
('audit change_profile -> /bin/ping,', [_('Qualifier'), 'audit', _('Exec Condition'), _('ALL'), _('Target Profile'), '/bin/ping',]),
|
|
|
|
('deny change_profile /bar -> /bin/bar,', [_('Qualifier'), 'deny', _('Exec Condition'), '/bar', _('Target Profile'), '/bin/bar', ]),
|
|
|
|
('allow change_profile unsafe /foo,', [_('Qualifier'), 'allow', _('Exec Mode'), 'unsafe', _('Exec Condition'), '/foo', _('Target Profile'), _('ALL'), ]),
|
|
|
|
('audit deny change_profile,', [_('Qualifier'), 'audit deny', _('Exec Condition'), _('ALL'), _('Target Profile'), _('ALL'), ]),
|
2015-06-06 14:19:09 +02:00
|
|
|
]
|
|
|
|
|
|
|
|
def _run_test(self, params, expected):
|
|
|
|
obj = ChangeProfileRule._parse(params)
|
|
|
|
self.assertEqual(obj.logprof_header(), expected)
|
|
|
|
|
2015-05-28 22:23:32 +02:00
|
|
|
# --- tests for ChangeProfileRuleset --- #
|
|
|
|
|
|
|
|
class ChangeProfileRulesTest(AATest):
|
|
|
|
def test_empty_ruleset(self):
|
|
|
|
ruleset = ChangeProfileRuleset()
|
|
|
|
ruleset_2 = ChangeProfileRuleset()
|
|
|
|
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))
|
|
|
|
|
|
|
|
def test_ruleset_1(self):
|
|
|
|
ruleset = ChangeProfileRuleset()
|
|
|
|
rules = [
|
|
|
|
'change_profile -> /bar,',
|
|
|
|
'change_profile /foo,',
|
|
|
|
]
|
|
|
|
|
|
|
|
expected_raw = [
|
|
|
|
'change_profile -> /bar,',
|
|
|
|
'change_profile /foo,',
|
|
|
|
'',
|
|
|
|
]
|
|
|
|
|
|
|
|
expected_clean = [
|
|
|
|
'change_profile -> /bar,',
|
|
|
|
'change_profile /foo,',
|
|
|
|
'',
|
|
|
|
]
|
|
|
|
|
|
|
|
for rule in rules:
|
|
|
|
ruleset.add(ChangeProfileRule.parse(rule))
|
|
|
|
|
|
|
|
self.assertEqual(expected_raw, ruleset.get_raw())
|
|
|
|
self.assertEqual(expected_clean, ruleset.get_clean())
|
|
|
|
|
|
|
|
def test_ruleset_2(self):
|
|
|
|
ruleset = ChangeProfileRuleset()
|
|
|
|
rules = [
|
|
|
|
'change_profile /foo -> /bar,',
|
|
|
|
'allow change_profile /asdf,',
|
|
|
|
'deny change_profile -> xy, # example comment',
|
|
|
|
]
|
|
|
|
|
|
|
|
expected_raw = [
|
|
|
|
' change_profile /foo -> /bar,',
|
|
|
|
' allow change_profile /asdf,',
|
|
|
|
' deny change_profile -> xy, # example comment',
|
|
|
|
'',
|
|
|
|
]
|
|
|
|
|
|
|
|
expected_clean = [
|
|
|
|
' deny change_profile -> xy, # example comment',
|
|
|
|
'',
|
|
|
|
' allow change_profile /asdf,',
|
|
|
|
' change_profile /foo -> /bar,',
|
|
|
|
'',
|
|
|
|
]
|
|
|
|
|
|
|
|
for rule in rules:
|
|
|
|
ruleset.add(ChangeProfileRule.parse(rule))
|
|
|
|
|
|
|
|
self.assertEqual(expected_raw, ruleset.get_raw(1))
|
|
|
|
self.assertEqual(expected_clean, ruleset.get_clean(1))
|
|
|
|
|
|
|
|
|
|
|
|
class ChangeProfileGlobTestAATest(AATest):
|
|
|
|
def setUp(self):
|
|
|
|
self.ruleset = ChangeProfileRuleset()
|
|
|
|
|
|
|
|
def test_glob_1(self):
|
|
|
|
self.assertEqual(self.ruleset.get_glob('change_profile /foo,'), 'change_profile,')
|
|
|
|
|
|
|
|
# not supported or used yet, glob behaviour not decided yet
|
|
|
|
# def test_glob_2(self):
|
|
|
|
# self.assertEqual(self.ruleset.get_glob('change_profile /foo -> /bar,'), 'change_profile -> /bar,')
|
|
|
|
|
|
|
|
def test_glob_ext(self):
|
2015-11-24 00:16:35 +01:00
|
|
|
with self.assertRaises(NotImplementedError):
|
2015-05-28 22:23:32 +02:00
|
|
|
# get_glob_ext is not available for change_profile rules
|
|
|
|
self.ruleset.get_glob_ext('change_profile /foo -> /bar,')
|
|
|
|
|
|
|
|
class ChangeProfileDeleteTestAATest(AATest):
|
|
|
|
pass
|
|
|
|
|
|
|
|
setup_all_loops(__name__)
|
|
|
|
if __name__ == '__main__':
|
2018-04-08 20:18:30 +02:00
|
|
|
unittest.main(verbosity=1)
|