/* Authors: Karl MacMillan <kmacmillan@tresys.com>
|
* Frank Mayer <mayerf@tresys.com>
|
* David Caplan <dac@tresys.com>
|
*
|
* Copyright (C) 2003 - 2005 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 <stdlib.h>
|
|
#include <sepol/policydb/flask_types.h>
|
#include <sepol/policydb/conditional.h>
|
|
#include "private.h"
|
|
/* move all type rules to top of t/f lists to help kernel on evaluation */
|
static void cond_optimize(cond_av_list_t ** l)
|
{
|
cond_av_list_t *top, *p, *cur;
|
|
top = p = cur = *l;
|
|
while (cur) {
|
if ((cur->node->key.specified & AVTAB_TYPE) && (top != cur)) {
|
p->next = cur->next;
|
cur->next = top;
|
top = cur;
|
cur = p->next;
|
} else {
|
p = cur;
|
cur = cur->next;
|
}
|
}
|
*l = top;
|
}
|
|
/* reorder t/f lists for kernel */
|
void cond_optimize_lists(cond_list_t * cl)
|
{
|
cond_list_t *n;
|
|
for (n = cl; n != NULL; n = n->next) {
|
cond_optimize(&n->true_list);
|
cond_optimize(&n->false_list);
|
}
|
}
|
|
static int bool_present(unsigned int target, unsigned int bools[],
|
unsigned int num_bools)
|
{
|
unsigned int i = 0;
|
int ret = 1;
|
|
if (num_bools > COND_MAX_BOOLS) {
|
return 0;
|
}
|
while (i < num_bools && target != bools[i])
|
i++;
|
if (i == num_bools)
|
ret = 0; /* got to end w/o match */
|
return ret;
|
}
|
|
static int same_bools(cond_node_t * a, cond_node_t * b)
|
{
|
unsigned int i, x;
|
|
x = a->nbools;
|
|
/* same number of bools? */
|
if (x != b->nbools)
|
return 0;
|
|
/* make sure all the bools in a are also in b */
|
for (i = 0; i < x; i++)
|
if (!bool_present(a->bool_ids[i], b->bool_ids, x))
|
return 0;
|
return 1;
|
}
|
|
/*
|
* Determine if two conditional expressions are equal.
|
*/
|
int cond_expr_equal(cond_node_t * a, cond_node_t * b)
|
{
|
cond_expr_t *cur_a, *cur_b;
|
|
if (a == NULL || b == NULL)
|
return 0;
|
|
if (a->nbools != b->nbools)
|
return 0;
|
|
/* if exprs have <= COND_MAX_BOOLS we can check the precompute values
|
* for the expressions.
|
*/
|
if (a->nbools <= COND_MAX_BOOLS && b->nbools <= COND_MAX_BOOLS) {
|
if (!same_bools(a, b))
|
return 0;
|
return (a->expr_pre_comp == b->expr_pre_comp);
|
}
|
|
/* for long expressions we check for exactly the same expression */
|
cur_a = a->expr;
|
cur_b = b->expr;
|
while (1) {
|
if (cur_a == NULL && cur_b == NULL)
|
return 1;
|
else if (cur_a == NULL || cur_b == NULL)
|
return 0;
|
if (cur_a->expr_type != cur_b->expr_type)
|
return 0;
|
if (cur_a->expr_type == COND_BOOL) {
|
if (cur_a->bool != cur_b->bool)
|
return 0;
|
}
|
cur_a = cur_a->next;
|
cur_b = cur_b->next;
|
}
|
return 1;
|
}
|
|
/* Create a new conditional node, optionally copying
|
* the conditional expression from an existing node.
|
* If node is NULL then a new node will be created
|
* with no conditional expression.
|
*/
|
cond_node_t *cond_node_create(policydb_t * p, cond_node_t * node)
|
{
|
cond_node_t *new_node;
|
unsigned int i;
|
|
new_node = (cond_node_t *)malloc(sizeof(cond_node_t));
|
if (!new_node) {
|
return NULL;
|
}
|
memset(new_node, 0, sizeof(cond_node_t));
|
|
if (node) {
|
new_node->expr = cond_copy_expr(node->expr);
|
if (!new_node->expr) {
|
free(new_node);
|
return NULL;
|
}
|
new_node->cur_state = cond_evaluate_expr(p, new_node->expr);
|
new_node->nbools = node->nbools;
|
for (i = 0; i < min(node->nbools, COND_MAX_BOOLS); i++)
|
new_node->bool_ids[i] = node->bool_ids[i];
|
new_node->expr_pre_comp = node->expr_pre_comp;
|
new_node->flags = node->flags;
|
}
|
|
return new_node;
|
}
|
|
/* Find a conditional (the needle) within a list of existing ones (the
|
* haystack) that has a matching expression. If found, return a
|
* pointer to the existing node, setting 'was_created' to 0.
|
* Otherwise create a new one and return it, setting 'was_created' to
|
* 1. */
|
cond_node_t *cond_node_find(policydb_t * p,
|
cond_node_t * needle, cond_node_t * haystack,
|
int *was_created)
|
{
|
while (haystack) {
|
if (cond_expr_equal(needle, haystack)) {
|
*was_created = 0;
|
return haystack;
|
}
|
haystack = haystack->next;
|
}
|
*was_created = 1;
|
|
return cond_node_create(p, needle);
|
}
|
|
/* return either a pre-existing matching node or create a new node */
|
cond_node_t *cond_node_search(policydb_t * p, cond_node_t * list,
|
cond_node_t * cn)
|
{
|
int was_created;
|
cond_node_t *result = cond_node_find(p, cn, list, &was_created);
|
if (result != NULL && was_created) {
|
/* add conditional node to policy list */
|
result->next = p->cond_list;
|
p->cond_list = result;
|
}
|
return result;
|
}
|
|
/*
|
* cond_evaluate_expr evaluates a conditional expr
|
* in reverse polish notation. It returns true (1), false (0),
|
* or undefined (-1). Undefined occurs when the expression
|
* exceeds the stack depth of COND_EXPR_MAXDEPTH.
|
*/
|
int cond_evaluate_expr(policydb_t * p, cond_expr_t * expr)
|
{
|
|
cond_expr_t *cur;
|
int s[COND_EXPR_MAXDEPTH];
|
int sp = -1;
|
|
s[0] = -1;
|
|
for (cur = expr; cur != NULL; cur = cur->next) {
|
switch (cur->expr_type) {
|
case COND_BOOL:
|
if (sp == (COND_EXPR_MAXDEPTH - 1))
|
return -1;
|
sp++;
|
s[sp] = p->bool_val_to_struct[cur->bool - 1]->state;
|
break;
|
case COND_NOT:
|
if (sp < 0)
|
return -1;
|
s[sp] = !s[sp];
|
break;
|
case COND_OR:
|
if (sp < 1)
|
return -1;
|
sp--;
|
s[sp] |= s[sp + 1];
|
break;
|
case COND_AND:
|
if (sp < 1)
|
return -1;
|
sp--;
|
s[sp] &= s[sp + 1];
|
break;
|
case COND_XOR:
|
if (sp < 1)
|
return -1;
|
sp--;
|
s[sp] ^= s[sp + 1];
|
break;
|
case COND_EQ:
|
if (sp < 1)
|
return -1;
|
sp--;
|
s[sp] = (s[sp] == s[sp + 1]);
|
break;
|
case COND_NEQ:
|
if (sp < 1)
|
return -1;
|
sp--;
|
s[sp] = (s[sp] != s[sp + 1]);
|
break;
|
default:
|
return -1;
|
}
|
}
|
return s[0];
|
}
|
|
cond_expr_t *cond_copy_expr(cond_expr_t * expr)
|
{
|
cond_expr_t *cur, *head, *tail, *new_expr;
|
tail = head = NULL;
|
cur = expr;
|
while (cur) {
|
new_expr = (cond_expr_t *) malloc(sizeof(cond_expr_t));
|
if (!new_expr)
|
goto free_head;
|
memset(new_expr, 0, sizeof(cond_expr_t));
|
|
new_expr->expr_type = cur->expr_type;
|
new_expr->bool = cur->bool;
|
|
if (!head)
|
head = new_expr;
|
if (tail)
|
tail->next = new_expr;
|
tail = new_expr;
|
cur = cur->next;
|
}
|
return head;
|
|
free_head:
|
while (head) {
|
tail = head->next;
|
free(head);
|
head = tail;
|
}
|
return NULL;
|
}
|
|
/*
|
* evaluate_cond_node evaluates the conditional stored in
|
* a cond_node_t and if the result is different than the
|
* current state of the node it sets the rules in the true/false
|
* list appropriately. If the result of the expression is undefined
|
* all of the rules are disabled for safety.
|
*/
|
static int evaluate_cond_node(policydb_t * p, cond_node_t * node)
|
{
|
int new_state;
|
cond_av_list_t *cur;
|
|
new_state = cond_evaluate_expr(p, node->expr);
|
if (new_state != node->cur_state) {
|
node->cur_state = new_state;
|
if (new_state == -1)
|
printf
|
("expression result was undefined - disabling all rules.\n");
|
/* turn the rules on or off */
|
for (cur = node->true_list; cur != NULL; cur = cur->next) {
|
if (new_state <= 0) {
|
cur->node->key.specified &= ~AVTAB_ENABLED;
|
} else {
|
cur->node->key.specified |= AVTAB_ENABLED;
|
}
|
}
|
|
for (cur = node->false_list; cur != NULL; cur = cur->next) {
|
/* -1 or 1 */
|
if (new_state) {
|
cur->node->key.specified &= ~AVTAB_ENABLED;
|
} else {
|
cur->node->key.specified |= AVTAB_ENABLED;
|
}
|
}
|
}
|
return 0;
|
}
|
|
/* precompute and simplify an expression if possible. If left with !expression, change
|
* to expression and switch t and f. precompute expression for expressions with limited
|
* number of bools.
|
*/
|
int cond_normalize_expr(policydb_t * p, cond_node_t * cn)
|
{
|
cond_expr_t *ne, *e;
|
cond_av_list_t *tmp;
|
unsigned int i, j, orig_value[COND_MAX_BOOLS];
|
int k;
|
uint32_t test = 0x0;
|
avrule_t *tmp2;
|
|
cn->nbools = 0;
|
|
memset(cn->bool_ids, 0, sizeof(cn->bool_ids));
|
cn->expr_pre_comp = 0x0;
|
|
/* take care of !expr case */
|
ne = NULL;
|
e = cn->expr;
|
|
/* becuase it's RPN look at last element */
|
while (e->next != NULL) {
|
ne = e;
|
e = e->next;
|
}
|
if (e->expr_type == COND_NOT) {
|
if (ne) {
|
ne->next = NULL;
|
} else { /* ne should never be NULL */
|
printf
|
("Found expr with no bools and only a ! - this should never happen.\n");
|
return -1;
|
}
|
/* swap the true and false lists */
|
tmp = cn->true_list;
|
cn->true_list = cn->false_list;
|
cn->false_list = tmp;
|
tmp2 = cn->avtrue_list;
|
cn->avtrue_list = cn->avfalse_list;
|
cn->avfalse_list = tmp2;
|
|
/* free the "not" node in the list */
|
free(e);
|
}
|
|
/* find all the bools in the expression */
|
for (e = cn->expr; e != NULL; e = e->next) {
|
switch (e->expr_type) {
|
case COND_BOOL:
|
i = 0;
|
/* see if we've already seen this bool */
|
if (!bool_present(e->bool, cn->bool_ids, cn->nbools)) {
|
/* count em all but only record up to COND_MAX_BOOLS */
|
if (cn->nbools < COND_MAX_BOOLS)
|
cn->bool_ids[cn->nbools++] = e->bool;
|
else
|
cn->nbools++;
|
}
|
break;
|
default:
|
break;
|
}
|
}
|
|
/* only precompute for exprs with <= COND_AX_BOOLS */
|
if (cn->nbools <= COND_MAX_BOOLS) {
|
/* save the default values for the bools so we can play with them */
|
for (i = 0; i < cn->nbools; i++) {
|
orig_value[i] =
|
p->bool_val_to_struct[cn->bool_ids[i] - 1]->state;
|
}
|
|
/* loop through all possible combinations of values for bools in expression */
|
for (test = 0x0; test < (0x1U << cn->nbools); test++) {
|
/* temporarily set the value for all the bools in the
|
* expression using the corr. bit in test */
|
for (j = 0; j < cn->nbools; j++) {
|
p->bool_val_to_struct[cn->bool_ids[j] -
|
1]->state =
|
(test & (0x1 << j)) ? 1 : 0;
|
}
|
k = cond_evaluate_expr(p, cn->expr);
|
if (k == -1) {
|
printf
|
("While testing expression, expression result "
|
"was undefined - this should never happen.\n");
|
return -1;
|
}
|
/* set the bit if expression evaluates true */
|
if (k)
|
cn->expr_pre_comp |= 0x1 << test;
|
}
|
|
/* restore bool default values */
|
for (i = 0; i < cn->nbools; i++)
|
p->bool_val_to_struct[cn->bool_ids[i] - 1]->state =
|
orig_value[i];
|
}
|
return 0;
|
}
|
|
int evaluate_conds(policydb_t * p)
|
{
|
int ret;
|
cond_node_t *cur;
|
|
for (cur = p->cond_list; cur != NULL; cur = cur->next) {
|
ret = evaluate_cond_node(p, cur);
|
if (ret)
|
return ret;
|
}
|
return 0;
|
}
|
|
int cond_policydb_init(policydb_t * p)
|
{
|
p->bool_val_to_struct = NULL;
|
p->cond_list = NULL;
|
if (avtab_init(&p->te_cond_avtab))
|
return -1;
|
|
return 0;
|
}
|
|
void cond_av_list_destroy(cond_av_list_t * list)
|
{
|
cond_av_list_t *cur, *next;
|
for (cur = list; cur != NULL; cur = next) {
|
next = cur->next;
|
/* the avtab_ptr_t node is destroy by the avtab */
|
free(cur);
|
}
|
}
|
|
void cond_expr_destroy(cond_expr_t * expr)
|
{
|
cond_expr_t *cur_expr, *next_expr;
|
|
if (!expr)
|
return;
|
|
for (cur_expr = expr; cur_expr != NULL; cur_expr = next_expr) {
|
next_expr = cur_expr->next;
|
free(cur_expr);
|
}
|
}
|
|
void cond_node_destroy(cond_node_t * node)
|
{
|
if (!node)
|
return;
|
|
cond_expr_destroy(node->expr);
|
avrule_list_destroy(node->avtrue_list);
|
avrule_list_destroy(node->avfalse_list);
|
cond_av_list_destroy(node->true_list);
|
cond_av_list_destroy(node->false_list);
|
}
|
|
void cond_list_destroy(cond_list_t * list)
|
{
|
cond_node_t *next, *cur;
|
|
if (list == NULL)
|
return;
|
|
for (cur = list; cur != NULL; cur = next) {
|
next = cur->next;
|
cond_node_destroy(cur);
|
free(cur);
|
}
|
}
|
|
void cond_policydb_destroy(policydb_t * p)
|
{
|
if (p->bool_val_to_struct != NULL)
|
free(p->bool_val_to_struct);
|
avtab_destroy(&p->te_cond_avtab);
|
cond_list_destroy(p->cond_list);
|
}
|
|
int cond_init_bool_indexes(policydb_t * p)
|
{
|
if (p->bool_val_to_struct)
|
free(p->bool_val_to_struct);
|
p->bool_val_to_struct = (cond_bool_datum_t **)
|
malloc(p->p_bools.nprim * sizeof(cond_bool_datum_t *));
|
if (!p->bool_val_to_struct)
|
return -1;
|
return 0;
|
}
|
|
int cond_destroy_bool(hashtab_key_t key, hashtab_datum_t datum, void *p
|
__attribute__ ((unused)))
|
{
|
if (key)
|
free(key);
|
free(datum);
|
return 0;
|
}
|
|
int cond_index_bool(hashtab_key_t key, hashtab_datum_t datum, void *datap)
|
{
|
policydb_t *p;
|
cond_bool_datum_t *booldatum;
|
|
booldatum = datum;
|
p = datap;
|
|
if (!booldatum->s.value || booldatum->s.value > p->p_bools.nprim)
|
return -EINVAL;
|
|
if (p->p_bool_val_to_name[booldatum->s.value - 1] != NULL)
|
return -EINVAL;
|
|
p->p_bool_val_to_name[booldatum->s.value - 1] = key;
|
p->bool_val_to_struct[booldatum->s.value - 1] = booldatum;
|
|
return 0;
|
}
|
|
static int bool_isvalid(cond_bool_datum_t * b)
|
{
|
if (!(b->state == 0 || b->state == 1))
|
return 0;
|
return 1;
|
}
|
|
int cond_read_bool(policydb_t * p,
|
hashtab_t h,
|
struct policy_file *fp)
|
{
|
char *key = 0;
|
cond_bool_datum_t *booldatum;
|
uint32_t buf[3], len;
|
int rc;
|
|
booldatum = malloc(sizeof(cond_bool_datum_t));
|
if (!booldatum)
|
return -1;
|
memset(booldatum, 0, sizeof(cond_bool_datum_t));
|
|
rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
|
if (rc < 0)
|
goto err;
|
|
booldatum->s.value = le32_to_cpu(buf[0]);
|
booldatum->state = le32_to_cpu(buf[1]);
|
|
if (!bool_isvalid(booldatum))
|
goto err;
|
|
len = le32_to_cpu(buf[2]);
|
if (str_read(&key, fp, len))
|
goto err;
|
|
if (p->policy_type != POLICY_KERN &&
|
p->policyvers >= MOD_POLICYDB_VERSION_TUNABLE_SEP) {
|
rc = next_entry(buf, fp, sizeof(uint32_t));
|
if (rc < 0)
|
goto err;
|
booldatum->flags = le32_to_cpu(buf[0]);
|
}
|
|
if (hashtab_insert(h, key, booldatum))
|
goto err;
|
|
return 0;
|
err:
|
cond_destroy_bool(key, booldatum, 0);
|
return -1;
|
}
|
|
struct cond_insertf_data {
|
struct policydb *p;
|
cond_av_list_t *other;
|
cond_av_list_t *head;
|
cond_av_list_t *tail;
|
};
|
|
static int cond_insertf(avtab_t * a
|
__attribute__ ((unused)), avtab_key_t * k,
|
avtab_datum_t * d, void *ptr)
|
{
|
struct cond_insertf_data *data = ptr;
|
struct policydb *p = data->p;
|
cond_av_list_t *other = data->other, *list, *cur;
|
avtab_ptr_t node_ptr;
|
uint8_t found;
|
|
/*
|
* For type rules we have to make certain there aren't any
|
* conflicting rules by searching the te_avtab and the
|
* cond_te_avtab.
|
*/
|
if (k->specified & AVTAB_TYPE) {
|
if (avtab_search(&p->te_avtab, k)) {
|
printf
|
("security: type rule already exists outside of a conditional.");
|
goto err;
|
}
|
/*
|
* If we are reading the false list other will be a pointer to
|
* the true list. We can have duplicate entries if there is only
|
* 1 other entry and it is in our true list.
|
*
|
* If we are reading the true list (other == NULL) there shouldn't
|
* be any other entries.
|
*/
|
if (other) {
|
node_ptr = avtab_search_node(&p->te_cond_avtab, k);
|
if (node_ptr) {
|
if (avtab_search_node_next
|
(node_ptr, k->specified)) {
|
printf
|
("security: too many conflicting type rules.");
|
goto err;
|
}
|
found = 0;
|
for (cur = other; cur != NULL; cur = cur->next) {
|
if (cur->node == node_ptr) {
|
found = 1;
|
break;
|
}
|
}
|
if (!found) {
|
printf
|
("security: conflicting type rules.\n");
|
goto err;
|
}
|
}
|
} else {
|
if (avtab_search(&p->te_cond_avtab, k)) {
|
printf
|
("security: conflicting type rules when adding type rule for true.\n");
|
goto err;
|
}
|
}
|
}
|
|
node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
|
if (!node_ptr) {
|
printf("security: could not insert rule.");
|
goto err;
|
}
|
node_ptr->parse_context = (void *)1;
|
|
list = malloc(sizeof(cond_av_list_t));
|
if (!list)
|
goto err;
|
memset(list, 0, sizeof(cond_av_list_t));
|
|
list->node = node_ptr;
|
if (!data->head)
|
data->head = list;
|
else
|
data->tail->next = list;
|
data->tail = list;
|
return 0;
|
|
err:
|
cond_av_list_destroy(data->head);
|
data->head = NULL;
|
return -1;
|
}
|
|
static int cond_read_av_list(policydb_t * p, void *fp,
|
cond_av_list_t ** ret_list, cond_av_list_t * other)
|
{
|
unsigned int i;
|
int rc;
|
uint32_t buf[1], len;
|
struct cond_insertf_data data;
|
|
*ret_list = NULL;
|
|
len = 0;
|
rc = next_entry(buf, fp, sizeof(uint32_t));
|
if (rc < 0)
|
return -1;
|
|
len = le32_to_cpu(buf[0]);
|
if (len == 0) {
|
return 0;
|
}
|
|
data.p = p;
|
data.other = other;
|
data.head = NULL;
|
data.tail = NULL;
|
for (i = 0; i < len; i++) {
|
rc = avtab_read_item(fp, p->policyvers, &p->te_cond_avtab,
|
cond_insertf, &data);
|
if (rc)
|
return rc;
|
|
}
|
|
*ret_list = data.head;
|
return 0;
|
}
|
|
static int expr_isvalid(policydb_t * p, cond_expr_t * expr)
|
{
|
if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) {
|
printf
|
("security: conditional expressions uses unknown operator.\n");
|
return 0;
|
}
|
|
if (expr->bool > p->p_bools.nprim) {
|
printf
|
("security: conditional expressions uses unknown bool.\n");
|
return 0;
|
}
|
return 1;
|
}
|
|
static int cond_read_node(policydb_t * p, cond_node_t * node, void *fp)
|
{
|
uint32_t buf[2];
|
int len, i, rc;
|
cond_expr_t *expr = NULL, *last = NULL;
|
|
rc = next_entry(buf, fp, sizeof(uint32_t));
|
if (rc < 0)
|
goto err;
|
|
node->cur_state = le32_to_cpu(buf[0]);
|
|
len = 0;
|
rc = next_entry(buf, fp, sizeof(uint32_t));
|
if (rc < 0)
|
goto err;
|
|
/* expr */
|
len = le32_to_cpu(buf[0]);
|
|
for (i = 0; i < len; i++) {
|
rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
|
if (rc < 0)
|
goto err;
|
|
expr = malloc(sizeof(cond_expr_t));
|
if (!expr) {
|
goto err;
|
}
|
memset(expr, 0, sizeof(cond_expr_t));
|
|
expr->expr_type = le32_to_cpu(buf[0]);
|
expr->bool = le32_to_cpu(buf[1]);
|
|
if (!expr_isvalid(p, expr)) {
|
free(expr);
|
goto err;
|
}
|
|
if (i == 0) {
|
node->expr = expr;
|
} else {
|
last->next = expr;
|
}
|
last = expr;
|
}
|
|
if (p->policy_type == POLICY_KERN) {
|
if (cond_read_av_list(p, fp, &node->true_list, NULL) != 0)
|
goto err;
|
if (cond_read_av_list(p, fp, &node->false_list, node->true_list)
|
!= 0)
|
goto err;
|
} else {
|
if (avrule_read_list(p, &node->avtrue_list, fp))
|
goto err;
|
if (avrule_read_list(p, &node->avfalse_list, fp))
|
goto err;
|
}
|
|
if (p->policy_type != POLICY_KERN &&
|
p->policyvers >= MOD_POLICYDB_VERSION_TUNABLE_SEP) {
|
rc = next_entry(buf, fp, sizeof(uint32_t));
|
if (rc < 0)
|
goto err;
|
node->flags = le32_to_cpu(buf[0]);
|
}
|
|
return 0;
|
err:
|
cond_node_destroy(node);
|
free(node);
|
return -1;
|
}
|
|
int cond_read_list(policydb_t * p, cond_list_t ** list, void *fp)
|
{
|
cond_node_t *node, *last = NULL;
|
uint32_t buf[1];
|
int i, len, rc;
|
|
rc = next_entry(buf, fp, sizeof(uint32_t));
|
if (rc < 0)
|
return -1;
|
|
len = le32_to_cpu(buf[0]);
|
|
rc = avtab_alloc(&p->te_cond_avtab, p->te_avtab.nel);
|
if (rc)
|
goto err;
|
|
for (i = 0; i < len; i++) {
|
node = malloc(sizeof(cond_node_t));
|
if (!node)
|
goto err;
|
memset(node, 0, sizeof(cond_node_t));
|
|
if (cond_read_node(p, node, fp) != 0)
|
goto err;
|
|
if (i == 0) {
|
*list = node;
|
} else {
|
last->next = node;
|
}
|
last = node;
|
}
|
return 0;
|
err:
|
return -1;
|
}
|
|
/* Determine whether additional permissions are granted by the conditional
|
* av table, and if so, add them to the result
|
*/
|
void cond_compute_av(avtab_t * ctab, avtab_key_t * key,
|
struct sepol_av_decision *avd)
|
{
|
avtab_ptr_t node;
|
|
if (!ctab || !key || !avd)
|
return;
|
|
for (node = avtab_search_node(ctab, key); node != NULL;
|
node = avtab_search_node_next(node, key->specified)) {
|
if ((uint16_t) (AVTAB_ALLOWED | AVTAB_ENABLED) ==
|
(node->key.specified & (AVTAB_ALLOWED | AVTAB_ENABLED)))
|
avd->allowed |= node->datum.data;
|
if ((uint16_t) (AVTAB_AUDITDENY | AVTAB_ENABLED) ==
|
(node->key.specified & (AVTAB_AUDITDENY | AVTAB_ENABLED)))
|
/* Since a '0' in an auditdeny mask represents a
|
* permission we do NOT want to audit (dontaudit), we use
|
* the '&' operand to ensure that all '0's in the mask
|
* are retained (much unlike the allow and auditallow cases).
|
*/
|
avd->auditdeny &= node->datum.data;
|
if ((uint16_t) (AVTAB_AUDITALLOW | AVTAB_ENABLED) ==
|
(node->key.specified & (AVTAB_AUDITALLOW | AVTAB_ENABLED)))
|
avd->auditallow |= node->datum.data;
|
}
|
return;
|
}
|
|
avtab_datum_t *cond_av_list_search(avtab_key_t * key,
|
cond_av_list_t * cond_list)
|
{
|
|
cond_av_list_t *cur_av;
|
|
for (cur_av = cond_list; cur_av != NULL; cur_av = cur_av->next) {
|
|
if (cur_av->node->key.source_type == key->source_type &&
|
cur_av->node->key.target_type == key->target_type &&
|
cur_av->node->key.target_class == key->target_class)
|
|
return &cur_av->node->datum;
|
|
}
|
return NULL;
|
|
}
|