diff: implement MLS rule (range_transition) diff.

Closes #45
This commit is contained in:
Chris PeBenito 2016-01-07 09:25:22 -05:00
parent d274954237
commit 0513f0bb5a
6 changed files with 417 additions and 51 deletions

48
sediff
View File

@ -1,5 +1,5 @@
#!/usr/bin/python
# Copyright 2015, Tresys Technology, LLC
# Copyright 2015-2016, Tresys Technology, LLC
#
# This file is part of SETools.
#
@ -487,6 +487,52 @@ try:
print()
if all_differences or args.range_trans:
if diff.added_range_transitions or diff.removed_range_transitions or \
diff.modified_range_transitions or args.range_trans:
print("Range_transition Rules ({0} Added, {1} Removed, {2} Modified)".format(
len(diff.added_range_transitions), len(diff.removed_range_transitions),
len(diff.modified_range_transitions)))
if diff.added_range_transitions:
print(" Added Range_transition Rules: {0}".format(
len(diff.added_range_transitions)))
for r in sorted(diff.added_range_transitions):
print(" + {0}".format(r))
if diff.removed_range_transitions:
print(" Removed Range_transition Rules: {0}".format(
len(diff.removed_range_transitions)))
for r in sorted(diff.removed_range_transitions):
print(" - {0}".format(r))
if diff.modified_range_transitions:
print(" Modified Range_transition Rules: {0}".format(
len(diff.modified_range_transitions)))
for rule, added_default, removed_default in sorted(diff.modified_range_transitions):
# added brackets around range change for clarity since ranges
# can have '-' and spaces.
rule_string = \
"{0.ruletype} {0.source} {0.target}:{0.tclass} +[{1}] -[{2}]".format(
rule, added_default, removed_default)
try:
rule_string += " {0}".format(self.filename)
except:
pass
rule_string += ";"
try:
rule_string += " [ {0} ]".format(rule.conditional)
except:
pass
print(" * {0}".format(rule_string))
print()
except Exception as err:
if args.debug:
import traceback

View File

