RoleAllow/Transition: Convert to direct sepol structure access.

This commit is contained in:
Chris PeBenito 2018-02-17 11:17:54 -05:00
parent f3f174df9e
commit 71cfccce06
4 changed files with 137 additions and 505 deletions

View File

@ -1,381 +0,0 @@
/**
* @file
* Defines public interface for iterating over RBAC rules.
*
* @author Jeremy A. Mowery jmowery@tresys.com
* @author Jason Tang jtang@tresys.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 <qpol/iterator.h>
#include <qpol/policy.h>
#include <qpol/rbacrule_query.h>
#include <stdlib.h>
#include "iterator_internal.h"
#include "qpol_internal.h"
#include <sepol/policydb/policydb.h>
typedef struct role_allow_state
{
role_allow_t *head;
role_allow_t *cur;
} role_allow_state_t;
static int role_allow_state_end(const qpol_iterator_t * iter)
{
role_allow_state_t *ras = NULL;
if (!iter || !(ras = qpol_iterator_state(iter))) {
errno = EINVAL;
return STATUS_ERR;
}
return ras->cur ? 0 : 1;
}
static void *role_allow_state_get_cur(const qpol_iterator_t * iter)
{
role_allow_state_t *ras = NULL;
const policydb_t *db = NULL;
if (!iter || !(ras = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter)) || role_allow_state_end(iter)) {
errno = EINVAL;
return NULL;
}
return ras->cur;
}
static int role_allow_state_next(qpol_iterator_t * iter)
{
role_allow_state_t *ras = NULL;
const policydb_t *db = NULL;
if (!iter || !(ras = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter))) {
errno = EINVAL;
return STATUS_ERR;
}
if (role_allow_state_end(iter)) {
errno = ERANGE;
return STATUS_ERR;
}
ras->cur = ras->cur->next;
return STATUS_SUCCESS;
}
static size_t role_allow_state_size(const qpol_iterator_t * iter)
{
role_allow_state_t *ras = NULL;
const policydb_t *db = NULL;
role_allow_t *tmp = NULL;
size_t count = 0;
if (!iter || !(ras = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter))) {
errno = EINVAL;
return STATUS_ERR;
}
for (tmp = ras->head; tmp; tmp = tmp->next)
count++;
return count;
}
int qpol_policy_get_role_allow_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter)
{
policydb_t *db = NULL;
role_allow_state_t *ras = NULL;
int error = 0;
if (iter)
*iter = NULL;
if (!policy || !iter) {
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
return STATUS_ERR;
}
db = &policy->p->p;
ras = calloc(1, sizeof(role_allow_state_t));
if (!ras) {
/* errno set by calloc */
ERR(policy, "%s", strerror(errno));
return STATUS_ERR;
}
ras->head = ras->cur = db->role_allow;
if (qpol_iterator_create
(policy, (void *)ras, role_allow_state_get_cur, role_allow_state_next, role_allow_state_end, role_allow_state_size,
free, iter)) {
error = errno;
free(ras);
errno = error;
return STATUS_ERR;
}
return STATUS_SUCCESS;
}
int qpol_role_allow_get_source_role(const qpol_policy_t * policy, const qpol_role_allow_t * rule, const qpol_role_t ** source)
{
policydb_t *db = NULL;
role_allow_t *ra = NULL;
if (source) {
*source = NULL;
}
if (!policy || !rule || !source) {
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
return STATUS_ERR;
}
db = &policy->p->p;
ra = (role_allow_t *) rule;
*source = (qpol_role_t *) db->role_val_to_struct[ra->role - 1];
return STATUS_SUCCESS;
}
int qpol_role_allow_get_target_role(const qpol_policy_t * policy, const qpol_role_allow_t * rule, const qpol_role_t ** target)
{
policydb_t *db = NULL;
role_allow_t *ra = NULL;
if (target) {
*target = NULL;
}
if (!policy || !rule || !target) {
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
return STATUS_ERR;
}
db = &policy->p->p;
ra = (role_allow_t *) rule;
*target = (qpol_role_t *) db->role_val_to_struct[ra->new_role - 1];
return STATUS_SUCCESS;
}
typedef struct role_trans_state
{
role_trans_t *head;
role_trans_t *cur;
} role_trans_state_t;
static int role_trans_state_end(const qpol_iterator_t * iter)
{
role_trans_state_t *rts = NULL;
if (!iter || !(rts = qpol_iterator_state(iter))) {
errno = EINVAL;
return STATUS_ERR;
}
return rts->cur ? 0 : 1;
}
static void *role_trans_state_get_cur(const qpol_iterator_t * iter)
{
role_trans_state_t *rts = NULL;
const policydb_t *db = NULL;
if (!iter || !(rts = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter)) || role_trans_state_end(iter)) {
errno = EINVAL;
return NULL;
}
return rts->cur;
}
static int role_trans_state_next(qpol_iterator_t * iter)
{
role_trans_state_t *rts = NULL;
const policydb_t *db = NULL;
if (!iter || !(rts = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter))) {
errno = EINVAL;
return STATUS_ERR;
}
if (role_trans_state_end(iter)) {
errno = ERANGE;
return STATUS_ERR;
}
rts->cur = rts->cur->next;
return STATUS_SUCCESS;
}
static size_t role_trans_state_size(const qpol_iterator_t * iter)
{
role_trans_state_t *rts = NULL;
const policydb_t *db = NULL;
role_trans_t *tmp = NULL;
size_t count = 0;
if (!iter || !(rts = qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter))) {
errno = EINVAL;
return STATUS_ERR;
}
for (tmp = rts->head; tmp; tmp = tmp->next)
count++;
return count;
}
int qpol_policy_get_role_trans_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter)
{
policydb_t *db = NULL;
role_trans_state_t *rts = NULL;
int error = 0;
if (iter)
*iter = NULL;
if (!policy || !iter) {
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
return STATUS_ERR;
}
db = &policy->p->p;
rts = calloc(1, sizeof(role_trans_state_t));
if (!rts) {
/* errno set by calloc */
ERR(policy, "%s", strerror(errno));
return STATUS_ERR;
}
rts->head = rts->cur = db->role_tr;
if (qpol_iterator_create
(policy, (void *)rts, role_trans_state_get_cur, role_trans_state_next, role_trans_state_end, role_trans_state_size,
free, iter)) {
error = errno;
free(rts);
errno = error;
return STATUS_ERR;
}
return STATUS_SUCCESS;
}
int qpol_role_trans_get_source_role(const qpol_policy_t * policy, const qpol_role_trans_t * rule, const qpol_role_t ** source)
{
policydb_t *db = NULL;
role_trans_t *rt = NULL;
if (source) {
*source = NULL;
}
if (!policy || !rule || !source) {
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
return STATUS_ERR;
}
db = &policy->p->p;
rt = (role_trans_t *) rule;
*source = (qpol_role_t *) db->role_val_to_struct[rt->role - 1];
return STATUS_SUCCESS;
}
int qpol_role_trans_get_target_type(const qpol_policy_t * policy, const qpol_role_trans_t * rule, const qpol_type_t ** target)
{
policydb_t *db = NULL;
role_trans_t *rt = NULL;
if (target) {
*target = NULL;
}
if (!policy || !rule || !target) {
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
return STATUS_ERR;
}
db = &policy->p->p;
rt = (role_trans_t *) rule;
*target = (qpol_type_t *) db->type_val_to_struct[rt->type - 1];
return STATUS_SUCCESS;
}
int qpol_role_trans_get_object_class(const qpol_policy_t * policy, const qpol_role_trans_t * rule, const qpol_class_t ** obj_class)
{
policydb_t *db = NULL;
role_trans_t *rt = NULL;
if (obj_class) {
*obj_class = NULL;
}
if (!policy || !rule || !obj_class) {
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
return STATUS_ERR;
}
db = &policy->p->p;
rt = (role_trans_t *) rule;
*obj_class = (qpol_class_t *) db->class_val_to_struct[rt->tclass - 1];
return STATUS_SUCCESS;
}
int qpol_role_trans_get_default_role(const qpol_policy_t * policy, const qpol_role_trans_t * rule, const qpol_role_t ** dflt)
{
policydb_t *db = NULL;
role_trans_t *rt = NULL;
if (dflt) {
*dflt = NULL;
}
if (!policy || !rule || !dflt) {
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
return STATUS_ERR;
}
db = &policy->p->p;
rt = (role_trans_t *) rule;
*dflt = (qpol_role_t *) db->role_val_to_struct[rt->new_role - 1];
return STATUS_SUCCESS;
}

