mirror of
https://github.com/SELinuxProject/setools
synced 2025-03-19 17:53:56 +00:00
Bounds: Convert to direct sepol structure use. Add iterator.
This commit is contained in:
parent
42ccafcdcc
commit
f39347d81f
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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."""
|
||||
|
Loading…
Reference in New Issue
Block a user