| # Copyright 2015-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 defaultdict, namedtuple |
| |
| from ..policyrep import ioctlSet |
| from ..policyrep.exception import RuleNotConditional, RuleUseError, TERuleNoFilename |
| |
| from .conditional import ConditionalExprWrapper |
| from .descriptors import DiffResultDescriptor |
| from .difference import Difference, SymbolWrapper, Wrapper |
| |
| |
| modified_avrule_record = namedtuple("modified_avrule", ["rule", |
| "added_perms", |
| "removed_perms", |
| "matched_perms"]) |
| |
| modified_terule_record = namedtuple("modified_terule", ["rule", "added_default", "removed_default"]) |
| |
| |
| def av_diff_template(ruletype): |
| |
| """ |
| This is a template for the access vector diff functions. |
| |
| Parameters: |
| ruletype The rule type, e.g. "allow". |
| """ |
| |
| def diff(self): |
| """Generate the difference in rules between the policies.""" |
| |
| self.log.info( |
| "Generating {0} differences from {1.left_policy} to {1.right_policy}". |
| format(ruletype, self)) |
| |
| if not self._left_te_rules or not self._right_te_rules: |
| self._create_te_rule_lists() |
| |
| added, removed, matched = self._set_diff( |
| self._expand_generator(self._left_te_rules[ruletype], AVRuleWrapper), |
| self._expand_generator(self._right_te_rules[ruletype], AVRuleWrapper)) |
| |
| modified = [] |
| for left_rule, right_rule in matched: |
| # Criteria for modified rules |
| # 1. change to permissions |
| added_perms, removed_perms, matched_perms = self._set_diff(left_rule.perms, |
| right_rule.perms) |
| |
| # the final set comprehension is to avoid having lists |
| # like [("perm1", "perm1"), ("perm2", "perm2")], as the |
| # matched_perms return from _set_diff is a set of tuples |
| if added_perms or removed_perms: |
| modified.append(modified_avrule_record(left_rule, |
| added_perms, |
| removed_perms, |
| set(p[0] for p in matched_perms))) |
| |
| setattr(self, "added_{0}s".format(ruletype), added) |
| setattr(self, "removed_{0}s".format(ruletype), removed) |
| setattr(self, "modified_{0}s".format(ruletype), modified) |
| |
| return diff |
| |
| |
| def avx_diff_template(ruletype): |
| |
| """ |
| This is a template for the extended permission access vector diff functions. |
| |
| Parameters: |
| ruletype The rule type, e.g. "allowxperm". |
| """ |
| |
| def diff(self): |
| """Generate the difference in rules between the policies.""" |
| |
| self.log.info( |
| "Generating {0} differences from {1.left_policy} to {1.right_policy}". |
| format(ruletype, self)) |
| |
| if not self._left_te_rules or not self._right_te_rules: |
| self._create_te_rule_lists() |
| |
| added, removed, matched = self._set_diff( |
| self._expand_generator(self._left_te_rules[ruletype], AVRuleXpermWrapper), |
| self._expand_generator(self._right_te_rules[ruletype], AVRuleXpermWrapper)) |
| |
| modified = [] |
| for left_rule, right_rule in matched: |
| # Criteria for modified rules |
| # 1. change to permissions |
| added_perms, removed_perms, matched_perms = self._set_diff(left_rule.perms, |
| right_rule.perms) |
| |
| # the final set comprehension is to avoid having lists |
| # like [("perm1", "perm1"), ("perm2", "perm2")], as the |
| # matched_perms return from _set_diff is a set of tuples |
| if added_perms or removed_perms: |
| modified.append(modified_avrule_record(left_rule, |
| ioctlSet(added_perms), |
| ioctlSet(removed_perms), |
| ioctlSet(p[0] for p in matched_perms))) |
| |
| setattr(self, "added_{0}s".format(ruletype), added) |
| setattr(self, "removed_{0}s".format(ruletype), removed) |
| setattr(self, "modified_{0}s".format(ruletype), modified) |
| |
| return diff |
| |
| |
| def te_diff_template(ruletype): |
| |
| """ |
| This is a template for the type_* diff functions. |
| |
| Parameters: |
| ruletype The rule type, e.g. "type_transition". |
| """ |
| |
| def diff(self): |
| """Generate the difference in rules between the policies.""" |
| |
| self.log.info( |
| "Generating {0} differences from {1.left_policy} to {1.right_policy}". |
| format(ruletype, self)) |
| |
| if not self._left_te_rules or not self._right_te_rules: |
| self._create_te_rule_lists() |
| |
| added, removed, matched = self._set_diff( |
| self._expand_generator(self._left_te_rules[ruletype], TERuleWrapper), |
| self._expand_generator(self._right_te_rules[ruletype], TERuleWrapper)) |
| |
| modified = [] |
| for left_rule, right_rule in matched: |
| # Criteria for modified rules |
| # 1. change to default type |
| if SymbolWrapper(left_rule.default) != SymbolWrapper(right_rule.default): |
| modified.append(modified_terule_record(left_rule, |
| right_rule.default, |
| left_rule.default)) |
| |
| setattr(self, "added_{0}s".format(ruletype), added) |
| setattr(self, "removed_{0}s".format(ruletype), removed) |
| setattr(self, "modified_{0}s".format(ruletype), modified) |
| |
| return diff |
| |
| |
| class TERulesDifference(Difference): |
| |
| """ |
| Determine the difference in type enforcement rules |
| between two policies. |
| """ |
| |
| diff_allows = av_diff_template("allow") |
| added_allows = DiffResultDescriptor("diff_allows") |
| removed_allows = DiffResultDescriptor("diff_allows") |
| modified_allows = DiffResultDescriptor("diff_allows") |
| |
| diff_auditallows = av_diff_template("auditallow") |
| added_auditallows = DiffResultDescriptor("diff_auditallows") |
| removed_auditallows = DiffResultDescriptor("diff_auditallows") |
| modified_auditallows = DiffResultDescriptor("diff_auditallows") |
| |
| diff_neverallows = av_diff_template("neverallow") |
| added_neverallows = DiffResultDescriptor("diff_neverallows") |
| removed_neverallows = DiffResultDescriptor("diff_neverallows") |
| modified_neverallows = DiffResultDescriptor("diff_neverallows") |
| |
| diff_dontaudits = av_diff_template("dontaudit") |
| added_dontaudits = DiffResultDescriptor("diff_dontaudits") |
| removed_dontaudits = DiffResultDescriptor("diff_dontaudits") |
| modified_dontaudits = DiffResultDescriptor("diff_dontaudits") |
| |
| diff_allowxperms = avx_diff_template("allowxperm") |
| added_allowxperms = DiffResultDescriptor("diff_allowxperms") |
| removed_allowxperms = DiffResultDescriptor("diff_allowxperms") |
| modified_allowxperms = DiffResultDescriptor("diff_allowxperms") |
| |
| diff_auditallowxperms = avx_diff_template("auditallowxperm") |
| added_auditallowxperms = DiffResultDescriptor("diff_auditallowxperms") |
| removed_auditallowxperms = DiffResultDescriptor("diff_auditallowxperms") |
| modified_auditallowxperms = DiffResultDescriptor("diff_auditallowxperms") |
| |
| diff_neverallowxperms = avx_diff_template("neverallowxperm") |
| added_neverallowxperms = DiffResultDescriptor("diff_neverallowxperms") |
| removed_neverallowxperms = DiffResultDescriptor("diff_neverallowxperms") |
| modified_neverallowxperms = DiffResultDescriptor("diff_neverallowxperms") |
| |
| diff_dontauditxperms = avx_diff_template("dontauditxperm") |
| added_dontauditxperms = DiffResultDescriptor("diff_dontauditxperms") |
| removed_dontauditxperms = DiffResultDescriptor("diff_dontauditxperms") |
| modified_dontauditxperms = DiffResultDescriptor("diff_dontauditxperms") |
| |
| diff_type_transitions = te_diff_template("type_transition") |
| added_type_transitions = DiffResultDescriptor("diff_type_transitions") |
| removed_type_transitions = DiffResultDescriptor("diff_type_transitions") |
| modified_type_transitions = DiffResultDescriptor("diff_type_transitions") |
| |
| diff_type_changes = te_diff_template("type_change") |
| added_type_changes = DiffResultDescriptor("diff_type_changes") |
| removed_type_changes = DiffResultDescriptor("diff_type_changes") |
| modified_type_changes = DiffResultDescriptor("diff_type_changes") |
| |
| diff_type_members = te_diff_template("type_member") |
| added_type_members = DiffResultDescriptor("diff_type_members") |
| removed_type_members = DiffResultDescriptor("diff_type_members") |
| modified_type_members = DiffResultDescriptor("diff_type_members") |
| |
| # Lists of rules for each policy |
| _left_te_rules = defaultdict(list) |
| _right_te_rules = defaultdict(list) |
| |
| # |
| # Internal functions |
| # |
| def _create_te_rule_lists(self): |
| """Create rule lists for both policies.""" |
| # do not expand yet, to keep memory |
| # use down as long as possible |
| self.log.debug("Building TE rule lists from {0.left_policy}".format(self)) |
| for rule in self.left_policy.terules(): |
| self._left_te_rules[rule.ruletype].append(rule) |
| |
| self.log.debug("Building TE rule lists from {0.right_policy}".format(self)) |
| for rule in self.right_policy.terules(): |
| self._right_te_rules[rule.ruletype].append(rule) |
| |
| self.log.debug("Completed building TE rule lists.") |
| |
| def _reset_diff(self): |
| """Reset diff results on policy changes.""" |
| self.log.debug("Resetting TE rule differences") |
| self.added_allows = None |
| self.removed_allows = None |
| self.modified_allows = None |
| self.added_auditallows = None |
| self.removed_auditallows = None |
| self.modified_auditallows = None |
| self.added_neverallows = None |
| self.removed_neverallows = None |
| self.modified_neverallows = None |
| self.added_dontaudits = None |
| self.removed_dontaudits = None |
| self.modified_dontaudits = None |
| self.added_allowxperms = None |
| self.removed_allowxperms = None |
| self.modified_allowxperms = None |
| self.added_auditallowxperms = None |
| self.removed_auditallowxperms = None |
| self.modified_auditallowxperms = None |
| self.added_neverallowxperms = None |
| self.removed_neverallowxperms = None |
| self.modified_neverallowxperms = None |
| self.added_dontauditxperms = None |
| self.removed_dontauditxperms = None |
| self.modified_dontauditxperms = None |
| self.added_type_transitions = None |
| self.removed_type_transitions = None |
| self.modified_type_transitions = None |
| self.added_type_changes = None |
| self.removed_type_changes = None |
| self.modified_type_changes = None |
| self.added_type_members = None |
| self.removed_type_members = None |
| self.modified_type_members = None |
| |
| # Sets of rules for each policy |
| self._left_te_rules.clear() |
| self._right_te_rules.clear() |
| |
| |
| class AVRuleWrapper(Wrapper): |
| |
| """Wrap access vector 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) |
| |
| try: |
| self.conditional = ConditionalExprWrapper(rule.conditional) |
| self.conditional_block = rule.conditional_block |
| except RuleNotConditional: |
| self.conditional = None |
| self.conditional_block = None |
| |
| def __hash__(self): |
| return self.key |
| |
| def __lt__(self, other): |
| return self.key < other.key |
| |
| def __eq__(self, other): |
| # because TERuleDifference groups rules by ruletype, |
| # the ruletype always matches. |
| return self.source == other.source and \ |
| self.target == other.target and \ |
| self.tclass == other.tclass and \ |
| self.conditional == other.conditional and \ |
| self.conditional_block == other.conditional_block |
| |
| |
| class AVRuleXpermWrapper(Wrapper): |
| |
| """Wrap extended permission access vector 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.xperm_type = rule.xperm_type |
| self.key = hash(rule) |
| |
| def __hash__(self): |
| return self.key |
| |
| def __lt__(self, other): |
| return self.key < other.key |
| |
| def __eq__(self, other): |
| # because TERuleDifference groups rules by ruletype, |
| # the ruletype always matches. |
| return self.source == other.source and \ |
| self.target == other.target and \ |
| self.tclass == other.tclass and \ |
| self.xperm_type == other.xperm_type |
| |
| |
| class TERuleWrapper(Wrapper): |
| |
| """Wrap type_* 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) |
| |
| try: |
| self.conditional = ConditionalExprWrapper(rule.conditional) |
| self.conditional_block = rule.conditional_block |
| except RuleNotConditional: |
| self.conditional = None |
| self.conditional_block = None |
| |
| try: |
| self.filename = rule.filename |
| except (RuleUseError, TERuleNoFilename): |
| self.filename = None |
| |
| def __hash__(self): |
| return self.key |
| |
| def __lt__(self, other): |
| return self.key < other.key |
| |
| def __eq__(self, other): |
| # because TERuleDifference groups rules by ruletype, |
| # the ruletype always matches. |
| return self.source == other.source and \ |
| self.target == other.target and \ |
| self.tclass == other.tclass and \ |
| self.conditional == other.conditional and \ |
| self.conditional_block == other.conditional_block and \ |
| self.filename == self.filename |