policyrep: Convert MLS symbols and levels/ranges to direct sepol structure access.

Add iterators.
This commit is contained in:
Chris PeBenito 2018-02-11 11:03:19 -05:00
parent 8260b9b166
commit d476f22055
9 changed files with 647 additions and 1282 deletions

View File

@ -571,42 +571,6 @@ void *ebitmap_state_get_cur_role(const qpol_iterator_t * iter)
return db->role_val_to_struct[es->cur];
}
void *ebitmap_state_get_cur_cat(const qpol_iterator_t * iter)
{
ebitmap_state_t *es = NULL;
const policydb_t *db = NULL;
const qpol_cat_t *cat = NULL;
sepol_policydb_t sp;
qpol_policy_t qp;
if (iter == NULL) {
errno = EINVAL;
return NULL;
}
es = qpol_iterator_state(iter);
if (es == NULL) {
errno = EINVAL;
return NULL;
}
db = qpol_iterator_policy(iter);
if (db == NULL) {
errno = EINVAL;
return NULL;
}
/* shallow copy is safe here */
sp.p = *db;
qp.p = &sp;
qp.fn = NULL;
qpol_policy_get_cat_by_name(&qp, db->p_cat_val_to_name[es->cur], &cat);
/* There is no val_to_struct for categories; this requires that qpol
* search for the struct, but it can't be returned as const here so
* cast it to void* explicitly. */
return (void *)cat;
}
void *ebitmap_state_get_cur_permissive(const qpol_iterator_t * iter)
{
ebitmap_state_t *es = NULL;

View File

@ -1,836 +0,0 @@
/**
* @file
* Implementation of the interface for searching and iterating over
* policy MLS components.
*
* @author Jeremy A. Mowery jmowery@tresys.com
* @author Jason Tang jtang@tresys.com
*
* Copyright (C) 2006-2007. 2015 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 <stdint.h>
#include <stdlib.h>
#include <qpol/iterator.h>
#include <sepol/policydb/policydb.h>
#include <sepol/policydb/expand.h>
#include "iterator_internal.h"
#include <qpol/mls_query.h>
#include "qpol_internal.h"
/* level */
int qpol_policy_get_level_by_name(const qpol_policy_t * policy, const char *name, const qpol_level_t ** datum)
{
policydb_t *db = NULL;
hashtab_datum_t internal_datum = NULL;
if (policy == NULL || name == NULL || datum == NULL) {
if (datum != NULL)
*datum = NULL;
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
return STATUS_ERR;
}
db = &policy->p->p;
internal_datum = hashtab_search(db->p_levels.table, (hashtab_key_t)name);
if (internal_datum == NULL) {
ERR(policy, "could not find datum for level %s", name);
errno = EINVAL;
*datum = NULL;
return STATUS_ERR;
}
*datum = (qpol_level_t *) internal_datum;
return STATUS_SUCCESS;
}
int qpol_policy_get_level_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_levels.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;
}
int qpol_level_get_isalias(const qpol_policy_t * policy, const qpol_level_t * datum, unsigned char *isalias)
{
level_datum_t *internal_datum;
if (policy == NULL || datum == NULL || isalias == NULL) {
if (isalias != NULL)
*isalias = 0;
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
return STATUS_ERR;
}
internal_datum = (level_datum_t *) datum;
*isalias = internal_datum->isalias;
return STATUS_SUCCESS;
}
int qpol_level_get_value(const qpol_policy_t * policy, const qpol_level_t * datum, uint32_t * value)
{
level_datum_t *internal_datum = NULL;
if (policy == NULL || datum == NULL || value == NULL) {
if (value != NULL)
*value = 0;
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
return STATUS_ERR;
}
internal_datum = (level_datum_t *) datum;
*value = internal_datum->level->sens;
return STATUS_SUCCESS;
}
int qpol_level_get_cat_iter(const qpol_policy_t * policy, const qpol_level_t * datum, qpol_iterator_t ** cats)
{
level_datum_t *internal_datum = NULL;
ebitmap_state_t *es = NULL;
int error = 0;
if (policy == NULL || datum == NULL || cats == NULL) {
if (cats != NULL)
*cats = NULL;
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
return STATUS_ERR;
}
internal_datum = (level_datum_t *) datum;
es = calloc(1, sizeof(ebitmap_state_t));
if (es == NULL) {
error = errno;
ERR(policy, "%s", strerror(ENOMEM));
errno = error;
return STATUS_ERR;
}
es->bmap = &(internal_datum->level->cat);
es->cur = es->bmap->node ? es->bmap->node->startbit : 0;
if (qpol_iterator_create(policy, es, ebitmap_state_get_cur_cat,
ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, free, cats)) {
free(es);
return STATUS_ERR;
}
if (es->bmap->node && !ebitmap_get_bit(es->bmap, es->cur))
ebitmap_state_next(*cats);
return STATUS_SUCCESS;
}
int qpol_level_get_name(const qpol_policy_t * policy, const qpol_level_t * datum, const char **name)
{
level_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;
}
db = &policy->p->p;
internal_datum = (level_datum_t *) datum;
*name = db->p_sens_val_to_name[internal_datum->level->sens - 1];
return STATUS_SUCCESS;
}
typedef struct level_alias_hash_state
{
unsigned int bucket;
hashtab_node_t *node;
hashtab_t *table;
uint32_t val;
} level_alias_hash_state_t;
static int hash_state_next_level_alias(qpol_iterator_t * iter)
{
level_alias_hash_state_t *hs = NULL;
level_datum_t *datum = NULL;
if (iter == NULL) {
errno = EINVAL;
return STATUS_ERR;
}
hs = (level_alias_hash_state_t *) qpol_iterator_state(iter);
if (hs == NULL) {
errno = EINVAL;
return STATUS_ERR;
}
if (hs->bucket >= (*(hs->table))->size) {
errno = ERANGE;
return STATUS_ERR;
}
do {
hash_state_next(iter);
datum = hs->node ? (level_datum_t *) hs->node->datum : NULL;
} while (datum != NULL && (datum->level->sens != hs->val || !datum->isalias));
return STATUS_SUCCESS;
}
static void *hash_state_get_cur_alias(const qpol_iterator_t * iter)
{
level_alias_hash_state_t *hs = NULL;
if (iter == NULL) {
errno = EINVAL;
return NULL;
}
hs = (level_alias_hash_state_t *) qpol_iterator_state(iter);
if (hs == NULL) {
errno = EINVAL;
return NULL;
}
if (hs->bucket >= (*(hs->table))->size) {
errno = ERANGE;
return NULL;
}
return hs->node->key;
}
static size_t hash_state_level_alias_size(const qpol_iterator_t * iter)
{
level_alias_hash_state_t *hs = NULL;
hashtab_node_t *tmp_node;
level_datum_t *tmp_lvl_datum;
uint32_t tmp_bucket = 0;
size_t count = 0;
if (iter == NULL || qpol_iterator_state(iter) == NULL) {
errno = EINVAL;
return 0;
}
hs = (level_alias_hash_state_t *) qpol_iterator_state(iter);
if (!hs) {
errno = EINVAL;
return STATUS_ERR;
}
for (tmp_bucket = 0; tmp_bucket < (*(hs->table))->size; tmp_bucket++) {
for (tmp_node = (*(hs->table))->htable[tmp_bucket]; tmp_node; tmp_node = tmp_node->next) {
tmp_lvl_datum = tmp_node ? tmp_node->datum : NULL;
if (tmp_lvl_datum) {
if (tmp_lvl_datum->isalias && tmp_lvl_datum->level->sens == hs->val)
count++;
}
}
}
return count;
}
int qpol_level_get_alias_iter(const qpol_policy_t * policy, const qpol_level_t * datum, qpol_iterator_t ** aliases)
{
level_datum_t *internal_datum = NULL;
policydb_t *db = NULL;
int error;
level_alias_hash_state_t *hs = NULL;
if (policy == NULL || datum == NULL || aliases == NULL) {
if (aliases != NULL)
*aliases = NULL;
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
return STATUS_ERR;
}
db = &policy->p->p;
internal_datum = (level_datum_t *) datum;
hs = calloc(1, sizeof(level_alias_hash_state_t));
if (hs == NULL) {
error = errno;
ERR(policy, "%s", strerror(ENOMEM));
errno = error;
return STATUS_ERR;
}
hs->table = &db->p_levels.table;
hs->node = (*(hs->table))->htable[0];
hs->val = internal_datum->level->sens;
if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur_alias,
hash_state_next_level_alias, hash_state_end, hash_state_level_alias_size, free, aliases)) {
free(hs);
return STATUS_ERR;
}
if (hs->node == NULL || !((level_datum_t *) hs->node->datum)->isalias
|| ((level_datum_t *) (hs->node->datum))->level->sens != hs->val)
hash_state_next_level_alias(*aliases);
return STATUS_SUCCESS;
}
/* cat */
int qpol_policy_get_cat_by_name(const qpol_policy_t * policy, const char *name, const qpol_cat_t ** datum)
{
hashtab_datum_t internal_datum;
policydb_t *db;
if (policy == NULL || name == NULL || datum == NULL) {
if (datum != NULL)
*datum = NULL;
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
return STATUS_ERR;
}
db = &policy->p->p;
internal_datum = hashtab_search(db->p_cats.table, (hashtab_key_t)name);
if (internal_datum == NULL) {
*datum = NULL;
ERR(policy, "could not find datum for cat %s", name);
errno = EINVAL;
return STATUS_ERR;
}
*datum = (qpol_cat_t *) internal_datum;
return STATUS_SUCCESS;
}
int qpol_policy_get_cat_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_cats.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;
}
int qpol_cat_get_value(const qpol_policy_t * policy, const qpol_cat_t * datum, uint32_t * value)
{
cat_datum_t *internal_datum = NULL;
if (policy == NULL || datum == NULL || value == NULL) {
if (value != NULL)
*value = 0;
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
return STATUS_ERR;
}
internal_datum = (cat_datum_t *) datum;
*value = internal_datum->s.value;
return STATUS_SUCCESS;
}
int qpol_cat_get_isalias(const qpol_policy_t * policy, const qpol_cat_t * datum, unsigned char *isalias)
{
cat_datum_t *internal_datum;
if (policy == NULL || datum == NULL || isalias == NULL) {
if (isalias != NULL)
*isalias = 0;
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
return STATUS_ERR;
}
internal_datum = (cat_datum_t *) datum;
*isalias = internal_datum->isalias;
return STATUS_SUCCESS;
}
int qpol_cat_get_name(const qpol_policy_t * policy, const qpol_cat_t * datum, const char **name)
{
cat_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;
}
db = &policy->p->p;
internal_datum = (cat_datum_t *) datum;
*name = db->p_cat_val_to_name[internal_datum->s.value - 1];
return STATUS_SUCCESS;
}
static int hash_state_next_cat_alias(qpol_iterator_t * iter)
{
/* using level alias state datum since data needed is identical */
level_alias_hash_state_t *hs = NULL;
cat_datum_t *datum = NULL;
if (iter == NULL) {
errno = EINVAL;
return STATUS_ERR;
}
hs = (level_alias_hash_state_t *) qpol_iterator_state(iter);
if (hs == NULL) {
errno = EINVAL;
return STATUS_ERR;
}
if (hs->bucket >= (*(hs->table))->size) {
errno = ERANGE;
return STATUS_ERR;
}
do {
hash_state_next(iter);
datum = hs->node ? (cat_datum_t *) hs->node->datum : NULL;
} while (datum != NULL && (datum->s.value != hs->val || !datum->isalias));
return STATUS_SUCCESS;
}
static size_t hash_state_cat_alias_size(const qpol_iterator_t * iter)
{
level_alias_hash_state_t *hs = NULL;
hashtab_node_t *tmp_node;
cat_datum_t *tmp_cat_datum;
uint32_t tmp_bucket = 0;
size_t count = 0;
if (iter == NULL || qpol_iterator_state(iter) == NULL) {
errno = EINVAL;
return 0;
}
hs = (level_alias_hash_state_t *) qpol_iterator_state(iter);
if (!hs) {
errno = EINVAL;
return STATUS_ERR;
}
for (tmp_bucket = 0; tmp_bucket < (*(hs->table))->size; tmp_bucket++) {
for (tmp_node = (*(hs->table))->htable[tmp_bucket]; tmp_node; tmp_node = tmp_node->next) {
tmp_cat_datum = tmp_node ? tmp_node->datum : NULL;
if (tmp_cat_datum) {
if (tmp_cat_datum->isalias && tmp_cat_datum->s.value == hs->val)
count++;
}
}
}
return count;
}
int qpol_cat_get_alias_iter(const qpol_policy_t * policy, const qpol_cat_t * datum, qpol_iterator_t ** aliases)
{
cat_datum_t *internal_datum = NULL;
policydb_t *db = NULL;
int error;
level_alias_hash_state_t *hs = NULL;
if (policy == NULL || datum == NULL || aliases == NULL) {
if (aliases != NULL)
*aliases = NULL;
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
return STATUS_ERR;
}
db = &policy->p->p;
internal_datum = (cat_datum_t *) datum;
hs = calloc(1, sizeof(level_alias_hash_state_t));
if (hs == NULL) {
error = errno;
ERR(policy, "%s", strerror(ENOMEM));
errno = error;
return STATUS_ERR;
}
hs->table = &db->p_cats.table;
hs->node = (*(hs->table))->htable[0];
hs->val = internal_datum->s.value;
if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur_alias,
hash_state_next_cat_alias, hash_state_end, hash_state_cat_alias_size, free, aliases)) {
free(hs);
return STATUS_ERR;
}
if (hs->node == NULL || ((cat_datum_t *) (hs->node->datum))->s.value != hs->val)
hash_state_next_cat_alias(*aliases);
return STATUS_SUCCESS;
}
/* mls range */
int qpol_policy_get_mls_range_from_mls_levels(const qpol_policy_t * policy, const qpol_mls_level_t *low, const qpol_mls_level_t *high, qpol_mls_range_t **dest)
{
mls_range_t *internal_range = NULL;
mls_level_t *internal_low = NULL, *internal_high = NULL;
if (policy == NULL || low == NULL || high == NULL || dest == NULL) {
if (dest != NULL)
*dest = NULL;
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
return STATUS_ERR;
}
*dest = NULL;
internal_low = (mls_level_t*)low;
internal_high = (mls_level_t*)high;
if (!mls_level_dom(internal_high, internal_low)) {
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
return STATUS_ERR;
}
internal_range = malloc(sizeof(mls_range_t));
if (!internal_range) {
ERR(policy, "%s", strerror(errno));
return STATUS_ERR;
}
mls_range_init(internal_range);
if (mls_level_cpy(&internal_range->level[0], internal_low) < 0) {
goto err;
}
if (mls_level_cpy(&internal_range->level[1], internal_high) < 0) {
goto err;
}
*dest = (qpol_mls_range_t*) internal_range;
return STATUS_SUCCESS;
err:
mls_range_destroy(internal_range);
free(internal_range);
errno = ENOMEM;
return STATUS_ERR;
}
int qpol_mls_range_get_low_level(const qpol_policy_t * policy, const qpol_mls_range_t * range, const qpol_mls_level_t ** level)
{
mls_range_t *internal_range = NULL;
if (policy == NULL || range == NULL || level == NULL) {
if (level != NULL)
*level = NULL;
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
return STATUS_ERR;
}
internal_range = (mls_range_t *) range;
*level = (qpol_mls_level_t *) & (internal_range->level[0]);
return STATUS_SUCCESS;
}
int qpol_mls_range_get_high_level(const qpol_policy_t * policy, const qpol_mls_range_t * range, const qpol_mls_level_t ** level)
{
mls_range_t *internal_range = NULL;
if (policy == NULL || range == NULL || level == NULL) {
if (level != NULL)
*level = NULL;
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
return STATUS_ERR;
}
internal_range = (mls_range_t *) range;
*level = (qpol_mls_level_t *) & (internal_range->level[1]);
return STATUS_SUCCESS;
}
/* mls_level */
int qpol_mls_level_get_sens_name(const qpol_policy_t * policy, const qpol_mls_level_t * level, const char **name)
{
policydb_t *db = NULL;
mls_level_t *internal_level = NULL;
if (policy == NULL || level == NULL || name == NULL) {
if (name != NULL)
*name = NULL;
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
return STATUS_ERR;
}
internal_level = (mls_level_t *) level;
db = &policy->p->p;
*name = db->p_sens_val_to_name[internal_level->sens - 1];
return STATUS_SUCCESS;
}
int qpol_mls_level_get_cat_iter(const qpol_policy_t * policy, const qpol_mls_level_t * level, qpol_iterator_t ** cats)
{
mls_level_t *internal_level = NULL;
ebitmap_state_t *es = NULL;
int error = 0;
if (policy == NULL || level == NULL || cats == NULL) {
if (cats != NULL)
*cats = NULL;
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
return STATUS_ERR;
}
internal_level = (mls_level_t *) level;
es = calloc(1, sizeof(ebitmap_state_t));
if (es == NULL) {
error = errno;
ERR(policy, "%s", strerror(ENOMEM));
errno = error;
return STATUS_ERR;
}
es->bmap = &(internal_level->cat);
es->cur = es->bmap->node ? es->bmap->node->startbit : 0;
if (qpol_iterator_create(policy, es, ebitmap_state_get_cur_cat,
ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, free, cats)) {
free(es);
return STATUS_ERR;
}
if (es->bmap->node && !ebitmap_get_bit(es->bmap, es->cur))
ebitmap_state_next(*cats);
return STATUS_SUCCESS;
}
int qpol_mls_level_from_semantic_level(const qpol_policy_t * policy, const qpol_semantic_level_t * src, qpol_mls_level_t **dest)
{
policydb_t *db = NULL;
mls_semantic_level_t *internal_semantic = NULL;
mls_level_t *internal_level = NULL;
if (policy == NULL || src == NULL || dest == NULL) {
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
*dest = NULL;
return STATUS_ERR;
}
internal_semantic = (mls_semantic_level_t*) src;
db = &policy->p->p;
internal_level = malloc(sizeof(mls_level_t));
if (!internal_level) {
return STATUS_ERR;
}
mls_level_init(internal_level);
if(mls_semantic_level_expand(internal_semantic, internal_level, db, policy->sh) < 0) {
mls_level_destroy(internal_level);
free(internal_level);
errno = EINVAL;
*dest = NULL;
return STATUS_ERR;
}
*dest = (qpol_mls_level_t*) internal_level;
return STATUS_SUCCESS;
}
/* semantic level */
int qpol_policy_get_semantic_level_by_name(const qpol_policy_t * policy, const char *name, qpol_semantic_level_t ** datum)
{
policydb_t *db = NULL;
hashtab_datum_t internal_datum = NULL;
mls_semantic_level_t *internal_semantic = NULL;
if (policy == NULL || name == NULL || datum == NULL) {
if (datum != NULL)
*datum = NULL;
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
return STATUS_ERR;
}
internal_semantic = malloc(sizeof(mls_semantic_level_t));
if (!internal_semantic) {
return STATUS_ERR;
}
mls_semantic_level_init(internal_semantic);
db = &policy->p->p;
internal_datum = hashtab_search(db->p_levels.table, (hashtab_key_t)name);
if (internal_datum == NULL) {
mls_semantic_level_destroy(internal_semantic);
free(internal_semantic);
*datum = NULL;
ERR(policy, "could not find datum for level %s", name);
errno = ENOENT;
return STATUS_ERR;
}
internal_semantic->sens = ((level_datum_t*)internal_datum)->level->sens;
*datum = (qpol_semantic_level_t *) internal_semantic;
return STATUS_SUCCESS;
}
int qpol_semantic_level_add_cats_by_name(const qpol_policy_t * policy, const qpol_semantic_level_t * level, const char *low, const char *high)
{
hashtab_datum_t internal_datum;
policydb_t *db = NULL;
mls_semantic_level_t *internal_level = NULL;
mls_semantic_cat_t *internal_cat = NULL;
if (policy == NULL || level == NULL || low == NULL || high == NULL) {
ERR(policy, "%s", strerror(EINVAL));
errno = EINVAL;
return STATUS_ERR;
}
internal_cat = malloc(sizeof(mls_semantic_cat_t));
if (!internal_cat) {
return STATUS_ERR;
}
mls_semantic_cat_init(internal_cat);
db = &policy->p->p;
internal_level = (mls_semantic_level_t*) level;
internal_datum = hashtab_search(db->p_cats.table, (hashtab_key_t)low);
if (internal_datum == NULL) {
ERR(policy, "could not find datum for cat %s", low);
goto err;
}
internal_cat->low = ((cat_datum_t*)internal_datum)->s.value;
internal_datum = hashtab_search(db->p_cats.table, (hashtab_key_t)high);
if (internal_datum == NULL) {
ERR(policy, "could not find datum for cat %s", high);
goto err;
}
internal_cat->high = ((cat_datum_t*)internal_datum)->s.value;
if (internal_cat->low > internal_cat->high) {
ERR(policy, "invalid semantic category range: %s.%s", low, high);
goto err;
}
if (!(internal_level->cat)) {
internal_level->cat = internal_cat;
} else {
mls_semantic_cat_t *curr = internal_level->cat;
while(curr->next) {
curr = curr->next;
}
curr->next = internal_cat;
}
return STATUS_SUCCESS;
err:
mls_semantic_cat_destroy(internal_cat);
free(internal_cat);
errno = ENOENT;
return STATUS_ERR;
}
void qpol_semantic_level_destroy(qpol_semantic_level_t * level)
{
if (level == NULL) {
return;
}
mls_semantic_level_destroy((mls_semantic_level_t*) level);
free(level);
}

