Bounds: Convert to direct sepol structure use. Add iterator.

This commit is contained in:
Chris PeBenito 2018-02-16 17:20:55 -05:00
parent 42ccafcdcc
commit f39347d81f
4 changed files with 79 additions and 404 deletions

View File

@ -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 <stddef.h>
#include <stdlib.h>
#include <stdint.h>
#include <qpol/iterator.h>
#include <qpol/policy.h>
#include <qpol/bounds_query.h>
#include <sepol/policydb/policydb.h>
#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;
}

View File

@ -1,5 +1,5 @@
# Copyright 2016, Tresys Technology, LLC
# Copyright 2016-2017, Chris PeBenito <pebenito@ieee.org>
# Copyright 2016-2018, Chris PeBenito <pebenito@ieee.org>
#
# This file is part of SETools.
#
@ -18,29 +18,6 @@
# <http://www.gnu.org/licenses/>.
#
#
# Factory functions
#
cdef inline Bounds bounds_factory_iter(SELinuxPolicy policy, QpolIteratorItem symbol):
"""Factory function variant for iterating over Bounds objects."""
return bounds_factory(policy, <const qpol_typebounds_t *> 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 = <sepol.type_datum_t *> self.curr.datum
while datum.flavor != sepol.TYPE_TYPE or datum.bounds == 0:
super().__next__()
datum = <sepol.type_datum_t *> 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 = <sepol.type_datum_t *>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 = <sepol.type_datum_t *> self.node.datum
while datum != NULL and datum.flavor != sepol.TYPE_TYPE and datum.bounds == 0:
self._next_node()
datum = <sepol.type_datum_t *> self.node.datum

View File

@ -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."""

View File

@ -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',