[apparmor] [patch] Implement in-profile de-duplication in BaseRuleset

Seth Arnold seth.arnold at canonical.com
Fri Apr 24 21:07:15 UTC 2015


On Fri, Apr 24, 2015 at 10:08:16PM +0200, Christian Boltz wrote:
> Hello,
> 
> Am Donnerstag, 23. April 2015 schrieb Seth Arnold:
> > On Sun, Apr 12, 2015 at 03:29:44AM +0200, Christian Boltz wrote:
> > > this patch implements in-profile de-duplication in BaseRuleset
> > > (currently affects "only" CapabilityRuleset, but will also work for
> > > all future *Ruleset classes).
> > > 
> > > The method I use is probably slightly confusing, but it works ;-)
> ...
> > > The patch also adds some tests that verify the in-profile
> > > deduplication.
> > This looks good; I've got one suggestion, though; in both
> > delete_duplicates and delete_in_profile_duplicates the 'deleted'
> > variable is a list of deleted rules, but no use is made of their
> > contents. deleted could be turned into an integer, and the .append()
> > calls turned into += 1 and returning the value directly.
> 
> That's there for historical reasons[tm], and you are right that just 
> counting is enough.
> 
> > Thanks for the tests; I think one more case would be nice to add,
> > something like:
> > 
> >   rules = [ 'audit capability chown', 'deny capability chown' ]
> > 
> > simply because I'm not confident at what the answer should be. Should
> > it be "audit deny capability chown" or "deny capability chown"? It'd
> > be nice to codify what the result should be.
> 
> The tools will keep both rules. Merging them to "audit deny capability 
> chown" would also be correct, but I doubt I want to implement that ;-)
> 
> Added as test_delete_duplicates_in_profile_04().
> 
> 
> Here's the updated patch:
> 
> [ 42-in-profile-deduplication.diff ]

Thanks!

Acked-by: Seth Arnold <seth.arnold at canonical.com>

> 
> === modified file utils/apparmor/rule/__init__.py
> --- utils/apparmor/rule/__init__.py     2015-04-24 21:47:02.319685749 +0200
> +++ utils/apparmor/rule/__init__.py     2015-04-24 21:50:18.690953604 +0200
> @@ -230,15 +230,39 @@
>  
>      def delete_duplicates(self, include_rules):
>          '''Delete duplicate rules.
> -           include_rules must be a *_rules object'''
> -        deleted = []
> -        if include_rules:  # avoid breakage until we have a proper function to ensure all profiles contain all *_rules objects
> +           include_rules must be a *_rules object or None'''
> +
> +        deleted = 0
> +
> +        # delete rules that are covered by include files
> +        if include_rules:
>              for rule in self.rules:
>                  if include_rules.is_covered(rule, True, True):
>                      self.delete(rule)
> -                    deleted.append(rule)
> +                    deleted += 1
> +
> +        # de-duplicate rules inside the profile
> +        deleted += self.delete_in_profile_duplicates()
> +        self.rules.reverse()
> +        deleted += self.delete_in_profile_duplicates()  # search again in reverse order - this will find the remaining duplicates
> +        self.rules.reverse()  # restore original order for raw output
> +
> +        return deleted
> +
> +    def delete_in_profile_duplicates(self):
> +        '''Delete duplicate rules inside a profile'''
> +
> +        deleted = 0
> +        oldrules = self.rules
> +        self.rules = []
> +
> +        for rule in oldrules:
> +            if not self.is_covered(rule, True, False):
> +                self.rules.append(rule)
> +            else:
> +                deleted += 1
>  
> -        return len(deleted)
> +        return deleted
>  
>      def get_glob_ext(self, path_or_rule):
>          '''returns the next possible glob with extension (for file rules only).
> === modified file utils/test/test-capability.py
> --- utils/test/test-capability.py       2015-04-24 21:47:02.320685689 +0200
> +++ utils/test/test-capability.py       2015-04-24 21:58:20.069631045 +0200
> @@ -855,5 +855,118 @@
>          self.assertEqual(expected_clean, self.ruleset.get_clean(1))
>  
>  
> +    def _check_test_delete_duplicates_in_profile(self, rules, expected_raw, expected_clean, expected_deleted):
> +        obj = CapabilityRuleset()
> +
> +        for rule in rules:
> +            obj.add(CapabilityRule.parse(rule))
> +
> +        deleted = obj.delete_duplicates(None)
> +
> +        self.assertEqual(expected_raw, obj.get_raw(1))
> +        self.assertEqual(expected_clean, obj.get_clean(1))
> +        self.assertEqual(deleted, expected_deleted)
> +
> +
> +    def test_delete_duplicates_in_profile_01(self):
> +        rules = [
> +            'audit capability chown,',
> +            'audit capability,',
> +            'capability dac_override,',
> +        ]
> +
> +        expected_raw = [
> +            '  audit capability,',
> +            '',
> +        ]
> +
> +        expected_clean = [
> +            '  audit capability,',
> +            '',
> +        ]
> +
> +        expected_deleted = 2
> +
> +        self._check_test_delete_duplicates_in_profile(rules, expected_raw, expected_clean, expected_deleted)
> +
> +    def test_delete_duplicates_in_profile_02(self):
> +        rules = [
> +            'audit capability chown,',
> +            'audit capability,',
> +            'audit capability dac_override,',
> +            'capability ,',
> +            'audit capability ,',
> +        ]
> +
> +        expected_raw = [
> +            '  audit capability,',
> +            '',
> +        ]
> +
> +        expected_clean = [
> +            '  audit capability,',
> +            '',
> +        ]
> +
> +        expected_deleted = 4
> +
> +        self._check_test_delete_duplicates_in_profile(rules, expected_raw, expected_clean, expected_deleted)
> +
> +    def test_delete_duplicates_in_profile_03(self):
> +        rules = [
> +            'audit capability chown,',
> +            'capability dac_override,',
> +            'deny capability dac_override,',
> +            'capability dac_override,',
> +            'audit capability chown,',
> +            'deny capability chown,',
> +            'audit deny capability chown,',
> +            'capability,',
> +            'audit capability,',
> +        ]
> +
> +        expected_raw = [
> +            '  deny capability dac_override,',
> +            '  audit deny capability chown,',
> +            '  audit capability,',
> +            '',
> +        ]
> +
> +        expected_clean = [
> +            '  audit deny capability chown,',
> +            '  deny capability dac_override,',
> +            '',
> +            '  audit capability,',
> +            '',
> +        ]
> +
> +        expected_deleted = 6
> +
> +        self._check_test_delete_duplicates_in_profile(rules, expected_raw, expected_clean, expected_deleted)
> +
> +    def test_delete_duplicates_in_profile_04(self):
> +        rules = [
> +            'audit capability chown,',
> +            'deny capability chown,',
> +        ]
> +
> +        expected_raw = [
> +            '  audit capability chown,',
> +            '  deny capability chown,',
> +            '',
> +        ]
> +
> +        expected_clean = [
> +            '  deny capability chown,',
> +            '',
> +            '  audit capability chown,',
> +            '',
> +        ]
> +
> +        expected_deleted = 0
> +
> +        self._check_test_delete_duplicates_in_profile(rules, expected_raw, expected_clean, expected_deleted)
> +
> +
>  if __name__ == "__main__":
>      unittest.main(verbosity=2)
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: Digital signature
URL: <https://lists.ubuntu.com/archives/apparmor/attachments/20150424/5d2e16ba/attachment.pgp>


More information about the AppArmor mailing list