https://launchpad.net/bugs/1584069
This patch adds support for the safe and unsafe exec modes for change_profile rules. The logic is pretty simple at this point because the kernel's default for exec modes changed in newer versions. Therefore, this patch simply retains any specified exec mode in parsed rules. If an exec mode is not specified in a rule, there is no attempt to force the usage of "safe" because older kernels do not support it. Signed-off-by: Tyler Hicks <tyhi...@canonical.com> Acked-by: Seth Arnold <seth.arn...@canonical.com> --- * Changes since v1: - Added Seth's acked-by - Addressed feedback from Christian + Embed execmode name in RE_SAFE_OR_UNSAFE + AppArmorBug() when an invalid execmode is used in a new ChangeProfileRule() + Don't use logprof_value_or_all() when setting execmode_txt + Only return "Exec Mode" element from logprof_header_localvars() when an execmode is set + Add invalid execcmode test to InvalidChangeProfileInit() + Make 'safe' execmode equivalent to '' and None utils/apparmor/regex.py | 2 + utils/apparmor/rule/change_profile.py | 41 ++++++++-- utils/test/test-change_profile.py | 136 +++++++++++++++++++-------------- utils/test/test-parser-simple-tests.py | 5 ++ 4 files changed, 123 insertions(+), 61 deletions(-) diff --git a/utils/apparmor/regex.py b/utils/apparmor/regex.py index 756c3e0..1e7e16d 100644 --- a/utils/apparmor/regex.py +++ b/utils/apparmor/regex.py @@ -30,6 +30,7 @@ RE_PROFILE_NAME = '(?P<%s>(\S+|"[^"]+"))' # string without spaces, or RE_PATH = '/\S+|"/[^"]+"' # filename (starting with '/') without spaces, or quoted filename. RE_PROFILE_PATH = '(?P<%s>(' + RE_PATH + '))' # quoted or unquoted filename. %s is the match group name RE_PROFILE_PATH_OR_VAR = '(?P<%s>(' + RE_PATH + '|@{\S+}\S*|"@{\S+}[^"]*"))' # quoted or unquoted filename or variable. %s is the match group name +RE_SAFE_OR_UNSAFE = '(?P<execmode>(safe|unsafe))' RE_PROFILE_END = re.compile('^\s*\}' + RE_EOL) RE_PROFILE_CAP = re.compile(RE_AUDIT_DENY + 'capability(?P<capability>(\s+\S+)+)?' + RE_COMMA_EOL) @@ -77,6 +78,7 @@ RE_PROFILE_START = re.compile( RE_PROFILE_CHANGE_PROFILE = re.compile( RE_AUDIT_DENY + 'change_profile' + + '(\s+' + RE_SAFE_OR_UNSAFE + ')?' + # optionally exec mode '(\s+' + RE_PROFILE_PATH_OR_VAR % 'execcond' + ')?' + # optionally exec condition '(\s+->\s*' + RE_PROFILE_NAME % 'targetprofile' + ')?' + # optionally '->' target profile RE_COMMA_EOL) diff --git a/utils/apparmor/rule/change_profile.py b/utils/apparmor/rule/change_profile.py index 6063b70..7eb5062 100644 --- a/utils/apparmor/rule/change_profile.py +++ b/utils/apparmor/rule/change_profile.py @@ -34,11 +34,13 @@ class ChangeProfileRule(BaseRule): rule_name = 'change_profile' - def __init__(self, execcond, targetprofile, audit=False, deny=False, allow_keyword=False, + equiv_execmodes = [ 'safe', '', None ] + + def __init__(self, execmode, execcond, targetprofile, audit=False, deny=False, allow_keyword=False, comment='', log_event=None): ''' - CHANGE_PROFILE RULE = 'change_profile' [ EXEC COND ] [ -> PROGRAMCHILD ] + CHANGE_PROFILE RULE = 'change_profile' [ [ EXEC MODE ] EXEC COND ] [ -> PROGRAMCHILD ] ''' super(ChangeProfileRule, self).__init__(audit=audit, deny=deny, @@ -46,6 +48,13 @@ class ChangeProfileRule(BaseRule): comment=comment, log_event=log_event) + if execmode: + if execmode != 'safe' and execmode != 'unsafe': + raise AppArmorBug('Unknown exec mode (%s) in change_profile rule' % execmode) + elif not execcond or execcond == ChangeProfileRule.ALL: + raise AppArmorException('Exec condition is required when unsafe or safe keywords are present') + self.execmode = execmode + self.execcond = None self.all_execconds = False if execcond == ChangeProfileRule.ALL: @@ -86,6 +95,8 @@ class ChangeProfileRule(BaseRule): audit, deny, allow_keyword, comment = parse_modifiers(matches) + execmode = matches.group('execmode') + if matches.group('execcond'): execcond = strip_quotes(matches.group('execcond')) else: @@ -96,7 +107,7 @@ class ChangeProfileRule(BaseRule): else: targetprofile = ChangeProfileRule.ALL - return ChangeProfileRule(execcond, targetprofile, + return ChangeProfileRule(execmode, execcond, targetprofile, audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment) def get_clean(self, depth=0): @@ -104,6 +115,11 @@ class ChangeProfileRule(BaseRule): space = ' ' * depth + if self.execmode: + execmode = ' %s' % self.execmode + else: + execmode = '' + if self.all_execconds: execcond = '' elif self.execcond: @@ -118,11 +134,16 @@ class ChangeProfileRule(BaseRule): else: raise AppArmorBug('Empty target profile in change_profile rule') - return('%s%schange_profile%s%s,%s' % (space, self.modifiers_str(), execcond, targetprofile, self.comment)) + return('%s%schange_profile%s%s%s,%s' % (space, self.modifiers_str(), execmode, execcond, targetprofile, self.comment)) def is_covered_localvars(self, other_rule): '''check if other_rule is covered by this rule object''' + if self.execmode != other_rule.execmode and \ + (self.execmode not in ChangeProfileRule.equiv_execmodes or \ + other_rule.execmode not in ChangeProfileRule.equiv_execmodes): + return False + if not self._is_covered_plain(self.execcond, self.all_execconds, other_rule.execcond, other_rule.all_execconds, 'exec condition'): # TODO: honor globbing and variables return False @@ -139,6 +160,11 @@ class ChangeProfileRule(BaseRule): if not type(rule_obj) == ChangeProfileRule: raise AppArmorBug('Passed non-change_profile rule: %s' % str(rule_obj)) + if self.execmode != rule_obj.execmode and \ + (self.execmode not in ChangeProfileRule.equiv_execmodes or \ + rule_obj.execmode not in ChangeProfileRule.equiv_execmodes): + return False + if (self.execcond != rule_obj.execcond or self.all_execconds != rule_obj.all_execconds): return False @@ -150,10 +176,15 @@ class ChangeProfileRule(BaseRule): return True def logprof_header_localvars(self): + headers = [] + + if self.execmode: + headers += [_('Exec Mode'), self.execmode] + execcond_txt = logprof_value_or_all(self.execcond, self.all_execconds) targetprofiles_txt = logprof_value_or_all(self.targetprofile, self.all_targetprofiles) - return [ + return headers + [ _('Exec Condition'), execcond_txt, _('Target Profile'), targetprofiles_txt, ] diff --git a/utils/test/test-change_profile.py b/utils/test/test-change_profile.py index 40003d2..32a684c 100644 --- a/utils/test/test-change_profile.py +++ b/utils/test/test-change_profile.py @@ -25,7 +25,7 @@ from apparmor.translations import init_translation _ = init_translation() exp = namedtuple('exp', ['audit', 'allow_keyword', 'deny', 'comment', - 'execcond', 'all_execconds', 'targetprofile', 'all_targetprofiles']) + 'execmode', 'execcond', 'all_execconds', 'targetprofile', 'all_targetprofiles']) # --- tests for single ChangeProfileRule --- # @@ -33,6 +33,7 @@ class ChangeProfileTest(AATest): def _compare_obj(self, obj, expected): self.assertEqual(expected.allow_keyword, obj.allow_keyword) self.assertEqual(expected.audit, obj.audit) + self.assertEqual(expected.execmode, obj.execmode) self.assertEqual(expected.execcond, obj.execcond) self.assertEqual(expected.targetprofile, obj.targetprofile) self.assertEqual(expected.all_execconds, obj.all_execconds) @@ -42,29 +43,33 @@ class ChangeProfileTest(AATest): class ChangeProfileTestParse(ChangeProfileTest): tests = [ - # rawrule audit allow deny comment execcond all? targetprof all? - ('change_profile,' , exp(False, False, False, '' , None , True , None , True )), - ('change_profile /foo,' , exp(False, False, False, '' , '/foo', False, None , True )), - ('change_profile /foo -> /bar,' , exp(False, False, False, '' , '/foo', False, '/bar' , False)), - ('deny change_profile /foo -> /bar, # comment' , exp(False, False, True , ' # comment' , '/foo', False, '/bar' , False)), - ('audit allow change_profile /foo,' , exp(True , True , False, '' , '/foo', False, None , True )), - ('change_profile -> /bar,' , exp(False, False, False, '' , None , True , '/bar' , False)), - ('audit allow change_profile -> /bar,' , exp(True , True , False, '' , None , True , '/bar' , False)), + # 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)), # quoted versions - ('change_profile "/foo",' , exp(False, False, False, '' , '/foo', False, None , True )), - ('change_profile "/foo" -> "/bar",' , exp(False, False, False, '' , '/foo', False, '/bar' , False)), - ('deny change_profile "/foo" -> "/bar", # cmt' , exp(False, False, True, ' # cmt' , '/foo', False, '/bar' , False)), - ('audit allow change_profile "/foo",' , exp(True , True , False, '' , '/foo', False, None , True )), - ('change_profile -> "/bar",' , exp(False, False, False, '' , None , True , '/bar' , False)), - ('audit allow change_profile -> "/bar",' , exp(True , True , False, '' , None , True , '/bar' , False)), + ('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)), # with globbing and/or named profiles - ('change_profile,' , exp(False, False, False, '' , None , True , None , True )), - ('change_profile /*,' , exp(False, False, False, '' , '/*' , False, None , True )), - ('change_profile /* -> bar,' , exp(False, False, False, '' , '/*' , False, 'bar' , False)), - ('deny change_profile /** -> bar, # comment' , exp(False, False, True , ' # comment' , '/**' , False, 'bar' , False)), - ('audit allow change_profile /**,' , exp(True , True , False, '' , '/**' , False, None , True )), - ('change_profile -> "ba r",' , exp(False, False, False, '' , None , True , 'ba r' , False)), - ('audit allow change_profile -> "ba r",' , exp(True , True , False, '' , None , True , 'ba r' , False)), + ('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)), ] def _run_test(self, rawrule, expected): @@ -77,6 +82,8 @@ class ChangeProfileTestParseInvalid(ChangeProfileTest): tests = [ ('change_profile -> ,' , AppArmorException), ('change_profile foo -> ,' , AppArmorException), + ('change_profile notsafe,' , AppArmorException), + ('change_profile safety -> /bar,' , AppArmorException), ] def _run_test(self, rawrule, expected): @@ -116,10 +123,10 @@ class ChangeProfileTestParseFromLog(ChangeProfileTest): 'name': None, }) - obj = ChangeProfileRule(ChangeProfileRule.ALL, parsed_event['name2'], log_event=parsed_event) + obj = ChangeProfileRule(None, ChangeProfileRule.ALL, parsed_event['name2'], log_event=parsed_event) - # audit allow deny comment execcond all? targetprof all? - expected = exp(False, False, False, '' , None, True, '/foo/rename', False) + # audit allow deny comment execmode execcond all? targetprof all? + expected = exp(False, False, False, '' , None, None, True, '/foo/rename', False) self._compare_obj(obj, expected) @@ -128,13 +135,15 @@ class ChangeProfileTestParseFromLog(ChangeProfileTest): class ChangeProfileFromInit(ChangeProfileTest): tests = [ - # ChangeProfileRule object audit allow deny comment execcond all? targetprof all? - (ChangeProfileRule('/foo', '/bar', deny=True) , exp(False, False, True , '' , '/foo', False, '/bar' , False)), - (ChangeProfileRule('/foo', '/bar') , exp(False, False, False, '' , '/foo', False, '/bar' , False)), - (ChangeProfileRule('/foo', ChangeProfileRule.ALL) , exp(False, False, False, '' , '/foo', False, None , True )), - (ChangeProfileRule(ChangeProfileRule.ALL, '/bar') , exp(False, False, False, '' , None , True , '/bar' , False)), - (ChangeProfileRule(ChangeProfileRule.ALL, - ChangeProfileRule.ALL) , exp(False, False, False, '' , None , True , None , True )), + # 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 )), ] def _run_test(self, obj, expected): @@ -144,20 +153,21 @@ class ChangeProfileFromInit(ChangeProfileTest): class InvalidChangeProfileInit(AATest): tests = [ # init params expected exception - (['/foo', '' ] , AppArmorBug), # empty targetprofile - (['' , '/bar' ] , AppArmorBug), # empty execcond - ([' ', '/bar' ] , AppArmorBug), # whitespace execcond - (['/foo', ' ' ] , AppArmorBug), # whitespace targetprofile - (['xyxy', '/bar' ] , AppArmorException), # invalid execcond - ([dict(), '/bar' ] , AppArmorBug), # wrong type for execcond - ([None , '/bar' ] , AppArmorBug), # wrong type for execcond - (['/foo', dict() ] , AppArmorBug), # wrong type for targetprofile - (['/foo', None ] , AppArmorBug), # wrong type for targetprofile + ([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 ] def _run_test(self, params, expected): with self.assertRaises(expected): - ChangeProfileRule(params[0], params[1]) + ChangeProfileRule(params[0], params[1], params[2]) def test_missing_params_1(self): with self.assertRaises(TypeError): @@ -184,14 +194,14 @@ class InvalidChangeProfileTest(AATest): self._check_invalid_rawrule('dbus,') # not a change_profile rule def test_empty_net_data_1(self): - obj = ChangeProfileRule('/foo', '/bar') + obj = ChangeProfileRule(None, '/foo', '/bar') obj.execcond = '' # no execcond set, and ALL not set with self.assertRaises(AppArmorBug): obj.get_clean(1) def test_empty_net_data_2(self): - obj = ChangeProfileRule('/foo', '/bar') + obj = ChangeProfileRule(None, '/foo', '/bar') obj.targetprofile = '' # no targetprofile set, and ALL not set with self.assertRaises(AppArmorBug): @@ -206,7 +216,7 @@ class WriteChangeProfileTestAATest(AATest): (' 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'), - (' allow change_profile /** -> /bar ,# foo bar' , 'allow change_profile /** -> /bar, # foo bar'), + (' allow change_profile unsafe /** -> /bar ,# foo bar' , 'allow change_profile unsafe /** -> /bar, # foo bar'), (' allow change_profile "/fo o" -> "/b ar",' , 'allow change_profile "/fo o" -> "/b ar",'), ] @@ -220,7 +230,7 @@ class WriteChangeProfileTestAATest(AATest): self.assertEqual(rawrule.strip(), raw, 'unexpected raw rule') def test_write_manually(self): - obj = ChangeProfileRule('/foo', 'bar', allow_keyword=True) + obj = ChangeProfileRule(None, '/foo', 'bar', allow_keyword=True) expected = ' allow change_profile /foo -> bar,' @@ -248,6 +258,8 @@ class ChangeProfileCoveredTest_01(ChangeProfileCoveredTest): # rule equal strict equal covered covered exact (' change_profile,' , [ False , False , False , False ]), (' change_profile /foo,' , [ True , True , True , True ]), + (' change_profile safe /foo,' , [ True , False , True , True ]), + (' change_profile unsafe /foo,' , [ False , False , False , False ]), (' change_profile /foo, # comment', [ True , False , True , True ]), (' allow change_profile /foo,' , [ True , False , True , True ]), (' change_profile /foo,' , [ True , False , True , True ]), @@ -269,6 +281,7 @@ class ChangeProfileCoveredTest_02(ChangeProfileCoveredTest): ( 'change_profile /foo,' , [ False , False , True , False ]), ('audit change_profile /foo,' , [ True , True , True , True ]), ( 'change_profile /foo -> /bar,' , [ False , False , True , False ]), + ( 'change_profile safe /foo -> /bar,' , [ False , False , True , False ]), ('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 ]), @@ -319,12 +332,23 @@ class ChangeProfileCoveredTest_05(ChangeProfileCoveredTest): ( 'deny change_profile,' , [ False , False , False , False ]), ] +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 ]), + ] class ChangeProfileCoveredTest_Invalid(AATest): def test_borked_obj_is_covered_1(self): obj = ChangeProfileRule.parse('change_profile /foo,') - testobj = ChangeProfileRule('/foo', '/bar') + testobj = ChangeProfileRule(None, '/foo', '/bar') testobj.execcond = '' with self.assertRaises(AppArmorBug): @@ -333,7 +357,7 @@ class ChangeProfileCoveredTest_Invalid(AATest): def test_borked_obj_is_covered_2(self): obj = ChangeProfileRule.parse('change_profile /foo,') - testobj = ChangeProfileRule('/foo', '/bar') + testobj = ChangeProfileRule(None, '/foo', '/bar') testobj.targetprofile = '' with self.assertRaises(AppArmorBug): @@ -357,14 +381,14 @@ class ChangeProfileCoveredTest_Invalid(AATest): class ChangeProfileLogprofHeaderTest(AATest): tests = [ - ('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 /foo,', [ _('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 /foo,', [_('Qualifier'), 'allow', _('Exec Condition'), '/foo', _('Target Profile'), _('ALL'), ]), - ('audit deny change_profile,', [_('Qualifier'), 'audit deny', _('Exec Condition'), _('ALL'), _('Target Profile'), _('ALL'), ]), + ('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'), ]), ] def _run_test(self, params, expected): diff --git a/utils/test/test-parser-simple-tests.py b/utils/test/test-parser-simple-tests.py index 304ff98..66b77ab 100644 --- a/utils/test/test-parser-simple-tests.py +++ b/utils/test/test-parser-simple-tests.py @@ -47,6 +47,11 @@ exception_not_raised = [ 'capability/bad_3.sd', 'capability/bad_4.sd', 'change_hat/bad_parsing.sd', + + # The tools don't detect conflicting change_profile exec modes + 'change_profile/onx_conflict_unsafe1.sd', + 'change_profile/onx_conflict_unsafe2.sd', + 'dbus/bad_regex_01.sd', 'dbus/bad_regex_02.sd', 'dbus/bad_regex_03.sd', -- 2.7.4 -- AppArmor mailing list AppArmor@lists.ubuntu.com Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/apparmor