View File

@ -1,5 +1,5 @@
# Copyright 2014, 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,62 +18,6 @@
# <http://www.gnu.org/licenses/>.
#
#
# Role allow factory functions
#
cdef inline RoleAllow role_allow_factory_iter(SELinuxPolicy policy, QpolIteratorItem symbol):
"""Factory function variant for iterating over RoleAllow objects."""
return role_allow_factory(policy, <const qpol_role_allow_t *> symbol.obj)
cdef inline RoleAllow role_allow_factory(SELinuxPolicy policy, const qpol_role_allow_t *symbol):
"""Factory function for creating RoleAllow objects."""
r = RoleAllow()
r.policy = policy
r.handle = symbol
return r
#
# Role transition factory functions
#
cdef inline RoleTransition role_trans_factory_iter(SELinuxPolicy policy, QpolIteratorItem symbol):
"""Factory function variant for iterating over RoleTransition objects."""
return role_trans_factory(policy, <const qpol_role_trans_t *> symbol.obj)
cdef inline RoleTransition role_trans_factory(SELinuxPolicy policy, const qpol_role_trans_t *symbol):
"""Factory function for creating RoleTransition objects."""
r = RoleTransition()
r.policy = policy
r.handle = symbol
return r
#
# Expanded RBAC rule factory functions
#
cdef inline ExpandedRoleAllow expanded_role_allow_factory(RoleAllow original, source, target):
"""Factory function for creating ExpandedRoleAllow objects."""
r = ExpandedRoleAllow()
r.policy = original.policy
r.handle = original.handle
r.source = source
r.target = target
r.origin = original
return r
cdef inline ExpandedRoleTransition expanded_role_trans_factory(RoleTransition original, source, target):
"""Factory function for creating ExpandedRoleTransition objects."""
r = ExpandedRoleTransition()
r.policy = original.policy
r.handle = original.handle
r.source = source
r.target = target
r.origin = original
return r
#
# Classes
#
@ -90,9 +34,17 @@ cdef class RoleAllow(PolicyRule):
"""A role allow rule."""
cdef:
const qpol_role_allow_t *handle
sepol.role_allow_t *handle
readonly object ruletype
@staticmethod
cdef factory(SELinuxPolicy policy, sepol.role_allow_t *symbol):
"""Factory function for creating RoleAllow objects."""
r = RoleAllow()
r.policy = policy
r.handle = symbol
return r
def __init__(self):
self.ruletype = RBACRuletype.allow
@ -106,26 +58,14 @@ cdef class RoleAllow(PolicyRule):
@property
def source(self):
"""The rule's source role."""
cdef const qpol_role_t *r
if qpol_role_allow_get_source_role(self.policy.handle, self.handle, &r):
ex = LowLevelPolicyError("Error reading source role for role allow rule: {}".format(
strerror(errno)))
ex.errno = errno
raise ex
return Role.factory(self.policy, <sepol.role_datum_t *>r)
return Role.factory(self.policy,
self.policy.handle.p.p.role_val_to_struct[self.handle.role - 1])
@property
def target(self):
"""The rule's target role."""
cdef const qpol_role_t *r
if qpol_role_allow_get_target_role(self.policy.handle, self.handle, &r):
ex = LowLevelPolicyError("Error reading target role for role allow rule: {}".format(
strerror(errno)))
ex.errno = errno
raise ex
return Role.factory(self.policy, <sepol.role_datum_t *>r)
return Role.factory(self.policy,
self.policy.handle.p.p.role_val_to_struct[self.handle.new_role - 1])
@property
def tclass(self):
@ -140,7 +80,14 @@ cdef class RoleAllow(PolicyRule):
def expand(self):
"""Expand the rule into an equivalent set of rules without attributes."""
for s, t in itertools.product(self.source.expand(), self.target.expand()):
yield expanded_role_allow_factory(self, s, t)
"""Factory function for creating ExpandedRoleAllow objects."""
r = ExpandedRoleAllow()
r.policy = self.policy
r.handle = self.handle
r.source = s
r.target = t
r.origin = self
yield r
cdef class RoleTransition(PolicyRule):
@ -148,9 +95,17 @@ cdef class RoleTransition(PolicyRule):
"""A role_transition rule."""
cdef:
const qpol_role_trans_t *handle
sepol.role_trans_t *handle
readonly object ruletype
@staticmethod
cdef factory(SELinuxPolicy policy, sepol.role_trans_t *symbol):
"""Factory function for creating RoleTransition objects."""
r = RoleTransition()
r.policy = policy
r.handle = symbol
return r
def __init__(self):
self.ruletype = RBACRuletype.role_transition
@ -164,55 +119,37 @@ cdef class RoleTransition(PolicyRule):
@property
def source(self):
"""The rule's source role."""
cdef const qpol_role_t *r
if qpol_role_trans_get_source_role(self.policy.handle, self.handle, &r):
ex = LowLevelPolicyError("Error reading source role for role_transition rule: {}".
format(strerror(errno)))
ex.errno = errno
raise ex
return Role.factory(self.policy, <sepol.role_datum_t *>r)
return Role.factory(self.policy,
self.policy.handle.p.p.role_val_to_struct[self.handle.role - 1])
@property
def target(self):
"""The rule's target type/attribute."""
cdef const qpol_type_t *t
if qpol_role_trans_get_target_type(self.policy.handle, self.handle, &t):
ex = LowLevelPolicyError("Error reading target type/attr for role_transition rule: {}".
format(strerror(errno)))
ex.errno = errno
raise ex
return type_or_attr_factory(self.policy, <sepol.type_datum_t *>t)
return type_or_attr_factory(self.policy,
self.policy.handle.p.p.type_val_to_struct[self.handle.type - 1])
@property
def tclass(self):
"""The rule's object class."""
cdef const qpol_class_t *c
if qpol_role_trans_get_object_class(self.policy.handle, self.handle, &c):
ex = LowLevelPolicyError("Error reading class for role_transition rule: {}".format(
strerror(errno)))
ex.errno = errno
raise ex
return ObjClass.factory(self.policy, <sepol.class_datum_t *>c)
return ObjClass.factory(self.policy,
self.policy.handle.p.p.class_val_to_struct[self.handle.tclass - 1])
@property
def default(self):
"""The rule's default role."""
cdef const qpol_role_t *r
if qpol_role_trans_get_default_role(self.policy.handle, self.handle, &r):
ex = LowLevelPolicyError("Error reading default role for role_transition rule: {}".
format(strerror(errno)))
ex.errno = errno
raise ex
return Role.factory(self.policy, <sepol.role_datum_t *>r)
return Role.factory(self.policy,
self.policy.handle.p.p.role_val_to_struct[self.handle.new_role - 1])
def expand(self):
"""Expand the rule into an equivalent set of rules without attributes."""
for s, t in itertools.product(self.source.expand(), self.target.expand()):
yield expanded_role_trans_factory(self, s, t)
r = ExpandedRoleTransition()
r.policy = self.policy
r.handle = self.handle
r.source = s
r.target = t
r.origin = self
yield r
cdef class ExpandedRoleAllow(RoleAllow):
@ -253,3 +190,90 @@ cdef class ExpandedRoleTransition(RoleTransition):
def __lt__(self, other):
return str(self) < str(other)
#
# Iterators
#
cdef class RoleAllowIterator(PolicyIterator):
"""Role allow rule iterator."""
cdef:
sepol.role_allow_t *head
sepol.role_allow_t *curr
@staticmethod
cdef factory(SELinuxPolicy policy, sepol.role_allow_t *head):
"""Role allow rule iterator factory."""
i = RoleAllowIterator()
i.policy = policy
i.head = head
i.reset()
return i
def __next__(self):
if self.curr == NULL:
raise StopIteration
item = RoleAllow.factory(self.policy, self.curr)
self.curr = self.curr.next
return item
def __len__(self):
cdef:
sepol.role_allow_t *curr
size_t count = 0
curr = self.head
while curr != NULL:
count += 1
curr = curr.next
return count
def reset(self):
"""Reset the iterator back to the start."""
self.curr = self.head
cdef class RoleTransitionIterator(PolicyIterator):
"""Role transition rule iterator."""
cdef:
sepol.role_trans_t *head
sepol.role_trans_t *curr
@staticmethod
cdef factory(SELinuxPolicy policy, sepol.role_trans_t *head):
"""Role transition rule iterator factory."""
i = RoleTransitionIterator()
i.policy = policy
i.head = head
i.reset()
return i
def __next__(self):
if self.curr == NULL:
raise StopIteration
item = RoleTransition.factory(self.policy, self.curr)
self.curr = self.curr.next
return item
def __len__(self):
cdef:
sepol.role_trans_t *curr
size_t count = 0
curr = self.head
while curr != NULL:
count += 1
curr = curr.next
return count
def reset(self):
"""Reset the iterator back to the start."""
self.curr = self.head

