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 exit: 125 return rc; 126 } 127 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 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 */ 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 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) 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 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