@ -1,4 +1,4 @@
# Copyright 2015, Tresys Technology, LLC
# Copyright 2015-2016, Tresys Technology, LLC
#
# This file is part of SETools.
#
@ -17,6 +17,7 @@
# <http://www.gnu.org/licenses/>.
#
from .commons import CommonDifference
from .mlsrules import MLSRulesDifference
from .objclass import ObjClassDifference
from .roles import RolesDifference
from .terules import TERulesDifference
@ -26,6 +27,7 @@ __all__ = ['PolicyDifference']
class PolicyDifference(CommonDifference,
MLSRulesDifference,
ObjClassDifference,
RolesDifference,
TERulesDifference,

135
setools/diff/mlsrules.py Normal file
View File

@ -0,0 +1,135 @@
# 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
# <http://www.gnu.org/licenses/>.
#
from collections import namedtuple
from ..policyrep.exception import RuleNotConditional, RuleUseError, TERuleNoFilename
from .descriptors import DiffResultDescriptor
from .difference import Difference, SymbolWrapper, Wrapper
from .mls import RangeWrapper
modified_mlsrule_record = namedtuple("modified_mlsrule", ["rule",
"added_default",
"removed_default"])
class MLSRulesDifference(Difference):
"""Determine the difference in MLS rules between two policies."""
added_range_transitions = DiffResultDescriptor("diff_range_transitions")
removed_range_transitions = DiffResultDescriptor("diff_range_transitions")
modified_range_transitions = DiffResultDescriptor("diff_range_transitions")
# Lists of rules for each policy
_left_range_transitions = None
_right_range_transitions = None
def diff_range_transitions(self):
"""Generate the difference in range_transition rules between the policies."""
self.log.info(
"Generating range_transition differences from {0.left_policy} to {0.right_policy}".
format(self))
if self._left_range_transitions is None or self._right_range_transitions is None:
self._create_mls_rule_lists()
self.added_range_transitions, \
self.removed_range_transitions, \
self.modified_range_transitions = self._diff_mls_rules(
self._expand_generator(self._left_range_transitions, MLSRuleWrapper),
self._expand_generator(self._right_range_transitions, MLSRuleWrapper))
#
# Internal functions
#
def _create_mls_rule_lists(self):
"""Create rule lists for both policies."""
self._left_range_transitions = []
for rule in self.left_policy.mlsrules():
# do not expand yet, to keep memory
# use down as long as possible
if rule.ruletype == "range_transition":
self._left_range_transitions.append(rule)
else:
raise TypeError("Unknown rule type: {0}".format(rule.ruletype))
self._right_range_transitions = []
for rule in self.right_policy.mlsrules():
# do not expand yet, to keep memory
# use down as long as possible
if rule.ruletype == "range_transition":
self._right_range_transitions.append(rule)
else:
raise TypeError("Unknown rule type: {0}".format(rule.ruletype))
def _diff_mls_rules(self, left_list, right_list):
"""Common method for comparing type_* rules."""
added, removed, matched = self._set_diff(left_list, right_list)
modified = []
for left_rule, right_rule in matched:
# Criteria for modified rules
# 1. change to default range
if RangeWrapper(left_rule.default) != RangeWrapper(right_rule.default):
modified.append(modified_mlsrule_record(left_rule,
right_rule.default,
left_rule.default))
return added, removed, modified
def _reset_diff(self):
"""Reset diff results on policy changes."""
self.log.debug("Resetting MLS rule differences")
self.added_range_transitions = None
self.removed_range_transitions = None
self.modified_range_transitions = None
# Sets of rules for each policy
self._left_range_transitions = None
self._right_range_transitions = None
class MLSRuleWrapper(Wrapper):
"""Wrap MLS rules to allow set operations."""
def __init__(self, rule):
self.origin = rule
self.ruletype = rule.ruletype
self.source = SymbolWrapper(rule.source)
self.target = SymbolWrapper(rule.target)
self.tclass = SymbolWrapper(rule.tclass)
self.key = hash(rule)
def __hash__(self):
return self.key
def __lt__(self, other):
return self.key < other.key
def __eq__(self, other):
# because MLSRuleDifference groups rules by ruletype,
# the ruletype always matches.
return self.source == other.source and \
self.target == other.target and \
self.tclass == other.tclass

View File

@ -1,4 +1,4 @@
# Copyright 2015, Tresys Technology, LLC
# Copyright 2015-2016, Tresys Technology, LLC
#
# This file is part of SETools.
#
@ -736,6 +736,48 @@ class PolicyDifferenceTest(ValidateRule, unittest.TestCase):
self.assertEqual("tm_new_type", added_default)
self.assertEqual("tm_old_type", removed_default)
#
# Range_transition rules
#
def test_added_range_transition_rules(self):
"""Diff: added range_transition rules."""
rules = sorted(self.diff.added_range_transitions)
self.assertEqual(2, len(rules))
# added rule with new type
self.validate_rule(rules[0], "range_transition", "added_type", "system", "infoflow4",
"s3")
# added rule with existing types
self.validate_rule(rules[1], "range_transition", "rt_added_rule_source",
"rt_added_rule_target", "infoflow", "s3")
def test_removed_range_transition_rules(self):
"""Diff: removed range_transition rules."""
rules = sorted(self.diff.removed_range_transitions)
self.assertEqual(2, len(rules))
# removed rule with new type
self.validate_rule(rules[0], "range_transition", "removed_type", "system", "infoflow4",
"s1")
# removed rule with existing types
self.validate_rule(rules[1], "range_transition", "rt_removed_rule_source",
"rt_removed_rule_target", "infoflow", "s1")
def test_modified_range_transition_rules(self):
"""Diff: modified range_transition rules."""
l = sorted(self.diff.modified_range_transitions)
self.assertEqual(1, len(l))
rule, added_default, removed_default = l[0]
self.assertEqual("range_transition", rule.ruletype)
self.assertEqual("rt_matched_source", rule.source)
self.assertEqual("system", rule.target)
self.assertEqual("infoflow", rule.tclass)
self.assertEqual("s0:c0,c4 - s1:c0.c2,c4", added_default)
self.assertEqual("s2:c0 - s3:c0.c2", removed_default)
class PolicyDifferenceTestNoDiff(unittest.TestCase):
@ -876,3 +918,15 @@ class PolicyDifferenceTestNoDiff(unittest.TestCase):
def test_modified_type_members(self):
"""NoDiff: no modified type_member rules."""
self.assertFalse(self.diff.modified_type_members)
def test_added_range_transitions(self):
"""NoDiff: no added range_transition rules."""
self.assertFalse(self.diff.added_range_transitions)
def test_removed_range_transitions(self):
"""NoDiff: no removed range_transition rules."""
self.assertFalse(self.diff.removed_range_transitions)
def test_modified_range_transitions(self):
"""NoDiff: no modified range_transition rules."""
self.assertFalse(self.diff.modified_range_transitions)

View File

@ -92,20 +92,38 @@ class modified_remove_perm
class modified_change_common
inherits removed_common
sensitivity low_s;
sensitivity medium_s alias med;
sensitivity high_s;
sensitivity s0;
sensitivity s1;
sensitivity s2;
sensitivity s3;
sensitivity s40;
sensitivity s41;
sensitivity s42;
sensitivity s43;
sensitivity s44;
sensitivity s45;
sensitivity s46;
dominance { low_s med high_s }
dominance { s0 s1 s2 s3 s40 s41 s42 s43 s44 s45 s46 }
category here;
category there;
category elsewhere alias lost;
category c0;
category c1;
category c2;
category c3;
category c4;
#level decl
level low_s:here.there;
level med:here, elsewhere;
level high_s:here.lost;
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 s42:c0.c4;
level s43:c0.c4;
level s44:c0.c4;
level s45:c0.c4;
level s46:c0.c4;
#some constraints
mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt));
@ -486,32 +504,78 @@ type_member tm_unioned_perm_via_attr system:infoflow2 system;
type_member tm_unioned_perm_via_attr_A_t system:infoflow2 system;
type_member tm_unioned_perm_via_attr_B_t system:infoflow2 system;
# range_transition rule differences
type rt_matched_source;
type rt_matched_target;
range_transition rt_matched_source rt_matched_target:infoflow s0;
type rt_removed_rule_source;
type rt_removed_rule_target;
range_transition rt_removed_rule_source rt_removed_rule_target:infoflow s1;
type rt_added_rule_source;
type rt_added_rule_target;
range_transition rt_matched_source system:infoflow s2:c0 - s3:c0.c2;
range_transition removed_type system:infoflow4 s1;
# range transitions cannot be conditional.
#type rt_move_to_bool;
#bool rt_move_to_bool_b false;
#range_transition rt_move_to_bool system:infoflow3 s0;
#type rt_move_from_bool;
#bool rt_move_from_bool_b false;
#if (rt_move_from_bool_b) {
#range_transition rt_move_from_bool system:infoflow4 s0;
#}
#type rt_switch_block;
#bool rt_switch_block_b false;
#if (rt_switch_block_b) {
#range_transition system rt_switch_block:infoflow5 s0;
#range_transition system rt_switch_block:infoflow6 s0;
#} else {
#range_transition system rt_switch_block:infoflow7 s0;
#}
attribute rt_match_rule_by_attr;
type rt_match_rule_by_attr_A_t, rt_match_rule_by_attr;
type rt_match_rule_by_attr_B_t, rt_match_rule_by_attr;
range_transition rt_match_rule_by_attr system:infoflow2 s0;
attribute rt_unioned_perm_via_attr;
type rt_unioned_perm_via_attr_A_t, rt_unioned_perm_via_attr;
type rt_unioned_perm_via_attr_B_t, rt_unioned_perm_via_attr;
range_transition rt_unioned_perm_via_attr system:infoflow2 s0;
range_transition rt_unioned_perm_via_attr_A_t system:infoflow2 s0;
################################################################################
#users
user system roles system level med range low_s - high_s:here.lost;
user system roles system level s0 range s0 - s46:c0.c4;
#normal constraints
constrain infoflow hi_w (u1 == u2);
#isids
sid kernel system:system:system:medium_s:here
sid security system:system:system:high_s:lost
sid kernel system:system:system:s0
sid security system:system:system:s0
#fs_use
fs_use_trans devpts system:object_r:system:low_s;
fs_use_xattr ext3 system:object_r:system:low_s;
fs_use_task pipefs system:object_r:system:low_s;
fs_use_trans devpts system:object_r:system:s0;
fs_use_xattr ext3 system:object_r:system:s0;
fs_use_task pipefs system:object_r:system:s0;
#genfscon
genfscon proc / system:object_r:system:med
genfscon proc /sys system:object_r:system:low_s
genfscon selinuxfs / system:object_r:system:high_s:here.there
genfscon proc / system:object_r:system:s0
genfscon proc /sys system:object_r:system:s0
genfscon selinuxfs / system:object_r:system:s0
portcon tcp 80 system:object_r:system:low_s
portcon tcp 80 system:object_r:system:s0
netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s
nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here
nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here
netifcon eth0 system:object_r:system:s0 system:object_r:system:s0
nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0
nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0

