699 lines
17 KiB
C
699 lines
17 KiB
C
/* Authors: Joshua Brindle <jbrindle@tresys.com>
|
|
* Jason Tang <jtang@tresys.com>
|
|
*
|
|
* Updates: KaiGai Kohei <kaigai@ak.jp.nec.com>
|
|
* adds checks based on newer boundary facility.
|
|
*
|
|
* A set of utility functions that aid policy decision when dealing
|
|
* with hierarchal namespaces.
|
|
*
|
|
* Copyright (C) 2005 Tresys Technology, LLC
|
|
*
|
|
* Copyright (c) 2008 NEC Corporation
|
|
*
|
|
* 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 <string.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <sepol/policydb/policydb.h>
|
|
#include <sepol/policydb/conditional.h>
|
|
#include <sepol/policydb/hierarchy.h>
|
|
#include <sepol/policydb/expand.h>
|
|
#include <sepol/policydb/util.h>
|
|
|
|
#include "debug.h"
|
|
|
|
#define BOUNDS_AVTAB_SIZE 1024
|
|
|
|
static int bounds_insert_helper(sepol_handle_t *handle, avtab_t *avtab,
|
|
avtab_key_t *avtab_key, avtab_datum_t *datum)
|
|
{
|
|
int rc = avtab_insert(avtab, avtab_key, datum);
|
|
if (rc) {
|
|
if (rc == SEPOL_ENOMEM)
|
|
ERR(handle, "Insufficient memory");
|
|
else
|
|
ERR(handle, "Unexpected error (%d)", rc);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
|
|
static int bounds_insert_rule(sepol_handle_t *handle, avtab_t *avtab,
|
|
avtab_t *global, avtab_t *other,
|
|
avtab_key_t *avtab_key, avtab_datum_t *datum)
|
|
{
|
|
int rc = 0;
|
|
avtab_datum_t *dup = avtab_search(avtab, avtab_key);
|
|
|
|
if (!dup) {
|
|
rc = bounds_insert_helper(handle, avtab, avtab_key, datum);
|
|
if (rc) goto exit;
|
|
} else {
|
|
dup->data |= datum->data;
|
|
}
|
|
|
|
if (other) {
|
|
/* Search the other conditional avtab for the key and
|
|
* add any common permissions to the global avtab
|
|
*/
|
|
uint32_t data = 0;
|
|
dup = avtab_search(other, avtab_key);
|
|
if (dup) {
|
|
data = dup->data & datum->data;
|
|
if (data) {
|
|
dup = avtab_search(global, avtab_key);
|
|
if (!dup) {
|
|
avtab_datum_t d;
|
|
d.data = data;
|
|
rc = bounds_insert_helper(handle, global,
|
|
avtab_key, &d);
|
|
if (rc) goto exit;
|
|
} else {
|
|
dup->data |= data;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
exit:
|
|
return rc;
|
|
}
|
|
|
|
static int bounds_expand_rule(sepol_handle_t *handle, policydb_t *p,
|
|
avtab_t *avtab, avtab_t *global, avtab_t *other,
|
|
uint32_t parent, uint32_t src, uint32_t tgt,
|
|
uint32_t class, uint32_t data)
|
|
{
|
|
int rc = 0;
|
|
avtab_key_t avtab_key;
|
|
avtab_datum_t datum;
|
|
ebitmap_node_t *tnode;
|
|
unsigned int i;
|
|
|
|
avtab_key.specified = AVTAB_ALLOWED;
|
|
avtab_key.target_class = class;
|
|
datum.data = data;
|
|
|
|
if (ebitmap_get_bit(&p->attr_type_map[src - 1], parent - 1)) {
|
|
avtab_key.source_type = parent;
|
|
ebitmap_for_each_positive_bit(&p->attr_type_map[tgt - 1], tnode, i) {
|
|
avtab_key.target_type = i + 1;
|
|
rc = bounds_insert_rule(handle, avtab, global, other,
|
|
&avtab_key, &datum);
|
|
if (rc) goto exit;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
return rc;
|
|
}
|
|
|
|
static int bounds_expand_cond_rules(sepol_handle_t *handle, policydb_t *p,
|
|
cond_av_list_t *cur, avtab_t *avtab,
|
|
avtab_t *global, avtab_t *other,
|
|
uint32_t parent)
|
|
{
|
|
int rc = 0;
|
|
|
|
for (; cur; cur = cur->next) {
|
|
avtab_ptr_t n = cur->node;
|
|
rc = bounds_expand_rule(handle, p, avtab, global, other, parent,
|
|
n->key.source_type, n->key.target_type,
|
|
n->key.target_class, n->datum.data);
|
|
if (rc) goto exit;
|
|
}
|
|
|
|
exit:
|
|
return rc;
|
|
}
|
|
|
|
struct bounds_expand_args {
|
|
sepol_handle_t *handle;
|
|
policydb_t *p;
|
|
avtab_t *avtab;
|
|
uint32_t parent;
|
|
};
|
|
|
|
static int bounds_expand_rule_callback(avtab_key_t *k, avtab_datum_t *d,
|
|
void *args)
|
|
{
|
|
struct bounds_expand_args *a = (struct bounds_expand_args *)args;
|
|
|
|
if (!(k->specified & AVTAB_ALLOWED))
|
|
return 0;
|
|
|
|
return bounds_expand_rule(a->handle, a->p, a->avtab, NULL, NULL,
|
|
a->parent, k->source_type, k->target_type,
|
|
k->target_class, d->data);
|
|
}
|
|
|
|
struct bounds_cond_info {
|
|
avtab_t true_avtab;
|
|
avtab_t false_avtab;
|
|
cond_list_t *cond_list;
|
|
struct bounds_cond_info *next;
|
|
};
|
|
|
|
static void bounds_destroy_cond_info(struct bounds_cond_info *cur)
|
|
{
|
|
struct bounds_cond_info *next;
|
|
|
|
for (; cur; cur = next) {
|
|
next = cur->next;
|
|
avtab_destroy(&cur->true_avtab);
|
|
avtab_destroy(&cur->false_avtab);
|
|
cur->next = NULL;
|
|
free(cur);
|
|
}
|
|
}
|
|
|
|
static int bounds_expand_parent_rules(sepol_handle_t *handle, policydb_t *p,
|
|
avtab_t *global_avtab,
|
|
struct bounds_cond_info **cond_info,
|
|
uint32_t parent)
|
|
{
|
|
int rc = 0;
|
|
struct bounds_expand_args args;
|
|
cond_list_t *cur;
|
|
|
|
avtab_init(global_avtab);
|
|
rc = avtab_alloc(global_avtab, BOUNDS_AVTAB_SIZE);
|
|
if (rc) goto oom;
|
|
|
|
args.handle = handle;
|
|
args.p = p;
|
|
args.avtab = global_avtab;
|
|
args.parent = parent;
|
|
rc = avtab_map(&p->te_avtab, bounds_expand_rule_callback, &args);
|
|
if (rc) goto exit;
|
|
|
|
*cond_info = NULL;
|
|
for (cur = p->cond_list; cur; cur = cur->next) {
|
|
struct bounds_cond_info *ci;
|
|
ci = malloc(sizeof(struct bounds_cond_info));
|
|
if (!ci) goto oom;
|
|
avtab_init(&ci->true_avtab);
|
|
avtab_init(&ci->false_avtab);
|
|
ci->cond_list = cur;
|
|
ci->next = *cond_info;
|
|
*cond_info = ci;
|
|
if (cur->true_list) {
|
|
rc = avtab_alloc(&ci->true_avtab, BOUNDS_AVTAB_SIZE);
|
|
if (rc) goto oom;
|
|
rc = bounds_expand_cond_rules(handle, p, cur->true_list,
|
|
&ci->true_avtab, NULL,
|
|
NULL, parent);
|
|
if (rc) goto exit;
|
|
}
|
|
if (cur->false_list) {
|
|
rc = avtab_alloc(&ci->false_avtab, BOUNDS_AVTAB_SIZE);
|
|
if (rc) goto oom;
|
|
rc = bounds_expand_cond_rules(handle, p, cur->false_list,
|
|
&ci->false_avtab,
|
|
global_avtab,
|
|
&ci->true_avtab, parent);
|
|
if (rc) goto exit;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
oom:
|
|
ERR(handle, "Insufficient memory");
|
|
|
|
exit:
|
|
ERR(handle,"Failed to expand parent rules");
|
|
avtab_destroy(global_avtab);
|
|
bounds_destroy_cond_info(*cond_info);
|
|
*cond_info = NULL;
|
|
return rc;
|
|
}
|
|
|
|
static int bounds_not_covered(avtab_t *global_avtab, avtab_t *cur_avtab,
|
|
avtab_key_t *avtab_key, uint32_t data)
|
|
{
|
|
avtab_datum_t *datum = avtab_search(cur_avtab, avtab_key);
|
|
if (datum)
|
|
data &= ~datum->data;
|
|
if (global_avtab && data) {
|
|
datum = avtab_search(global_avtab, avtab_key);
|
|
if (datum)
|
|
data &= ~datum->data;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
static int bounds_add_bad(sepol_handle_t *handle, uint32_t src, uint32_t tgt,
|
|
uint32_t class, uint32_t data, avtab_ptr_t *bad)
|
|
{
|
|
struct avtab_node *new = malloc(sizeof(struct avtab_node));
|
|
if (new == NULL) {
|
|
ERR(handle, "Insufficient memory");
|
|
return SEPOL_ENOMEM;
|
|
}
|
|
memset(new, 0, sizeof(struct avtab_node));
|
|
new->key.source_type = src;
|
|
new->key.target_type = tgt;
|
|
new->key.target_class = class;
|
|
new->datum.data = data;
|
|
new->next = *bad;
|
|
*bad = new;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int bounds_check_rule(sepol_handle_t *handle, policydb_t *p,
|
|
avtab_t *global_avtab, avtab_t *cur_avtab,
|
|
uint32_t child, uint32_t parent, uint32_t src,
|
|
uint32_t tgt, uint32_t class, uint32_t data,
|
|
avtab_ptr_t *bad, int *numbad)
|
|
{
|
|
int rc = 0;
|
|
avtab_key_t avtab_key;
|
|
type_datum_t *td;
|
|
ebitmap_node_t *tnode;
|
|
unsigned int i;
|
|
uint32_t d;
|
|
|
|
avtab_key.specified = AVTAB_ALLOWED;
|
|
avtab_key.target_class = class;
|
|
|
|
if (ebitmap_get_bit(&p->attr_type_map[src - 1], child - 1)) {
|
|
avtab_key.source_type = parent;
|
|
ebitmap_for_each_positive_bit(&p->attr_type_map[tgt - 1], tnode, i) {
|
|
td = p->type_val_to_struct[i];
|
|
if (td && td->bounds) {
|
|
avtab_key.target_type = td->bounds;
|
|
d = bounds_not_covered(global_avtab, cur_avtab,
|
|
&avtab_key, data);
|
|
} else {
|
|
avtab_key.target_type = i + 1;
|
|
d = bounds_not_covered(global_avtab, cur_avtab,
|
|
&avtab_key, data);
|
|
}
|
|
if (d) {
|
|
(*numbad)++;
|
|
rc = bounds_add_bad(handle, child, i+1, class, d, bad);
|
|
if (rc) goto exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
exit:
|
|
return rc;
|
|
}
|
|
|
|
static int bounds_check_cond_rules(sepol_handle_t *handle, policydb_t *p,
|
|
avtab_t *global_avtab, avtab_t *cond_avtab,
|
|
cond_av_list_t *rules, uint32_t child,
|
|
uint32_t parent, avtab_ptr_t *bad,
|
|
int *numbad)
|
|
{
|
|
int rc = 0;
|
|
cond_av_list_t *cur;
|
|
|
|
for (cur = rules; cur; cur = cur->next) {
|
|
avtab_ptr_t ap = cur->node;
|
|
avtab_key_t *key = &ap->key;
|
|
avtab_datum_t *datum = &ap->datum;
|
|
if (!(key->specified & AVTAB_ALLOWED))
|
|
continue;
|
|
rc = bounds_check_rule(handle, p, global_avtab, cond_avtab,
|
|
child, parent, key->source_type,
|
|
key->target_type, key->target_class,
|
|
datum->data, bad, numbad);
|
|
if (rc) goto exit;
|
|
}
|
|
|
|
exit:
|
|
return rc;
|
|
}
|
|
|
|
struct bounds_check_args {
|
|
sepol_handle_t *handle;
|
|
policydb_t *p;
|
|
avtab_t *cur_avtab;
|
|
uint32_t child;
|
|
uint32_t parent;
|
|
avtab_ptr_t bad;
|
|
int numbad;
|
|
};
|
|
|
|
static int bounds_check_rule_callback(avtab_key_t *k, avtab_datum_t *d,
|
|
void *args)
|
|
{
|
|
struct bounds_check_args *a = (struct bounds_check_args *)args;
|
|
|
|
if (!(k->specified & AVTAB_ALLOWED))
|
|
return 0;
|
|
|
|
return bounds_check_rule(a->handle, a->p, NULL, a->cur_avtab, a->child,
|
|
a->parent, k->source_type, k->target_type,
|
|
k->target_class, d->data, &a->bad, &a->numbad);
|
|
}
|
|
|
|
static int bounds_check_child_rules(sepol_handle_t *handle, policydb_t *p,
|
|
avtab_t *global_avtab,
|
|
struct bounds_cond_info *cond_info,
|
|
uint32_t child, uint32_t parent,
|
|
avtab_ptr_t *bad, int *numbad)
|
|
{
|
|
int rc;
|
|
struct bounds_check_args args;
|
|
struct bounds_cond_info *cur;
|
|
|
|
args.handle = handle;
|
|
args.p = p;
|
|
args.cur_avtab = global_avtab;
|
|
args.child = child;
|
|
args.parent = parent;
|
|
args.bad = NULL;
|
|
args.numbad = 0;
|
|
rc = avtab_map(&p->te_avtab, bounds_check_rule_callback, &args);
|
|
if (rc) goto exit;
|
|
|
|
for (cur = cond_info; cur; cur = cur->next) {
|
|
cond_list_t *node = cur->cond_list;
|
|
rc = bounds_check_cond_rules(handle, p, global_avtab,
|
|
&cur->true_avtab,
|
|
node->true_list, child, parent,
|
|
&args.bad, &args.numbad);
|
|
if (rc) goto exit;
|
|
|
|
rc = bounds_check_cond_rules(handle, p, global_avtab,
|
|
&cur->false_avtab,
|
|
node->false_list, child, parent,
|
|
&args.bad, &args.numbad);
|
|
if (rc) goto exit;
|
|
}
|
|
|
|
*numbad += args.numbad;
|
|
*bad = args.bad;
|
|
|
|
exit:
|
|
return rc;
|
|
}
|
|
|
|
int bounds_check_type(sepol_handle_t *handle, policydb_t *p, uint32_t child,
|
|
uint32_t parent, avtab_ptr_t *bad, int *numbad)
|
|
{
|
|
int rc = 0;
|
|
avtab_t global_avtab;
|
|
struct bounds_cond_info *cond_info = NULL;
|
|
|
|
rc = bounds_expand_parent_rules(handle, p, &global_avtab, &cond_info, parent);
|
|
if (rc) goto exit;
|
|
|
|
rc = bounds_check_child_rules(handle, p, &global_avtab, cond_info,
|
|
child, parent, bad, numbad);
|
|
|
|
bounds_destroy_cond_info(cond_info);
|
|
avtab_destroy(&global_avtab);
|
|
|
|
exit:
|
|
return rc;
|
|
}
|
|
|
|
struct bounds_args {
|
|
sepol_handle_t *handle;
|
|
policydb_t *p;
|
|
int numbad;
|
|
};
|
|
|
|
static void bounds_report(sepol_handle_t *handle, policydb_t *p, uint32_t child,
|
|
uint32_t parent, avtab_ptr_t cur)
|
|
{
|
|
ERR(handle, "Child type %s exceeds bounds of parent %s in the following rules:",
|
|
p->p_type_val_to_name[child - 1],
|
|
p->p_type_val_to_name[parent - 1]);
|
|
for (; cur; cur = cur->next) {
|
|
ERR(handle, " %s %s : %s { %s }",
|
|
p->p_type_val_to_name[cur->key.source_type - 1],
|
|
p->p_type_val_to_name[cur->key.target_type - 1],
|
|
p->p_class_val_to_name[cur->key.target_class - 1],
|
|
sepol_av_to_string(p, cur->key.target_class,
|
|
cur->datum.data));
|
|
}
|
|
}
|
|
|
|
void bounds_destroy_bad(avtab_ptr_t cur)
|
|
{
|
|
avtab_ptr_t next;
|
|
|
|
for (; cur; cur = next) {
|
|
next = cur->next;
|
|
cur->next = NULL;
|
|
free(cur);
|
|
}
|
|
}
|
|
|
|
static int bounds_check_type_callback(hashtab_key_t k __attribute__ ((unused)),
|
|
hashtab_datum_t d, void *args)
|
|
{
|
|
int rc = 0;
|
|
struct bounds_args *a = (struct bounds_args *)args;
|
|
type_datum_t *t = (type_datum_t *)d;
|
|
avtab_ptr_t bad = NULL;
|
|
|
|
if (t->bounds) {
|
|
rc = bounds_check_type(a->handle, a->p, t->s.value, t->bounds,
|
|
&bad, &a->numbad);
|
|
if (bad) {
|
|
bounds_report(a->handle, a->p, t->s.value, t->bounds,
|
|
bad);
|
|
bounds_destroy_bad(bad);
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int bounds_check_types(sepol_handle_t *handle, policydb_t *p)
|
|
{
|
|
int rc;
|
|
struct bounds_args args;
|
|
|
|
args.handle = handle;
|
|
args.p = p;
|
|
args.numbad = 0;
|
|
|
|
rc = hashtab_map(p->p_types.table, bounds_check_type_callback, &args);
|
|
if (rc) goto exit;
|
|
|
|
if (args.numbad > 0) {
|
|
ERR(handle, "%d errors found during type bounds check",
|
|
args.numbad);
|
|
rc = SEPOL_ERR;
|
|
}
|
|
|
|
exit:
|
|
return rc;
|
|
}
|
|
|
|
/* The role bounds is defined as: a child role cannot have a type that
|
|
* its parent doesn't have.
|
|
*/
|
|
static int bounds_check_role_callback(hashtab_key_t k,
|
|
hashtab_datum_t d, void *args)
|
|
{
|
|
struct bounds_args *a = (struct bounds_args *)args;
|
|
role_datum_t *r = (role_datum_t *) d;
|
|
role_datum_t *rp = NULL;
|
|
|
|
if (!r->bounds)
|
|
return 0;
|
|
|
|
rp = a->p->role_val_to_struct[r->bounds - 1];
|
|
|
|
if (rp && !ebitmap_contains(&rp->types.types, &r->types.types)) {
|
|
ERR(a->handle, "Role bounds violation, %s exceeds %s",
|
|
(char *)k, a->p->p_role_val_to_name[rp->s.value - 1]);
|
|
a->numbad++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bounds_check_roles(sepol_handle_t *handle, policydb_t *p)
|
|
{
|
|
struct bounds_args args;
|
|
|
|
args.handle = handle;
|
|
args.p = p;
|
|
args.numbad = 0;
|
|
|
|
hashtab_map(p->p_roles.table, bounds_check_role_callback, &args);
|
|
|
|
if (args.numbad > 0) {
|
|
ERR(handle, "%d errors found during role bounds check",
|
|
args.numbad);
|
|
return SEPOL_ERR;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* The user bounds is defined as: a child user cannot have a role that
|
|
* its parent doesn't have.
|
|
*/
|
|
static int bounds_check_user_callback(hashtab_key_t k,
|
|
hashtab_datum_t d, void *args)
|
|
{
|
|
struct bounds_args *a = (struct bounds_args *)args;
|
|
user_datum_t *u = (user_datum_t *) d;
|
|
user_datum_t *up = NULL;
|
|
|
|
if (!u->bounds)
|
|
return 0;
|
|
|
|
up = a->p->user_val_to_struct[u->bounds - 1];
|
|
|
|
if (up && !ebitmap_contains(&up->roles.roles, &u->roles.roles)) {
|
|
ERR(a->handle, "User bounds violation, %s exceeds %s",
|
|
(char *) k, a->p->p_user_val_to_name[up->s.value - 1]);
|
|
a->numbad++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bounds_check_users(sepol_handle_t *handle, policydb_t *p)
|
|
{
|
|
struct bounds_args args;
|
|
|
|
args.handle = handle;
|
|
args.p = p;
|
|
args.numbad = 0;
|
|
|
|
hashtab_map(p->p_users.table, bounds_check_user_callback, &args);
|
|
|
|
if (args.numbad > 0) {
|
|
ERR(handle, "%d errors found during user bounds check",
|
|
args.numbad);
|
|
return SEPOL_ERR;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define add_hierarchy_callback_template(prefix) \
|
|
int hierarchy_add_##prefix##_callback(hashtab_key_t k __attribute__ ((unused)), \
|
|
hashtab_datum_t d, void *args) \
|
|
{ \
|
|
struct bounds_args *a = (struct bounds_args *)args; \
|
|
sepol_handle_t *handle = a->handle; \
|
|
policydb_t *p = a->p; \
|
|
prefix##_datum_t *datum = (prefix##_datum_t *)d; \
|
|
prefix##_datum_t *parent; \
|
|
char *parent_name, *datum_name, *tmp; \
|
|
\
|
|
if (!datum->bounds) { \
|
|
datum_name = p->p_##prefix##_val_to_name[datum->s.value - 1]; \
|
|
\
|
|
tmp = strrchr(datum_name, '.'); \
|
|
/* no '.' means it has no parent */ \
|
|
if (!tmp) return 0; \
|
|
\
|
|
parent_name = strdup(datum_name); \
|
|
if (!parent_name) { \
|
|
ERR(handle, "Insufficient memory"); \
|
|
return SEPOL_ENOMEM; \
|
|
} \
|
|
parent_name[tmp - datum_name] = '\0'; \
|
|
\
|
|
parent = hashtab_search(p->p_##prefix##s.table, parent_name); \
|
|
if (!parent) { \
|
|
/* Orphan type/role/user */ \
|
|
ERR(handle, "%s doesn't exist, %s is an orphan",\
|
|
parent_name, \
|
|
p->p_##prefix##_val_to_name[datum->s.value - 1]); \
|
|
free(parent_name); \
|
|
a->numbad++; \
|
|
return 0; \
|
|
} \
|
|
datum->bounds = parent->s.value; \
|
|
free(parent_name); \
|
|
} \
|
|
\
|
|
return 0; \
|
|
} \
|
|
|
|
static add_hierarchy_callback_template(type)
|
|
static add_hierarchy_callback_template(role)
|
|
static add_hierarchy_callback_template(user)
|
|
|
|
int hierarchy_add_bounds(sepol_handle_t *handle, policydb_t *p)
|
|
{
|
|
int rc = 0;
|
|
struct bounds_args args;
|
|
|
|
args.handle = handle;
|
|
args.p = p;
|
|
args.numbad = 0;
|
|
|
|
rc = hashtab_map(p->p_users.table, hierarchy_add_user_callback, &args);
|
|
if (rc) goto exit;
|
|
|
|
rc = hashtab_map(p->p_roles.table, hierarchy_add_role_callback, &args);
|
|
if (rc) goto exit;
|
|
|
|
rc = hashtab_map(p->p_types.table, hierarchy_add_type_callback, &args);
|
|
if (rc) goto exit;
|
|
|
|
if (args.numbad > 0) {
|
|
ERR(handle, "%d errors found while adding hierarchies",
|
|
args.numbad);
|
|
rc = SEPOL_ERR;
|
|
}
|
|
|
|
exit:
|
|
return rc;
|
|
}
|
|
|
|
int hierarchy_check_constraints(sepol_handle_t * handle, policydb_t * p)
|
|
{
|
|
int rc = 0;
|
|
int violation = 0;
|
|
|
|
rc = hierarchy_add_bounds(handle, p);
|
|
if (rc) goto exit;
|
|
|
|
rc = bounds_check_users(handle, p);
|
|
if (rc)
|
|
violation = 1;
|
|
|
|
rc = bounds_check_roles(handle, p);
|
|
if (rc)
|
|
violation = 1;
|
|
|
|
rc = bounds_check_types(handle, p);
|
|
if (rc) {
|
|
if (rc == SEPOL_ERR)
|
|
violation = 1;
|
|
else
|
|
goto exit;
|
|
}
|
|
|
|
if (violation)
|
|
rc = SEPOL_ERR;
|
|
|
|
exit:
|
|
return rc;
|
|
}
|