• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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