Home | History | Annotate | Download | only in policyrep
      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