mirror of
https://github.com/SELinuxProject/setools
synced 2025-03-18 08:35:19 +00:00
policyrep: Refactor MLS classes to load most attributes on construction.
Category sets and aliases deferred still, to prevent too much construction up-front. However, the results are saved, rather than lost.
This commit is contained in:
parent
bfdb1e66d8
commit
745a7ae9bd
@ -47,28 +47,34 @@ cdef class Category(PolicySymbol):
|
||||
|
||||
"""An MLS category."""
|
||||
|
||||
cdef sepol.cat_datum_t *handle
|
||||
cdef:
|
||||
sepol.cat_datum_t *handle
|
||||
readonly str name
|
||||
readonly uint32_t _value
|
||||
list _aliases
|
||||
|
||||
@staticmethod
|
||||
cdef factory(SELinuxPolicy policy, sepol.cat_datum_t *symbol):
|
||||
cdef inline Category factory(SELinuxPolicy policy, sepol.cat_datum_t *symbol):
|
||||
"""Factory function for creating Category objects."""
|
||||
cdef Category c
|
||||
if not policy.mls:
|
||||
raise MLSDisabled
|
||||
|
||||
try:
|
||||
return _cat_cache[<uintptr_t>symbol]
|
||||
except KeyError:
|
||||
c = Category()
|
||||
c = Category.__new__(Category)
|
||||
c.policy = policy
|
||||
c.handle = symbol
|
||||
c.name = policy.category_value_to_name(symbol.s.value - 1)
|
||||
c._value = symbol.s.value
|
||||
_cat_cache[<uintptr_t>symbol] = c
|
||||
return c
|
||||
|
||||
def __str__(self):
|
||||
return self.policy.category_value_to_name(self.handle.s.value - 1)
|
||||
return self.name
|
||||
|
||||
def __hash__(self):
|
||||
return hash(str(self))
|
||||
return hash(self.name)
|
||||
|
||||
def __lt__(self, other):
|
||||
# Comparison based on their index instead of their names.
|
||||
@ -78,27 +84,29 @@ cdef class Category(PolicySymbol):
|
||||
"""Low-level equality check (C pointers)."""
|
||||
return self.handle == other.handle
|
||||
|
||||
@property
|
||||
def _value(self):
|
||||
"""
|
||||
The value of the category.
|
||||
|
||||
This is a low-level policy detail exposed for internal use only.
|
||||
"""
|
||||
return self.handle.s.value
|
||||
cdef inline void _load_aliases(self):
|
||||
"""Helper method to load aliases."""
|
||||
if self._aliases is None:
|
||||
self._aliases = list(self.policy.category_aliases(self))
|
||||
|
||||
def aliases(self):
|
||||
"""Generator that yields all aliases for this category."""
|
||||
self._load_aliases()
|
||||
return self.policy.category_aliases(self)
|
||||
|
||||
def statement(self):
|
||||
aliases = list(self.aliases())
|
||||
stmt = "category {0}".format(self)
|
||||
if aliases:
|
||||
if len(aliases) > 1:
|
||||
stmt += " alias {{ {0} }}".format(' '.join(aliases))
|
||||
else:
|
||||
stmt += " alias {0}".format(aliases[0])
|
||||
cdef:
|
||||
str stmt
|
||||
size_t count
|
||||
|
||||
self._load_aliases()
|
||||
count = len(self._aliases)
|
||||
|
||||
stmt = "category {0}".format(self.name)
|
||||
if count > 1:
|
||||
stmt += " alias {{ {0} }}".format(' '.join(self._aliases))
|
||||
elif count == 1:
|
||||
stmt += " alias {0}".format(self._aliases[0])
|
||||
stmt += ";"
|
||||
return stmt
|
||||
|
||||
@ -107,28 +115,36 @@ cdef class Sensitivity(PolicySymbol):
|
||||
|
||||
"""An MLS sensitivity"""
|
||||
|
||||
cdef sepol.level_datum_t *handle
|
||||
cdef:
|
||||
sepol.level_datum_t *handle
|
||||
readonly str name
|
||||
readonly uint32_t _value
|
||||
list _aliases
|
||||
LevelDecl _leveldecl
|
||||
|
||||
@staticmethod
|
||||
cdef factory(SELinuxPolicy policy, sepol.level_datum_t *symbol):
|
||||
cdef inline Sensitivity factory(SELinuxPolicy policy, sepol.level_datum_t *symbol):
|
||||
"""Factory function for creating Sensitivity objects."""
|
||||
cdef Sensitivity s
|
||||
if not policy.mls:
|
||||
raise MLSDisabled
|
||||
|
||||
try:
|
||||
return _sens_cache[<uintptr_t>symbol]
|
||||
except KeyError:
|
||||
s = Sensitivity()
|
||||
s = Sensitivity.__new__(Sensitivity)
|
||||
_sens_cache[<uintptr_t>symbol] = s
|
||||
s.policy = policy
|
||||
s.handle = symbol
|
||||
_sens_cache[<uintptr_t>symbol] = s
|
||||
s.name = policy.level_value_to_name(symbol.level.sens - 1)
|
||||
s._value = symbol.level.sens
|
||||
return s
|
||||
|
||||
def __str__(self):
|
||||
return self.policy.level_value_to_name(self.handle.level.sens - 1)
|
||||
return self.name
|
||||
|
||||
def __hash__(self):
|
||||
return hash(str(self))
|
||||
return hash(self.name)
|
||||
|
||||
def __ge__(self, other):
|
||||
return self._value >= other._value
|
||||
@ -146,31 +162,36 @@ cdef class Sensitivity(PolicySymbol):
|
||||
"""Low-level equality check (C pointers)."""
|
||||
return self.handle == other.handle
|
||||
|
||||
@property
|
||||
def _value(self):
|
||||
"""
|
||||
The value of the component.
|
||||
|
||||
This is a low-level policy detail exposed for internal use only.
|
||||
"""
|
||||
return self.handle.level.sens
|
||||
cdef inline void _load_aliases(self):
|
||||
"""Helper method to load aliases."""
|
||||
if self._aliases is None:
|
||||
self._aliases = list(self.policy.sensitivity_aliases(self))
|
||||
|
||||
def aliases(self):
|
||||
"""Generator that yields all aliases for this sensitivity."""
|
||||
return self.policy.sensitivity_aliases(self)
|
||||
self._load_aliases()
|
||||
return iter(self._aliases)
|
||||
|
||||
def level_decl(self):
|
||||
"""Get the level declaration corresponding to this sensitivity."""
|
||||
return LevelDecl.factory(self.policy, self.handle)
|
||||
if self._leveldecl is None:
|
||||
self._leveldecl = LevelDecl.factory(self.policy, self.handle)
|
||||
|
||||
return self._leveldecl
|
||||
|
||||
def statement(self):
|
||||
aliases = list(self.aliases())
|
||||
stmt = "sensitivity {0}".format(self)
|
||||
if aliases:
|
||||
if len(aliases) > 1:
|
||||
stmt += " alias {{ {0} }}".format(' '.join(aliases))
|
||||
else:
|
||||
stmt += " alias {0}".format(aliases[0])
|
||||
cdef:
|
||||
str stmt
|
||||
size_t count
|
||||
|
||||
self._load_aliases()
|
||||
count = len(self._aliases)
|
||||
|
||||
stmt = "sensitivity {0}".format(self.name)
|
||||
if count > 1:
|
||||
stmt += " alias {{ {0} }}".format(' '.join(self._aliases))
|
||||
elif count == 1:
|
||||
stmt += " alias {0}".format(self._aliases[0])
|
||||
stmt += ";"
|
||||
return stmt
|
||||
|
||||
@ -179,11 +200,15 @@ cdef class BaseMLSLevel(PolicySymbol):
|
||||
|
||||
"""Base class for MLS levels."""
|
||||
|
||||
cdef:
|
||||
set _categories
|
||||
readonly Sensitivity sensitivity
|
||||
|
||||
def __str__(self):
|
||||
lvl = str(self.sensitivity)
|
||||
|
||||
# sort by policy declaration order
|
||||
cats = sorted(self.categories(), key=lambda k: k._value)
|
||||
cats = sorted(self._categories, key=lambda k: k._value)
|
||||
|
||||
if cats:
|
||||
# generate short category notation
|
||||
@ -206,11 +231,7 @@ cdef class BaseMLSLevel(PolicySymbol):
|
||||
All categories are yielded, not a compact notation such as
|
||||
c0.c255
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
def sensitivity(self):
|
||||
raise NotImplementedError
|
||||
return iter(self._categories)
|
||||
|
||||
|
||||
cdef class LevelDecl(BaseMLSLevel):
|
||||
@ -221,21 +242,22 @@ cdef class LevelDecl(BaseMLSLevel):
|
||||
level s7:c0.c1023;
|
||||
"""
|
||||
|
||||
cdef sepol.level_datum_t *handle
|
||||
|
||||
@staticmethod
|
||||
cdef factory(SELinuxPolicy policy, sepol.level_datum_t *symbol):
|
||||
cdef inline LevelDecl factory(SELinuxPolicy policy, sepol.level_datum_t *symbol):
|
||||
"""Factory function for creating LevelDecl objects."""
|
||||
cdef LevelDecl l
|
||||
if not policy.mls:
|
||||
raise MLSDisabled
|
||||
|
||||
try:
|
||||
return _leveldecl_cache[<uintptr_t>symbol]
|
||||
except KeyError:
|
||||
l = LevelDecl()
|
||||
l.policy = policy
|
||||
l.handle = symbol
|
||||
l = LevelDecl.__new__(LevelDecl)
|
||||
_leveldecl_cache[<uintptr_t>symbol] = l
|
||||
l.policy = policy
|
||||
l._categories = set(CategoryEbitmapIterator.factory(policy, &symbol.level.cat))
|
||||
# the datum for levels is also used for Sensitivity objects
|
||||
l.sensitivity = Sensitivity.factory(policy, symbol)
|
||||
return l
|
||||
|
||||
def __hash__(self):
|
||||
@ -271,25 +293,6 @@ cdef class LevelDecl(BaseMLSLevel):
|
||||
assert not isinstance(other, Level), "Levels cannot be compared to level declarations"
|
||||
return self.sensitivity < other.sensitivity
|
||||
|
||||
def _eq(self, LevelDecl other):
|
||||
"""Low-level equality check (C pointers)."""
|
||||
return self.handle == other.handle
|
||||
|
||||
def categories(self):
|
||||
"""
|
||||
Generator that yields all individual categories for this level.
|
||||
All categories are yielded, not a compact notation such as
|
||||
c0.c255
|
||||
"""
|
||||
return CategoryEbitmapIterator.factory(self.policy, &self.handle.level.cat)
|
||||
|
||||
@property
|
||||
def sensitivity(self):
|
||||
"""The sensitivity of the level."""
|
||||
# since the datum for levels is also used for
|
||||
# Sensitivity objects, use self's datum
|
||||
return Sensitivity.factory(self.policy, self.handle)
|
||||
|
||||
def statement(self):
|
||||
return "level {0};".format(self)
|
||||
|
||||
@ -303,39 +306,43 @@ cdef class Level(BaseMLSLevel):
|
||||
if the level is user-generated.
|
||||
"""
|
||||
|
||||
cdef:
|
||||
sepol.mls_level_t *handle
|
||||
list _categories
|
||||
Sensitivity _sensitivity
|
||||
|
||||
@staticmethod
|
||||
cdef factory(SELinuxPolicy policy, sepol.mls_level_t *symbol):
|
||||
cdef inline Level factory(SELinuxPolicy policy, sepol.mls_level_t *symbol):
|
||||
"""Factory function for creating Level objects."""
|
||||
if not policy.mls:
|
||||
raise MLSDisabled
|
||||
|
||||
l = Level()
|
||||
cdef Level l = Level.__new__(Level)
|
||||
l.policy = policy
|
||||
l.handle = symbol
|
||||
l.sensitivity = Sensitivity.factory(policy, policy.level_value_to_datum(symbol.sens - 1))
|
||||
l._categories = set(CategoryEbitmapIterator.factory(policy, &symbol.cat))
|
||||
return l
|
||||
|
||||
@staticmethod
|
||||
cdef factory_from_string(SELinuxPolicy policy, str name):
|
||||
cdef inline Level factory_from_string(SELinuxPolicy policy, str name):
|
||||
"""Factory function variant for constructing Level objects by a string."""
|
||||
|
||||
if not policy.mls:
|
||||
raise MLSDisabled
|
||||
|
||||
sens_split = name.split(":")
|
||||
sens = sens_split[0]
|
||||
cdef:
|
||||
Level l = Level.__new__(Level)
|
||||
list sens_split = name.split(":")
|
||||
str sens = sens_split[0]
|
||||
Sensitivity s
|
||||
list c
|
||||
str cats
|
||||
list catrange
|
||||
str group
|
||||
|
||||
l.policy = policy
|
||||
|
||||
try:
|
||||
s = policy.lookup_sensitivity(sens)
|
||||
l.sensitivity = policy.lookup_sensitivity(sens)
|
||||
except InvalidSensitivity as ex:
|
||||
raise InvalidLevel("{0} is not a valid level ({1} is not a valid sensitivity)". \
|
||||
format(name, sens)) from ex
|
||||
|
||||
c = []
|
||||
l._categories = set()
|
||||
|
||||
try:
|
||||
cats = sens_split[1]
|
||||
@ -346,9 +353,9 @@ cdef class Level(BaseMLSLevel):
|
||||
catrange = group.split(".")
|
||||
if len(catrange) == 2:
|
||||
try:
|
||||
c.extend(expand_cat_range(policy,
|
||||
policy.lookup_category(catrange[0]),
|
||||
policy.lookup_category(catrange[1])))
|
||||
l._categories.update(expand_cat_range(policy,
|
||||
policy.lookup_category(catrange[0]),
|
||||
policy.lookup_category(catrange[1])))
|
||||
except InvalidCategory as ex:
|
||||
raise InvalidLevel(
|
||||
"{0} is not a valid level ({1} is not a valid category range)".
|
||||
@ -356,7 +363,7 @@ cdef class Level(BaseMLSLevel):
|
||||
|
||||
elif len(catrange) == 1:
|
||||
try:
|
||||
c.append(policy.lookup_category(catrange[0]))
|
||||
l._categories.add(policy.lookup_category(catrange[0]))
|
||||
except InvalidCategory as ex:
|
||||
raise InvalidLevel("{0} is not a valid level ({1} is not a valid category)".
|
||||
format(name, group)) from ex
|
||||
@ -364,15 +371,8 @@ cdef class Level(BaseMLSLevel):
|
||||
else:
|
||||
raise InvalidLevel("{0} is not a valid level (level parsing error)".format(name))
|
||||
|
||||
# build object
|
||||
l = Level()
|
||||
l.policy = policy
|
||||
l.handle = NULL
|
||||
l._sensitivity = s
|
||||
l._categories = c
|
||||
|
||||
# verify level is valid
|
||||
if not l <= s.level_decl():
|
||||
if not l <= l.sensitivity.level_decl():
|
||||
raise InvalidLevel(
|
||||
"{0} is not a valid level (one or more categories are not associated with the "
|
||||
"sensitivity)".format(name))
|
||||
@ -388,61 +388,32 @@ cdef class Level(BaseMLSLevel):
|
||||
except AttributeError:
|
||||
return str(self) == str(other)
|
||||
else:
|
||||
selfcats = set(self.categories())
|
||||
return self.sensitivity == other.sensitivity and selfcats == othercats
|
||||
return self.sensitivity == other.sensitivity and self._categories == othercats
|
||||
|
||||
def __ge__(self, other):
|
||||
# Dom operator
|
||||
selfcats = set(self.categories())
|
||||
othercats = set(other.categories())
|
||||
return self.sensitivity >= other.sensitivity and selfcats >= othercats
|
||||
return self.sensitivity >= other.sensitivity and self._categories >= othercats
|
||||
|
||||
def __gt__(self, other):
|
||||
selfcats = set(self.categories())
|
||||
othercats = set(other.categories())
|
||||
return ((self.sensitivity > other.sensitivity and selfcats >= othercats) or
|
||||
(self.sensitivity >= other.sensitivity and selfcats > othercats))
|
||||
return ((self.sensitivity > other.sensitivity and self._categories >= othercats) or
|
||||
(self.sensitivity >= other.sensitivity and self._categories > othercats))
|
||||
|
||||
def __le__(self, other):
|
||||
# Domby operator
|
||||
selfcats = set(self.categories())
|
||||
othercats = set(other.categories())
|
||||
return self.sensitivity <= other.sensitivity and selfcats <= othercats
|
||||
return self.sensitivity <= other.sensitivity and self._categories <= othercats
|
||||
|
||||
def __lt__(self, other):
|
||||
selfcats = set(self.categories())
|
||||
othercats = set(other.categories())
|
||||
return ((self.sensitivity < other.sensitivity and selfcats <= othercats) or
|
||||
(self.sensitivity <= other.sensitivity and selfcats < othercats))
|
||||
return ((self.sensitivity < other.sensitivity and self._categories <= othercats) or
|
||||
(self.sensitivity <= other.sensitivity and self._categories < othercats))
|
||||
|
||||
def __xor__(self, other):
|
||||
# Incomp operator
|
||||
return not (self >= other or self <= other)
|
||||
|
||||
def _eq(self, Level other):
|
||||
"""Low-level equality check (C pointers)."""
|
||||
return self.handle == other.handle
|
||||
|
||||
def categories(self):
|
||||
"""
|
||||
Generator that yields all individual categories for this level.
|
||||
All categories are yielded, not a compact notation such as
|
||||
c0.c255
|
||||
"""
|
||||
if self.handle == NULL:
|
||||
return iter(self._categories)
|
||||
else:
|
||||
return CategoryEbitmapIterator.factory(self.policy, &self.handle.cat)
|
||||
|
||||
@property
|
||||
def sensitivity(self):
|
||||
"""The sensitivity of the level."""
|
||||
if self.handle == NULL:
|
||||
return self._sensitivity
|
||||
else:
|
||||
return Sensitivity.factory(self.policy,
|
||||
self.policy.level_value_to_datum(self.handle.sens - 1))
|
||||
|
||||
def statement(self):
|
||||
raise NoStatement
|
||||
|
||||
@ -452,63 +423,58 @@ cdef class Range(PolicySymbol):
|
||||
"""An MLS range"""
|
||||
|
||||
cdef:
|
||||
sepol.mls_range_t *handle
|
||||
Level _low
|
||||
Level _high
|
||||
readonly Level low
|
||||
readonly Level high
|
||||
|
||||
@staticmethod
|
||||
cdef factory(SELinuxPolicy policy, sepol.mls_range_t *symbol):
|
||||
cdef inline Range factory(SELinuxPolicy policy, sepol.mls_range_t *symbol):
|
||||
"""Factory function for creating Range objects."""
|
||||
if not policy.mls:
|
||||
raise MLSDisabled
|
||||
|
||||
r = Range()
|
||||
cdef Range r = Range.__new__(Range)
|
||||
r.policy = policy
|
||||
r.handle = symbol
|
||||
r.low = Level.factory(policy, &symbol.level[0])
|
||||
r.high = Level.factory(policy, &symbol.level[1])
|
||||
return r
|
||||
|
||||
@staticmethod
|
||||
cdef factory_from_string(SELinuxPolicy policy, str name):
|
||||
cdef inline Range factory_from_string(SELinuxPolicy policy, str name):
|
||||
"""Factory function variant for constructing Range objects by name."""
|
||||
if not policy.mls:
|
||||
raise MLSDisabled
|
||||
|
||||
cdef Range r = Range.__new__(Range)
|
||||
r.policy = policy
|
||||
|
||||
# build range:
|
||||
levels = name.split("-")
|
||||
cdef list levels = name.split("-")
|
||||
|
||||
# strip() levels to handle ranges with spaces in them,
|
||||
# e.g. s0:c1 - s0:c0.c255
|
||||
try:
|
||||
low = Level.factory_from_string(policy, levels[0].strip())
|
||||
r.low = Level.factory_from_string(policy, levels[0].strip())
|
||||
except InvalidLevel as ex:
|
||||
raise InvalidRange("{0} is not a valid range ({1}).".format(name, ex)) from ex
|
||||
|
||||
try:
|
||||
high = Level.factory_from_string(policy, levels[1].strip())
|
||||
r.high = Level.factory_from_string(policy, levels[1].strip())
|
||||
except InvalidLevel as ex:
|
||||
raise InvalidRange("{0} is not a valid range ({1}).".format(name, ex)) from ex
|
||||
except IndexError:
|
||||
high = low
|
||||
r.high = r.low
|
||||
|
||||
# verify high level dominates low range
|
||||
if not high >= low:
|
||||
raise InvalidRange("{0} is not a valid range ({1} is not dominated by {2})".
|
||||
format(name, low, high))
|
||||
|
||||
r = Range()
|
||||
r.policy = policy
|
||||
r.handle = NULL
|
||||
r._low = low
|
||||
r._high = high
|
||||
if not r.high >= r.low:
|
||||
raise InvalidRange("{0} is not a valid range ({1.low} is not dominated by {1.high})".
|
||||
format(name, r))
|
||||
return r
|
||||
|
||||
def __str__(self):
|
||||
high = self.high
|
||||
low = self.low
|
||||
if high == low:
|
||||
return str(low)
|
||||
if self.high == self.low:
|
||||
return str(self.low)
|
||||
|
||||
return "{0} - {1}".format(low, high)
|
||||
return "{0.low} - {0.high}".format(self)
|
||||
|
||||
def __hash__(self):
|
||||
return hash(str(self))
|
||||
@ -527,26 +493,6 @@ cdef class Range(PolicySymbol):
|
||||
def __contains__(self, other):
|
||||
return self.low <= other <= self.high
|
||||
|
||||
def _eq(self, Range other):
|
||||
"""Low-level equality check (C pointers)."""
|
||||
return self.handle == other.handle
|
||||
|
||||
@property
|
||||
def high(self):
|
||||
"""The high end/clearance level of this range."""
|
||||
if self.handle == NULL:
|
||||
return self._high
|
||||
else:
|
||||
return Level.factory(self.policy, &self.handle.level[1])
|
||||
|
||||
@property
|
||||
def low(self):
|
||||
"""The low end/current level of this range."""
|
||||
if self.handle == NULL:
|
||||
return self._low
|
||||
else:
|
||||
return Level.factory(self.policy, &self.handle.level[0])
|
||||
|
||||
def statement(self):
|
||||
raise NoStatement
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user