From f39347d81febb99b44b009c5b49f39cc22e35337 Mon Sep 17 00:00:00 2001 From: Chris PeBenito Date: Fri, 16 Feb 2018 17:20:55 -0500 Subject: [PATCH] Bounds: Convert to direct sepol structure use. Add iterator. --- libqpol/bounds_query.c | 350 ---------------------------- setools/policyrep/bounds.pxi | 123 ++++++---- setools/policyrep/selinuxpolicy.pxi | 9 +- setup.py | 1 - 4 files changed, 79 insertions(+), 404 deletions(-) delete mode 100644 libqpol/bounds_query.c diff --git a/libqpol/bounds_query.c b/libqpol/bounds_query.c deleted file mode 100644 index 996bf31..0000000 --- a/libqpol/bounds_query.c +++ /dev/null @@ -1,350 +0,0 @@ -/** -* @file -* Defines the public interface for searching and iterating over the permissive types. -* -* @author Richard Haines richard_c_haines@btinternet.com -* -* Copyright (C) 2006-2007 Tresys Technology, LLC -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include -#include -#include -#include -#include -#include "qpol_internal.h" -#include "iterator_internal.h" - - /************ TYPEBOUNDS *************/ -int qpol_typebounds_get_parent_name(const qpol_policy_t *policy, const qpol_typebounds_t * datum, const char **name) -{ - type_datum_t *internal_datum = NULL; - policydb_t *db = NULL; - - if (policy == NULL || datum == NULL || name == NULL) { - if (name != NULL) - *name = NULL; - ERR(policy, "%s", strerror(EINVAL)); - errno = EINVAL; - return STATUS_ERR; - } - *name = NULL; - - /* The bounds rules started in ver 24 */ - if (!qpol_policy_has_capability(policy, QPOL_CAP_BOUNDS)) - return STATUS_SUCCESS; - - db = &policy->p->p; - internal_datum = (type_datum_t *)datum; - - /* This will be zero if not a typebounds statement */ - if (internal_datum->flavor == TYPE_TYPE && internal_datum->bounds != 0) { - *name = db->p_type_val_to_name[internal_datum->bounds - 1]; - } - return STATUS_SUCCESS; -} - -int qpol_typebounds_get_child_name(const qpol_policy_t *policy, const qpol_typebounds_t * datum, const char **name) -{ - type_datum_t *internal_datum = NULL; - policydb_t *db = NULL; - - if (policy == NULL || datum == NULL || name == NULL) { - if (name != NULL) - *name = NULL; - ERR(policy, "%s", strerror(EINVAL)); - errno = EINVAL; - return STATUS_ERR; - } - *name = NULL; - - /* The bounds rules started in ver 24 */ - if (!qpol_policy_has_capability(policy, QPOL_CAP_BOUNDS)) - return STATUS_SUCCESS; - - db = &policy->p->p; - internal_datum = (type_datum_t *)datum; - - if (internal_datum->flavor == TYPE_TYPE && internal_datum->bounds != 0) { - *name = db->p_type_val_to_name[internal_datum->s.value - 1]; - } - return STATUS_SUCCESS; -} - -static int hash_state_next_typebounds(qpol_iterator_t * iter) -{ - void *datum = NULL; - type_datum_t *internal_datum = NULL; - - do { - hash_state_next(iter); - if (qpol_iterator_end(iter)) - break; - - qpol_iterator_get_item(iter, &datum); - internal_datum = (type_datum_t *) datum; - - /* keep going on attributes */ - if (internal_datum -> flavor != TYPE_TYPE) - continue; - /* keep going if type has no bounding */ - } while (internal_datum->bounds == 0); - - return STATUS_SUCCESS; -} - -int qpol_policy_get_typebounds_iter(const qpol_policy_t *policy, qpol_iterator_t **iter) -{ - policydb_t *db; - int error = 0; - hash_state_t *hs = NULL; - - if (policy == NULL || iter == NULL) { - if (iter != NULL) - *iter = NULL; - ERR(policy, "%s", strerror(EINVAL)); - errno = EINVAL; - return STATUS_ERR; - } - - db = &policy->p->p; - hs = calloc(1, sizeof(hash_state_t)); - if (hs == NULL) { - error = errno; - ERR(policy, "%s", strerror(ENOMEM)); - errno = error; - return STATUS_ERR; - } - hs->table = &db->p_types.table; - hs->node = (*(hs->table))->htable[0]; - - if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur, - hash_state_next_typebounds, hash_state_end, hash_state_size, free, iter)) { - free(hs); - return STATUS_ERR; - } - - if (hs->node == NULL) - hash_state_next_typebounds(*iter); - - /* since we are iterating over all types, ensure our first item is actually bounded. */ - if (!qpol_iterator_end(*iter)) { - void *datum = NULL; - type_datum_t *internal_datum = NULL; - - qpol_iterator_get_item(*iter, &datum); - internal_datum = (type_datum_t *) datum; - - if (internal_datum -> flavor != TYPE_TYPE || internal_datum->bounds == 0) - hash_state_next_typebounds(*iter); - } - - return STATUS_SUCCESS; -} - - /************ ROLEBOUNDS *************/ -int qpol_rolebounds_get_parent_name(const qpol_policy_t *policy, const qpol_rolebounds_t * datum, const char **name) -{ - role_datum_t *internal_datum = NULL; - policydb_t *db = NULL; - - if (policy == NULL || datum == NULL || name == NULL) { - if (name != NULL) - *name = NULL; - ERR(policy, "%s", strerror(EINVAL)); - errno = EINVAL; - return STATUS_ERR; - } - *name = NULL; - - /* The bounds rules started in ver 24 */ - if (!qpol_policy_has_capability(policy, QPOL_CAP_BOUNDS)) - return STATUS_SUCCESS; - - db = &policy->p->p; - internal_datum = (role_datum_t *)datum; - - /* This will be zero if not a rolebounds statement */ - if (internal_datum->flavor == ROLE_ROLE && internal_datum->bounds != 0) { - *name = db->p_role_val_to_name[internal_datum->bounds - 1]; - } - return STATUS_SUCCESS; -} - -int qpol_rolebounds_get_child_name(const qpol_policy_t *policy, const qpol_rolebounds_t * datum, const char **name) -{ - role_datum_t *internal_datum = NULL; - policydb_t *db = NULL; - - if (policy == NULL || datum == NULL || name == NULL) { - if (name != NULL) - *name = NULL; - ERR(policy, "%s", strerror(EINVAL)); - errno = EINVAL; - return STATUS_ERR; - } - *name = NULL; - - /* The bounds rules started in ver 24 */ - if (!qpol_policy_has_capability(policy, QPOL_CAP_BOUNDS)) - return STATUS_SUCCESS; - - db = &policy->p->p; - internal_datum = (role_datum_t *)datum; - - if (internal_datum->flavor == ROLE_ROLE && internal_datum->bounds != 0) { - *name = db->p_role_val_to_name[internal_datum->s.value - 1]; - } - return STATUS_SUCCESS; -} - -/* As rolebounds are in roles use these, however will need to calc number of bounds manually in top.tcl*/ -int qpol_policy_get_rolebounds_iter(const qpol_policy_t *policy, qpol_iterator_t **iter) -{ - policydb_t *db; - int error = 0; - hash_state_t *hs = NULL; - - if (policy == NULL || iter == NULL) { - if (iter != NULL) - *iter = NULL; - ERR(policy, "%s", strerror(EINVAL)); - errno = EINVAL; - return STATUS_ERR; - } - - db = &policy->p->p; - - hs = calloc(1, sizeof(hash_state_t)); - if (hs == NULL) { - error = errno; - ERR(policy, "%s", strerror(ENOMEM)); - errno = error; - return STATUS_ERR; - } - hs->table = &db->p_roles.table; - hs->node = (*(hs->table))->htable[0]; - - if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur, - hash_state_next, hash_state_end, hash_state_size, free, iter)) { - free(hs); - return STATUS_ERR; - } - - if (hs->node == NULL) - hash_state_next(*iter); - - return STATUS_SUCCESS; -} - - /************ USERBOUNDS *************/ -int qpol_userbounds_get_parent_name(const qpol_policy_t *policy, const qpol_userbounds_t * datum, const char **name) -{ - user_datum_t *internal_datum = NULL; - policydb_t *db = NULL; - - if (policy == NULL || datum == NULL || name == NULL) { - if (name != NULL) - *name = NULL; - ERR(policy, "%s", strerror(EINVAL)); - errno = EINVAL; - return STATUS_ERR; - } - *name = NULL; - - /* The bounds rules started in ver 24 */ - if (!qpol_policy_has_capability(policy, QPOL_CAP_BOUNDS)) - return STATUS_SUCCESS; - - db = &policy->p->p; - internal_datum = (user_datum_t *)datum; - - /* This will be zero if not a userbounds statement */ - if (internal_datum->bounds != 0) { - *name = db->p_user_val_to_name[internal_datum->bounds - 1]; - } - return STATUS_SUCCESS; -} - -int qpol_userbounds_get_child_name(const qpol_policy_t *policy, const qpol_userbounds_t * datum, const char **name) -{ - user_datum_t *internal_datum = NULL; - policydb_t *db = NULL; - - if (policy == NULL || datum == NULL || name == NULL) { - if (name != NULL) - *name = NULL; - ERR(policy, "%s", strerror(EINVAL)); - errno = EINVAL; - return STATUS_ERR; - } - *name = NULL; - - /* The bounds rules started in ver 24 */ - if (!qpol_policy_has_capability(policy, QPOL_CAP_BOUNDS)) - return STATUS_SUCCESS; - - db = &policy->p->p; - internal_datum = (user_datum_t *)datum; - - if (internal_datum->bounds != 0) { - *name = db->p_user_val_to_name[internal_datum->s.value - 1]; - } - return STATUS_SUCCESS; -} - -/* As userbounds are in users use these, however will need to calc number of bounds manually in top.tcl*/ -int qpol_policy_get_userbounds_iter(const qpol_policy_t *policy, qpol_iterator_t **iter) -{ - policydb_t *db; - int error = 0; - hash_state_t *hs = NULL; - - if (policy == NULL || iter == NULL) { - if (iter != NULL) - *iter = NULL; - ERR(policy, "%s", strerror(EINVAL)); - errno = EINVAL; - return STATUS_ERR; - } - - db = &policy->p->p; - - hs = calloc(1, sizeof(hash_state_t)); - if (hs == NULL) { - error = errno; - ERR(policy, "%s", strerror(ENOMEM)); - errno = error; - return STATUS_ERR; - } - hs->table = &db->p_users.table; - hs->node = (*(hs->table))->htable[0]; - - if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur, - hash_state_next, hash_state_end, hash_state_size, free, iter)) { - free(hs); - return STATUS_ERR; - } - - if (hs->node == NULL) - hash_state_next(*iter); - - return STATUS_SUCCESS; -} - diff --git a/setools/policyrep/bounds.pxi b/setools/policyrep/bounds.pxi index f1d7fce..beabac0 100644 --- a/setools/policyrep/bounds.pxi +++ b/setools/policyrep/bounds.pxi @@ -1,5 +1,5 @@ # Copyright 2016, Tresys Technology, LLC -# Copyright 2016-2017, Chris PeBenito +# Copyright 2016-2018, Chris PeBenito # # This file is part of SETools. # @@ -18,29 +18,6 @@ # . # -# -# Factory functions -# -cdef inline Bounds bounds_factory_iter(SELinuxPolicy policy, QpolIteratorItem symbol): - """Factory function variant for iterating over Bounds objects.""" - return bounds_factory(policy, symbol.obj) - - -cdef inline Bounds bounds_factory(SELinuxPolicy policy, const qpol_typebounds_t *symbol): - """Factory function for creating Bounds objects.""" - r = Bounds() - r.policy = policy - r.handle = symbol - return r - - -#def validate_ruletype(t): -# """Validate *bounds rule types.""" -# try: -# return BoundsRuletype.lookup(t) -# except KeyError as ex: -# raise exception.InvalidBoundsType("{0} is not a valid *bounds rule type.".format(t)) from ex - # # Classes @@ -54,13 +31,24 @@ class BoundsRuletype(PolicyEnum): cdef class Bounds(PolicySymbol): - """A typebounds statement.""" + """A bounds statement.""" - cdef const qpol_typebounds_t *handle - cdef readonly object ruletype + cdef: + readonly object ruletype + readonly object parent + readonly object child - def __init__(self): + @staticmethod + cdef factory(SELinuxPolicy policy, parent, child): + """Factory function for creating Bounds objects.""" + b = Bounds(parent, child) + b.policy = policy + return b + + def __init__(self, parent, child): self.ruletype = BoundsRuletype.typebounds + self.parent = parent + self.child = child def __str__(self): return "{0.ruletype} {0.parent} {0.child};".format(self) @@ -68,29 +56,72 @@ cdef class Bounds(PolicySymbol): def __hash__(self): return hash("{0.ruletype}|{0.child};".format(self)) + def __eq__(self, other): + return self.policy == other.policy \ + and self.ruletype == other.ruletype \ + and self.parent == other.parent \ + and self.child == other.child + def __lt__(self, other): # this is used by Python sorting functions return str(self) < str(other) - def _eq(self, Bounds other): - """Low-level equality check (C pointers).""" - return self.handle == other.handle - # TODO: look at qpol code to see if these functions - # can be converted to return symbols rather than names - @property - def parent(self): - cdef const char *name - if qpol_typebounds_get_parent_name(self.policy.handle, self.handle, &name): - raise RuntimeError("Could not get parent name") +# +# Iterators +# +cdef class TypeboundsIterator(HashtabIterator): - return self.policy.lookup_type(name) + """Iterate over typebounds rules in the policy.""" - @property - def child(self): - pass - cdef const char *name - if qpol_typebounds_get_child_name(self.policy.handle, self.handle, &name): - raise RuntimeError("Could not get child name") + @staticmethod + cdef factory(SELinuxPolicy policy, sepol.hashtab_t *table): + """Factory function for creating typebounds iterators.""" + i = TypeboundsIterator() + i.policy = policy + i.table = table + i.reset() + return i - return self.policy.lookup_type(name) + def __next__(self): + cdef sepol.type_datum_t *datum + super().__next__() + + datum = self.curr.datum + while datum.flavor != sepol.TYPE_TYPE or datum.bounds == 0: + super().__next__() + datum = self.curr.datum + + return Bounds.factory(self.policy, + Type.factory(self.policy, self.policy.handle.p.p.type_val_to_struct[datum.bounds - 1]), + Type.factory(self.policy, datum)) + + 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 datum.flavor == sepol.TYPE_TYPE and datum.bounds != 0: + count += 1 + + node = node.next + + bucket += 1 + + return count + + def reset(self): + cdef sepol.type_datum_t * datum + + super().reset() + + # advance over any attributes or aliases + datum = self.node.datum + while datum != NULL and datum.flavor != sepol.TYPE_TYPE and datum.bounds == 0: + self._next_node() + datum = self.node.datum diff --git a/setools/policyrep/selinuxpolicy.pxi b/setools/policyrep/selinuxpolicy.pxi index 7f79e56..281b864 100644 --- a/setools/policyrep/selinuxpolicy.pxi +++ b/setools/policyrep/selinuxpolicy.pxi @@ -419,8 +419,7 @@ cdef class SELinuxPolicy: @property def typebounds_count(self): """The number of typebounds rules.""" - return sum(1 for b in self.bounds() - if b.ruletype == BoundsRuletype.typebounds) + return len(TypeboundsIterator.factory(self, &self.handle.p.p.symtab[sepol.SYM_TYPES].table)) @property def user_count(self): @@ -540,11 +539,7 @@ cdef class SELinuxPolicy: def bounds(self): """Iterator which yields all *bounds statements (typebounds, etc.)""" - cdef qpol_iterator_t *iter - if qpol_policy_get_typebounds_iter(self.handle, &iter): - raise MemoryError - - return qpol_iterator_factory(self, iter, bounds_factory_iter) + return TypeboundsIterator.factory(self, &self.handle.p.p.symtab[sepol.SYM_TYPES].table) def categories(self): """Iterator which yields all MLS categories.""" diff --git a/setup.py b/setup.py index d897a09..2e0e4ba 100644 --- a/setup.py +++ b/setup.py @@ -67,7 +67,6 @@ else: ext_py_mods = [Extension('setools.policyrep.libpolicyrep', ['setools/policyrep/libpolicyrep.pyx', 'libqpol/avrule_query.c', - 'libqpol/bounds_query.c', 'libqpol/class_perm_query.c', 'libqpol/cond_query.c', 'libqpol/constraint_query.c',