diff --git a/utils/apparmor/rule/__init__.py b/utils/apparmor/rule/__init__.py index 85b9e790a..4d9426839 100644 --- a/utils/apparmor/rule/__init__.py +++ b/utils/apparmor/rule/__init__.py @@ -26,6 +26,8 @@ class BaseRule(object): # type specific rules should inherit from this class. # Methods that subclasses need to implement: # __init__ + # _match(cls, raw_rule) (as a class method) + # - parses a raw rule and returns a regex match object # _parse(cls, raw_rule) (as a class method) # - parses a raw rule and returns an object of the Rule subclass # get_clean(depth) @@ -48,8 +50,26 @@ class BaseRule(object): # Set only in the parse() class method self.raw_rule = None + @classmethod + def match(cls, raw_rule): + '''return True if raw_rule matches the class (main) regex, False otherwise + Note: This function just provides an answer to "is this your job?". + It does not guarantee that the rule is completely valid.''' + + if cls._match(raw_rule): + return True + else: + return False + + # @abstractmethod FIXME - uncomment when python3 only + @classmethod + def _match(cls, raw_rule): + '''parse raw_rule and return regex match object''' + raise AppArmorBug("'%s' needs to implement _match(), but didn't" % (str(cls))) + @classmethod def parse(cls, raw_rule): + '''parse raw_rule and return a rule object''' rule = cls._parse(raw_rule) rule.raw_rule = raw_rule.strip() return rule diff --git a/utils/apparmor/rule/capability.py b/utils/apparmor/rule/capability.py index a7673a0e8..85f1de048 100644 --- a/utils/apparmor/rule/capability.py +++ b/utils/apparmor/rule/capability.py @@ -60,11 +60,15 @@ class CapabilityRule(BaseRule): if len(cap.strip()) == 0: raise AppArmorBug('Passed empty capability to CapabilityRule: %s' % str(cap_list)) + @classmethod + def _match(cls, raw_rule): + return RE_PROFILE_CAP.search(raw_rule) + @classmethod def _parse(cls, raw_rule): '''parse raw_rule and return CapabilityRule''' - matches = RE_PROFILE_CAP.search(raw_rule) + matches = cls._match(raw_rule) if not matches: raise AppArmorException(_("Invalid capability rule '%s'") % raw_rule) diff --git a/utils/apparmor/rule/network.py b/utils/apparmor/rule/network.py index 2e5b2c0c4..21cc95eb2 100644 --- a/utils/apparmor/rule/network.py +++ b/utils/apparmor/rule/network.py @@ -97,11 +97,15 @@ class NetworkRule(BaseRule): else: raise AppArmorBug('Passed unknown object to NetworkRule: %s' % str(type_or_protocol)) + @classmethod + def _match(cls, raw_rule): + return RE_PROFILE_NETWORK.search(raw_rule) + @classmethod def _parse(cls, raw_rule): '''parse raw_rule and return NetworkRule''' - matches = RE_PROFILE_NETWORK.search(raw_rule) + matches = cls._match(raw_rule) if not matches: raise AppArmorException(_("Invalid network rule '%s'") % raw_rule) diff --git a/utils/test/test-baserule.py b/utils/test/test-baserule.py index 82dabbd4b..a73e57403 100644 --- a/utils/test/test-baserule.py +++ b/utils/test/test-baserule.py @@ -22,6 +22,18 @@ class TestBaserule(AATest): with self.assertRaises(AppArmorBug): BaseRule._parse('foo') + def test_abstract__parse_2(self): + with self.assertRaises(AppArmorBug): + BaseRule.parse('foo') + + def test_abstract__match(self): + with self.assertRaises(AppArmorBug): + BaseRule._match('foo') + + def test_abstract__match2(self): + with self.assertRaises(AppArmorBug): + BaseRule.match('foo') + def test_is_equal_localvars(self): obj = BaseRule() with self.assertRaises(AppArmorBug): diff --git a/utils/test/test-capability.py b/utils/test/test-capability.py index 8e9e956bb..fcd607329 100644 --- a/utils/test/test-capability.py +++ b/utils/test/test-capability.py @@ -30,6 +30,7 @@ class CapabilityTest(unittest.TestCase): obj = CapabilityRule.parse(rawrule) + self.assertTrue(CapabilityRule.match(rawrule)) self.assertEqual(rawrule.strip(), obj.raw_rule) self._compare_obj(obj, expected) @@ -220,6 +221,7 @@ class InvalidCapabilityTest(unittest.TestCase): with self.assertRaises(AppArmorException): obj = CapabilityRule(CapabilityRule.parse(rawrule)) + self.assertFalse(CapabilityRule.match(rawrule)) self.assertIsNone(obj, 'CapbilityRule handed back an object unexpectedly') def test_invalid_cap_missing_comma(self): @@ -269,6 +271,7 @@ class WriteCapabilityTest(unittest.TestCase): clean = obj.get_clean() raw = obj.get_raw() + self.assertTrue(CapabilityRule.match(rawrule)) self.assertEqual(cleanrule.strip(), clean, 'unexpected clean rule') self.assertEqual(rawrule.strip(), raw, 'unexpected raw rule') @@ -294,12 +297,15 @@ class CapabilityCoveredTest(unittest.TestCase): self.maxDiff = None def _is_covered(self, obj, rule_to_test): + self.assertTrue(CapabilityRule.match(rule_to_test)) return obj.is_covered(CapabilityRule.parse(rule_to_test)) def _is_covered_exact(self, obj, rule_to_test): + self.assertTrue(CapabilityRule.match(rule_to_test)) return obj.is_covered(CapabilityRule.parse(rule_to_test), True, True) def _is_equal(self, obj, rule_to_test, strict): + self.assertTrue(CapabilityRule.match(rule_to_test)) return obj.is_equal(CapabilityRule.parse(rule_to_test), strict) def test_covered_single(self): diff --git a/utils/test/test-network.py b/utils/test/test-network.py index 9b0f5ca08..2608e4818 100644 --- a/utils/test/test-network.py +++ b/utils/test/test-network.py @@ -49,6 +49,7 @@ class NetworkTestParse(NetworkTest): ] def _run_test(self, rawrule, expected): + self.assertTrue(NetworkRule.match(rawrule)) obj = NetworkRule.parse(rawrule) self.assertEqual(rawrule.strip(), obj.raw_rule) self._compare_obj(obj, expected) @@ -63,6 +64,7 @@ class NetworkTestParseInvalid(NetworkTest): ] def _run_test(self, rawrule, expected): + self.assertTrue(NetworkRule.match(rawrule)) # the above invalid rules still match the main regex! with self.assertRaises(expected): NetworkRule.parse(rawrule) @@ -152,6 +154,7 @@ class InvalidNetworkInit(AATest): class InvalidNetworkTest(AATest): def _check_invalid_rawrule(self, rawrule): obj = None + self.assertFalse(NetworkRule.match(rawrule)) with self.assertRaises(AppArmorException): obj = NetworkRule(NetworkRule.parse(rawrule)) @@ -180,6 +183,7 @@ class InvalidNetworkTest(AATest): class WriteNetworkTestAATest(AATest): def _run_test(self, rawrule, expected): + self.assertTrue(NetworkRule.match(rawrule)) obj = NetworkRule.parse(rawrule) clean = obj.get_clean() raw = obj.get_raw() @@ -210,6 +214,8 @@ class NetworkCoveredTest(AATest): obj = NetworkRule.parse(self.rule) check_obj = NetworkRule.parse(param) + self.assertTrue(NetworkRule.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])