View File

@ -92,20 +92,39 @@ class modified_remove_perm
class modified_change_common
inherits added_common
sensitivity low_s;
sensitivity medium_s alias med;
sensitivity high_s;
sensitivity s0;
sensitivity s1;
sensitivity s2;
sensitivity s3;
sensitivity s40;
sensitivity s41;
sensitivity s42;
sensitivity s43;
sensitivity s44;
sensitivity s45;
sensitivity s46;
dominance { low_s med high_s }
dominance { s0 s1 s2 s3 s40 s41 s42 s43 s44 s45 s46 }
category here;
category there;
category elsewhere alias lost;
category c0;
category c0a;
category c1;
category c2;
category c3;
category c4;
#level decl
level low_s:here.there;
level med:here, elsewhere;
level high_s:here.lost;
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 s42:c0.c4;
level s43:c0.c4;
level s44:c0.c4;
level s45:c0.c4;
level s46:c0.c4;
#some constraints
mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt));
@ -486,32 +505,78 @@ type_member tm_unioned_perm_via_attr system:infoflow2 system;
type_member tm_unioned_perm_via_attr_A_t system:infoflow2 system;
type_member tm_unioned_perm_via_attr_B_t system:infoflow2 system;
# range_transition rule differences
type rt_matched_source;
type rt_matched_target;
range_transition rt_matched_source rt_matched_target:infoflow s0;
type rt_removed_rule_source;
type rt_removed_rule_target;
type rt_added_rule_source;
type rt_added_rule_target;
range_transition rt_added_rule_source rt_added_rule_target:infoflow s3;
range_transition rt_matched_source system:infoflow s0:c0,c4 - s1:c0.c2,c4;
range_transition added_type system:infoflow4 s3;
# range transitions cannot be conditional.
#type rt_move_to_bool;
#bool rt_move_to_bool_b false;
#if (rt_move_to_bool_b) {
#range_transition rt_move_to_bool system:infoflow3 s0;
#}
#type rt_move_from_bool;
#bool rt_move_from_bool_b false;
#range_transition rt_move_from_bool system:infoflow4 s0;
#type rt_switch_block;
#bool rt_switch_block_b false;
#if (rt_switch_block_b) {
#range_transition system rt_switch_block:infoflow5 s0;
#} else {
#range_transition system rt_switch_block:infoflow6 s0;
#range_transition system rt_switch_block:infoflow7 s0;
#}
attribute rt_match_rule_by_attr;
type rt_match_rule_by_attr_A_t, rt_match_rule_by_attr;
type rt_match_rule_by_attr_B_t, rt_match_rule_by_attr;
range_transition rt_match_rule_by_attr system:infoflow2 s0;
attribute rt_unioned_perm_via_attr;
type rt_unioned_perm_via_attr_A_t, rt_unioned_perm_via_attr;
type rt_unioned_perm_via_attr_B_t, rt_unioned_perm_via_attr;
range_transition rt_unioned_perm_via_attr system:infoflow2 s0;
range_transition rt_unioned_perm_via_attr_B_t system:infoflow2 s0;
################################################################################
#users
user system roles system level med range low_s - high_s:here.lost;
user system roles system level s0 range s0 - s46:c0.c4;
#normal constraints
constrain infoflow hi_w (u1 == u2);
#isids
sid kernel system:system:system:medium_s:here
sid security system:system:system:high_s:lost
sid kernel system:system:system:s0
sid security system:system:system:s0
#fs_use
fs_use_trans devpts system:object_r:system:low_s;
fs_use_xattr ext3 system:object_r:system:low_s;
fs_use_task pipefs system:object_r:system:low_s;
fs_use_trans devpts system:object_r:system:s0;
fs_use_xattr ext3 system:object_r:system:s0;
fs_use_task pipefs system:object_r:system:s0;
#genfscon
genfscon proc / system:object_r:system:med
genfscon proc /sys system:object_r:system:low_s
genfscon selinuxfs / system:object_r:system:high_s:here.there
genfscon proc / system:object_r:system:s0
genfscon proc /sys system:object_r:system:s0
genfscon selinuxfs / system:object_r:system:s0
portcon tcp 80 system:object_r:system:low_s
portcon tcp 80 system:object_r:system:s0
netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s
nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here
nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here
netifcon eth0 system:object_r:system:s0 system:object_r:system:s0
nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0
nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0