View File

@ -72,11 +72,10 @@ cdef class Context(PolicySymbol):
@property
def range_(self):
"""The MLS range of the context."""
cdef const qpol_mls_range_t *r
if qpol_context_get_range(self.policy.handle, self.handle, &r):
raise RuntimeError("Could not get range from context")
if not self.policy.mls:
raise MLSDisabled
return range_factory(self.policy, r)
return Range.factory(self.policy, &self.handle.range)
def statement(self):
raise NoStatement

View File

@ -224,34 +224,6 @@ cdef extern from "include/qpol/mls_query.h":
pass
ctypedef struct qpol_semantic_level_t:
pass
# level
int qpol_policy_get_level_by_name(const qpol_policy_t * policy, const char *name, const qpol_level_t ** datum)
int qpol_policy_get_level_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter)
int qpol_level_get_isalias(const qpol_policy_t * policy, const qpol_level_t * datum, unsigned char *isalias)
int qpol_level_get_value(const qpol_policy_t * policy, const qpol_level_t * datum, uint32_t * value)
int qpol_level_get_cat_iter(const qpol_policy_t * policy, const qpol_level_t * datum, qpol_iterator_t ** cats)
int qpol_level_get_name(const qpol_policy_t * policy, const qpol_level_t * datum, const char **name)
int qpol_level_get_alias_iter(const qpol_policy_t * policy, const qpol_level_t * datum, qpol_iterator_t ** aliases)
# category
int qpol_policy_get_cat_by_name(const qpol_policy_t * policy, const char *name, const qpol_cat_t ** datum)
int qpol_policy_get_cat_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter)
int qpol_cat_get_value(const qpol_policy_t * policy, const qpol_cat_t * datum, uint32_t * value)
int qpol_cat_get_isalias(const qpol_policy_t * policy, const qpol_cat_t * datum, unsigned char *isalias)
int qpol_cat_get_name(const qpol_policy_t * policy, const qpol_cat_t * datum, const char **name)
int qpol_cat_get_alias_iter(const qpol_policy_t * policy, const qpol_cat_t * datum, qpol_iterator_t ** aliases)
# MLS range
int qpol_mls_range_get_low_level(const qpol_policy_t * policy, const qpol_mls_range_t * range, const qpol_mls_level_t ** level)
int qpol_mls_range_get_high_level(const qpol_policy_t * policy, const qpol_mls_range_t * range, const qpol_mls_level_t ** level)
# MLS level
int qpol_mls_level_get_sens_name(const qpol_policy_t * policy, const qpol_mls_level_t * level, const char **name)
int qpol_mls_level_get_cat_iter(const qpol_policy_t * policy, const qpol_mls_level_t * level, qpol_iterator_t ** cats)
# Semantic levels
int qpol_policy_get_semantic_level_by_name(const qpol_policy_t * policy, const char *name, qpol_semantic_level_t ** datum)
int qpol_semantic_level_add_cats_by_name(const qpol_policy_t * policy, const qpol_semantic_level_t * level, const char *low, const char *high)
int qpol_mls_level_from_semantic_level(const qpol_policy_t * policy, qpol_semantic_level_t * src, qpol_mls_level_t **dest)
void qpol_semantic_level_destroy(qpol_semantic_level_t * level)
# Semantic ranges
int qpol_policy_get_mls_range_from_mls_levels(const qpol_policy_t * policy, const qpol_mls_level_t * low, const qpol_mls_level_t *high, qpol_mls_range_t **dest)
cdef extern from "include/qpol/mlsrule_query.h":
ctypedef struct qpol_range_trans_t:

