From 64d6d4d075e2a5b1b752e3366aac7cfed8547924 Mon Sep 17 00:00:00 2001 From: Chris PeBenito Date: Sat, 9 Jan 2016 11:45:22 -0500 Subject: [PATCH] PolicyDifference: implement initial SID diff Closes #42 --- sediff | 23 +++++++++++++++ setools/diff/__init__.py | 2 ++ setools/diff/context.py | 44 +++++++++++++++++++++++++++ setools/diff/initsid.py | 64 ++++++++++++++++++++++++++++++++++++++++ tests/diff.py | 31 +++++++++++++++++++ tests/diff_left.conf | 6 ++++ tests/diff_right.conf | 6 ++++ 7 files changed, 176 insertions(+) create mode 100644 setools/diff/context.py create mode 100644 setools/diff/initsid.py diff --git a/sediff b/sediff index 41d55e8..eef54da 100755 --- a/sediff +++ b/sediff @@ -743,6 +743,29 @@ try: print() + if all_differences or args.initialsid: + if diff.added_initialsids or diff.removed_initialsids or diff.modified_initialsids \ + or args.sensitivity: + print("Initial SIDs ({0} Added, {1} Removed, {2} Modified)".format( + len(diff.added_initialsids), len(diff.removed_initialsids), + len(diff.modified_initialsids))) + if diff.added_initialsids and not args.stats: + print(" Added Initial SIDs: {0}".format(len(diff.added_initialsids))) + for s in sorted(diff.added_initialsids): + print(" + {0}".format(s)) + if diff.removed_initialsids and not args.stats: + print(" Removed Initial SIDs: {0}".format(len(diff.removed_initialsids))) + for s in sorted(diff.removed_initialsids): + print(" - {0}".format(s)) + if diff.modified_initialsids and not args.stats: + print(" Modified Initial SIDs: {0}".format(len(diff.modified_initialsids))) + for name, mod in sorted(diff.modified_initialsids.items()): + print(" * {0} (Modified context)".format(name)) + print(" + {0}".format(mod.added_context)) + print(" - {0}".format(mod.removed_context)) + + print() + except Exception as err: if args.debug: import traceback diff --git a/setools/diff/__init__.py b/setools/diff/__init__.py index 331b4d5..dd04ad9 100644 --- a/setools/diff/__init__.py +++ b/setools/diff/__init__.py @@ -18,6 +18,7 @@ # from .bool import BooleansDifference from .commons import CommonDifference +from .initsid import InitialSIDsDifference from .mls import CategoriesDifference, SensitivitiesDifference from .mlsrules import MLSRulesDifference from .objclass import ObjClassDifference @@ -34,6 +35,7 @@ __all__ = ['PolicyDifference'] class PolicyDifference(BooleansDifference, CategoriesDifference, CommonDifference, + InitialSIDsDifference, MLSRulesDifference, ObjClassDifference, RBACRulesDifference, diff --git a/setools/diff/context.py b/setools/diff/context.py new file mode 100644 index 0000000..4124aff --- /dev/null +++ b/setools/diff/context.py @@ -0,0 +1,44 @@ +# Copyright 2016, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# . +# +from ..policyrep.exception import MLSDisabled + +from .difference import SymbolWrapper, Wrapper +from .mls import RangeWrapper + + +class ContextWrapper(Wrapper): + + """Wrap contexts to allow comparisons.""" + + def __init__(self, ctx): + self.origin = ctx + self.user = SymbolWrapper(ctx.user) + self.role = SymbolWrapper(ctx.role) + self.type_ = SymbolWrapper(ctx.type_) + + try: + self.range_ = RangeWrapper(ctx.range_) + except MLSDisabled: + self.range_ = None + + def __eq__(self, other): + return self.user == other.user and \ + self.role == other.role and \ + self.type_ == other.type_ and \ + self.range_ == other.range_ diff --git a/setools/diff/initsid.py b/setools/diff/initsid.py new file mode 100644 index 0000000..33098ad --- /dev/null +++ b/setools/diff/initsid.py @@ -0,0 +1,64 @@ +# Copyright 2016, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 of +# the License, or (at your option) any later version. +# +# SETools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# . +# +from collections import namedtuple + +from .context import ContextWrapper +from .descriptors import DiffResultDescriptor +from .difference import Difference, SymbolWrapper + + +modified_initsids_record = namedtuple("modified_initsid", ["added_context", "removed_context"]) + + +class InitialSIDsDifference(Difference): + + """Determine the difference in initsids between two policies.""" + + added_initialsids = DiffResultDescriptor("diff_initialsids") + removed_initialsids = DiffResultDescriptor("diff_initialsids") + modified_initialsids = DiffResultDescriptor("diff_initialsids") + + def diff_initialsids(self): + """Generate the difference in initial SIDs between the policies.""" + + self.log.info("Generating initial SID differences from {0.left_policy} to {0.right_policy}". + format(self)) + + self.added_initialsids, self.removed_initialsids, matched_initialsids = self._set_diff( + (SymbolWrapper(i) for i in self.left_policy.initialsids()), + (SymbolWrapper(i) for i in self.right_policy.initialsids())) + + self.modified_initialsids = dict() + + for left_initialsid, right_initialsid in matched_initialsids: + # Criteria for modified initialsids + # 1. change to context + if ContextWrapper(left_initialsid.context) != ContextWrapper(right_initialsid.context): + self.modified_initialsids[left_initialsid] = modified_initsids_record( + right_initialsid.context, left_initialsid.context) + + # + # Internal functions + # + def _reset_diff(self): + """Reset diff results on policy changes.""" + self.log.debug("Resetting initialsid differences") + self.added_initialsids = None + self.removed_initialsids = None + self.modified_initialsids = None diff --git a/tests/diff.py b/tests/diff.py index dbcf147..55f7b2b 100644 --- a/tests/diff.py +++ b/tests/diff.py @@ -974,6 +974,25 @@ class PolicyDifferenceTest(ValidateRule, unittest.TestCase): self.assertFalse(self.diff.modified_sensitivities["s0"].added_aliases) self.assertEqual(set(["al2"]), self.diff.modified_sensitivities["s0"].removed_aliases) + # + # Initial SIDs + # + def test_added_initialsids(self): + """Diff: added initialsids.""" + self.assertSetEqual(set(["added_sid"]), self.diff.added_initialsids) + + def test_removed_initialsids(self): + """Diff: removed initialsids.""" + self.assertSetEqual(set(["removed_sid"]), self.diff.removed_initialsids) + + def test_modified_initialsids(self): + """Diff: modified initialsids.""" + self.assertEqual(1, len(self.diff.modified_initialsids)) + self.assertEqual("modified_add_role:system:system:s2", + self.diff.modified_initialsids["modified_sid"].added_context) + self.assertEqual("system:system:system:s0", + self.diff.modified_initialsids["modified_sid"].removed_context) + class PolicyDifferenceTestNoDiff(unittest.TestCase): @@ -1210,3 +1229,15 @@ class PolicyDifferenceTestNoDiff(unittest.TestCase): def test_modified_sensitivities(self): """NoDiff: no modified sensitivities.""" self.assertFalse(self.diff.modified_sensitivities) + + def test_added_initialsids(self): + """NoDiff: no added initialsids.""" + self.assertFalse(self.diff.added_initialsids) + + def test_removed_initialsids(self): + """NoDiff: no removed initialsids.""" + self.assertFalse(self.diff.removed_initialsids) + + def test_modified_initialsids(self): + """NoDiff: no modified initialsids.""" + self.assertFalse(self.diff.modified_initialsids) diff --git a/tests/diff_left.conf b/tests/diff_left.conf index 0238767..3e3d046 100644 --- a/tests/diff_left.conf +++ b/tests/diff_left.conf @@ -12,6 +12,9 @@ class modified_change_common sid kernel sid security +sid matched_sid +sid removed_sid +sid modified_sid common infoflow { @@ -608,6 +611,9 @@ constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 +sid matched_sid system:system:system:s0 +sid removed_sid removed_user:system:system:s0 +sid modified_sid system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; diff --git a/tests/diff_right.conf b/tests/diff_right.conf index b9bcd07..9cf89f1 100644 --- a/tests/diff_right.conf +++ b/tests/diff_right.conf @@ -12,6 +12,9 @@ class modified_change_common sid kernel sid security +sid matched_sid +sid added_sid +sid modified_sid common infoflow { @@ -608,6 +611,9 @@ constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 +sid matched_sid system:system:system:s0 +sid added_sid added_user:system:system:s1 +sid modified_sid modified_add_role:system:system:s2 #fs_use fs_use_trans devpts system:object_r:system:s0;