diff --git a/utils/apparmor/regex.py b/utils/apparmor/regex.py index 1c78df37a..da936f98f 100644 --- a/utils/apparmor/regex.py +++ b/utils/apparmor/regex.py @@ -145,16 +145,23 @@ RE_MAGIC_OR_QUOTED_PATH = '(<(?P.*)>|"(?P.*)"|(?P\s+if\s+exists)?\s*' + RE_MAGIC_OR_QUOTED_PATH + RE_EOL) +def re_match_include_parse(line, rule_name): + '''Matches the path for include, include if exists and abi rules + + rule_name can be 'include' or 'abi' -def re_match_include_parse(line): - '''Matches the path for include or include if exists. Returns a tuple with - if the "if exists" condition is given - - the include path + - the include/abi path - if the path is a magic path (enclosed in <...>) ''' - matches = RE_INCLUDE.search(line) + if rule_name == 'include': + matches = RE_INCLUDE.search(line) + elif rule_name == 'abi': + matches = RE_ABI.search(line) + else: + raise AppArmorBug('re_match_include_parse() called with invalid rule name %s' % rule_name) if not matches: return None, None, None @@ -167,31 +174,31 @@ def re_match_include_parse(line): elif matches.group('unquotedpath'): # LP: #1738879 - parser doesn't handle unquoted paths everywhere # path = matches.group('unquotedpath').strip() - raise AppArmorException(_('Syntax error: #include must use quoted path or <...>')) + raise AppArmorException(_('Syntax error: %s must use quoted path or <...>') % rule_name) elif matches.group('quotedpath'): path = matches.group('quotedpath') # LP: 1738880 - parser doesn't handle relative paths everywhere, and # neither do we (see aa.py) if len(path) > 0 and path[0] != '/': - raise AppArmorException(_('Syntax error: #include must use quoted path or <...>')) + raise AppArmorException(_('Syntax error: %s must use quoted path or <...>') % rule_name) # if path is empty or the empty string if path is None or path == "": - raise AppArmorException(_('Syntax error: #include rule with empty filename')) + raise AppArmorException(_('Syntax error: %s rule with empty filename') % rule_name) # LP: #1738877 - parser doesn't handle files with spaces in the name if re.search('\s', path): - raise AppArmorException(_('Syntax error: #include rule filename cannot contain spaces')) + raise AppArmorException(_('Syntax error: %s rule filename cannot contain spaces') % rule_name) ifexists = False - if matches.group('ifexists'): + if rule_name == 'include' and matches.group('ifexists'): ifexists = True return path, ifexists, ismagic def re_match_include(line): ''' return path of a 'include' rule ''' - (path, ifexists, ismagic) = re_match_include_parse(line) + (path, ifexists, ismagic) = re_match_include_parse(line, 'include') if not ifexists: return path diff --git a/utils/apparmor/rule/include.py b/utils/apparmor/rule/include.py index d93d675b3..66bf9c5e2 100644 --- a/utils/apparmor/rule/include.py +++ b/utils/apparmor/rule/include.py @@ -68,7 +68,7 @@ class IncludeRule(BaseRule): comment = parse_comment(matches) # TODO: move re_match_include_parse() from regex.py to this class after converting all code to use IncludeRule - path, ifexists, ismagic = re_match_include_parse(raw_rule) + path, ifexists, ismagic = re_match_include_parse(raw_rule, cls.rule_name) return IncludeRule(path, ifexists, ismagic, audit=False, deny=False, allow_keyword=False, comment=comment) diff --git a/utils/test/test-regex_matches.py b/utils/test/test-regex_matches.py index cfae050e0..7f3355fa4 100644 --- a/utils/test/test-regex_matches.py +++ b/utils/test/test-regex_matches.py @@ -567,10 +567,47 @@ class Test_re_match_include_parse(AATest): (' /etc/fstab r,', (None, None, None ) ), ('/usr/include r,', (None, None, None ) ), ('/include r,', (None, None, None ) ), + ('abi ,', (None, None, None ) ), # abi rule ] def _run_test(self, params, expected): - self.assertEqual(re_match_include_parse(params), expected) + self.assertEqual(re_match_include_parse(params, 'include'), expected) + +class Test_re_match_include_parse_abi(AATest): + tests = [ + # path if exists magic path + ('abi ,', ('abi/4.19', False, True ) ), # magic path + ('abi , # comment', ('abi/4.19', False, True ) ), + (' abi , # comment', ('abi/4.19', False, True ) ), + ('abi "/abi/4.19" ,', ('/abi/4.19', False, False) ), # quoted path starting with / + ('abi "/abi/4.19", # comment', ('/abi/4.19', False, False) ), + (' abi "/abi/4.19" , # comment ', ('/abi/4.19', False, False) ), +# (' abi "abi/4.19" , # comment ', ('abi/4.19', False, False) ), # quoted path, no leading / +# ('abi abi/4.19,', ('abi/4.19', False, False) ), # without quotes + ('some abi ,', (None, None, None ) ), # non-matching + (' /etc/fstab r,', (None, None, None ) ), + ('/usr/abi r,', (None, None, None ) ), + ('/abi r,', (None, None, None ) ), + ('#include ', (None, None, None ) ), # include rule path + ] + + def _run_test(self, params, expected): + self.assertEqual(re_match_include_parse(params, 'abi'), expected) + +class Test_re_match_include_parse_empty_filename(AATest): + tests = [ + (('include <>', 'include'), AppArmorException), + (('include ""', 'include'), AppArmorException), + (('include ', 'include'), AppArmorException), + (('abi <>,', 'abi'), AppArmorException), + (('abi "",', 'abi'), AppArmorException), + (('abi ,', 'abi'), AppArmorException), + ] + + def _run_test(self, params, expected): + with self.assertRaises(expected): + rule, rule_name = params + re_match_include_parse(rule, rule_name) class TestStripParenthesis(AATest): tests = [