View File

@ -1,5 +1,5 @@
# Copyright 2014-2016, Tresys Technology, LLC
# Copyright 2017, Chris PeBenito <pebenito@ieee.org>
# Copyright 2017-2018, Chris PeBenito <pebenito@ieee.org>
#
# This file is part of SETools.
#
@ -20,281 +20,52 @@
# pylint: disable=protected-access
import itertools
# qpol does not expose an equivalent of a sensitivity declaration.
# qpol_level_t is equivalent to the level declaration:
# level s0:c0.c1023;
# qpol_mls_level_t represents a level as used in contexts,
# such as range_transitions or labeling statements such as
# portcon and nodecon.
# Here qpol_level_t is also used for MLSSensitivity
# since it has the sensitivity name, dominance, and there
# is a 1:1 correspondence between the sensitivity declarations
# and level declarations.
# Hashing has to be handled below because the qpol references,
# normally used for a hash key, are not the same for multiple
# instances of the same object (except for level decl).
#
# Category factory functions
#
cdef inline Category category_factory_lookup(SELinuxPolicy policy, str name):
"""Factory function variant for constructing Category objects by name."""
if not policy.mls:
raise MLSDisabled
cdef const qpol_cat_t *symbol
if qpol_policy_get_cat_by_name(policy.handle, name, &symbol):
raise InvalidCategory("{0} is not a valid category".format(name))
return category_factory(policy, symbol)
cdef inline Category category_factory_iter(SELinuxPolicy policy, QpolIteratorItem symbol):
"""Factory function variant for iterating over Category objects."""
return category_factory(policy, <const qpol_cat_t *> symbol.obj)
cdef inline Category category_factory(SELinuxPolicy policy, const qpol_cat_t *symbol):
"""Factory function for creating Category objects."""
cdef unsigned char isalias
cdef const char *name
if not policy.mls:
raise MLSDisabled
if qpol_cat_get_isalias(policy.handle, symbol, &isalias):
ex = LowLevelPolicyError("Error determining category alias status: {}".format(
strerror(errno)))
ex.errno = errno
raise ex
if isalias:
if qpol_cat_get_name(policy.handle, symbol, &name):
raise ValueError("The category is an alias")
raise ValueError("{0} is an alias".format(name))
r = Category()
r.policy = policy
r.handle = symbol
return r
#
# Sensitivity factory functions
#
cdef inline Sensitivity sensitivity_factory_lookup(SELinuxPolicy policy, str name):
"""Factory function variant for constructing Sensitivity objects by name."""
cdef const qpol_level_t *symbol
if not policy.mls:
raise MLSDisabled
if qpol_policy_get_level_by_name(policy.handle, name, &symbol):
raise InvalidSensitivity("{0} is not a valid sensitivity".format(name))
return sensitivity_factory(policy, symbol)
cdef inline Sensitivity sensitivity_factory_iter(SELinuxPolicy policy, QpolIteratorItem symbol):
"""Factory function variant for iterating over Sensitivity objects."""
return sensitivity_factory(policy, <const qpol_level_t *> symbol.obj)
cdef inline Sensitivity sensitivity_factory(SELinuxPolicy policy, const qpol_level_t *symbol):
"""Factory function for creating Sensitivity objects."""
cdef unsigned char isalias
cdef const char *name
if not policy.mls:
raise MLSDisabled
if qpol_level_get_isalias(policy.handle, symbol, &isalias):
ex = LowLevelPolicyError("Error determining sensitivity alias status: {}".format(
strerror(errno)))
ex.errno = errno
raise ex
if isalias:
if qpol_level_get_name(policy.handle, symbol, &name):
raise ValueError("The sensitivity is an alias")
raise ValueError("{0} is an alias".format(name))
r = Sensitivity()
r.policy = policy
r.handle = symbol
return r
#
# Level declaration factory functions
#
cdef inline LevelDecl level_decl_factory_iter(SELinuxPolicy policy, QpolIteratorItem symbol):
"""Factory function variant for iterating over LevelDecl objects."""
return level_decl_factory(policy, <const qpol_level_t *> symbol.obj)
cdef inline LevelDecl level_decl_factory(SELinuxPolicy policy, const qpol_level_t *symbol):
"""Factory function for creating LevelDecl objects."""
cdef unsigned char isalias
cdef const char *name
if not policy.mls:
raise MLSDisabled
if qpol_level_get_isalias(policy.handle, symbol, &isalias):
ex = LowLevelPolicyError("Error determining level alias status: {}".format(
strerror(errno)))
ex.errno = errno
raise ex
if isalias:
if qpol_level_get_name(policy.handle, symbol, &name):
raise ValueError("The level decl is an alias")
raise ValueError("{0} is an alias".format(name))
r = LevelDecl()
r.policy = policy
r.handle = symbol
return r
#
# Level factory functions
#
cdef inline Level level_factory_lookup(SELinuxPolicy policy, str name):
"""Factory function variant for constructing Level objects by name."""
cdef qpol_semantic_level_t *l
cdef qpol_mls_level_t *level
if not policy.mls:
raise MLSDisabled
sens_split = name.split(":")
sens = sens_split[0]
if qpol_policy_get_semantic_level_by_name(policy.handle, sens, &l):
raise InvalidLevel("{0} is not a valid level ({1} is not a valid sensitivity)". \
format(name, sens))
try:
cats = sens_split[1]
except IndexError:
pass
else:
for group in cats.split(","):
catrange = group.split(".")
if len(catrange) == 2:
if qpol_semantic_level_add_cats_by_name(policy.handle, l, catrange[0], catrange[1]):
raise InvalidLevel(
"{0} is not a valid level ({1} is not a valid category range)".
format(name, group))
elif len(catrange) == 1:
if qpol_semantic_level_add_cats_by_name(policy.handle, l, catrange[0], catrange[0]):
raise InvalidLevel("{0} is not a valid level ({1} is not a valid category)".
format(name, group))
else:
raise InvalidLevel("{0} is not a valid level (level parsing error)".format(name))
# convert to level symbol
if qpol_mls_level_from_semantic_level(policy.handle, l, &level):
raise InvalidLevel(
"{0} is not a valid level (one or more categories are not associated with the "
"sensitivity)".format(name))
qpol_semantic_level_destroy(l)
# TODO: since this is user-generated, the level will need a destructor
return level_factory(policy, level)
cdef inline Level level_factory(SELinuxPolicy policy, const qpol_mls_level_t *symbol):
"""Factory function for creating Level objects."""
if not policy.mls:
raise MLSDisabled
r = Level()
r.policy = policy
r.handle = symbol
return r
#
# Range factory functions
#
cdef inline Range range_factory_lookup(SELinuxPolicy policy, str name):
"""Factory function variant for constructing Range objects by name."""
cdef qpol_mls_range_t *range
if not policy.mls:
raise MLSDisabled
# build range:
levels = name.split("-")
# strip() levels to handle ranges with spaces in them,
# e.g. s0:c1 - s0:c0.c255
try:
low = level_factory_lookup(policy, levels[0].strip())
except InvalidLevel as ex:
raise InvalidRange("{0} is not a valid range ({1}).".format(name, ex)) from ex
try:
high = level_factory_lookup(policy, levels[1].strip())
except InvalidLevel as ex:
raise InvalidRange("{0} is not a valid range ({1}).".format(name, ex)) from ex
except IndexError:
high = low
# convert to range object
if qpol_policy_get_mls_range_from_mls_levels(policy.handle, low.handle, high.handle, &range):
raise InvalidRange("{0} is not a valid range ({1} is not dominated by {2})".
format(name, low, high))
# TODO: since this is user-generated, the range will need a destructor
return range_factory(policy, range)
cdef inline Range range_factory(SELinuxPolicy policy, const qpol_mls_range_t *symbol):
"""Factory function for creating Range objects."""
if not policy.mls:
raise MLSDisabled
r = Range()
r.policy = policy
r.handle = symbol
return r
cdef dict _cat_cache = {}
cdef dict _sens_cache = {}
cdef dict _leveldecl_cache = {}
#
# Classes
#
cdef list expand_cat_range(SELinuxPolicy policy, Category low, Category high):
"""
Helper function to expand a category range, e.g. c0.c1023
into the full set of categories by using the low and high
categories of the set.
"""
cdef list expanded
expanded = [low, high]
for value in range(low._value, high._value):
expanded.append(Category.factory(policy, policy.cat_val_to_struct[value]))
return expanded
cdef class Category(PolicySymbol):
"""An MLS category."""
cdef const qpol_cat_t *handle
cdef sepol.cat_datum_t *handle
@staticmethod
cdef factory(SELinuxPolicy policy, sepol.cat_datum_t *symbol):
"""Factory function for creating Category objects."""
if not policy.mls:
raise MLSDisabled
try:
return _cat_cache[<uintptr_t>symbol]
except KeyError:
c = Category()
c.policy = policy
c.handle = symbol
_cat_cache[<uintptr_t>symbol] = c
return c
def __str__(self):
cdef const char *name
if qpol_cat_get_name(self.policy.handle, self.handle, &name):
ex = LowLevelPolicyError("Error reading category name: {}".format(strerror(errno)))
ex.errno = errno
raise ex
return intern(name)
return intern(self.policy.handle.p.p.sym_val_to_name[sepol.SYM_CATS][self.handle.s.value - 1])
def __hash__(self):
return hash(str(self))
@ -310,25 +81,15 @@ cdef class Category(PolicySymbol):
@property
def _value(self):
"""
The value of the component.
The value of the category.
This is a low-level policy detail exposed for internal use only.
"""
cdef uint32_t v
if qpol_cat_get_value(self.policy.handle, self.handle, &v):
ex = LowLevelPolicyError("Error reading category value: {}".format(strerror(errno)))
ex.errno = errno
raise ex
return v
return self.handle.s.value
def aliases(self):
"""Generator that yields all aliases for this category."""
cdef qpol_iterator_t *iter
if qpol_cat_get_alias_iter(self.policy.handle, self.handle, &iter):
raise MemoryError
return qpol_iterator_factory(self.policy, iter, string_factory_iter)
return CategoryAliasHashtabIterator.factory(self.policy, &self.policy.handle.p.p.symtab[sepol.SYM_CATS].table, self)
def statement(self):
aliases = list(self.aliases())
@ -346,17 +107,25 @@ cdef class Sensitivity(PolicySymbol):
"""An MLS sensitivity"""
cdef const qpol_level_t *handle
cdef sepol.level_datum_t *handle
@staticmethod
cdef factory(SELinuxPolicy policy, sepol.level_datum_t *symbol):
"""Factory function for creating Sensitivity objects."""
if not policy.mls:
raise MLSDisabled
try:
return _sens_cache[<uintptr_t>symbol]
except KeyError:
s = Sensitivity()
s.policy = policy
s.handle = symbol
_sens_cache[<uintptr_t>symbol] = s
return s
def __str__(self):
cdef const char *name
if qpol_level_get_name(self.policy.handle, self.handle, &name):
ex = LowLevelPolicyError("Error reading sensitivity name: {}".format(strerror(errno)))
ex.errno = errno
raise ex
return intern(name)
return intern(self.policy.handle.p.p.sym_val_to_name[sepol.SYM_LEVELS][self.handle.level.sens - 1])
def __hash__(self):
return hash(str(self))
@ -384,21 +153,15 @@ cdef class Sensitivity(PolicySymbol):
This is a low-level policy detail exposed for internal use only.
"""
cdef uint32_t v
if qpol_level_get_value(self.policy.handle, self.handle, &v):
ex = LowLevelPolicyError("Error reading sensitivity value: {}".format(strerror(errno)))
ex.errno = errno
raise ex
return v
return self.handle.level.sens
def aliases(self):
"""Generator that yields all aliases for this sensitivity."""
cdef qpol_iterator_t *iter
if qpol_level_get_alias_iter(self.policy.handle, self.handle, &iter):
raise MemoryError
return SensitivityAliasHashtabIterator.factory(self.policy, &self.policy.handle.p.p.symtab[sepol.SYM_LEVELS].table, self)
return qpol_iterator_factory(self.policy, iter, string_factory_iter)
def level_decl(self):
"""Get the level declaration corresponding to this sensitivity."""
return LevelDecl.factory(self.policy, self.handle)
def statement(self):
aliases = list(self.aliases())
@ -458,7 +221,22 @@ cdef class LevelDecl(BaseMLSLevel):
level s7:c0.c1023;
"""
cdef const qpol_level_t *handle
cdef sepol.level_datum_t *handle
@staticmethod
cdef factory(SELinuxPolicy policy, sepol.level_datum_t *symbol):
"""Factory function for creating LevelDecl objects."""
if not policy.mls:
raise MLSDisabled
try:
return _leveldecl_cache[<uintptr_t>symbol]
except KeyError:
l = LevelDecl()
l.policy = policy
l.handle = symbol
_leveldecl_cache[<uintptr_t>symbol] = l
return l
def __hash__(self):
return hash(self.sensitivity)
@ -503,18 +281,14 @@ cdef class LevelDecl(BaseMLSLevel):
All categories are yielded, not a compact notation such as
c0.c255
"""
cdef qpol_iterator_t *iter
if qpol_level_get_cat_iter(self.policy.handle, self.handle, &iter):
raise MemoryError
return qpol_iterator_factory(self.policy, iter, category_factory_iter)
return CategoryEbitmapIterator.factory(self.policy, &self.handle.level.cat)
@property
def sensitivity(self):
"""The sensitivity of the level."""
# since the qpol symbol for levels is also used for
# MLSSensitivity objects, use self's qpol symbol
return sensitivity_factory(self.policy, self.handle)
# since the datum for levels is also used for
# Sensitivity objects, use self's datum
return Sensitivity.factory(self.policy, self.handle)
def statement(self):
return "level {0};".format(self)
@ -522,9 +296,88 @@ cdef class LevelDecl(BaseMLSLevel):
cdef class Level(BaseMLSLevel):
"""An MLS level used in contexts."""
"""
An MLS level used in contexts.
cdef const qpol_mls_level_t *handle
The _sensitivity and _categories attributes are only populated
if the level is user-generated.
"""
cdef:
sepol.mls_level_t *handle
list _categories
Sensitivity _sensitivity
@staticmethod
cdef factory(SELinuxPolicy policy, sepol.mls_level_t *symbol):
"""Factory function for creating Level objects."""
if not policy.mls:
raise MLSDisabled
l = Level()
l.policy = policy
l.handle = symbol
return l
@staticmethod
cdef factory_from_string(SELinuxPolicy policy, str name):
"""Factory function variant for constructing Level objects by a string."""
if not policy.mls:
raise MLSDisabled
sens_split = name.split(":")
sens = sens_split[0]
try:
s = policy.lookup_sensitivity(sens)
except InvalidSensitivity as ex:
raise InvalidLevel("{0} is not a valid level ({1} is not a valid sensitivity)". \
format(name, sens)) from ex
c = []
try:
cats = sens_split[1]
except IndexError:
pass
else:
for group in cats.split(","):
catrange = group.split(".")
if len(catrange) == 2:
try:
c.extend(expand_cat_range(policy,
policy.lookup_category(catrange[0]),
policy.lookup_category(catrange[1])))
except InvalidCategory as ex:
raise InvalidLevel(
"{0} is not a valid level ({1} is not a valid category range)".
format(name, group)) from ex
elif len(catrange) == 1:
try:
c.append(policy.lookup_category(catrange[0]))
except InvalidCategory as ex:
raise InvalidLevel("{0} is not a valid level ({1} is not a valid category)".
format(name, group)) from ex
else:
raise InvalidLevel("{0} is not a valid level (level parsing error)".format(name))
# build object
l = Level()
l.policy = policy
l.handle = NULL
l._sensitivity = s
l._categories = c
# verify level is valid
if not l <= s.level_decl():
raise InvalidLevel(
"{0} is not a valid level (one or more categories are not associated with the "
"sensitivity)".format(name))
return l
def __hash__(self):
return hash(str(self))
@ -576,23 +429,18 @@ cdef class Level(BaseMLSLevel):
All categories are yielded, not a compact notation such as
c0.c255
"""
cdef qpol_iterator_t *iter
if qpol_mls_level_get_cat_iter(self.policy.handle, self.handle, &iter):
raise MemoryError
return qpol_iterator_factory(self.policy, iter, category_factory_iter)
if self.handle == NULL:
return iter(self._categories)
else:
return CategoryEbitmapIterator.factory(self.policy, &self.handle.cat)
@property
def sensitivity(self):
"""The sensitivity of the level."""
cdef const char *name
if qpol_mls_level_get_sens_name(self.policy.handle, self.handle, &name):
ex = LowLevelPolicyError("Error reading level sensitivity name: {}".format(
strerror(errno)))
ex.errno = errno
raise ex
return sensitivity_factory_lookup(self.policy, name)
if self.handle == NULL:
return self._sensitivity
else:
return Sensitivity.factory(self.policy, self.policy.level_val_to_struct[self.handle.sens - 1])
def statement(self):
raise NoStatement
@ -602,7 +450,56 @@ cdef class Range(PolicySymbol):
"""An MLS range"""
cdef const qpol_mls_range_t *handle
cdef:
sepol.mls_range_t *handle
Level _low
Level _high
@staticmethod
cdef factory(SELinuxPolicy policy, sepol.mls_range_t *symbol):
"""Factory function for creating Range objects."""
if not policy.mls:
raise MLSDisabled
r = Range()
r.policy = policy
r.handle = symbol
return r
@staticmethod
cdef factory_from_string(SELinuxPolicy policy, str name):
"""Factory function variant for constructing Range objects by name."""
if not policy.mls:
raise MLSDisabled
# build range:
levels = name.split("-")
# strip() levels to handle ranges with spaces in them,
# e.g. s0:c1 - s0:c0.c255
try:
low = Level.factory_from_string(policy, levels[0].strip())
except InvalidLevel as ex:
raise InvalidRange("{0} is not a valid range ({1}).".format(name, ex)) from ex
try:
high = Level.factory_from_string(policy, levels[1].strip())
except InvalidLevel as ex:
raise InvalidRange("{0} is not a valid range ({1}).".format(name, ex)) from ex
except IndexError:
high = low
# verify high level dominates low range
if not high >= low:
raise InvalidRange("{0} is not a valid range ({1} is not dominated by {2})".
format(name, low, high))
r = Range()
r.policy = policy
r.handle = NULL
r._low = low
r._high = high
return r
def __str__(self):
high = self.high
@ -636,24 +533,333 @@ cdef class Range(PolicySymbol):
@property
def high(self):
"""The high end/clearance level of this range."""
cdef const qpol_mls_level_t *l
if qpol_mls_range_get_high_level(self.policy.handle, self.handle, &l):
ex = LowLevelPolicyError("Error reading range high level: {}".format(strerror(errno)))
ex.errno = errno
raise ex
return level_factory(self.policy, l)
if self.handle == NULL:
return self._high
else:
return Level.factory(self.policy, &self.handle.level[1])
@property
def low(self):
"""The low end/current level of this range."""
cdef const qpol_mls_level_t *l
if qpol_mls_range_get_low_level(self.policy.handle, self.handle, &l):
ex = LowLevelPolicyError("Error reading range low level: {}".format(strerror(errno)))
ex.errno = errno
raise ex
return level_factory(self.policy, l)
if self.handle == NULL:
return self._low
else:
return Level.factory(self.policy, &self.handle.level[0])
def statement(self):
raise NoStatement
#
# Hash Table Iterators
#
cdef class CategoryHashtabIterator(HashtabIterator):
"""Iterate over categories in the policy."""
@staticmethod
cdef factory(SELinuxPolicy policy, sepol.hashtab_t *table):
"""Factory function for creating category iterators."""
i = CategoryHashtabIterator()
i.policy = policy
i.table = table
i.reset()
return i
def __next__(self):
super().__next__()
datum = <sepol.cat_datum_t *> self.curr.datum if self.curr else NULL
while datum != NULL and datum.isalias:
super().__next__()
datum = <sepol.cat_datum_t *> self.curr.datum if self.curr else NULL
return Category.factory(self.policy, datum)
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 = <sepol.cat_datum_t *>node.datum if node else NULL
if datum != NULL and not datum.isalias:
count += 1
node = node.next
bucket += 1
return count
def reset(self):
super().reset()
cdef sepol.cat_datum_t *datum = <sepol.cat_datum_t *> self.node.datum if self.node else NULL
# advance over any attributes or aliases
while datum != NULL and datum.isalias:
self._next_node()
if self.node == NULL or self.bucket >= self.table[0].size:
break
datum = <sepol.cat_datum_t *> 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 = <sepol.cat_datum_t *> self.curr.datum if self.curr else NULL
while datum != NULL and (not datum.isalias or datum.s.value != self.primary):
super().__next__()
datum = <sepol.cat_datum_t *> 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 = <sepol.cat_datum_t *>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 = <sepol.cat_datum_t *> 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 = <sepol.cat_datum_t *> self.node.datum if self.node else NULL
cdef class SensitivityHashtabIterator(HashtabIterator):
"""Iterate over sensitivity in the policy."""
@staticmethod
cdef factory(SELinuxPolicy policy, sepol.hashtab_t *table):
"""Factory function for creating category iterators."""
i = SensitivityHashtabIterator()
i.policy = policy
i.table = table
i.reset()
return i
def __next__(self):
super().__next__()
datum = <sepol.level_datum_t *> self.curr.datum if self.curr else NULL
while datum != NULL and datum.isalias:
super().__next__()
datum = <sepol.level_datum_t *> self.curr.datum if self.curr else NULL
return Sensitivity.factory(self.policy, datum)
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 = <sepol.level_datum_t *>node.datum if node else NULL
if datum != NULL and not datum.isalias:
count += 1
node = node.next
bucket += 1
return count
def reset(self):
super().reset()
cdef sepol.level_datum_t *datum = <sepol.level_datum_t *> self.node.datum if self.node else NULL
# advance over any attributes or aliases
while datum != NULL and datum.isalias:
self._next_node()
if self.node == NULL or self.bucket >= self.table[0].size:
break
datum = <sepol.level_datum_t *> 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 = <sepol.level_datum_t *> self.curr.datum if self.curr else NULL
while datum != NULL and (not datum.isalias or datum.level.sens != self.primary):
super().__next__()
datum = <sepol.level_datum_t *> 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 = <sepol.level_datum_t *>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 = <sepol.level_datum_t *> 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 = <sepol.level_datum_t *> self.node.datum if self.node else NULL
cdef class LevelDeclHashtabIterator(HashtabIterator):
"""Iterate over level declarations in the policy."""
@staticmethod
cdef factory(SELinuxPolicy policy, sepol.hashtab_t *table):
"""Factory function for creating level declarations iterators."""
i = LevelDeclHashtabIterator()
i.policy = policy
i.table = table
i.reset()
return i
def __next__(self):
super().__next__()
datum = <sepol.level_datum_t *> self.curr.datum if self.curr else NULL
while datum != NULL and datum.isalias:
super().__next__()
datum = <sepol.level_datum_t *> self.curr.datum if self.curr else NULL
return LevelDecl.factory(self.policy, datum)
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 = <sepol.level_datum_t *>node.datum if node else NULL
if datum != NULL and not datum.isalias:
count += 1
node = node.next
bucket += 1
return count
def reset(self):
super().reset()
cdef sepol.level_datum_t *datum = <sepol.level_datum_t *> self.node.datum if self.node else NULL
# advance over any attributes or aliases
while datum != NULL and datum.isalias:
self._next_node()
if self.node == NULL or self.bucket >= self.table[0].size:
break
datum = <sepol.level_datum_t *> self.node.datum if self.node else NULL
#
# Ebitmap Iterators
#
cdef class CategoryEbitmapIterator(EbitmapIterator):
"""Iterate over a category ebitmap."""
@staticmethod
cdef factory(SELinuxPolicy policy, sepol.ebitmap_t *symbol):
"""Factory function for creating CategoryEbitmapIterator."""
i = CategoryEbitmapIterator()
i.policy = policy
i.bmap = symbol
i.reset()
return i
def __next__(self):
super().__next__()
return Category.factory(self.policy, self.policy.cat_val_to_struct[self.bit])

