1 # Copyright 2015-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 defaultdict, namedtuple 20 21 from ..policyrep import ioctlSet 22 from ..policyrep.exception import RuleNotConditional, RuleUseError, TERuleNoFilename 23 24 from .conditional import ConditionalExprWrapper 25 from .descriptors import DiffResultDescriptor 26 from .difference import Difference, SymbolWrapper, Wrapper 27 28 29 modified_avrule_record = namedtuple("modified_avrule", ["rule", 30 "added_perms", 31 "removed_perms", 32 "matched_perms"]) 33 34 modified_terule_record = namedtuple("modified_terule", ["rule", "added_default", "removed_default"]) 35 36 37 def av_diff_template(ruletype): 38 39 """ 40 This is a template for the access vector diff functions. 41 42 Parameters: 43 ruletype The rule type, e.g. "allow". 44 """ 45 46 def diff(self): 47 """Generate the difference in rules between the policies.""" 48 49 self.log.info( 50 "Generating {0} differences from {1.left_policy} to {1.right_policy}". 51 format(ruletype, self)) 52 53 if not self._left_te_rules or not self._right_te_rules: 54 self._create_te_rule_lists() 55 56 added, removed, matched = self._set_diff( 57 self._expand_generator(self._left_te_rules[ruletype], AVRuleWrapper), 58 self._expand_generator(self._right_te_rules[ruletype], AVRuleWrapper)) 59 60 modified = [] 61 for left_rule, right_rule in matched: 62 # Criteria for modified rules 63 # 1. change to permissions 64 added_perms, removed_perms, matched_perms = self._set_diff(left_rule.perms, 65 right_rule.perms) 66 67 # the final set comprehension is to avoid having lists 68 # like [("perm1", "perm1"), ("perm2", "perm2")], as the 69 # matched_perms return from _set_diff is a set of tuples 70 if added_perms or removed_perms: 71 modified.append(modified_avrule_record(left_rule, 72 added_perms, 73 removed_perms, 74 set(p[0] for p in matched_perms))) 75 76 setattr(self, "added_{0}s".format(ruletype), added) 77 setattr(self, "removed_{0}s".format(ruletype), removed) 78 setattr(self, "modified_{0}s".format(ruletype), modified) 79 80 return diff 81 82 83 def avx_diff_template(ruletype): 84 85 """ 86 This is a template for the extended permission access vector diff functions. 87 88 Parameters: 89 ruletype The rule type, e.g. "allowxperm". 90 """ 91 92 def diff(self): 93 """Generate the difference in rules between the policies.""" 94 95 self.log.info( 96 "Generating {0} differences from {1.left_policy} to {1.right_policy}". 97 format(ruletype, self)) 98 99 if not self._left_te_rules or not self._right_te_rules: 100 self._create_te_rule_lists() 101 102 added, removed, matched = self._set_diff( 103 self._expand_generator(self._left_te_rules[ruletype], AVRuleXpermWrapper), 104 self._expand_generator(self._right_te_rules[ruletype], AVRuleXpermWrapper)) 105 106 modified = [] 107 for left_rule, right_rule in matched: 108 # Criteria for modified rules 109 # 1. change to permissions 110 added_perms, removed_perms, matched_perms = self._set_diff(left_rule.perms, 111 right_rule.perms) 112 113 # the final set comprehension is to avoid having lists 114 # like [("perm1", "perm1"), ("perm2", "perm2")], as the 115 # matched_perms return from _set_diff is a set of tuples 116 if added_perms or removed_perms: 117 modified.append(modified_avrule_record(left_rule, 118 ioctlSet(added_perms), 119 ioctlSet(removed_perms), 120 ioctlSet(p[0] for p in matched_perms))) 121 122 setattr(self, "added_{0}s".format(ruletype), added) 123 setattr(self, "removed_{0}s".format(ruletype), removed) 124 setattr(self, "modified_{0}s".format(ruletype), modified) 125 126 return diff 127 128 129 def te_diff_template(ruletype): 130 131 """ 132 This is a template for the type_* diff functions. 133 134 Parameters: 135 ruletype The rule type, e.g. "type_transition". 136 """ 137 138 def diff(self): 139 """Generate the difference in rules between the policies.""" 140 141 self.log.info( 142 "Generating {0} differences from {1.left_policy} to {1.right_policy}". 143 format(ruletype, self)) 144 145 if not self._left_te_rules or not self._right_te_rules: 146 self._create_te_rule_lists() 147 148 added, removed, matched = self._set_diff( 149 self._expand_generator(self._left_te_rules[ruletype], TERuleWrapper), 150 self._expand_generator(self._right_te_rules[ruletype], TERuleWrapper)) 151 152 modified = [] 153 for left_rule, right_rule in matched: 154 # Criteria for modified rules 155 # 1. change to default type 156 if SymbolWrapper(left_rule.default) != SymbolWrapper(right_rule.default): 157 modified.append(modified_terule_record(left_rule, 158 right_rule.default, 159 left_rule.default)) 160 161 setattr(self, "added_{0}s".format(ruletype), added) 162 setattr(self, "removed_{0}s".format(ruletype), removed) 163 setattr(self, "modified_{0}s".format(ruletype), modified) 164 165 return diff 166 167 168 class TERulesDifference(Difference): 169 170 """ 171 Determine the difference in type enforcement rules 172 between two policies. 173 """ 174 175 diff_allows = av_diff_template("allow") 176 added_allows = DiffResultDescriptor("diff_allows") 177 removed_allows = DiffResultDescriptor("diff_allows") 178 modified_allows = DiffResultDescriptor("diff_allows") 179 180 diff_auditallows = av_diff_template("auditallow") 181 added_auditallows = DiffResultDescriptor("diff_auditallows") 182 removed_auditallows = DiffResultDescriptor("diff_auditallows") 183 modified_auditallows = DiffResultDescriptor("diff_auditallows") 184 185 diff_neverallows = av_diff_template("neverallow") 186 added_neverallows = DiffResultDescriptor("diff_neverallows") 187 removed_neverallows = DiffResultDescriptor("diff_neverallows") 188 modified_neverallows = DiffResultDescriptor("diff_neverallows") 189 190 diff_dontaudits = av_diff_template("dontaudit") 191 added_dontaudits = DiffResultDescriptor("diff_dontaudits") 192 removed_dontaudits = DiffResultDescriptor("diff_dontaudits") 193 modified_dontaudits = DiffResultDescriptor("diff_dontaudits") 194 195 diff_allowxperms = avx_diff_template("allowxperm") 196 added_allowxperms = DiffResultDescriptor("diff_allowxperms") 197 removed_allowxperms = DiffResultDescriptor("diff_allowxperms") 198 modified_allowxperms = DiffResultDescriptor("diff_allowxperms") 199 200 diff_auditallowxperms = avx_diff_template("auditallowxperm") 201 added_auditallowxperms = DiffResultDescriptor("diff_auditallowxperms") 202 removed_auditallowxperms = DiffResultDescriptor("diff_auditallowxperms") 203 modified_auditallowxperms = DiffResultDescriptor("diff_auditallowxperms") 204 205 diff_neverallowxperms = avx_diff_template("neverallowxperm") 206 added_neverallowxperms = DiffResultDescriptor("diff_neverallowxperms") 207 removed_neverallowxperms = DiffResultDescriptor("diff_neverallowxperms") 208 modified_neverallowxperms = DiffResultDescriptor("diff_neverallowxperms") 209 210 diff_dontauditxperms = avx_diff_template("dontauditxperm") 211 added_dontauditxperms = DiffResultDescriptor("diff_dontauditxperms") 212 removed_dontauditxperms = DiffResultDescriptor("diff_dontauditxperms") 213 modified_dontauditxperms = DiffResultDescriptor("diff_dontauditxperms") 214 215 diff_type_transitions = te_diff_template("type_transition") 216 added_type_transitions = DiffResultDescriptor("diff_type_transitions") 217 removed_type_transitions = DiffResultDescriptor("diff_type_transitions") 218 modified_type_transitions = DiffResultDescriptor("diff_type_transitions") 219 220 diff_type_changes = te_diff_template("type_change") 221 added_type_changes = DiffResultDescriptor("diff_type_changes") 222 removed_type_changes = DiffResultDescriptor("diff_type_changes") 223 modified_type_changes = DiffResultDescriptor("diff_type_changes") 224 225 diff_type_members = te_diff_template("type_member") 226 added_type_members = DiffResultDescriptor("diff_type_members") 227 removed_type_members = DiffResultDescriptor("diff_type_members") 228 modified_type_members = DiffResultDescriptor("diff_type_members") 229 230 # Lists of rules for each policy 231 _left_te_rules = defaultdict(list) 232 _right_te_rules = defaultdict(list) 233 234 # 235 # Internal functions 236 # 237 def _create_te_rule_lists(self): 238 """Create rule lists for both policies.""" 239 # do not expand yet, to keep memory 240 # use down as long as possible 241 self.log.debug("Building TE rule lists from {0.left_policy}".format(self)) 242 for rule in self.left_policy.terules(): 243 self._left_te_rules[rule.ruletype].append(rule) 244 245 self.log.debug("Building TE rule lists from {0.right_policy}".format(self)) 246 for rule in self.right_policy.terules(): 247 self._right_te_rules[rule.ruletype].append(rule) 248 249 self.log.debug("Completed building TE rule lists.") 250 251 def _reset_diff(self): 252 """Reset diff results on policy changes.""" 253 self.log.debug("Resetting TE rule differences") 254 self.added_allows = None 255 self.removed_allows = None 256 self.modified_allows = None 257 self.added_auditallows = None 258 self.removed_auditallows = None 259 self.modified_auditallows = None 260 self.added_neverallows = None 261 self.removed_neverallows = None 262 self.modified_neverallows = None 263 self.added_dontaudits = None 264 self.removed_dontaudits = None 265 self.modified_dontaudits = None 266 self.added_allowxperms = None 267 self.removed_allowxperms = None 268 self.modified_allowxperms = None 269 self.added_auditallowxperms = None 270 self.removed_auditallowxperms = None 271 self.modified_auditallowxperms = None 272 self.added_neverallowxperms = None 273 self.removed_neverallowxperms = None 274 self.modified_neverallowxperms = None 275 self.added_dontauditxperms = None 276 self.removed_dontauditxperms = None 277 self.modified_dontauditxperms = None 278 self.added_type_transitions = None 279 self.removed_type_transitions = None 280 self.modified_type_transitions = None 281 self.added_type_changes = None 282 self.removed_type_changes = None 283 self.modified_type_changes = None 284 self.added_type_members = None 285 self.removed_type_members = None 286 self.modified_type_members = None 287 288 # Sets of rules for each policy 289 self._left_te_rules.clear() 290 self._right_te_rules.clear() 291 292 293 class AVRuleWrapper(Wrapper): 294 295 """Wrap access vector rules to allow set operations.""" 296 297 def __init__(self, rule): 298 self.origin = rule 299 self.ruletype = rule.ruletype 300 self.source = SymbolWrapper(rule.source) 301 self.target = SymbolWrapper(rule.target) 302 self.tclass = SymbolWrapper(rule.tclass) 303 self.key = hash(rule) 304 305 try: 306 self.conditional = ConditionalExprWrapper(rule.conditional) 307 self.conditional_block = rule.conditional_block 308 except RuleNotConditional: 309 self.conditional = None 310 self.conditional_block = None 311 312 def __hash__(self): 313 return self.key 314 315 def __lt__(self, other): 316 return self.key < other.key 317 318 def __eq__(self, other): 319 # because TERuleDifference groups rules by ruletype, 320 # the ruletype always matches. 321 return self.source == other.source and \ 322 self.target == other.target and \ 323 self.tclass == other.tclass and \ 324 self.conditional == other.conditional and \ 325 self.conditional_block == other.conditional_block 326 327 328 class AVRuleXpermWrapper(Wrapper): 329 330 """Wrap extended permission access vector rules to allow set operations.""" 331 332 def __init__(self, rule): 333 self.origin = rule 334 self.ruletype = rule.ruletype 335 self.source = SymbolWrapper(rule.source) 336 self.target = SymbolWrapper(rule.target) 337 self.tclass = SymbolWrapper(rule.tclass) 338 self.xperm_type = rule.xperm_type 339 self.key = hash(rule) 340 341 def __hash__(self): 342 return self.key 343 344 def __lt__(self, other): 345 return self.key < other.key 346 347 def __eq__(self, other): 348 # because TERuleDifference groups rules by ruletype, 349 # the ruletype always matches. 350 return self.source == other.source and \ 351 self.target == other.target and \ 352 self.tclass == other.tclass and \ 353 self.xperm_type == other.xperm_type 354 355 356 class TERuleWrapper(Wrapper): 357 358 """Wrap type_* rules to allow set operations.""" 359 360 def __init__(self, rule): 361 self.origin = rule 362 self.ruletype = rule.ruletype 363 self.source = SymbolWrapper(rule.source) 364 self.target = SymbolWrapper(rule.target) 365 self.tclass = SymbolWrapper(rule.tclass) 366 self.key = hash(rule) 367 368 try: 369 self.conditional = ConditionalExprWrapper(rule.conditional) 370 self.conditional_block = rule.conditional_block 371 except RuleNotConditional: 372 self.conditional = None 373 self.conditional_block = None 374 375 try: 376 self.filename = rule.filename 377 except (RuleUseError, TERuleNoFilename): 378 self.filename = None 379 380 def __hash__(self): 381 return self.key 382 383 def __lt__(self, other): 384 return self.key < other.key 385 386 def __eq__(self, other): 387 # because TERuleDifference groups rules by ruletype, 388 # the ruletype always matches. 389 return self.source == other.source and \ 390 self.target == other.target and \ 391 self.tclass == other.tclass and \ 392 self.conditional == other.conditional and \ 393 self.conditional_block == other.conditional_block and \ 394 self.filename == self.filename 395