From 2fad2d1b1df43ea0d85e25e2ebad88ad02997d7c Mon Sep 17 00:00:00 2001 From: Chris PeBenito Date: Mon, 29 Apr 2019 07:57:16 -0400 Subject: [PATCH 1/3] SELinuxPolicy: Create a map of aliases on policy load. Addresses a performance regression after the alias fixes in #17. Closes #20 --- setools/policyrep/mls.pxi | 138 +--------------------------- setools/policyrep/selinuxpolicy.pxi | 107 +++++++++++++++++---- setools/policyrep/typeattr.pxi | 70 +------------- 3 files changed, 95 insertions(+), 220 deletions(-) diff --git a/setools/policyrep/mls.pxi b/setools/policyrep/mls.pxi index c40d032..30464b7 100644 --- a/setools/policyrep/mls.pxi +++ b/setools/policyrep/mls.pxi @@ -1,5 +1,5 @@ # Copyright 2014-2016, Tresys Technology, LLC -# Copyright 2017-2018, Chris PeBenito +# Copyright 2017-2019, Chris PeBenito # # This file is part of SETools. # @@ -65,6 +65,7 @@ cdef class Category(PolicySymbol): c.key = symbol c.name = policy.category_value_to_name(symbol.s.value - 1) c._value = symbol.s.value + c._aliases = policy.category_alias_map[symbol.s.value] _cat_cache[policy][symbol] = c return c @@ -75,14 +76,8 @@ cdef class Category(PolicySymbol): # Comparison based on their index instead of their names. return self._value < other._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 iter(self._aliases) def statement(self): @@ -90,7 +85,6 @@ cdef class Category(PolicySymbol): str stmt size_t count - self._load_aliases() count = len(self._aliases) stmt = "category {0}".format(self.name) @@ -127,6 +121,7 @@ cdef class Sensitivity(PolicySymbol): s.key = symbol s.name = policy.level_value_to_name(symbol.level.sens - 1) s._value = symbol.level.sens + s._aliases = policy.sensitivity_alias_map[symbol.level.sens] return s def __hash__(self): @@ -144,14 +139,8 @@ cdef class Sensitivity(PolicySymbol): def __lt__(self, other): return self._value < other._value - 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.""" - self._load_aliases() return iter(self._aliases) def level_decl(self): @@ -167,7 +156,6 @@ cdef class Sensitivity(PolicySymbol): str stmt size_t count - self._load_aliases() count = len(self._aliases) stmt = "sensitivity {0}".format(self.name) @@ -540,66 +528,6 @@ cdef class CategoryHashtabIterator(HashtabIterator): datum = self.node.datum if self.node else NULL -cdef class CategoryAliasHashtabIterator(HashtabIterator): - - """Iterate over category aliases in the policy.""" - - cdef uint32_t primary - - @staticmethod - cdef factory(SELinuxPolicy policy, sepol.hashtab_t *table, Category primary): - """Factory function for creating category alias iterators.""" - i = CategoryAliasHashtabIterator() - i.policy = policy - i.table = table - i.primary = primary._value - i.reset() - return i - - def __next__(self): - super().__next__() - datum = self.curr.datum if self.curr else NULL - - while datum != NULL and (not datum.isalias or datum.s.value != self.primary): - super().__next__() - datum = self.curr.datum if self.curr else NULL - - return intern(self.curr.key) - - def __len__(self): - cdef sepol.cat_datum_t *datum - cdef sepol.hashtab_node_t *node - cdef uint32_t bucket = 0 - cdef size_t count = 0 - - while bucket < self.table[0].size: - node = self.table[0].htable[bucket] - while node != NULL: - datum = node.datum if node else NULL - if datum != NULL and self.primary == datum.s.value and datum.isalias: - count += 1 - - node = node.next - - bucket += 1 - - return count - - def reset(self): - super().reset() - - cdef sepol.cat_datum_t *datum = self.node.datum if self.node else NULL - - # advance over any attributes or aliases - while datum != NULL and (not datum.isalias and self.primary != datum.s.value): - self._next_node() - - if self.node == NULL or self.bucket >= self.table[0].size: - break - - datum = self.node.datum if self.node else NULL - - cdef class SensitivityHashtabIterator(HashtabIterator): """Iterate over sensitivity in the policy.""" @@ -657,66 +585,6 @@ cdef class SensitivityHashtabIterator(HashtabIterator): datum = self.node.datum if self.node else NULL -cdef class SensitivityAliasHashtabIterator(HashtabIterator): - - """Iterate over sensitivity aliases in the policy.""" - - cdef uint32_t primary - - @staticmethod - cdef factory(SELinuxPolicy policy, sepol.hashtab_t *table, Sensitivity primary): - """Factory function for creating Sensitivity alias iterators.""" - i = SensitivityAliasHashtabIterator() - i.policy = policy - i.table = table - i.primary = primary._value - i.reset() - return i - - def __next__(self): - super().__next__() - datum = self.curr.datum if self.curr else NULL - - while datum != NULL and (not datum.isalias or datum.level.sens != self.primary): - super().__next__() - datum = self.curr.datum if self.curr else NULL - - return intern(self.curr.key) - - def __len__(self): - cdef sepol.level_datum_t *datum - cdef sepol.hashtab_node_t *node - cdef uint32_t bucket = 0 - cdef size_t count = 0 - - while bucket < self.table[0].size: - node = self.table[0].htable[bucket] - while node != NULL: - datum = node.datum if node else NULL - if datum != NULL and self.primary == datum.level.sens and datum.isalias: - count += 1 - - node = node.next - - bucket += 1 - - return count - - def reset(self): - super().reset() - - cdef sepol.level_datum_t *datum = self.node.datum if self.node else NULL - - # advance over any attributes or aliases - while datum != NULL and (not datum.isalias and self.primary != datum.level.sens): - self._next_node() - - if self.node == NULL or self.bucket >= self.table[0].size: - break - - datum = self.node.datum if self.node else NULL - - cdef class LevelDeclHashtabIterator(HashtabIterator): """Iterate over level declarations in the policy.""" diff --git a/setools/policyrep/selinuxpolicy.pxi b/setools/policyrep/selinuxpolicy.pxi index 1a3eb5c..1541549 100644 --- a/setools/policyrep/selinuxpolicy.pxi +++ b/setools/policyrep/selinuxpolicy.pxi @@ -46,6 +46,9 @@ cdef class SELinuxPolicy: object log object constraint_counts object terule_counts + dict type_alias_map + dict category_alias_map + dict sensitivity_alias_map object __weakref__ # Public attributes: @@ -598,12 +601,6 @@ cdef class SELinuxPolicy: """Return the category datum for the specified category value.""" return self.cat_val_to_struct[value] - cdef inline category_aliases(self, Category primary): - """Return an interator for the aliases for the specified category.""" - return CategoryAliasHashtabIterator.factory(self, - &self.handle.p.symtab[sepol.SYM_CATS].table, - primary) - cdef inline str category_value_to_name(self, size_t value): """Return the name of the category by its value.""" return intern(self.handle.p.sym_val_to_name[sepol.SYM_CATS][value]) @@ -636,17 +633,6 @@ cdef class SELinuxPolicy: """Return the name of the role by its value.""" return intern(self.handle.p.sym_val_to_name[sepol.SYM_ROLES][value]) - cdef inline sensitivity_aliases(self, Sensitivity primary): - """Return an interator for the aliases for the specified sensitivity.""" - return SensitivityAliasHashtabIterator.factory(self, - &self.handle.p.symtab[sepol.SYM_LEVELS].table, primary) - - cdef inline type_aliases(self, Type primary): - """Return an iterator for the aliases for the specified type.""" - return TypeAliasHashtabIterator.factory(self, - &self.handle.p.symtab[sepol.SYM_TYPES].table, - primary) - cdef inline sepol.type_datum_t* type_value_to_datum(self, size_t value): """Return the type datum for the specified type value.""" return self.handle.p.type_val_to_struct[value] @@ -725,6 +711,15 @@ cdef class SELinuxPolicy: if self.mls: self._create_mls_val_to_struct() + # + # Create value to alias mappings + # + self._load_type_aliases() + + if self.mls: + self._load_sensitivity_aliases() + self._load_category_aliases() + self.log.info("Successfully opened SELinux policy \"{0}\"".format(filename)) self.path = filename @@ -846,6 +841,84 @@ cdef class SELinuxPolicy: bucket += 1 + cdef _load_category_aliases(self): + """Build map of aliases to categories""" + cdef: + sepol.hashtab_t *table = &self.handle.p.symtab[sepol.SYM_CATS].table + sepol.cat_datum_t *datum + sepol.hashtab_node_t *node + uint32_t bucket = 0 + list entry + + self.category_alias_map = dict() + + while bucket < table[0].size: + node = table[0].htable[bucket] + while node != NULL: + datum = node.datum if node else NULL + if datum == NULL: + continue + + entry = self.category_alias_map.setdefault(datum.s.value, list()) + if datum.isalias: + entry.append(intern(node.key)) + + node = node.next + + bucket += 1 + + cdef _load_sensitivity_aliases(self): + """Build map of aliases to sensitivities""" + cdef: + sepol.hashtab_t *table = &self.handle.p.symtab[sepol.SYM_LEVELS].table + sepol.level_datum_t *datum + sepol.hashtab_node_t *node + uint32_t bucket = 0 + list entry + + self.sensitivity_alias_map = dict() + + while bucket < table[0].size: + node = table[0].htable[bucket] + while node != NULL: + datum = node.datum if node else NULL + if datum == NULL: + continue + + entry = self.sensitivity_alias_map.setdefault(datum.level.sens, list()) + if datum.isalias: + entry.append(intern(node.key)) + + node = node.next + + bucket += 1 + + cdef _load_type_aliases(self): + """Build map of aliases to types""" + cdef: + sepol.hashtab_t *table = &self.handle.p.symtab[sepol.SYM_TYPES].table + sepol.type_datum_t *datum + sepol.hashtab_node_t *node + uint32_t bucket = 0 + list entry + + self.type_alias_map = dict() + + while bucket < table[0].size: + node = table[0].htable[bucket] + while node != NULL: + datum = node.datum if node else NULL + if datum == NULL: + continue + + entry = self.type_alias_map.setdefault(datum.s.value, list()) + if type_is_alias(datum): + entry.append(intern(node.key)) + + node = node.next + + bucket += 1 + cdef _rebuild_attrs_from_map(self): """ Rebuilds data for the attributes and inserts them into the policydb. diff --git a/setools/policyrep/typeattr.pxi b/setools/policyrep/typeattr.pxi index d989ca9..1d8901e 100644 --- a/setools/policyrep/typeattr.pxi +++ b/setools/policyrep/typeattr.pxi @@ -1,5 +1,5 @@ # Copyright 2014, Tresys Technology, LLC -# Copyright 2017-2018, Chris PeBenito +# Copyright 2017-2019, Chris PeBenito # # This file is part of SETools. # @@ -86,13 +86,9 @@ cdef class Type(BaseType): t.value = symbol.s.value t.name = policy.type_value_to_name(symbol.s.value - 1) t.ispermissive = symbol.flags & sepol.TYPE_FLAGS_PERMISSIVE + t._aliases = policy.type_alias_map[symbol.s.value] return t - cdef inline void _load_aliases(self): - """Helper method to load aliases.""" - if self._aliases is None: - self._aliases = list(self.policy.type_aliases(self)) - cdef inline void _load_attributes(self): """Helper method to load attributes.""" cdef sepol.type_datum_t *symbol = self.key @@ -110,7 +106,6 @@ cdef class Type(BaseType): def aliases(self): """Generator that yields all aliases for this type.""" - self._load_aliases() return iter(self._aliases) def statement(self): @@ -119,7 +114,6 @@ cdef class Type(BaseType): str stmt self._load_attributes() - self._load_aliases() count = len(self._aliases) stmt = "type {0}".format(self.name) @@ -297,66 +291,6 @@ cdef class TypeAttributeHashtabIterator(HashtabIterator): self._next_node() -cdef class TypeAliasHashtabIterator(HashtabIterator): - - """Iterate over type aliases in the policy.""" - - cdef uint32_t primary - - @staticmethod - cdef factory(SELinuxPolicy policy, sepol.hashtab_t *table, Type primary): - """Factory function for creating type alias iterators.""" - i = TypeAliasHashtabIterator() - i.policy = policy - i.table = table - i.primary = primary.value - i.reset() - return i - - def __next__(self): - super().__next__() - datum = self.curr.datum if self.curr else NULL - - while datum != NULL and (not type_is_alias(datum) or datum.s.value != self.primary): - super().__next__() - datum = self.curr.datum if self.curr else NULL - - return intern(self.curr.key) - - def __len__(self): - cdef sepol.type_datum_t *datum - cdef sepol.hashtab_node_t *node - cdef uint32_t bucket = 0 - cdef size_t count = 0 - - while bucket < self.table[0].size: - node = self.table[0].htable[bucket] - while node != NULL: - datum = node.datum if node else NULL - if datum != NULL and self.primary == datum.s.value and type_is_alias(datum): - count += 1 - - node = node.next - - bucket += 1 - - return count - - def reset(self): - super().reset() - - cdef sepol.type_datum_t *datum = self.node.datum if self.node else NULL - - # advance over any attributes or aliases - while datum != NULL and (not type_is_alias(datum) and self.primary != datum.s.value): - self._next_node() - - if self.node == NULL or self.bucket >= self.table[0].size: - break - - datum = self.node.datum if self.node else NULL - - # # Ebitmap Iterator Classes # -- 2.17.2