View File

@ -369,14 +369,12 @@ cdef class SELinuxPolicy:
@property
def role_allow_count(self):
"""The number of role allow rules."""
return sum(1 for r in self.rbacrules()
if r.ruletype == RBACRuletype.allow)
return len(RoleAllowIterator.factory(self, self.handle.p.p.role_allow))
@property
def role_transition_count(self):
"""The number of role_transition rules."""
return sum(1 for r in self.rbacrules()
if r.ruletype == RBACRuletype.role_transition)
return len(RoleTransitionIterator.factory(self, self.handle.p.p.role_tr))
@property
def range_transition_count(self):
@ -603,16 +601,8 @@ cdef class SELinuxPolicy:
def rbacrules(self):
"""Iterator over all RBAC rules."""
cdef qpol_iterator_t *ra_iter
if qpol_policy_get_role_allow_iter(self.handle, &ra_iter):
raise MemoryError
cdef qpol_iterator_t *rt_iter
if qpol_policy_get_role_trans_iter(self.handle, &rt_iter):
raise MemoryError
return chain(qpol_iterator_factory(self, ra_iter, role_allow_factory_iter),
qpol_iterator_factory(self, rt_iter, role_trans_factory_iter))
return chain(RoleAllowIterator.factory(self, self.handle.p.p.role_allow),
RoleTransitionIterator.factory(self, self.handle.p.p.role_tr))
def terules(self):
"""Iterator over all type enforcement rules."""

View File

@ -71,7 +71,6 @@ ext_py_mods = [Extension('setools.policyrep.libpolicyrep',
'libqpol/iterator.c',
'libqpol/policy.c',
'libqpol/policy_extend.c',
'libqpol/rbacrule_query.c',
'libqpol/terule_query.c'],
include_dirs=include_dirs,
libraries=['selinux'],