mirror of
https://github.com/SELinuxProject/setools
synced 2025-04-07 10:01:20 +00:00
If multiple rule types were diffed, the rule lists would be generated multiple times if one or more of the rule lists were empty.
124 lines
4.5 KiB
Python
124 lines
4.5 KiB
Python
# 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 defaultdict, namedtuple
|
|
|
|
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_mls_rules = defaultdict(list)
|
|
_right_mls_rules = defaultdict(list)
|
|
|
|
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 not self._left_mls_rules or not self._right_mls_rules:
|
|
self._create_mls_rule_lists()
|
|
|
|
added, removed, matched = self._set_diff(
|
|
self._expand_generator(self._left_mls_rules["range_transition"], MLSRuleWrapper),
|
|
self._expand_generator(self._right_mls_rules["range_transition"], MLSRuleWrapper))
|
|
|
|
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))
|
|
|
|
self.added_range_transitions = added
|
|
self.removed_range_transitions = removed
|
|
self.modified_range_transitions = modified
|
|
|
|
#
|
|
# Internal functions
|
|
#
|
|
def _create_mls_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 MLS rule lists from {0.left_policy}".format(self))
|
|
for rule in self.left_policy.mlsrules():
|
|
self._left_mls_rules[rule.ruletype].append(rule)
|
|
|
|
self.log.debug("Building MLS rule lists from {0.right_policy}".format(self))
|
|
for rule in self.right_policy.mlsrules():
|
|
self._right_mls_rules[rule.ruletype].append(rule)
|
|
|
|
self.log.debug("Completed building MLS rule lists.")
|
|
|
|
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_mls_rules.clear()
|
|
self._right_mls_rules.clear()
|
|
|
|
|
|
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
|