From e5876ed9639f84119c5ac949f9f1f96f06a08317 Mon Sep 17 00:00:00 2001 From: Juraj Marcin Date: Thu, 5 Oct 2023 17:21:57 +0200 Subject: [PATCH] policyrep: add prefix/suffix matching to filename type transitions Currently, filename transitions are stored separately from other type enforcement rules and only support exact name matching. However, in practice, the names contain variable parts. This leads to many duplicated rules in the policy that differ only in the part of the name, or it is even impossible to cover all possible combinations. This patch reflects changes in libsepol implemented in this patch [1]. The patch adds additional filename transition tables to policydb structure for prefix and suffix rules and updates the functions that access them. [1]: https://lore.kernel.org/selinux/20231108103345.4014148-1-juraj@jurajmarcin.com/ Reviewed-by: Ondrej Mosnacek Signed-off-by: Juraj Marcin --- setools/policyrep.pyi | 6 +++++ setools/policyrep/selinuxpolicy.pxi | 8 +++++-- setools/policyrep/sepol.pxd | 6 ++++- setools/policyrep/terule.pxi | 37 +++++++++++++++++++++++------ 4 files changed, 47 insertions(+), 10 deletions(-) diff --git a/setools/policyrep.pyi b/setools/policyrep.pyi index 752a22c4..28266b2b 100644 --- a/setools/policyrep.pyi +++ b/setools/policyrep.pyi @@ -462,6 +462,7 @@ class FSUseRuletype(PolicyEnum): class FileNameTERule(BaseTERule): default: Type = ... filename: str = ... + match_type: FileNameTERuleMatchType = ... perms: NoReturn = ... ruletype: TERuletype = ... source: TypeOrAttr = ... @@ -490,6 +491,11 @@ class FileNameTERuleIterator(HashtabIterator): def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... +class FileNameTERuleMatchType(PolicyEnum): + exact: int = ... + prefix: int = ... + suffix: int = ... + class GenfsFiletype(int): _filetype_to_text: Any = ... @classmethod diff --git a/setools/policyrep/selinuxpolicy.pxi b/setools/policyrep/selinuxpolicy.pxi index cff3b5ed..f072402d 100644 --- a/setools/policyrep/selinuxpolicy.pxi +++ b/setools/policyrep/selinuxpolicy.pxi @@ -510,7 +510,9 @@ cdef class SELinuxPolicy: def terules(self): """Iterator over all type enforcement rules.""" yield from TERuleIterator.factory(self, &self.handle.p.te_avtab) - yield from FileNameTERuleIterator.factory(self, &self.handle.p.filename_trans) + yield from FileNameTERuleIterator.factory(self, &self.handle.p.filename_trans[sepol.FILENAME_TRANS_MATCH_EXACT], sepol.FILENAME_TRANS_MATCH_EXACT) + yield from FileNameTERuleIterator.factory(self, &self.handle.p.filename_trans[sepol.FILENAME_TRANS_MATCH_PREFIX], sepol.FILENAME_TRANS_MATCH_PREFIX) + yield from FileNameTERuleIterator.factory(self, &self.handle.p.filename_trans[sepol.FILENAME_TRANS_MATCH_SUFFIX], sepol.FILENAME_TRANS_MATCH_SUFFIX) for c in self.conditionals(): yield from c.true_rules() @@ -1064,7 +1066,9 @@ cdef class SELinuxPolicy: if not self.terule_counts: self.terule_counts = TERuleIterator.factory(self, &self.handle.p.te_avtab).ruletype_count() self.terule_counts[TERuletype.type_transition.value] += \ - len(FileNameTERuleIterator.factory(self, &self.handle.p.filename_trans)) + len(FileNameTERuleIterator.factory(self, &self.handle.p.filename_trans[sepol.FILENAME_TRANS_MATCH_EXACT], sepol.FILENAME_TRANS_MATCH_EXACT)) + \ + len(FileNameTERuleIterator.factory(self, &self.handle.p.filename_trans[sepol.FILENAME_TRANS_MATCH_PREFIX], sepol.FILENAME_TRANS_MATCH_PREFIX)) + \ + len(FileNameTERuleIterator.factory(self, &self.handle.p.filename_trans[sepol.FILENAME_TRANS_MATCH_SUFFIX], sepol.FILENAME_TRANS_MATCH_SUFFIX)) for c in self.conditionals(): self.terule_counts.update(c.true_rules().ruletype_count()) diff --git a/setools/policyrep/sepol.pxd b/setools/policyrep/sepol.pxd index 922065e4..331844ca 100644 --- a/setools/policyrep/sepol.pxd +++ b/setools/policyrep/sepol.pxd @@ -793,6 +793,10 @@ cdef extern from "": cdef int SYM_CATS cdef int SYM_NUM + cdef int FILENAME_TRANS_MATCH_EXACT + cdef int FILENAME_TRANS_MATCH_PREFIX + cdef int FILENAME_TRANS_MATCH_SUFFIX + cdef struct policydb: uint32_t policy_type char *name @@ -819,7 +823,7 @@ cdef extern from "": ocontext_t *ocontexts[9] # TODO: OCON_NUM=9 genfs_t *genfs hashtab_t range_tr - hashtab_t filename_trans + hashtab_t filename_trans[3] ebitmap_t *type_attr_map ebitmap_t *attr_type_map # not saved in the binary policy ebitmap_t policycaps diff --git a/setools/policyrep/terule.pxi b/setools/policyrep/terule.pxi index 4f4a95f5..08501384 100644 --- a/setools/policyrep/terule.pxi +++ b/setools/policyrep/terule.pxi @@ -469,6 +469,15 @@ cdef class TERule(BaseTERule): return self.rule_string +class FileNameTERuleMatchType(PolicyEnum): + + """Enumeration of name match type of FileName TE rules.""" + + exact = sepol.FILENAME_TRANS_MATCH_EXACT + prefix = sepol.FILENAME_TRANS_MATCH_PREFIX + suffix = sepol.FILENAME_TRANS_MATCH_SUFFIX + + cdef class FileNameTERule(BaseTERule): """A type_transition type enforcement rule with filename.""" @@ -476,11 +485,13 @@ cdef class FileNameTERule(BaseTERule): cdef: Type dft readonly str filename + readonly object match_type @staticmethod cdef inline FileNameTERule factory(SELinuxPolicy policy, sepol.filename_trans_key_t *key, - Type stype, size_t otype): + Type stype, uint32_t match_type, + size_t otype): """Factory function for creating FileNameTERule objects.""" cdef FileNameTERule r = FileNameTERule.__new__(FileNameTERule) r.policy = policy @@ -491,11 +502,12 @@ cdef class FileNameTERule(BaseTERule): r.tclass = ObjClass.factory(policy, policy.class_value_to_datum(key.tclass - 1)) r.dft = Type.factory(policy, policy.type_value_to_datum(otype - 1)) r.filename = intern(key.name) + r.match_type = FileNameTERuleMatchType(match_type) r.origin = None return r def __hash__(self): - return hash("{0.ruletype}|{0.source}|{0.target}|{0.tclass}|{0.filename}|{1}|{2}".format( + return hash("{0.ruletype}|{0.source}|{0.target}|{0.tclass}|{0.filename}|{0.match_type}|{1}|{2}".format( self, None, None)) def __lt__(self, other): @@ -525,6 +537,7 @@ cdef class FileNameTERule(BaseTERule): r.tclass = self.tclass r.dft = self.dft r.filename = self.filename + r.match_type = self.match_type r.origin = None r._conditional = self._conditional r._conditional_block = self._conditional_block @@ -536,8 +549,16 @@ cdef class FileNameTERule(BaseTERule): yield self def statement(self): - return "{0.ruletype} {0.source} {0.target}:{0.tclass} {0.default} {0.filename};". \ - format(self) + if self.match_type == FileNameTERuleMatchType.exact: + match_type_str = "" + elif self.match_type == FileNameTERuleMatchType.prefix: + match_type_str = " prefix" + elif self.match_type == FileNameTERuleMatchType.suffix: + match_type_str = " suffix" + else: + raise ValueError("Invalid filename trans match type") + return "{0.ruletype} {0.source} {0.target}:{0.tclass} {0.default} {0.filename}{1};". \ + format(self, match_type_str) # @@ -720,13 +741,15 @@ cdef class FileNameTERuleIterator(HashtabIterator): cdef: sepol.filename_trans_datum_t *datum TypeEbitmapIterator stypei + uint32_t match_type @staticmethod - cdef factory(SELinuxPolicy policy, sepol.hashtab_t *table): + cdef factory(SELinuxPolicy policy, sepol.hashtab_t *table, uint32_t match_type): """Factory function for creating FileNameTERule iterators.""" i = FileNameTERuleIterator() i.policy = policy i.table = table + i.match_type = match_type i.reset() return i @@ -748,10 +771,10 @@ cdef class FileNameTERuleIterator(HashtabIterator): stype = self._next_stype() return FileNameTERule.factory(self.policy, self.curr.key, - stype, self.datum.otype) + stype, self.match_type, self.datum.otype) def __len__(self): - return sum(1 for r in FileNameTERuleIterator.factory(self.policy, self.table)) + return sum(1 for r in FileNameTERuleIterator.factory(self.policy, self.table, self.match_type)) def reset(self): super().reset()