1 # Copyright 2016, Tresys Technology, LLC 2 # 3 # This file is part of SETools. 4 # 5 # SETools is free software: you can redistribute it and/or modify 6 # it under the terms of the GNU Lesser General Public License as 7 # published by the Free Software Foundation, either version 2.1 of 8 # the License, or (at your option) any later version. 9 # 10 # SETools is distributed in the hope that it will be useful, 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 # GNU Lesser General Public License for more details. 14 # 15 # You should have received a copy of the GNU Lesser General Public 16 # License along with SETools. If not, see 17 # <http://www.gnu.org/licenses/>. 18 # 19 from collections import namedtuple 20 21 from .descriptors import DiffResultDescriptor 22 from .difference import Difference, SymbolWrapper, Wrapper 23 24 25 modified_bounds_record = namedtuple("modified_bound", ["rule", "added_bound", "removed_bound"]) 26 27 28 class BoundsDifference(Difference): 29 30 """Determine the difference in *bounds between two policies.""" 31 32 added_typebounds = DiffResultDescriptor("diff_typebounds") 33 removed_typebounds = DiffResultDescriptor("diff_typebounds") 34 modified_typebounds = DiffResultDescriptor("diff_typebounds") 35 36 # Lists of rules for each policy 37 _left_typebounds = None 38 _right_typebounds = None 39 40 def diff_typebounds(self): 41 """Generate the difference in typebound rules between the policies.""" 42 43 self.log.info("Generating typebounds differences from {0.left_policy} to {0.right_policy}". 44 format(self)) 45 46 if self._left_typebounds is None or self._right_typebounds is None: 47 self._create_typebound_lists() 48 49 self.added_typebounds, self.removed_typebounds, matched_typebounds = self._set_diff( 50 (BoundsWrapper(c) for c in self._left_typebounds), 51 (BoundsWrapper(c) for c in self._right_typebounds), 52 key=lambda b: str(b.child)) 53 54 self.modified_typebounds = [] 55 56 for left_bound, right_bound in matched_typebounds: 57 if SymbolWrapper(left_bound.parent) != SymbolWrapper(right_bound.parent): 58 self.modified_typebounds.append(modified_bounds_record( 59 left_bound, right_bound.parent, left_bound.parent)) 60 61 # 62 # Internal functions 63 # 64 def _create_typebound_lists(self): 65 """Create rule lists for both policies.""" 66 self._left_typebounds = [] 67 for rule in self.left_policy.bounds(): 68 if rule.ruletype == "typebounds": 69 self._left_typebounds.append(rule) 70 else: 71 self.log.error("Unknown rule type: {0} (This is an SETools bug)". 72 format(rule.ruletype)) 73 74 self._right_typebounds = [] 75 for rule in self.right_policy.bounds(): 76 if rule.ruletype == "typebounds": 77 self._right_typebounds.append(rule) 78 else: 79 self.log.error("Unknown rule type: {0} (This is an SETools bug)". 80 format(rule.ruletype)) 81 82 def _reset_diff(self): 83 """Reset diff results on policy changes.""" 84 self.log.debug("Resetting all *bounds differences") 85 self.added_typebounds = None 86 self.removed_typebounds = None 87 88 # Sets of rules for each policy 89 self._left_typebounds = None 90 self._right_typebounds = None 91 92 93 class BoundsWrapper(Wrapper): 94 95 """Wrap *bounds for diff purposes.""" 96 97 def __init__(self, rule): 98 self.origin = rule 99 self.ruletype = rule.ruletype 100 self.parent = SymbolWrapper(rule.parent) 101 self.child = SymbolWrapper(rule.child) 102 self.key = hash(rule) 103 104 def __hash__(self): 105 return self.key 106 107 def __lt__(self, other): 108 return self.key < other.key 109 110 def __eq__(self, other): 111 return self.ruletype == other.ruletype and \ 112 self.child == other.child 113