diff --git a/sediff b/sediff index ac09035..bc6abb6 100755 --- a/sediff +++ b/sediff @@ -82,6 +82,34 @@ try: p2 = setools.SELinuxPolicy(args.POLICY2[0]) diff = setools.PolicyDifference(p1, p2) + if diff.added_commons or diff.removed_commons or diff.modified_commons: + print("Commons ({0} Added, {1} Removed, {2} Modified)".format(len(diff.added_commons), + len(diff.removed_commons), + len(diff.modified_commons))) + if diff.added_commons: + print(" Added Commons: {0}".format(len(diff.added_commons))) + for c in sorted(diff.added_commons): + print(" + {0}".format(c)) + if diff.removed_commons: + print(" Removed Commons: {0}".format(len(diff.removed_commons))) + for c in sorted(diff.removed_commons): + print(" - {0}".format(c)) + if diff.modified_commons: + print(" Modified Commons: {0}".format(len(diff.modified_commons))) + for name, mod in sorted(diff.modified_commons.items()): + change = [] + if mod.added_perms: + change.append("{0} Added permissions".format(len(mod.added_perms))) + if mod.removed_perms: + change.append("{0} Removed permissions".format(len(mod.removed_perms))) + + print(" * {0} ({1})".format(name, ", ".join(change))) + for p in sorted(mod.added_perms): + print(" + {0}".format(p)) + for p in sorted(mod.removed_perms): + print(" - {0}".format(p)) + print() + if diff.added_roles or diff.removed_roles or diff.modified_roles: print("Roles ({0} Added, {1} Removed, {2} Modified)".format(len(diff.added_roles), len(diff.removed_roles), diff --git a/setools/diff.py b/setools/diff.py index 269f3fb..d971403 100644 --- a/setools/diff.py +++ b/setools/diff.py @@ -23,6 +23,10 @@ from weakref import WeakKeyDictionary __all__ = ['PolicyDifference'] +modified_commons_record = namedtuple("modified_common", ["added_perms", + "removed_perms", + "matched_perms"]) + modified_roles_record = namedtuple("modified_role", ["added_types", "removed_types", "matched_types"]) @@ -106,6 +110,38 @@ class PolicyDifference(object): self._right_policy = policy self._reset_diff() + # + # Common differences + # + added_commons = DiffResultDescriptor("diff_commons") + removed_commons = DiffResultDescriptor("diff_commons") + modified_commons = DiffResultDescriptor("diff_commons") + + def diff_commons(self): + """Generate the difference in commons between the policies.""" + + self.log.info( + "Generating common differences from {0.left_policy} to {0.right_policy}".format(self)) + + self.added_commons, self.removed_commons, matched_commons = self._set_diff( + self.left_policy.commons(), self.right_policy.commons()) + + self.modified_commons = dict() + + for name in matched_commons: + # Criteria for modified commons + # 1. change to permissions + left_common = self.left_policy.lookup_common(name) + right_common = self.right_policy.lookup_common(name) + + added_perms, removed_perms, matched_perms = self._set_diff(left_common.perms, + right_common.perms) + + if added_perms or removed_perms: + self.modified_commons[name] = modified_commons_record(added_perms, + removed_perms, + matched_perms) + # # Role differences # @@ -190,6 +226,9 @@ class PolicyDifference(object): # def _reset_diff(self): """Reset diff results on policy changes.""" + self.added_commons = None + self.removed_commons = None + self.modified_commons = None self.added_roles = None self.removed_roles = None self.modified_roles = None diff --git a/tests/diff.py b/tests/diff.py index 1deea75..9f55de2 100644 --- a/tests/diff.py +++ b/tests/diff.py @@ -141,6 +141,30 @@ class PolicyDifferenceTest(unittest.TestCase): self.diff.modified_roles["modified_remove_type"].removed_types) self.assertFalse(self.diff.modified_roles["modified_remove_type"].added_types) + def test_added_common(self): + """Diff: added common.""" + self.assertSetEqual(set(["added_common"]), self.diff.added_commons) + + def test_removed_common(self): + """Diff: removed common.""" + self.assertSetEqual(set(["removed_common"]), self.diff.removed_commons) + + def test_modified_common_count(self): + """Diff: modified common count.""" + self.assertEqual(2, len(self.diff.modified_commons)) + + def test_modified_common_add_perm(self): + """Diff: modified common with added perm.""" + self.assertSetEqual(set(["added_perm"]), + self.diff.modified_commons["modified_add_perm"].added_perms) + self.assertFalse(self.diff.modified_commons["modified_add_perm"].removed_perms) + + def test_modified_common_remove_perm(self): + """Diff: modified common with removed perm.""" + self.assertSetEqual(set(["removed_perm"]), + self.diff.modified_commons["modified_remove_perm"].removed_perms) + self.assertFalse(self.diff.modified_commons["modified_remove_perm"].added_perms) + class PolicyDifferenceTestNoDiff(unittest.TestCase): @@ -173,3 +197,15 @@ class PolicyDifferenceTestNoDiff(unittest.TestCase): def test_modified_roles(self): """NoDiff: no modified roles.""" self.assertFalse(self.diff.modified_roles) + + def test_added_commons(self): + """NoDiff: no added commons.""" + self.assertFalse(self.diff.added_commons) + + def test_removed_commons(self): + """NoDiff: no removed commons.""" + self.assertFalse(self.diff.removed_commons) + + def test_modified_commons(self): + """NoDiff: no modified commons.""" + self.assertFalse(self.diff.modified_commons) diff --git a/tests/diff_left.conf b/tests/diff_left.conf index 54efc25..5d43c0f 100644 --- a/tests/diff_left.conf +++ b/tests/diff_left.conf @@ -19,6 +19,22 @@ common infoflow hi_r } +common removed_common +{ + old_com +} + +common modified_remove_perm +{ + same_perm + removed_perm +} + +common modified_add_perm +{ + matched_perm +} + class infoflow inherits infoflow diff --git a/tests/diff_right.conf b/tests/diff_right.conf index 73ffdb2..b8be4e0 100644 --- a/tests/diff_right.conf +++ b/tests/diff_right.conf @@ -19,6 +19,22 @@ common infoflow hi_r } +common added_common +{ + new_com +} + +common modified_remove_perm +{ + same_perm +} + +common modified_add_perm +{ + matched_perm + added_perm +} + class infoflow inherits infoflow