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