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 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
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)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
bounds_expand_rule_callback(avtab_key_t * k,avtab_datum_t * d,void * args)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
bounds_destroy_cond_info(struct bounds_cond_info * cur)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
bounds_expand_parent_rules(sepol_handle_t * handle,policydb_t * p,avtab_t * global_avtab,struct bounds_cond_info ** cond_info,uint32_t parent)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
bounds_not_covered(avtab_t * global_avtab,avtab_t * cur_avtab,avtab_key_t * avtab_key,uint32_t data)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
bounds_add_bad(sepol_handle_t * handle,uint32_t src,uint32_t tgt,uint32_t class,uint32_t data,avtab_ptr_t * bad)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
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)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
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)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
bounds_check_rule_callback(avtab_key_t * k,avtab_datum_t * d,void * args)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
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)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
bounds_check_type(sepol_handle_t * handle,policydb_t * p,uint32_t child,uint32_t parent,avtab_ptr_t * bad,int * numbad)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
bounds_report(sepol_handle_t * handle,policydb_t * p,uint32_t child,uint32_t parent,avtab_ptr_t cur)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
bounds_destroy_bad(avtab_ptr_t cur)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
bounds_check_type_callback(hashtab_key_t k,hashtab_datum_t d,void * args)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
bounds_check_types(sepol_handle_t * handle,policydb_t * p)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 */
bounds_check_role_callback(hashtab_key_t k,hashtab_datum_t d,void * args)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
bounds_check_roles(sepol_handle_t * handle,policydb_t * p)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 */
bounds_check_user_callback(hashtab_key_t k,hashtab_datum_t d,void * args)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
bounds_check_users(sepol_handle_t * handle,policydb_t * p)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)
add_hierarchy_callback_template(role)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
hierarchy_check_constraints(sepol_handle_t * handle,policydb_t * p)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