[apparmor] [patch] Implement in-profile de-duplication in BaseRuleset
Christian Boltz
apparmor at cboltz.de
Fri Apr 24 20:08:16 UTC 2015
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 ]
=== 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)
Regards,
Christian Boltz
--
Maybe the next openSUSE conference should have a mandatory group hug
after all... ;-) [Jos Poortvliet in opensuse-factory]
More information about the AppArmor
mailing list