View File

@ -67,7 +67,7 @@ cdef class MLSRule(PolicyRule):
"""An MLS rule."""
cdef:
const qpol_range_trans_t *handle
sepol.range_trans_t *handle
readonly object ruletype
def __init__(self):
@ -119,14 +119,10 @@ cdef class MLSRule(PolicyRule):
@property
def default(self):
"""The rule's default range."""
cdef const qpol_mls_range_t *r
if qpol_range_trans_get_range(self.policy.handle, self.handle, &r):
ex = LowLevelPolicyError("Error reading range for range_transition rule: {}".format(
strerror(errno)))
ex.errno = errno
raise ex
return range_factory(self.policy, r)
cdef sepol.mls_range_t *default_range
default_range = <sepol.mls_range_t *> hashtab_search(self.policy.handle.p.p.range_tr,
<sepol.hashtab_key_t> self.handle)
return Range.factory(self.policy, default_range)
def expand(self):
"""Expand the rule into an equivalent set of rules without attributes."""

View File

@ -53,6 +53,8 @@ cdef void qpol_log_callback(void *varg, const qpol_policy_t *p, int level, const
cdef class SELinuxPolicy:
cdef:
qpol_policy_t *handle
sepol.cat_datum_t **cat_val_to_struct
sepol.level_datum_t **level_val_to_struct
readonly str path
object log
@ -72,7 +74,17 @@ cdef class SELinuxPolicy:
except NameError:
raise RuntimeError("Loading the running policy requires libselinux Python bindings")
self._policy_extend()
def __cinit__(self):
self.handle = NULL
self.cat_val_to_struct = NULL
self.level_val_to_struct = NULL
def __dealloc__(self):
PyMem_Free(self.cat_val_to_struct)
PyMem_Free(self.level_val_to_struct)
if self.handle:
qpol_policy_destroy(&self.handle)
@ -435,6 +447,14 @@ cdef class SELinuxPolicy:
raise InvalidBoolean("{0} is not a valid Boolean".format(name))
def lookup_category(self, name):
"""Look up a category."""
for c in self.categories():
if c == name:
return c
raise InvalidCategory("{0} is not a valid category".format(name))
def lookup_class(self, name):
"""Look up an object class."""
return class_factory_lookup(self, name)
@ -453,15 +473,19 @@ cdef class SELinuxPolicy:
def lookup_level(self, level):
"""Look up a MLS level."""
return level_factory_lookup(self, level)
return Level.factory_from_string(self, level)
def lookup_sensitivity(self, name):
"""Look up a MLS sensitivity by name."""
return sensitivity_factory_lookup(self, name)
for s in self.sensitivities():
if s == name:
return s
raise InvalidSensitivity("{0} is not a valid sensitivity".format(name))
def lookup_range(self, range_):
"""Look up a MLS range."""
return range_factory_lookup(self, range_)
return Range.factory_from_string(self, range_)
def lookup_role(self, name):
"""Look up a role by name."""
@ -500,11 +524,7 @@ cdef class SELinuxPolicy:
def categories(self):
"""Iterator which yields all MLS categories."""
cdef qpol_iterator_t *iter
if qpol_policy_get_cat_iter(self.handle, &iter):
raise MemoryError
return qpol_iterator_factory(self, iter, category_factory_iter, ValueError)
return CategoryHashtabIterator.factory(self, &self.handle.p.p.symtab[sepol.SYM_CATS].table)
def classes(self):
"""Iterator which yields all object classes."""
@ -532,11 +552,7 @@ cdef class SELinuxPolicy:
def levels(self):
"""Iterator which yields all level declarations."""
cdef qpol_iterator_t *iter
if qpol_policy_get_level_iter(self.handle, &iter):
raise MemoryError
return qpol_iterator_factory(self, iter, level_decl_factory_iter, ValueError)
return LevelDeclHashtabIterator.factory(self, &self.handle.p.p.symtab[sepol.SYM_LEVELS].table)
def polcaps(self):
"""Iterator which yields all policy capabilities."""
@ -552,12 +568,7 @@ cdef class SELinuxPolicy:
def sensitivities(self):
"""Iterator over all sensitivities."""
# see mls.pxi for more info on why level_iter is used here.
cdef qpol_iterator_t *iter
if qpol_policy_get_level_iter(self.handle, &iter):
raise MemoryError
return qpol_iterator_factory(self, iter, sensitivity_factory_iter, ValueError)
return SensitivityHashtabIterator.factory(self, &self.handle.p.p.symtab[sepol.SYM_LEVELS].table)
def types(self):
"""Iterator over all types."""
@ -712,3 +723,63 @@ cdef class SELinuxPolicy:
def pirqcons(self):
"""Iterator over all pirqcon statements."""
return PirqconIterator.factory(self, self.handle.p.p.ocontexts[sepol.OCON_XEN_PIRQ])
#
# Internal methods
#
cdef _policy_extend(self):
"""Create supplementary data structures (linkages) from the policydb."""
cdef sepol.cat_datum_t *cat_datum
cdef sepol.hashtab_node_t *node
cdef uint32_t bucket = 0
cdef size_t bucket_len
cdef size_t map_len
if self.mls:
#
# Create cat_val_to_struct (indexed by value -1)
#
map_len = self.handle.p.p.symtab[sepol.SYM_CATS].table.nel
bucket_len = self.handle.p.p.symtab[sepol.SYM_CATS].table[0].size
self.cat_val_to_struct = <sepol.cat_datum_t**>PyMem_Malloc(
map_len * sizeof(sepol.cat_datum_t*))
if self.cat_val_to_struct == NULL:
raise MemoryError
while bucket < bucket_len:
node = self.handle.p.p.symtab[sepol.SYM_CATS].table[0].htable[bucket]
while node != NULL:
cat_datum = <sepol.cat_datum_t *>node.datum
if cat_datum != NULL:
self.cat_val_to_struct[cat_datum.s.value - 1] = cat_datum
node = node.next
bucket += 1
#
# Create level_val_to_struct (indexed by value -1)
#
map_len = self.handle.p.p.symtab[sepol.SYM_LEVELS].table.nel
bucket_len = self.handle.p.p.symtab[sepol.SYM_LEVELS].table[0].size
bucket = 0
self.level_val_to_struct = <sepol.level_datum_t**>PyMem_Malloc(
map_len * sizeof(sepol.level_datum_t*))
if self.level_val_to_struct == NULL:
raise MemoryError
while bucket < bucket_len:
node = self.handle.p.p.symtab[sepol.SYM_LEVELS].table[0].htable[bucket]
while node != NULL:
level_datum = <sepol.level_datum_t *>node.datum
if level_datum != NULL:
self.level_val_to_struct[level_datum.level.sens - 1] = level_datum
node = node.next
bucket += 1

View File

@ -77,24 +77,18 @@ cdef class User(PolicySymbol):
@property
def mls_level(self):
"""The user's default MLS level."""
cdef const qpol_mls_level_t *l
if qpol_user_get_dfltlevel(self.policy.handle, self.handle, &l):
ex = LowLevelPolicyError("Error reading user default level: {}".format(strerror(errno)))
ex.errno = errno
raise ex
if not self.policy.mls:
raise MLSDisabled
return level_factory(self.policy, l)
return Level.factory(self.policy, &self.handle.exp_dfltlevel)
@property
def mls_range(self):
"""The user's MLS range."""
cdef const qpol_mls_range_t *r
if qpol_user_get_range(self.policy.handle, self.handle, &r):
ex = LowLevelPolicyError("Error reading user range: {}".format(strerror(errno)))
ex.errno = errno
raise ex
if not self.policy.mls:
raise MLSDisabled
return range_factory(self.policy, r)
return Range.factory(self.policy, &self.handle.exp_range)
def statement(self):
roles = list(str(r) for r in self.roles)

View File

@ -75,7 +75,6 @@ ext_py_mods = [Extension('setools.policyrep.libpolicyrep',
'libqpol/default_object_query.c',
'libqpol/ftrule_query.c',
'libqpol/iterator.c',
'libqpol/mls_query.c',
'libqpol/mlsrule_query.c',
'libqpol/permissive_query.c',
'libqpol/policy.c',