1 /* Authors: Joshua Brindle <jbrindle@tresys.com>
2 * Jason Tang <jtang@tresys.com>
3 *
4 * Updates: KaiGai Kohei <kaigai@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
bounds_insert_helper(sepol_handle_t * handle,avtab_t * avtab,avtab_key_t * avtab_key,avtab_datum_t * datum)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
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)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
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)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_positive_bit(&p->attr_type_map[tgt - 1], tnode, i) {
115 avtab_key.target_type = i + 1;
116 rc = bounds_insert_rule(handle, avtab, global, other,
117 &avtab_key, &datum);
118 if (rc) goto exit;
119 }
120 }
121
122 exit:
123 return rc;
124 }
125
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)126 static int bounds_expand_cond_rules(sepol_handle_t *handle, policydb_t *p,
127 cond_av_list_t *cur, avtab_t *avtab,
128 avtab_t *global, avtab_t *other,
129 uint32_t parent)
130 {
131 int rc = 0;
132
133 for (; cur; cur = cur->next) {
134 avtab_ptr_t n = cur->node;
135 rc = bounds_expand_rule(handle, p, avtab, global, other, parent,
136 n->key.source_type, n->key.target_type,
137 n->key.target_class, n->datum.data);
138 if (rc) goto exit;
139 }
140
141 exit:
142 return rc;
143 }
144
145 struct bounds_expand_args {
146 sepol_handle_t *handle;
147 policydb_t *p;
148 avtab_t *avtab;
149 uint32_t parent;
150 };
151
bounds_expand_rule_callback(avtab_key_t * k,avtab_datum_t * d,void * args)152 static int bounds_expand_rule_callback(avtab_key_t *k, avtab_datum_t *d,
153 void *args)
154 {
155 struct bounds_expand_args *a = (struct bounds_expand_args *)args;
156
157 if (!(k->specified & AVTAB_ALLOWED))
158 return 0;
159
160 return bounds_expand_rule(a->handle, a->p, a->avtab, NULL, NULL,
161 a->parent, k->source_type, k->target_type,
162 k->target_class, d->data);
163 }
164
165 struct bounds_cond_info {
166 avtab_t true_avtab;
167 avtab_t false_avtab;
168 cond_list_t *cond_list;
169 struct bounds_cond_info *next;
170 };
171
bounds_destroy_cond_info(struct bounds_cond_info * cur)172 static void bounds_destroy_cond_info(struct bounds_cond_info *cur)
173 {
174 struct bounds_cond_info *next;
175
176 for (; cur; cur = next) {
177 next = cur->next;
178 avtab_destroy(&cur->true_avtab);
179 avtab_destroy(&cur->false_avtab);
180 cur->next = NULL;
181 free(cur);
182 }
183 }
184
bounds_expand_parent_rules(sepol_handle_t * handle,policydb_t * p,avtab_t * global_avtab,struct bounds_cond_info ** cond_info,uint32_t parent)185 static int bounds_expand_parent_rules(sepol_handle_t *handle, policydb_t *p,
186 avtab_t *global_avtab,
187 struct bounds_cond_info **cond_info,
188 uint32_t parent)
189 {
190 int rc = 0;
191 struct bounds_expand_args args;
192 cond_list_t *cur;
193
194 avtab_init(global_avtab);
195 rc = avtab_alloc(global_avtab, BOUNDS_AVTAB_SIZE);
196 if (rc) goto oom;
197
198 args.handle = handle;
199 args.p = p;
200 args.avtab = global_avtab;
201 args.parent = parent;
202 rc = avtab_map(&p->te_avtab, bounds_expand_rule_callback, &args);
203 if (rc) goto exit;
204
205 *cond_info = NULL;
206 for (cur = p->cond_list; cur; cur = cur->next) {
207 struct bounds_cond_info *ci;
208 ci = malloc(sizeof(struct bounds_cond_info));
209 if (!ci) goto oom;
210 avtab_init(&ci->true_avtab);
211 avtab_init(&ci->false_avtab);
212 ci->cond_list = cur;
213 ci->next = *cond_info;
214 *cond_info = ci;
215 if (cur->true_list) {
216 rc = avtab_alloc(&ci->true_avtab, BOUNDS_AVTAB_SIZE);
217 if (rc) goto oom;
218 rc = bounds_expand_cond_rules(handle, p, cur->true_list,
219 &ci->true_avtab, NULL,
220 NULL, parent);
221 if (rc) goto exit;
222 }
223 if (cur->false_list) {
224 rc = avtab_alloc(&ci->false_avtab, BOUNDS_AVTAB_SIZE);
225 if (rc) goto oom;
226 rc = bounds_expand_cond_rules(handle, p, cur->false_list,
227 &ci->false_avtab,
228 global_avtab,
229 &ci->true_avtab, parent);
230 if (rc) goto exit;
231 }
232 }
233
234 return 0;
235
236 oom:
237 ERR(handle, "Insufficient memory");
238
239 exit:
240 ERR(handle,"Failed to expand parent rules");
241 avtab_destroy(global_avtab);
242 bounds_destroy_cond_info(*cond_info);
243 *cond_info = NULL;
244 return rc;
245 }
246
bounds_not_covered(avtab_t * global_avtab,avtab_t * cur_avtab,avtab_key_t * avtab_key,uint32_t data)247 static int bounds_not_covered(avtab_t *global_avtab, avtab_t *cur_avtab,
248 avtab_key_t *avtab_key, uint32_t data)
249 {
250 avtab_datum_t *datum = avtab_search(cur_avtab, avtab_key);
251 if (datum)
252 data &= ~datum->data;
253 if (global_avtab && data) {
254 datum = avtab_search(global_avtab, avtab_key);
255 if (datum)
256 data &= ~datum->data;
257 }
258
259 return data;
260 }
261
bounds_add_bad(sepol_handle_t * handle,uint32_t src,uint32_t tgt,uint32_t class,uint32_t data,avtab_ptr_t * bad)262 static int bounds_add_bad(sepol_handle_t *handle, uint32_t src, uint32_t tgt,
263 uint32_t class, uint32_t data, avtab_ptr_t *bad)
264 {
265 struct avtab_node *new = malloc(sizeof(struct avtab_node));
266 if (new == NULL) {
267 ERR(handle, "Insufficient memory");
268 return SEPOL_ENOMEM;
269 }
270 memset(new, 0, sizeof(struct avtab_node));
271 new->key.source_type = src;
272 new->key.target_type = tgt;
273 new->key.target_class = class;
274 new->datum.data = data;
275 new->next = *bad;
276 *bad = new;
277
278 return 0;
279 }
280
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)281 static int bounds_check_rule(sepol_handle_t *handle, policydb_t *p,
282 avtab_t *global_avtab, avtab_t *cur_avtab,
283 uint32_t child, uint32_t parent, uint32_t src,
284 uint32_t tgt, uint32_t class, uint32_t data,
285 avtab_ptr_t *bad, int *numbad)
286 {
287 int rc = 0;
288 avtab_key_t avtab_key;
289 type_datum_t *td;
290 ebitmap_node_t *tnode;
291 unsigned int i;
292 uint32_t d;
293
294 avtab_key.specified = AVTAB_ALLOWED;
295 avtab_key.target_class = class;
296
297 if (ebitmap_get_bit(&p->attr_type_map[src - 1], child - 1)) {
298 avtab_key.source_type = parent;
299 ebitmap_for_each_positive_bit(&p->attr_type_map[tgt - 1], tnode, i) {
300 td = p->type_val_to_struct[i];
301 if (td && td->bounds) {
302 avtab_key.target_type = td->bounds;
303 d = bounds_not_covered(global_avtab, cur_avtab,
304 &avtab_key, data);
305 } else {
306 avtab_key.target_type = i + 1;
307 d = bounds_not_covered(global_avtab, cur_avtab,
308 &avtab_key, data);
309 }
310 if (d) {
311 (*numbad)++;
312 rc = bounds_add_bad(handle, child, i+1, class, d, bad);
313 if (rc) goto exit;
314 }
315 }
316 }
317
318 exit:
319 return rc;
320 }
321
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)322 static int bounds_check_cond_rules(sepol_handle_t *handle, policydb_t *p,
323 avtab_t *global_avtab, avtab_t *cond_avtab,
324 cond_av_list_t *rules, uint32_t child,
325 uint32_t parent, avtab_ptr_t *bad,
326 int *numbad)
327 {
328 int rc = 0;
329 cond_av_list_t *cur;
330
331 for (cur = rules; cur; cur = cur->next) {
332 avtab_ptr_t ap = cur->node;
333 avtab_key_t *key = &ap->key;
334 avtab_datum_t *datum = &ap->datum;
335 if (!(key->specified & AVTAB_ALLOWED))
336 continue;
337 rc = bounds_check_rule(handle, p, global_avtab, cond_avtab,
338 child, parent, key->source_type,
339 key->target_type, key->target_class,
340 datum->data, bad, numbad);
341 if (rc) goto exit;
342 }
343
344 exit:
345 return rc;
346 }
347
348 struct bounds_check_args {
349 sepol_handle_t *handle;
350 policydb_t *p;
351 avtab_t *cur_avtab;
352 uint32_t child;
353 uint32_t parent;
354 avtab_ptr_t bad;
355 int numbad;
356 };
357
bounds_check_rule_callback(avtab_key_t * k,avtab_datum_t * d,void * args)358 static int bounds_check_rule_callback(avtab_key_t *k, avtab_datum_t *d,
359 void *args)
360 {
361 struct bounds_check_args *a = (struct bounds_check_args *)args;
362
363 if (!(k->specified & AVTAB_ALLOWED))
364 return 0;
365
366 return bounds_check_rule(a->handle, a->p, NULL, a->cur_avtab, a->child,
367 a->parent, k->source_type, k->target_type,
368 k->target_class, d->data, &a->bad, &a->numbad);
369 }
370
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)371 static int bounds_check_child_rules(sepol_handle_t *handle, policydb_t *p,
372 avtab_t *global_avtab,
373 struct bounds_cond_info *cond_info,
374 uint32_t child, uint32_t parent,
375 avtab_ptr_t *bad, int *numbad)
376 {
377 int rc;
378 struct bounds_check_args args;
379 struct bounds_cond_info *cur;
380
381 args.handle = handle;
382 args.p = p;
383 args.cur_avtab = global_avtab;
384 args.child = child;
385 args.parent = parent;
386 args.bad = NULL;
387 args.numbad = 0;
388 rc = avtab_map(&p->te_avtab, bounds_check_rule_callback, &args);
389 if (rc) goto exit;
390
391 for (cur = cond_info; cur; cur = cur->next) {
392 cond_list_t *node = cur->cond_list;
393 rc = bounds_check_cond_rules(handle, p, global_avtab,
394 &cur->true_avtab,
395 node->true_list, child, parent,
396 &args.bad, &args.numbad);
397 if (rc) goto exit;
398
399 rc = bounds_check_cond_rules(handle, p, global_avtab,
400 &cur->false_avtab,
401 node->false_list, child, parent,
402 &args.bad, &args.numbad);
403 if (rc) goto exit;
404 }
405
406 *numbad += args.numbad;
407 *bad = args.bad;
408
409 exit:
410 return rc;
411 }
412
bounds_check_type(sepol_handle_t * handle,policydb_t * p,uint32_t child,uint32_t parent,avtab_ptr_t * bad,int * numbad)413 int bounds_check_type(sepol_handle_t *handle, policydb_t *p, uint32_t child,
414 uint32_t parent, avtab_ptr_t *bad, int *numbad)
415 {
416 int rc = 0;
417 avtab_t global_avtab;
418 struct bounds_cond_info *cond_info = NULL;
419
420 rc = bounds_expand_parent_rules(handle, p, &global_avtab, &cond_info, parent);
421 if (rc) goto exit;
422
423 rc = bounds_check_child_rules(handle, p, &global_avtab, cond_info,
424 child, parent, bad, numbad);
425
426 bounds_destroy_cond_info(cond_info);
427 avtab_destroy(&global_avtab);
428
429 exit:
430 return rc;
431 }
432
433 struct bounds_args {
434 sepol_handle_t *handle;
435 policydb_t *p;
436 int numbad;
437 };
438
bounds_report(sepol_handle_t * handle,policydb_t * p,uint32_t child,uint32_t parent,avtab_ptr_t cur)439 static void bounds_report(sepol_handle_t *handle, policydb_t *p, uint32_t child,
440 uint32_t parent, avtab_ptr_t cur)
441 {
442 ERR(handle, "Child type %s exceeds bounds of parent %s in the following rules:",
443 p->p_type_val_to_name[child - 1],
444 p->p_type_val_to_name[parent - 1]);
445 for (; cur; cur = cur->next) {
446 ERR(handle, " %s %s : %s { %s }",
447 p->p_type_val_to_name[cur->key.source_type - 1],
448 p->p_type_val_to_name[cur->key.target_type - 1],
449 p->p_class_val_to_name[cur->key.target_class - 1],
450 sepol_av_to_string(p, cur->key.target_class,
451 cur->datum.data));
452 }
453 }
454
bounds_destroy_bad(avtab_ptr_t cur)455 void bounds_destroy_bad(avtab_ptr_t cur)
456 {
457 avtab_ptr_t next;
458
459 for (; cur; cur = next) {
460 next = cur->next;
461 cur->next = NULL;
462 free(cur);
463 }
464 }
465
bounds_check_type_callback(hashtab_key_t k,hashtab_datum_t d,void * args)466 static int bounds_check_type_callback(hashtab_key_t k __attribute__ ((unused)),
467 hashtab_datum_t d, void *args)
468 {
469 int rc = 0;
470 struct bounds_args *a = (struct bounds_args *)args;
471 type_datum_t *t = (type_datum_t *)d;
472 avtab_ptr_t bad = NULL;
473
474 if (t->bounds) {
475 rc = bounds_check_type(a->handle, a->p, t->s.value, t->bounds,
476 &bad, &a->numbad);
477 if (bad) {
478 bounds_report(a->handle, a->p, t->s.value, t->bounds,
479 bad);
480 bounds_destroy_bad(bad);
481 }
482 }
483
484 return rc;
485 }
486
bounds_check_types(sepol_handle_t * handle,policydb_t * p)487 int bounds_check_types(sepol_handle_t *handle, policydb_t *p)
488 {
489 int rc;
490 struct bounds_args args;
491
492 args.handle = handle;
493 args.p = p;
494 args.numbad = 0;
495
496 rc = hashtab_map(p->p_types.table, bounds_check_type_callback, &args);
497 if (rc) goto exit;
498
499 if (args.numbad > 0) {
500 ERR(handle, "%d errors found during type bounds check",
501 args.numbad);
502 rc = SEPOL_ERR;
503 }
504
505 exit:
506 return rc;
507 }
508
509 /* The role bounds is defined as: a child role cannot have a type that
510 * its parent doesn't have.
511 */
bounds_check_role_callback(hashtab_key_t k,hashtab_datum_t d,void * args)512 static int bounds_check_role_callback(hashtab_key_t k,
513 hashtab_datum_t d, void *args)
514 {
515 struct bounds_args *a = (struct bounds_args *)args;
516 role_datum_t *r = (role_datum_t *) d;
517 role_datum_t *rp = NULL;
518
519 if (!r->bounds)
520 return 0;
521
522 rp = a->p->role_val_to_struct[r->bounds - 1];
523
524 if (rp && !ebitmap_contains(&rp->types.types, &r->types.types)) {
525 ERR(a->handle, "Role bounds violation, %s exceeds %s",
526 (char *)k, a->p->p_role_val_to_name[rp->s.value - 1]);
527 a->numbad++;
528 }
529
530 return 0;
531 }
532
bounds_check_roles(sepol_handle_t * handle,policydb_t * p)533 int bounds_check_roles(sepol_handle_t *handle, policydb_t *p)
534 {
535 struct bounds_args args;
536
537 args.handle = handle;
538 args.p = p;
539 args.numbad = 0;
540
541 hashtab_map(p->p_roles.table, bounds_check_role_callback, &args);
542
543 if (args.numbad > 0) {
544 ERR(handle, "%d errors found during role bounds check",
545 args.numbad);
546 return SEPOL_ERR;
547 }
548
549 return 0;
550 }
551
552 /* The user bounds is defined as: a child user cannot have a role that
553 * its parent doesn't have.
554 */
bounds_check_user_callback(hashtab_key_t k,hashtab_datum_t d,void * args)555 static int bounds_check_user_callback(hashtab_key_t k,
556 hashtab_datum_t d, void *args)
557 {
558 struct bounds_args *a = (struct bounds_args *)args;
559 user_datum_t *u = (user_datum_t *) d;
560 user_datum_t *up = NULL;
561
562 if (!u->bounds)
563 return 0;
564
565 up = a->p->user_val_to_struct[u->bounds - 1];
566
567 if (up && !ebitmap_contains(&up->roles.roles, &u->roles.roles)) {
568 ERR(a->handle, "User bounds violation, %s exceeds %s",
569 (char *) k, a->p->p_user_val_to_name[up->s.value - 1]);
570 a->numbad++;
571 }
572
573 return 0;
574 }
575
bounds_check_users(sepol_handle_t * handle,policydb_t * p)576 int bounds_check_users(sepol_handle_t *handle, policydb_t *p)
577 {
578 struct bounds_args args;
579
580 args.handle = handle;
581 args.p = p;
582 args.numbad = 0;
583
584 hashtab_map(p->p_users.table, bounds_check_user_callback, &args);
585
586 if (args.numbad > 0) {
587 ERR(handle, "%d errors found during user bounds check",
588 args.numbad);
589 return SEPOL_ERR;
590 }
591
592 return 0;
593 }
594
595 #define add_hierarchy_callback_template(prefix) \
596 int hierarchy_add_##prefix##_callback(hashtab_key_t k __attribute__ ((unused)), \
597 hashtab_datum_t d, void *args) \
598 { \
599 struct bounds_args *a = (struct bounds_args *)args; \
600 sepol_handle_t *handle = a->handle; \
601 policydb_t *p = a->p; \
602 prefix##_datum_t *datum = (prefix##_datum_t *)d; \
603 prefix##_datum_t *parent; \
604 char *parent_name, *datum_name, *tmp; \
605 \
606 if (!datum->bounds) { \
607 datum_name = p->p_##prefix##_val_to_name[datum->s.value - 1]; \
608 \
609 tmp = strrchr(datum_name, '.'); \
610 /* no '.' means it has no parent */ \
611 if (!tmp) return 0; \
612 \
613 parent_name = strdup(datum_name); \
614 if (!parent_name) { \
615 ERR(handle, "Insufficient memory"); \
616 return SEPOL_ENOMEM; \
617 } \
618 parent_name[tmp - datum_name] = '\0'; \
619 \
620 parent = hashtab_search(p->p_##prefix##s.table, parent_name); \
621 if (!parent) { \
622 /* Orphan type/role/user */ \
623 ERR(handle, "%s doesn't exist, %s is an orphan",\
624 parent_name, \
625 p->p_##prefix##_val_to_name[datum->s.value - 1]); \
626 free(parent_name); \
627 a->numbad++; \
628 return 0; \
629 } \
630 datum->bounds = parent->s.value; \
631 free(parent_name); \
632 } \
633 \
634 return 0; \
635 } \
636
637 static add_hierarchy_callback_template(type)
add_hierarchy_callback_template(role)638 static add_hierarchy_callback_template(role)
639 static add_hierarchy_callback_template(user)
640
641 int hierarchy_add_bounds(sepol_handle_t *handle, policydb_t *p)
642 {
643 int rc = 0;
644 struct bounds_args args;
645
646 args.handle = handle;
647 args.p = p;
648 args.numbad = 0;
649
650 rc = hashtab_map(p->p_users.table, hierarchy_add_user_callback, &args);
651 if (rc) goto exit;
652
653 rc = hashtab_map(p->p_roles.table, hierarchy_add_role_callback, &args);
654 if (rc) goto exit;
655
656 rc = hashtab_map(p->p_types.table, hierarchy_add_type_callback, &args);
657 if (rc) goto exit;
658
659 if (args.numbad > 0) {
660 ERR(handle, "%d errors found while adding hierarchies",
661 args.numbad);
662 rc = SEPOL_ERR;
663 }
664
665 exit:
666 return rc;
667 }
668
hierarchy_check_constraints(sepol_handle_t * handle,policydb_t * p)669 int hierarchy_check_constraints(sepol_handle_t * handle, policydb_t * p)
670 {
671 int rc = 0;
672 int violation = 0;
673
674 rc = hierarchy_add_bounds(handle, p);
675 if (rc) goto exit;
676
677 rc = bounds_check_users(handle, p);
678 if (rc)
679 violation = 1;
680
681 rc = bounds_check_roles(handle, p);
682 if (rc)
683 violation = 1;
684
685 rc = bounds_check_types(handle, p);
686 if (rc) {
687 if (rc == SEPOL_ERR)
688 violation = 1;
689 else
690 goto exit;
691 }
692
693 if (violation)
694 rc = SEPOL_ERR;
695
696 exit:
697 return rc;
698 }
699