PolicyDifference: implement level decl difference

Closes #36
This commit is contained in:
Chris PeBenito 2016-01-12 16:07:54 -05:00
parent 3a82ebd9d3
commit 00bc854968
6 changed files with 147 additions and 4 deletions

30
sediff
View File

@ -395,6 +395,36 @@ try:
print()
if all_differences or args.level:
if diff.added_levels or diff.removed_levels or \
diff.modified_levels or args.level:
print("Levels ({0} Added, {1} Removed, {2} Modified)".format(
len(diff.added_levels), len(diff.removed_levels),
len(diff.modified_levels)))
if diff.added_levels and not args.stats:
print(" Added Levels: {0}".format(len(diff.added_levels)))
for l in sorted(diff.added_levels):
print(" + {0}".format(l))
if diff.removed_levels and not args.stats:
print(" Removed Levels: {0}".format(len(diff.removed_levels)))
for l in sorted(diff.removed_levels):
print(" - {0}".format(l))
if diff.modified_levels and not args.stats:
print(" Modified Levels: {0}".format(len(diff.modified_levels)))
for level, added_categories, removed_categories, _ in sorted(diff.modified_levels):
change = []
if added_categories:
change.append("{0} Added Categories".format(len(added_categories)))
if removed_categories:
change.append("{0} Removed Categories".format(len(removed_categories)))
print(" * {0} ({1})".format(level.sensitivity, ", ".join(change)))
for c in sorted(added_categories):
print(" + {0}".format(c))
for c in sorted(removed_categories):
print(" - {0}".format(c))
print()
if all_differences or args.allow:
if diff.added_allows or diff.removed_allows or diff.modified_allows or args.allow:
print("Allow Rules ({0} Added, {1} Removed, {2} Modified)".format(

View File

@ -21,7 +21,7 @@ from .commons import CommonDifference
from .fsuse import FSUsesDifference
from .genfscon import GenfsconsDifference
from .initsid import InitialSIDsDifference
from .mls import CategoriesDifference, SensitivitiesDifference
from .mls import CategoriesDifference, LevelDeclsDifference, SensitivitiesDifference
from .mlsrules import MLSRulesDifference
from .objclass import ObjClassDifference
from .rbacrules import RBACRulesDifference
@ -40,6 +40,7 @@ class PolicyDifference(BooleansDifference,
FSUsesDifference,
GenfsconsDifference,
InitialSIDsDifference,
LevelDeclsDifference,
MLSRulesDifference,
ObjClassDifference,
RBACRulesDifference,

View File

@ -29,6 +29,11 @@ modified_sens_record = namedtuple("modified_sensitivity", ["added_aliases",
"removed_aliases",
"matched_aliases"])
modified_level_record = namedtuple("modified_level", ["level",
"added_categories",
"removed_categories",
"matched_categories"])
class CategoriesDifference(Difference):
@ -116,6 +121,71 @@ class SensitivitiesDifference(Difference):
self.modified_sensitivities = None
class LevelDeclsDifference(Difference):
"""Determine the difference in levels between two policies."""
added_levels = DiffResultDescriptor("diff_levels")
removed_levels = DiffResultDescriptor("diff_levels")
modified_levels = DiffResultDescriptor("diff_levels")
def diff_levels(self):
"""Generate the difference in levels between the policies."""
self.log.info(
"Generating level decl differences from {0.left_policy} to {0.right_policy}".
format(self))
self.added_levels, self.removed_levels, matched_levels = \
self._set_diff(
(LevelDeclWrapper(s) for s in self.left_policy.levels()),
(LevelDeclWrapper(s) for s in self.right_policy.levels()))
self.modified_levels = []
for left_level, right_level in matched_levels:
# Criteria for modified levels
# 1. change to allowed categories
added_categories, removed_categories, matched_categories = self._set_diff(
(SymbolWrapper(c) for c in left_level.categories()),
(SymbolWrapper(c) for c in right_level.categories()))
if added_categories or removed_categories:
self.modified_levels.append(modified_level_record(
left_level, added_categories, removed_categories, matched_categories))
#
# Internal functions
#
def _reset_diff(self):
"""Reset diff results on policy changes."""
self.log.debug("Resetting sensitivity differences")
self.added_levels = None
self.removed_levels = None
self.modified_levels = None
class LevelDeclWrapper(Wrapper):
"""Wrap level declarations to allow comparisons."""
def __init__(self, level):
self.origin = level
self.sensitivity = SymbolWrapper(level.sensitivity)
self.key = hash(level)
def __hash__(self):
return self.key
def __eq__(self, other):
# non-MLS policies have no level declarations so there
# should be no AttributeError possiblity here
return self.sensitivity == other.sensitivity
def __lt__(self, other):
return self.sensitivity < other.sensitivity
class LevelWrapper(Wrapper):
"""Wrap levels to allow comparisons."""

View File

@ -1071,6 +1071,36 @@ class PolicyDifferenceTest(ValidateRule, unittest.TestCase):
self.assertEqual("added_user:object_r:system:s0", added_context)
self.assertEqual("removed_user:object_r:system:s0", removed_context)
#
# level decl
#
def test_added_levels(self):
"""Diff: added levels."""
l = sorted(self.diff.added_levels)
self.assertEqual(1, len(l))
self.assertEqual("s46:c0.c4", l[0])
def test_removed_levels(self):
"""Diff: removed levels."""
l = sorted(self.diff.removed_levels)
self.assertEqual(1, len(l))
self.assertEqual("s47:c0.c4", l[0])
def test_modified_levels(self):
"""Diff: modified levels."""
l = sorted(self.diff.modified_levels)
self.assertEqual(2, len(l))
level = l[0]
self.assertEqual("s40", level.level.sensitivity)
self.assertSetEqual(set(["c3"]), level.added_categories)
self.assertFalse(level.removed_categories)
level = l[1]
self.assertEqual("s41", level.level.sensitivity)
self.assertFalse(level.added_categories)
self.assertSetEqual(set(["c4"]), level.removed_categories)
class PolicyDifferenceTestNoDiff(unittest.TestCase):
@ -1343,3 +1373,15 @@ class PolicyDifferenceTestNoDiff(unittest.TestCase):
def test_modified_genfscons(self):
"""NoDiff: no modified genfscons."""
self.assertFalse(self.diff.modified_genfscons)
def test_added_levels(self):
"""NoDiff: no added levels."""
self.assertFalse(self.diff.added_levels)
def test_removed_levels(self):
"""NoDiff: no removed levels."""
self.assertFalse(self.diff.removed_levels)
def test_modified_levels(self):
"""NoDiff: no modified levels."""
self.assertFalse(self.diff.modified_levels)

View File

@ -121,7 +121,7 @@ level s0:c0.c4;
level s1:c0.c4;
level s2:c0.c4;
level s3:c0.c4;
level s40:c0.c4;
level s40:c1;
level s41:c0.c4;
level s42:c0.c4;
level s43:c0.c4;

View File

@ -121,8 +121,8 @@ level s0:c0.c4;
level s1:c0.c4;
level s2:c0.c4;
level s3:c0.c4;
level s40:c0.c4;
level s41:c0.c4;
level s40:c1,c3;
level s41:c0.c3;
level s42:c0.c4;
level s43:c0.c4;
level s44:c0.c4;