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