1 # Copyright 2014-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 # pylint: disable=too-many-public-methods 20 # 21 # Create a Python representation of the policy. 22 # The idea is that this is module provides convenient 23 # abstractions and methods for accessing the policy 24 # structures. 25 import logging 26 from itertools import chain 27 from errno import ENOENT 28 29 try: 30 import selinux 31 except ImportError: 32 pass 33 34 from . import qpol 35 36 # The libqpol SWIG class is not quite natural for 37 # Python the policy is repeatedly referenced in the 38 # function calls, which makes sense for C code 39 # but not for python code, so each object keeps 40 # a reference to the policy for internal use. 41 # This also makes sense since an object would only 42 # be valid for the policy it comes from. 43 44 # Components 45 from . import boolcond 46 from . import bounds 47 from . import default 48 from . import mls 49 from . import objclass 50 from . import polcap 51 from . import role 52 from . import typeattr 53 from . import user 54 55 # Rules 56 from . import mlsrule 57 from . import rbacrule 58 from . import terule 59 60 # Constraints 61 from . import constraint 62 63 # In-policy Labeling 64 from . import fscontext 65 from . import initsid 66 from . import netcontext 67 68 # Xen 69 from . import xencontext 70 71 # Classes useful for policyrep users: 72 from . import exception 73 from .netcontext import PortconProtocol, port_range 74 from .terule import ioctlSet 75 76 77 class SELinuxPolicy(object): 78 79 """The complete SELinux policy.""" 80 81 def __init__(self, policyfile=None): 82 """ 83 Parameter: 84 policyfile Path to a policy to open. 85 """ 86 87 self.log = logging.getLogger(__name__) 88 self.policy = None 89 self.filename = None 90 91 if policyfile: 92 self._load_policy(policyfile) 93 else: 94 try: 95 self._load_running_policy() 96 except NameError: 97 raise RuntimeError("Loading the running policy requires libselinux Python bindings") 98 99 def __repr__(self): 100 return "<SELinuxPolicy(\"{0}\")>".format(self.filename) 101 102 def __str__(self): 103 return self.filename 104 105 def __deepcopy__(self, memo): 106 # shallow copy as all of the members are immutable 107 newobj = SELinuxPolicy.__new__(SELinuxPolicy) 108 newobj.policy = self.policy 109 newobj.filename = self.filename 110 memo[id(self)] = newobj 111 return newobj 112 113 # 114 # Policy loading functions 115 # 116 117 def _load_policy(self, filename): 118 """Load the specified policy.""" 119 self.log.info("Opening SELinux policy \"{0}\"".format(filename)) 120 121 try: 122 self.policy = qpol.qpol_policy_factory(str(filename)) 123 except SyntaxError as err: 124 raise exception.InvalidPolicy("Error opening policy file \"{0}\": {1}". 125 format(filename, err)) 126 127 self.log.info("Successfully opened SELinux policy \"{0}\"".format(filename)) 128 self.filename = filename 129 130 @staticmethod 131 def _potential_policies(): 132 """Generate a list of potential policies to use.""" 133 # try libselinux for current policy 134 if selinux.selinuxfs_exists(): 135 yield selinux.selinux_current_policy_path() 136 137 # otherwise look through the supported policy versions 138 base_policy_path = selinux.selinux_binary_policy_path() 139 for version in range(qpol.QPOL_POLICY_MAX_VERSION, qpol.QPOL_POLICY_MIN_VERSION-1, -1): 140 yield "{0}.{1}".format(base_policy_path, version) 141 142 def _load_running_policy(self): 143 """Try to load the current running policy.""" 144 self.log.info("Attempting to locate current running policy.") 145 146 for filename in self._potential_policies(): 147 try: 148 self._load_policy(filename) 149 except OSError as err: 150 if err.errno != ENOENT: 151 raise 152 else: 153 break 154 else: 155 raise RuntimeError("Unable to locate an SELinux policy to load.") 156 157 # 158 # Policy properties 159 # 160 @property 161 def handle_unknown(self): 162 """The handle unknown permissions setting (allow,deny,reject)""" 163 return self.policy.handle_unknown() 164 165 @property 166 def mls(self): 167 """(T/F) The policy has MLS enabled.""" 168 return mls.enabled(self.policy) 169 170 @property 171 def version(self): 172 """The policy database version (e.g. v29)""" 173 return self.policy.version() 174 175 @property 176 def target_platform(self): 177 """The policy platform (selinux or xen)""" 178 return self.policy.target_platform() 179 180 # 181 # Policy statistics 182 # 183 184 @property 185 def allow_count(self): 186 """The number of (type) allow rules.""" 187 return self.policy.avrule_allow_count() 188 189 @property 190 def allowxperm_count(self): 191 """The number of allowxperm rules.""" 192 return self.policy.avrule_allowx_count() 193 194 @property 195 def auditallow_count(self): 196 """The number of auditallow rules.""" 197 return self.policy.avrule_auditallow_count() 198 199 @property 200 def auditallowxperm_count(self): 201 """The number of auditallowxperm rules.""" 202 return self.policy.avrule_auditallowx_count() 203 204 @property 205 def boolean_count(self): 206 """The number of Booleans.""" 207 return self.policy.bool_count() 208 209 @property 210 def category_count(self): 211 """The number of categories.""" 212 return sum(1 for _ in self.categories()) 213 214 @property 215 def class_count(self): 216 """The number of object classes.""" 217 return self.policy.class_count() 218 219 @property 220 def common_count(self): 221 """The number of common permission sets.""" 222 return self.policy.common_count() 223 224 @property 225 def conditional_count(self): 226 """The number of conditionals.""" 227 return self.policy.cond_count() 228 229 @property 230 def constraint_count(self): 231 """The number of standard constraints.""" 232 return sum(1 for c in self.constraints() if c.ruletype == "constrain") 233 234 @property 235 def default_count(self): 236 """The number of default_* rules.""" 237 return sum(1 for d in self.defaults()) 238 239 @property 240 def devicetreecon_count(self): 241 """The number of Xen devicetreecon statements.""" 242 return self.policy.devicetreecon_count() 243 244 @property 245 def dontaudit_count(self): 246 """The number of dontaudit rules.""" 247 return self.policy.avrule_dontaudit_count() 248 249 @property 250 def dontauditxperm_count(self): 251 """The number of dontauditxperm rules.""" 252 return self.policy.avrule_dontauditx_count() 253 254 @property 255 def fs_use_count(self): 256 """fs_use_* statements.""" 257 return self.policy.fs_use_count() 258 259 @property 260 def genfscon_count(self): 261 """The number of genfscon statements.""" 262 return self.policy.genfscon_count() 263 264 @property 265 def initialsids_count(self): 266 """The number of initial sid statements.""" 267 return self.policy.isid_count() 268 269 @property 270 def iomemcon_count(self): 271 """The number of Xen iomemcon statements.""" 272 return self.policy.iomemcon_count() 273 274 @property 275 def ioportcon_count(self): 276 """The number of Xen ioportcon statements.""" 277 return self.policy.ioportcon_count() 278 279 @property 280 def level_count(self): 281 """The number of levels.""" 282 return sum(1 for _ in self.levels()) 283 284 @property 285 def mlsconstraint_count(self): 286 """The number of MLS constraints.""" 287 return sum(1 for c in self.constraints() if c.ruletype == "mlsconstrain") 288 289 @property 290 def mlsvalidatetrans_count(self): 291 """The number of MLS validatetrans.""" 292 return sum(1 for v in self.constraints() if v.ruletype == "mlsvalidatetrans") 293 294 @property 295 def netifcon_count(self): 296 """The number of netifcon statements.""" 297 return self.policy.netifcon_count() 298 299 @property 300 def neverallow_count(self): 301 """The number of neverallow rules.""" 302 return self.policy.avrule_neverallow_count() 303 304 @property 305 def neverallowxperm_count(self): 306 """The number of neverallowxperm rules.""" 307 return self.policy.avrule_neverallowx_count() 308 309 @property 310 def nodecon_count(self): 311 """The number of nodecon statements.""" 312 return self.policy.nodecon_count() 313 314 @property 315 def pcidevicecon_count(self): 316 """The number of Xen pcidevicecon statements.""" 317 return self.policy.pcidevicecon_count() 318 319 @property 320 def permission_count(self): 321 """The number of permissions.""" 322 return sum(len(c.perms) for c in chain(self.commons(), self.classes())) 323 324 @property 325 def permissives_count(self): 326 """The number of permissive types.""" 327 return self.policy.permissive_count() 328 329 @property 330 def pirqcon_count(self): 331 """The number of Xen pirqcon statements.""" 332 return self.policy.pirqcon_count() 333 334 @property 335 def polcap_count(self): 336 """The number of policy capabilities.""" 337 return self.policy.polcap_count() 338 339 @property 340 def portcon_count(self): 341 """The number of portcon statements.""" 342 return self.policy.portcon_count() 343 344 @property 345 def range_transition_count(self): 346 """The number of range_transition rules.""" 347 return self.policy.range_trans_count() 348 349 @property 350 def role_count(self): 351 """The number of roles.""" 352 return self.policy.role_count() 353 354 @property 355 def role_allow_count(self): 356 """The number of (role) allow rules.""" 357 return self.policy.role_allow_count() 358 359 @property 360 def role_transition_count(self): 361 """The number of role_transition rules.""" 362 return self.policy.role_trans_count() 363 364 @property 365 def type_attribute_count(self): 366 """The number of (type) attributes.""" 367 return sum(1 for _ in self.typeattributes()) 368 369 @property 370 def type_count(self): 371 """The number of types.""" 372 return sum(1 for _ in self.types()) 373 374 @property 375 def type_change_count(self): 376 """The number of type_change rules.""" 377 return self.policy.terule_change_count() 378 379 @property 380 def type_member_count(self): 381 """The number of type_member rules.""" 382 return self.policy.terule_member_count() 383 384 @property 385 def type_transition_count(self): 386 """The number of type_transition rules.""" 387 return self.policy.terule_trans_count() + self.policy.filename_trans_count() 388 389 @property 390 def typebounds_count(self): 391 """The number of typebounds rules.""" 392 return sum(1 for b in self.bounds() if b.ruletype == "typebounds") 393 394 @property 395 def user_count(self): 396 """The number of users.""" 397 return self.policy.user_count() 398 399 @property 400 def validatetrans_count(self): 401 """The number of validatetrans.""" 402 return sum(1 for v in self.constraints() if v.ruletype == "validatetrans") 403 404 # 405 # Policy components lookup functions 406 # 407 def lookup_boolean(self, name): 408 """Look up a Boolean.""" 409 return boolcond.boolean_factory(self.policy, name) 410 411 def lookup_class(self, name): 412 """Look up an object class.""" 413 return objclass.class_factory(self.policy, name) 414 415 def lookup_common(self, name): 416 """Look up a common permission set.""" 417 return objclass.common_factory(self.policy, name) 418 419 def lookup_initialsid(self, name): 420 """Look up an initial sid.""" 421 return initsid.initialsid_factory(self.policy, name) 422 423 def lookup_level(self, level): 424 """Look up a MLS level.""" 425 return mls.level_factory(self.policy, level) 426 427 def lookup_sensitivity(self, name): 428 """Look up a MLS sensitivity by name.""" 429 return mls.sensitivity_factory(self.policy, name) 430 431 def lookup_range(self, range_): 432 """Look up a MLS range.""" 433 return mls.range_factory(self.policy, range_) 434 435 def lookup_role(self, name): 436 """Look up a role by name.""" 437 return role.role_factory(self.policy, name) 438 439 def lookup_type(self, name): 440 """Look up a type by name.""" 441 return typeattr.type_factory(self.policy, name, deref=True) 442 443 def lookup_type_or_attr(self, name): 444 """Look up a type or type attribute by name.""" 445 return typeattr.type_or_attr_factory(self.policy, name, deref=True) 446 447 def lookup_typeattr(self, name): 448 """Look up a type attribute by name.""" 449 return typeattr.attribute_factory(self.policy, name) 450 451 def lookup_user(self, name): 452 """Look up a user by name.""" 453 return user.user_factory(self.policy, name) 454 455 # 456 # Policy components generators 457 # 458 459 def bools(self): 460 """Generator which yields all Booleans.""" 461 for bool_ in self.policy.bool_iter(): 462 yield boolcond.boolean_factory(self.policy, bool_) 463 464 def bounds(self): 465 """Generator which yields all *bounds statements (typebounds, etc.)""" 466 for bound in self.policy.typebounds_iter(): 467 yield bounds.bounds_factory(self.policy, bound) 468 469 def categories(self): 470 """Generator which yields all MLS categories.""" 471 for cat in self.policy.cat_iter(): 472 try: 473 yield mls.category_factory(self.policy, cat) 474 except TypeError: 475 # libqpol unfortunately iterates over aliases too 476 pass 477 478 def classes(self): 479 """Generator which yields all object classes.""" 480 for class_ in self.policy.class_iter(): 481 yield objclass.class_factory(self.policy, class_) 482 483 def commons(self): 484 """Generator which yields all commons.""" 485 for common in self.policy.common_iter(): 486 yield objclass.common_factory(self.policy, common) 487 488 def defaults(self): 489 """Generator which yields all default_* statements.""" 490 for default_ in self.policy.default_iter(): 491 try: 492 for default_obj in default.default_factory(self.policy, default_): 493 yield default_obj 494 except exception.NoDefaults: 495 # qpol iterates over all classes. Handle case 496 # where a class has no default_* settings. 497 pass 498 499 def levels(self): 500 """Generator which yields all level declarations.""" 501 for level in self.policy.level_iter(): 502 503 try: 504 yield mls.level_decl_factory(self.policy, level) 505 except TypeError: 506 # libqpol unfortunately iterates over levels and sens aliases 507 pass 508 509 def polcaps(self): 510 """Generator which yields all policy capabilities.""" 511 for cap in self.policy.polcap_iter(): 512 yield polcap.polcap_factory(self.policy, cap) 513 514 def roles(self): 515 """Generator which yields all roles.""" 516 for role_ in self.policy.role_iter(): 517 yield role.role_factory(self.policy, role_) 518 519 def sensitivities(self): 520 """Generator which yields all sensitivities.""" 521 # see mls.py for more info on why level_iter is used here. 522 for sens in self.policy.level_iter(): 523 try: 524 yield mls.sensitivity_factory(self.policy, sens) 525 except TypeError: 526 # libqpol unfortunately iterates over sens and aliases 527 pass 528 529 def types(self): 530 """Generator which yields all types.""" 531 for type_ in self.policy.type_iter(): 532 try: 533 yield typeattr.type_factory(self.policy, type_) 534 except TypeError: 535 # libqpol unfortunately iterates over attributes and aliases 536 pass 537 538 def typeattributes(self): 539 """Generator which yields all (type) attributes.""" 540 for type_ in self.policy.type_iter(): 541 try: 542 yield typeattr.attribute_factory(self.policy, type_) 543 except TypeError: 544 # libqpol unfortunately iterates over attributes and aliases 545 pass 546 547 def users(self): 548 """Generator which yields all users.""" 549 for user_ in self.policy.user_iter(): 550 yield user.user_factory(self.policy, user_) 551 552 # 553 # Policy rules generators 554 # 555 def mlsrules(self): 556 """Generator which yields all MLS rules.""" 557 for rule in self.policy.range_trans_iter(): 558 yield mlsrule.mls_rule_factory(self.policy, rule) 559 560 def rbacrules(self): 561 """Generator which yields all RBAC rules.""" 562 for rule in chain(self.policy.role_allow_iter(), 563 self.policy.role_trans_iter()): 564 yield rbacrule.rbac_rule_factory(self.policy, rule) 565 566 def terules(self): 567 """Generator which yields all type enforcement rules.""" 568 for rule in chain(self.policy.avrule_iter(), 569 self.policy.avrulex_iter(), 570 self.policy.terule_iter(), 571 self.policy.filename_trans_iter()): 572 yield terule.te_rule_factory(self.policy, rule) 573 574 # 575 # Policy rule type validators 576 # 577 @staticmethod 578 def validate_bounds_ruletype(types): 579 """Validate constraint types.""" 580 return bounds.validate_ruletype(types) 581 582 @staticmethod 583 def validate_constraint_ruletype(types): 584 """Validate constraint types.""" 585 return constraint.validate_ruletype(types) 586 587 @staticmethod 588 def validate_default_ruletype(types): 589 """Validate default_* types.""" 590 return default.validate_ruletype(types) 591 592 @staticmethod 593 def validate_default_value(value): 594 """Validate default_* values.""" 595 return default.validate_default_value(value) 596 597 @staticmethod 598 def validate_default_range(value): 599 """Validate default_range range.""" 600 return default.validate_default_range(value) 601 602 @staticmethod 603 def validate_fs_use_ruletype(types): 604 """Validate fs_use_* rule types.""" 605 return fscontext.validate_ruletype(types) 606 607 @staticmethod 608 def validate_mls_ruletype(types): 609 """Validate MLS rule types.""" 610 return mlsrule.validate_ruletype(types) 611 612 @staticmethod 613 def validate_rbac_ruletype(types): 614 """Validate RBAC rule types.""" 615 return rbacrule.validate_ruletype(types) 616 617 @staticmethod 618 def validate_te_ruletype(types): 619 """Validate type enforcement rule types.""" 620 return terule.validate_ruletype(types) 621 622 # 623 # Constraints generators 624 # 625 626 def constraints(self): 627 """Generator which yields all constraints (regular and MLS).""" 628 for constraint_ in chain(self.policy.constraint_iter(), 629 self.policy.validatetrans_iter()): 630 631 yield constraint.constraint_factory(self.policy, constraint_) 632 633 # 634 # In-policy Labeling statement generators 635 # 636 def fs_uses(self): 637 """Generator which yields all fs_use_* statements.""" 638 for fs_use in self.policy.fs_use_iter(): 639 yield fscontext.fs_use_factory(self.policy, fs_use) 640 641 def genfscons(self): 642 """Generator which yields all genfscon statements.""" 643 for fscon in self.policy.genfscon_iter(): 644 yield fscontext.genfscon_factory(self.policy, fscon) 645 646 def initialsids(self): 647 """Generator which yields all initial SID statements.""" 648 for sid in self.policy.isid_iter(): 649 yield initsid.initialsid_factory(self.policy, sid) 650 651 def netifcons(self): 652 """Generator which yields all netifcon statements.""" 653 for ifcon in self.policy.netifcon_iter(): 654 yield netcontext.netifcon_factory(self.policy, ifcon) 655 656 def nodecons(self): 657 """Generator which yields all nodecon statements.""" 658 for node in self.policy.nodecon_iter(): 659 yield netcontext.nodecon_factory(self.policy, node) 660 661 def portcons(self): 662 """Generator which yields all portcon statements.""" 663 for port in self.policy.portcon_iter(): 664 yield netcontext.portcon_factory(self.policy, port) 665 666 # 667 # Xen labeling statements 668 # 669 def iomemcons(self): 670 """Generator which yields all iomemcon statements.""" 671 for mem_addr in self.policy.iomemcon_iter(): 672 yield xencontext.iomemcon_factory(self.policy, mem_addr) 673 674 def ioportcons(self): 675 """Generator which yields all ioportcon statements.""" 676 for port in self.policy.ioportcon_iter(): 677 yield xencontext.ioportcon_factory(self.policy, port) 678 679 def pcidevicecons(self): 680 """Generator which yields all pcidevicecon statements.""" 681 for device in self.policy.pcidevicecon_iter(): 682 yield xencontext.pcidevicecon_factory(self.policy, device) 683 684 def pirqcons(self): 685 """Generator which yields all pirqcon statements.""" 686 for irq in self.policy.pirqcon_iter(): 687 yield xencontext.pirqcon_factory(self.policy, irq) 688 689 def devicetreecons(self): 690 """Generator which yields all devicetreecon statements.""" 691 for path in self.policy.devicetreecon_iter(): 692 yield xencontext.devicetreecon_factory(self.policy, path) 693