Home | History | Annotate | Download | only in src
      1 /* Authors: Joshua Brindle <jbrindle (at) tresys.com>
      2  * 	    Jason Tang <jtang (at) tresys.com>
      3  *
      4  * Updates: KaiGai Kohei <kaigai (at) ak.jp.nec.com>
      5  *          adds checks based on newer boundary facility.
      6  *
      7  * A set of utility functions that aid policy decision when dealing
      8  * with hierarchal namespaces.
      9  *
     10  * Copyright (C) 2005 Tresys Technology, LLC
     11  *
     12  * Copyright (c) 2008 NEC Corporation
     13  *
     14  *  This library is free software; you can redistribute it and/or
     15  *  modify it under the terms of the GNU Lesser General Public
     16  *  License as published by the Free Software Foundation; either
     17  *  version 2.1 of the License, or (at your option) any later version.
     18  *
     19  *  This library is distributed in the hope that it will be useful,
     20  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     21  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     22  *  Lesser General Public License for more details.
     23  *
     24  *  You should have received a copy of the GNU Lesser General Public
     25  *  License along with this library; if not, write to the Free Software
     26  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     27  */
     28 
     29 #include <string.h>
     30 #include <stdlib.h>
     31 #include <assert.h>
     32 #include <sepol/policydb/policydb.h>
     33 #include <sepol/policydb/conditional.h>
     34 #include <sepol/policydb/hierarchy.h>
     35 #include <sepol/policydb/expand.h>
     36 #include <sepol/policydb/util.h>
     37 
     38 #include "debug.h"
     39 
     40 #define BOUNDS_AVTAB_SIZE 1024
     41 
     42 static int bounds_insert_helper(sepol_handle_t *handle, avtab_t *avtab,
     43 				avtab_key_t *avtab_key, avtab_datum_t *datum)
     44 {
     45 	int rc = avtab_insert(avtab, avtab_key, datum);
     46 	if (rc) {
     47 		if (rc == SEPOL_ENOMEM)
     48 			ERR(handle, "Insufficient memory");
     49 		else
     50 			ERR(handle, "Unexpected error (%d)", rc);
     51 	}
     52 	return rc;
     53 }
     54 
     55 
     56 static int bounds_insert_rule(sepol_handle_t *handle, avtab_t *avtab,
     57 			      avtab_t *global, avtab_t *other,
     58 			      avtab_key_t *avtab_key, avtab_datum_t *datum)
     59 {
     60 	int rc = 0;
     61 	avtab_datum_t *dup = avtab_search(avtab, avtab_key);
     62 
     63 	if (!dup) {
     64 		rc = bounds_insert_helper(handle, avtab, avtab_key, datum);
     65 		if (rc) goto exit;
     66 	} else {
     67 		dup->data |= datum->data;
     68 	}
     69 
     70 	if (other) {
     71 		/* Search the other conditional avtab for the key and
     72 		 * add any common permissions to the global avtab
     73 		 */
     74 		uint32_t data = 0;
     75 		dup = avtab_search(other, avtab_key);
     76 		if (dup) {
     77 			data = dup->data & datum->data;
     78 			if (data) {
     79 				dup = avtab_search(global, avtab_key);
     80 				if (!dup) {
     81 					avtab_datum_t d;
     82 					d.data = data;
     83 					rc = bounds_insert_helper(handle, global,
     84 								  avtab_key, &d);
     85 					if (rc) goto exit;
     86 				} else {
     87 					dup->data |= data;
     88 				}
     89 			}
     90 		}
     91 	}
     92 
     93 exit:
     94 	return rc;
     95 }
     96 
     97 static int bounds_expand_rule(sepol_handle_t *handle, policydb_t *p,
     98 			      avtab_t *avtab, avtab_t *global, avtab_t *other,
     99 			      uint32_t parent, uint32_t src, uint32_t tgt,
    100 			      uint32_t class, uint32_t data)
    101 {
    102 	int rc = 0;
    103 	avtab_key_t avtab_key;
    104 	avtab_datum_t datum;
    105 	ebitmap_node_t *tnode;
    106 	unsigned int i;
    107 
    108 	avtab_key.specified = AVTAB_ALLOWED;
    109 	avtab_key.target_class = class;
    110 	datum.data = data;
    111 
    112 	if (ebitmap_get_bit(&p->attr_type_map[src - 1], parent - 1)) {
    113 		avtab_key.source_type = parent;
    114 		ebitmap_for_each_bit(&p->attr_type_map[tgt - 1], tnode, i) {
    115 			if (!ebitmap_node_get_bit(tnode, i))
    116 				continue;
    117 			avtab_key.target_type = i + 1;
    118 			rc = bounds_insert_rule(handle, avtab, global, other,
    119 						&avtab_key, &datum);
    120 			if (rc) goto exit;
    121 		}
    122 	}
    123 
    124 	if (ebitmap_get_bit(&p->attr_type_map[tgt - 1], parent - 1)) {
    125 		avtab_key.target_type = parent;
    126 		ebitmap_for_each_bit(&p->attr_type_map[src - 1], tnode, i) {
    127 			if (!ebitmap_node_get_bit(tnode, i))
    128 				continue;
    129 			avtab_key.source_type = i + 1;
    130 			rc = bounds_insert_rule(handle, avtab, global, other,
    131 						&avtab_key, &datum);
    132 			if (rc) goto exit;
    133 		}
    134 	}
    135 
    136 exit:
    137 	return rc;
    138 }
    139 
    140 static int bounds_expand_cond_rules(sepol_handle_t *handle, policydb_t *p,
    141 				    cond_av_list_t *cur, avtab_t *avtab,
    142 				    avtab_t *global, avtab_t *other,
    143 				    uint32_t parent)
    144 {
    145 	int rc = 0;
    146 
    147 	for (; cur; cur = cur->next) {
    148 		avtab_ptr_t n = cur->node;
    149 		rc = bounds_expand_rule(handle, p, avtab, global, other, parent,
    150 					n->key.source_type, n->key.target_type,
    151 					n->key.target_class, n->datum.data);
    152 		if (rc) goto exit;
    153 	}
    154 
    155 exit:
    156 	return rc;
    157 }
    158 
    159 struct bounds_expand_args {
    160 	sepol_handle_t *handle;
    161 	policydb_t *p;
    162 	avtab_t *avtab;
    163 	uint32_t parent;
    164 };
    165 
    166 static int bounds_expand_rule_callback(avtab_key_t *k, avtab_datum_t *d,
    167 				       void *args)
    168 {
    169 	struct bounds_expand_args *a = (struct bounds_expand_args *)args;
    170 
    171 	if (!(k->specified & AVTAB_ALLOWED))
    172 		return 0;
    173 
    174 	return bounds_expand_rule(a->handle, a->p, a->avtab, NULL, NULL,
    175 				  a->parent, k->source_type, k->target_type,
    176 				  k->target_class, d->data);
    177 }
    178 
    179 struct bounds_cond_info {
    180 	avtab_t true_avtab;
    181 	avtab_t false_avtab;
    182 	cond_list_t *cond_list;
    183 	struct bounds_cond_info *next;
    184 };
    185 
    186 static void bounds_destroy_cond_info(struct bounds_cond_info *cur)
    187 {
    188 	struct bounds_cond_info *next;
    189 
    190 	for (; cur; cur = next) {
    191 		next = cur->next;
    192 		avtab_destroy(&cur->true_avtab);
    193 		avtab_destroy(&cur->false_avtab);
    194 		cur->next = NULL;
    195 		free(cur);
    196 	}
    197 }
    198 
    199 static int bounds_expand_parent_rules(sepol_handle_t *handle, policydb_t *p,
    200 				      avtab_t *global_avtab,
    201 				      struct bounds_cond_info **cond_info,
    202 				      uint32_t parent)
    203 {
    204 	int rc = 0;
    205 	struct bounds_expand_args args;
    206 	cond_list_t *cur;
    207 
    208 	avtab_init(global_avtab);
    209 	rc = avtab_alloc(global_avtab, BOUNDS_AVTAB_SIZE);
    210 	if (rc) goto oom;
    211 
    212 	args.handle = handle;
    213 	args.p = p;
    214 	args.avtab = global_avtab;
    215 	args.parent = parent;
    216 	rc = avtab_map(&p->te_avtab, bounds_expand_rule_callback, &args);
    217 	if (rc) goto exit;
    218 
    219 	*cond_info = NULL;
    220 	for (cur = p->cond_list; cur; cur = cur->next) {
    221 		struct bounds_cond_info *ci;
    222 		ci = malloc(sizeof(struct bounds_cond_info));
    223 		if (!ci) goto oom;
    224 		avtab_init(&ci->true_avtab);
    225 		avtab_init(&ci->false_avtab);
    226 		ci->cond_list = cur;
    227 		ci->next = *cond_info;
    228 		*cond_info = ci;
    229 		if (cur->true_list) {
    230 			rc = avtab_alloc(&ci->true_avtab, BOUNDS_AVTAB_SIZE);
    231 			if (rc) goto oom;
    232 			rc = bounds_expand_cond_rules(handle, p, cur->true_list,
    233 						      &ci->true_avtab, NULL,
    234 						      NULL, parent);
    235 			if (rc) goto exit;
    236 		}
    237 		if (cur->false_list) {
    238 			rc = avtab_alloc(&ci->false_avtab, BOUNDS_AVTAB_SIZE);
    239 			if (rc) goto oom;
    240 			rc = bounds_expand_cond_rules(handle, p, cur->false_list,
    241 						      &ci->false_avtab,
    242 						      global_avtab,
    243 						      &ci->true_avtab, parent);
    244 			if (rc) goto exit;
    245 		}
    246 	}
    247 
    248 	return 0;
    249 
    250 oom:
    251 	ERR(handle, "Insufficient memory");
    252 
    253 exit:
    254 	ERR(handle,"Failed to expand parent rules\n");
    255 	avtab_destroy(global_avtab);
    256 	bounds_destroy_cond_info(*cond_info);
    257 	*cond_info = NULL;
    258 	return rc;
    259 }
    260 
    261 static int bounds_not_covered(avtab_t *global_avtab, avtab_t *cur_avtab,
    262 			      avtab_key_t *avtab_key, uint32_t data)
    263 {
    264 	avtab_datum_t *datum = avtab_search(cur_avtab, avtab_key);
    265 	if (datum)
    266 		data &= ~datum->data;
    267 	if (global_avtab && data) {
    268 		datum = avtab_search(global_avtab, avtab_key);
    269 		if (datum)
    270 			data &= ~datum->data;
    271 	}
    272 
    273 	return data;
    274 }
    275 
    276 static int bounds_add_bad(sepol_handle_t *handle, uint32_t src, uint32_t tgt,
    277 			  uint32_t class, uint32_t data, avtab_ptr_t *bad)
    278 {
    279 	struct avtab_node *new = malloc(sizeof(struct avtab_node));
    280 	if (new == NULL) {
    281 		ERR(handle, "Insufficient memory");
    282 		return SEPOL_ENOMEM;
    283 	}
    284 	memset(new, 0, sizeof(struct avtab_node));
    285 	new->key.source_type = src;
    286 	new->key.target_type = tgt;
    287 	new->key.target_class = class;
    288 	new->datum.data = data;
    289 	new->next = *bad;
    290 	*bad = new;
    291 
    292 	return 0;
    293 }
    294 
    295 static int bounds_check_rule(sepol_handle_t *handle, policydb_t *p,
    296 			     avtab_t *global_avtab, avtab_t *cur_avtab,
    297 			     uint32_t child, uint32_t parent, uint32_t src,
    298 			     uint32_t tgt, uint32_t class, uint32_t data,
    299 			     avtab_ptr_t *bad, int *numbad)
    300 {
    301 	int rc = 0;
    302 	avtab_key_t avtab_key;
    303 	type_datum_t *td;
    304 	ebitmap_node_t *tnode;
    305 	unsigned int i;
    306 	uint32_t d;
    307 
    308 	avtab_key.specified = AVTAB_ALLOWED;
    309 	avtab_key.target_class = class;
    310 
    311 	if (ebitmap_get_bit(&p->attr_type_map[src - 1], child - 1)) {
    312 		avtab_key.source_type = parent;
    313 		ebitmap_for_each_bit(&p->attr_type_map[tgt - 1], tnode, i) {
    314 			if (!ebitmap_node_get_bit(tnode, i))
    315 				continue;
    316 			avtab_key.target_type = i + 1;
    317 			d = bounds_not_covered(global_avtab, cur_avtab,
    318 					       &avtab_key, data);
    319 			if (!d) continue;
    320 			td = p->type_val_to_struct[i];
    321 			if (td && td->bounds) {
    322 				avtab_key.target_type = td->bounds;
    323 				d = bounds_not_covered(global_avtab, cur_avtab,
    324 						       &avtab_key, data);
    325 				if (!d) continue;
    326 			}
    327 			(*numbad)++;
    328 			rc = bounds_add_bad(handle, child, i+1, class, d, bad);
    329 			if (rc) goto exit;
    330 		}
    331 	}
    332 	if (ebitmap_get_bit(&p->attr_type_map[tgt - 1], child - 1)) {
    333 		avtab_key.target_type = parent;
    334 		ebitmap_for_each_bit(&p->attr_type_map[src - 1], tnode, i) {
    335 			if (!ebitmap_node_get_bit(tnode, i))
    336 				continue;
    337 			avtab_key.source_type = i + 1;
    338 			if (avtab_key.source_type == child) {
    339 				/* Checked above */
    340 				continue;
    341 			}
    342 			d = bounds_not_covered(global_avtab, cur_avtab,
    343 					       &avtab_key, data);
    344 			if (!d) continue;
    345 			td = p->type_val_to_struct[i];
    346 			if (td && td->bounds) {
    347 				avtab_key.source_type = td->bounds;
    348 				d = bounds_not_covered(global_avtab, cur_avtab,
    349 						       &avtab_key, data);
    350 				if (!d) continue;
    351 			}
    352 			(*numbad)++;
    353 			rc = bounds_add_bad(handle, i+1, child, class, d, bad);
    354 			if (rc) goto exit;
    355 		}
    356 	}
    357 
    358 exit:
    359 	return rc;
    360 }
    361 
    362 static int bounds_check_cond_rules(sepol_handle_t *handle, policydb_t *p,
    363 				   avtab_t *global_avtab, avtab_t *cond_avtab,
    364 				   cond_av_list_t *rules, uint32_t child,
    365 				   uint32_t parent, avtab_ptr_t *bad,
    366 				   int *numbad)
    367 {
    368 	int rc = 0;
    369 	cond_av_list_t *cur;
    370 
    371 	for (cur = rules; cur; cur = cur->next) {
    372 		avtab_ptr_t ap = cur->node;
    373 		avtab_key_t *key = &ap->key;
    374 		avtab_datum_t *datum = &ap->datum;
    375 		if (!(key->specified & AVTAB_ALLOWED))
    376 			continue;
    377 		rc = bounds_check_rule(handle, p, global_avtab, cond_avtab,
    378 				       child, parent, key->source_type,
    379 				       key->target_type, key->target_class,
    380 				       datum->data, bad, numbad);
    381 		if (rc) goto exit;
    382 	}
    383 
    384 exit:
    385 	return rc;
    386 }
    387 
    388 struct bounds_check_args {
    389 	sepol_handle_t *handle;
    390 	policydb_t *p;
    391 	avtab_t *cur_avtab;
    392 	uint32_t child;
    393 	uint32_t parent;
    394 	avtab_ptr_t bad;
    395 	int numbad;
    396 };
    397 
    398 static int bounds_check_rule_callback(avtab_key_t *k, avtab_datum_t *d,
    399 				      void *args)
    400 {
    401 	struct bounds_check_args *a = (struct bounds_check_args *)args;
    402 
    403 	if (!(k->specified & AVTAB_ALLOWED))
    404 		return 0;
    405 
    406 	return bounds_check_rule(a->handle, a->p, NULL, a->cur_avtab, a->child,
    407 				 a->parent, k->source_type, k->target_type,
    408 				 k->target_class, d->data, &a->bad, &a->numbad);
    409 }
    410 
    411 static int bounds_check_child_rules(sepol_handle_t *handle, policydb_t *p,
    412 				    avtab_t *global_avtab,
    413 				    struct bounds_cond_info *cond_info,
    414 				    uint32_t child, uint32_t parent,
    415 				    avtab_ptr_t *bad, int *numbad)
    416 {
    417 	int rc;
    418 	struct bounds_check_args args;
    419 	struct bounds_cond_info *cur;
    420 
    421 	args.handle = handle;
    422 	args.p = p;
    423 	args.cur_avtab = global_avtab;
    424 	args.child = child;
    425 	args.parent = parent;
    426 	args.bad = NULL;
    427 	args.numbad = 0;
    428 	rc = avtab_map(&p->te_avtab, bounds_check_rule_callback, &args);
    429 	if (rc) goto exit;
    430 
    431 	for (cur = cond_info; cur; cur = cur->next) {
    432 		cond_list_t *node = cur->cond_list;
    433 		rc = bounds_check_cond_rules(handle, p, global_avtab,
    434 					     &cur->true_avtab,
    435 					     node->true_list, child, parent,
    436 					     &args.bad, &args.numbad);
    437 		if (rc) goto exit;
    438 
    439 		rc = bounds_check_cond_rules(handle, p, global_avtab,
    440 					     &cur->false_avtab,
    441 					     node->false_list, child, parent,
    442 					     &args.bad, &args.numbad);
    443 		if (rc) goto exit;
    444 	}
    445 
    446 	*numbad += args.numbad;
    447 	*bad = args.bad;
    448 
    449 exit:
    450 	return rc;
    451 }
    452 
    453 int bounds_check_type(sepol_handle_t *handle, policydb_t *p, uint32_t child,
    454 		      uint32_t parent, avtab_ptr_t *bad, int *numbad)
    455 {
    456 	int rc = 0;
    457 	avtab_t global_avtab;
    458 	struct bounds_cond_info *cond_info = NULL;
    459 
    460 	rc = bounds_expand_parent_rules(handle, p, &global_avtab, &cond_info, parent);
    461 	if (rc) goto exit;
    462 
    463 	rc = bounds_check_child_rules(handle, p, &global_avtab, cond_info,
    464 				      child, parent, bad, numbad);
    465 
    466 	bounds_destroy_cond_info(cond_info);
    467 	avtab_destroy(&global_avtab);
    468 
    469 exit:
    470 	return rc;
    471 }
    472 
    473 struct bounds_args {
    474 	sepol_handle_t *handle;
    475 	policydb_t *p;
    476 	int numbad;
    477 };
    478 
    479 static void bounds_report(sepol_handle_t *handle, policydb_t *p, uint32_t child,
    480 			  uint32_t parent, avtab_ptr_t cur)
    481 {
    482 	ERR(handle, "Child type %s exceeds bounds of parent %s in the following rules:",
    483 	    p->p_type_val_to_name[child - 1],
    484 	    p->p_type_val_to_name[parent - 1]);
    485 	for (; cur; cur = cur->next) {
    486 		ERR(handle, "    %s %s : %s { %s }",
    487 		    p->p_type_val_to_name[cur->key.source_type - 1],
    488 		    p->p_type_val_to_name[cur->key.target_type - 1],
    489 		    p->p_class_val_to_name[cur->key.target_class - 1],
    490 		    sepol_av_to_string(p, cur->key.target_class,
    491 				       cur->datum.data));
    492 	}
    493 }
    494 
    495 void bounds_destroy_bad(avtab_ptr_t cur)
    496 {
    497 	avtab_ptr_t next;
    498 
    499 	for (; cur; cur = next) {
    500 		next = cur->next;
    501 		cur->next = NULL;
    502 		free(cur);
    503 	}
    504 }
    505 
    506 static int bounds_check_type_callback(hashtab_key_t k __attribute__ ((unused)),
    507 				      hashtab_datum_t d, void *args)
    508 {
    509 	int rc = 0;
    510 	struct bounds_args *a = (struct bounds_args *)args;
    511 	type_datum_t *t = (type_datum_t *)d;
    512 	avtab_ptr_t bad = NULL;
    513 
    514 	if (t->bounds) {
    515 		rc = bounds_check_type(a->handle, a->p, t->s.value, t->bounds,
    516 				       &bad, &a->numbad);
    517 		if (bad) {
    518 			bounds_report(a->handle, a->p, t->s.value, t->bounds,
    519 				      bad);
    520 			bounds_destroy_bad(bad);
    521 		}
    522 	}
    523 
    524 	return rc;
    525 }
    526 
    527 int bounds_check_types(sepol_handle_t *handle, policydb_t *p)
    528 {
    529 	int rc;
    530 	struct bounds_args args;
    531 
    532 	args.handle = handle;
    533 	args.p = p;
    534 	args.numbad = 0;
    535 
    536 	rc = hashtab_map(p->p_types.table, bounds_check_type_callback, &args);
    537 	if (rc) goto exit;
    538 
    539 	if (args.numbad > 0) {
    540 		ERR(handle, "%d errors found during type bounds check",
    541 		    args.numbad);
    542 		rc = SEPOL_ERR;
    543 	}
    544 
    545 exit:
    546 	return rc;
    547 }
    548 
    549 /* The role bounds is defined as: a child role cannot have a type that
    550  * its parent doesn't have.
    551  */
    552 static int bounds_check_role_callback(hashtab_key_t k __attribute__ ((unused)),
    553 				      hashtab_datum_t d, void *args)
    554 {
    555 	struct bounds_args *a = (struct bounds_args *)args;
    556 	role_datum_t *r = (role_datum_t *) d;
    557 	role_datum_t *rp = NULL;
    558 
    559 	if (!r->bounds)
    560 		return 0;
    561 
    562 	rp = a->p->role_val_to_struct[r->bounds - 1];
    563 
    564 	if (rp && !ebitmap_contains(&rp->types.types, &r->types.types)) {
    565 		ERR(a->handle, "Role bounds violation, %s exceeds %s",
    566 		    (char *)k, a->p->p_role_val_to_name[rp->s.value - 1]);
    567 		a->numbad++;
    568 	}
    569 
    570 	return 0;
    571 }
    572 
    573 int bounds_check_roles(sepol_handle_t *handle, policydb_t *p)
    574 {
    575 	struct bounds_args args;
    576 
    577 	args.handle = handle;
    578 	args.p = p;
    579 	args.numbad = 0;
    580 
    581 	hashtab_map(p->p_roles.table, bounds_check_role_callback, &args);
    582 
    583 	if (args.numbad > 0) {
    584 		ERR(handle, "%d errors found during role bounds check",
    585 		    args.numbad);
    586 		return SEPOL_ERR;
    587 	}
    588 
    589 	return 0;
    590 }
    591 
    592 /* The user bounds is defined as: a child user cannot have a role that
    593  * its parent doesn't have.
    594  */
    595 static int bounds_check_user_callback(hashtab_key_t k __attribute__ ((unused)),
    596 				      hashtab_datum_t d, void *args)
    597 {
    598 	struct bounds_args *a = (struct bounds_args *)args;
    599 	user_datum_t *u = (user_datum_t *) d;
    600 	user_datum_t *up = NULL;
    601 
    602 	if (!u->bounds)
    603 		return 0;
    604 
    605 	up = a->p->user_val_to_struct[u->bounds - 1];
    606 
    607 	if (up && !ebitmap_contains(&up->roles.roles, &u->roles.roles)) {
    608 		ERR(a->handle, "User bounds violation, %s exceeds %s",
    609 		    (char *) k, a->p->p_user_val_to_name[up->s.value - 1]);
    610 		a->numbad++;
    611 	}
    612 
    613 	return 0;
    614 }
    615 
    616 int bounds_check_users(sepol_handle_t *handle, policydb_t *p)
    617 {
    618 	struct bounds_args args;
    619 
    620 	args.handle = handle;
    621 	args.p = p;
    622 	args.numbad = 0;
    623 
    624 	hashtab_map(p->p_users.table, bounds_check_user_callback, &args);
    625 
    626 	if (args.numbad > 0) {
    627 		ERR(handle, "%d errors found during user bounds check",
    628 		    args.numbad);
    629 		return SEPOL_ERR;
    630 	}
    631 
    632 	return 0;
    633 }
    634 
    635 #define add_hierarchy_callback_template(prefix)				\
    636 	int hierarchy_add_##prefix##_callback(hashtab_key_t k __attribute__ ((unused)), \
    637 					    hashtab_datum_t d, void *args) \
    638 {								\
    639 	struct bounds_args *a = (struct bounds_args *)args;		\
    640 	sepol_handle_t *handle = a->handle;				\
    641 	policydb_t *p = a->p;						\
    642 	prefix##_datum_t *datum = (prefix##_datum_t *)d;		\
    643 	prefix##_datum_t *parent;					\
    644 	char *parent_name, *datum_name, *tmp;				\
    645 									\
    646 	if (!datum->bounds) {						\
    647 		datum_name = p->p_##prefix##_val_to_name[datum->s.value - 1]; \
    648 									\
    649 		tmp = strrchr(datum_name, '.');				\
    650 		/* no '.' means it has no parent */			\
    651 		if (!tmp) return 0;					\
    652 									\
    653 		parent_name = strdup(datum_name);			\
    654 		if (!parent_name) {					\
    655 			ERR(handle, "Insufficient memory");		\
    656 			return SEPOL_ENOMEM;				\
    657 		}							\
    658 		parent_name[tmp - datum_name] = '\0';			\
    659 									\
    660 		parent = hashtab_search(p->p_##prefix##s.table, parent_name); \
    661 		if (!parent) {						\
    662 			/* Orphan type/role/user */			\
    663 			ERR(handle, "%s doesn't exist, %s is an orphan",\
    664 			    parent_name,				\
    665 			    p->p_##prefix##_val_to_name[datum->s.value - 1]); \
    666 			free(parent_name);				\
    667 			a->numbad++;					\
    668 			return 0;					\
    669 		}							\
    670 		datum->bounds = parent->s.value;			\
    671 		free(parent_name);					\
    672 	}								\
    673 									\
    674 	return 0;							\
    675 }								\
    676 
    677 static add_hierarchy_callback_template(type)
    678 static add_hierarchy_callback_template(role)
    679 static add_hierarchy_callback_template(user)
    680 
    681 int hierarchy_add_bounds(sepol_handle_t *handle, policydb_t *p)
    682 {
    683 	int rc = 0;
    684 	struct bounds_args args;
    685 
    686 	args.handle = handle;
    687 	args.p = p;
    688 	args.numbad = 0;
    689 
    690 	rc = hashtab_map(p->p_users.table, hierarchy_add_user_callback, &args);
    691 	if (rc) goto exit;
    692 
    693 	rc = hashtab_map(p->p_roles.table, hierarchy_add_role_callback, &args);
    694 	if (rc) goto exit;
    695 
    696 	rc = hashtab_map(p->p_types.table, hierarchy_add_type_callback, &args);
    697 	if (rc) goto exit;
    698 
    699 	if (args.numbad > 0) {
    700 		ERR(handle, "%d errors found while adding hierarchies",
    701 		    args.numbad);
    702 		rc = SEPOL_ERR;
    703 	}
    704 
    705 exit:
    706 	return rc;
    707 }
    708 
    709 int hierarchy_check_constraints(sepol_handle_t * handle, policydb_t * p)
    710 {
    711 	int rc = 0;
    712 	int violation = 0;
    713 
    714 	rc = hierarchy_add_bounds(handle, p);
    715 	if (rc) goto exit;
    716 
    717 	rc = bounds_check_users(handle, p);
    718 	if (rc)
    719 		violation = 1;
    720 
    721 	rc = bounds_check_roles(handle, p);
    722 	if (rc)
    723 		violation = 1;
    724 
    725 	rc = bounds_check_types(handle, p);
    726 	if (rc) {
    727 		if (rc == SEPOL_ERR)
    728 			violation = 1;
    729 		else
    730 			goto exit;
    731 	}
    732 
    733 	if (violation)
    734 		rc = SEPOL_ERR;
    735 
    736 exit:
    737 	return rc;
    738 }
    739