| | 474 | /** State tracking struct used in the functions check_disabled, remove_symbol, and prune_disabled_symbols to handle disabled symbols */ |
|---|
| | 475 | struct symbol_pruning_state |
|---|
| | 476 | { |
|---|
| | 477 | qpol_policy_t *p; /**< The policy */ |
|---|
| | 478 | int symbol_type; /**< The current symbol type being processed */ |
|---|
| | 479 | }; |
|---|
| | 480 | |
|---|
| | 481 | /** Apply callback for hashtab_map_remove_on_error. |
|---|
| | 482 | * This function tests whether a symbol referenced by the policy is declared or only ever required. |
|---|
| | 483 | * Symbols without a declaration are disabled and must be removed. |
|---|
| | 484 | * @param key Symbol key to check. |
|---|
| | 485 | * @param datum Symbol datum to check. |
|---|
| | 486 | * @param args State object (of type struct symbol_pruning_state) |
|---|
| | 487 | * @return 0 if symbol is enabled, 1 if not enabled. |
|---|
| | 488 | */ |
|---|
| | 489 | static int check_disabled(hashtab_key_t key, hashtab_datum_t datum, void *args) |
|---|
| | 490 | { |
|---|
| | 491 | struct symbol_pruning_state *s = args; |
|---|
| | 492 | if (!is_id_enabled((char *)key, &(s->p->p->p), s->symbol_type)) |
|---|
| | 493 | return 1; |
|---|
| | 494 | return 0; |
|---|
| | 495 | } |
|---|
| | 496 | |
|---|
| | 497 | /** Remove callback for hashtab_map_remove_on_error. |
|---|
| | 498 | * Frees all memory associated with a disabled symbol that has been removed from the symbol table. |
|---|
| | 499 | * @param key Symbol key to remove |
|---|
| | 500 | * @param datum Symbol datum to remove |
|---|
| | 501 | * @param args State object (of type struct symbol_pruning_state) |
|---|
| | 502 | * @post All memory associated with the symbol is freed. |
|---|
| | 503 | */ |
|---|
| | 504 | static void remove_symbol(hashtab_key_t key, hashtab_datum_t datum, void *args) |
|---|
| | 505 | { |
|---|
| | 506 | struct symbol_pruning_state *s = args; |
|---|
| | 507 | switch (s->symbol_type) { |
|---|
| | 508 | case SYM_ROLES: |
|---|
| | 509 | { |
|---|
| | 510 | role_datum_destroy((role_datum_t *) datum); |
|---|
| | 511 | break; |
|---|
| | 512 | } |
|---|
| | 513 | case SYM_TYPES: |
|---|
| | 514 | { |
|---|
| | 515 | type_datum_destroy((type_datum_t *) datum); |
|---|
| | 516 | break; |
|---|
| | 517 | } |
|---|
| | 518 | case SYM_USERS: |
|---|
| | 519 | { |
|---|
| | 520 | user_datum_destroy((user_datum_t *) datum); |
|---|
| | 521 | break; |
|---|
| | 522 | } |
|---|
| | 523 | case SYM_BOOLS: |
|---|
| | 524 | { |
|---|
| | 525 | /* no-op */ |
|---|
| | 526 | break; |
|---|
| | 527 | } |
|---|
| | 528 | case SYM_LEVELS: |
|---|
| | 529 | { |
|---|
| | 530 | level_datum_destroy((level_datum_t *) datum); |
|---|
| | 531 | break; |
|---|
| | 532 | } |
|---|
| | 533 | case SYM_CATS: |
|---|
| | 534 | { |
|---|
| | 535 | cat_datum_destroy((cat_datum_t *) datum); |
|---|
| | 536 | break; |
|---|
| | 537 | } |
|---|
| | 538 | default: |
|---|
| | 539 | return; /* invalid type of datum to free; do nothing */ |
|---|
| | 540 | } |
|---|
| | 541 | free(key); |
|---|
| | 542 | free(datum); |
|---|
| | 543 | } |
|---|
| | 544 | |
|---|
| | 545 | /** Remove symbols that are only required but never declared from the policy. |
|---|
| | 546 | * Removes each disabled symbol freeing all memory associated with it. |
|---|
| | 547 | * @param policy The policy from which disabled symbols should be removed. |
|---|
| | 548 | * @return always 0. |
|---|
| | 549 | * @note Since hashtab_map_remove_on_error does not return any error status, |
|---|
| | 550 | * it is impossible to tell if it has failed; if it fails, the policy will |
|---|
| | 551 | * be in an inconsistent state. |
|---|
| | 552 | */ |
|---|
| | 553 | static int prune_disabled_symbols(qpol_policy_t * policy) |
|---|
| | 554 | { |
|---|
| | 555 | if (policy->type == QPOL_POLICY_KERNEL_BINARY) |
|---|
| | 556 | return 0; /* checkpolicy already prunes disabled symbols */ |
|---|
| | 557 | struct symbol_pruning_state state; |
|---|
| | 558 | state.p = policy; |
|---|
| | 559 | for (state.symbol_type = SYM_ROLES; state.symbol_type < SYM_NUM; state.symbol_type++) { |
|---|
| | 560 | hashtab_map_remove_on_error(policy->p->p.symtab[state.symbol_type].table, check_disabled, remove_symbol, &state); |
|---|
| | 561 | } |
|---|
| | 562 | return 0; |
|---|
| | 563 | } |
|---|
| | 564 | |
|---|
| | 565 | /** For all symbols that are multiply defined (such as attributes, roles, and users), |
|---|
| | 566 | * union the relevant sets of types and roles from each declaration. |
|---|
| | 567 | * @param policy The policy containig the symbols to union. |
|---|
| | 568 | * @return 0 on success, non-zero on error; if the call fails, |
|---|
| | 569 | * errno will be set, and the policy should be considered invalid. |
|---|
| | 570 | */ |
|---|
| | 571 | static int union_multiply_declared_symbols(qpol_policy_t * policy) { |
|---|
| | 572 | /* general structure of this function: |
|---|
| | 573 | walk role and user symbol tables for each role/user/attribute |
|---|
| | 574 | get datum from symtab, get key from array |
|---|
| | 575 | look up symbol in scope table |
|---|
| | 576 | foreach decl_id in scope entry |
|---|
| | 577 | union types/roles bitmap with datum's copy |
|---|
| | 578 | */ |
|---|
| | 579 | qpol_iterator_t * iter = NULL; |
|---|
| | 580 | int error = 0; |
|---|
| | 581 | if (qpol_policy_get_type_iter(policy, &iter)) { |
|---|
| | 582 | return 1; |
|---|
| | 583 | } |
|---|
| | 584 | for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { |
|---|
| | 585 | type_datum_t *attr; |
|---|
| | 586 | if (qpol_iterator_get_item(iter, (void**)&attr)) { |
|---|
| | 587 | error = errno; |
|---|
| | 588 | goto err; |
|---|
| | 589 | } |
|---|
| | 590 | unsigned char isattr = 0; |
|---|
| | 591 | if (qpol_type_get_isattr(policy, attr, &isattr)) { |
|---|
| | 592 | error = errno; |
|---|
| | 593 | goto err; |
|---|
| | 594 | } |
|---|
| | 595 | if (!isattr) |
|---|
| | 596 | continue; |
|---|
| | 597 | const char *name; |
|---|
| | 598 | if (qpol_type_get_name(policy, (qpol_type_t*)attr, &name)) { |
|---|
| | 599 | error = errno; |
|---|
| | 600 | goto err; |
|---|
| | 601 | } |
|---|
| | 602 | policydb_t *db = &policy->p->p; |
|---|
| | 603 | avrule_block_t *blk = db->global; |
|---|
| | 604 | for (; blk; blk = blk->next) { |
|---|
| | 605 | avrule_decl_t *decl = blk->enabled; |
|---|
| | 606 | if (!decl) |
|---|
| | 607 | continue; /* disabled */ |
|---|
| | 608 | type_datum_t *internal_datum = hashtab_search(decl->symtab[SYM_TYPES].table, (const hashtab_key_t)name); |
|---|
| | 609 | if (internal_datum == NULL) { |
|---|
| | 610 | continue; /* not declared here */ |
|---|
| | 611 | } |
|---|
| | 612 | if (ebitmap_union(&attr->types, &internal_datum->types)) |
|---|
| | 613 | { |
|---|
| | 614 | error = errno; |
|---|
| | 615 | ERR(policy, "could not merge declarations for attribute %s", name); |
|---|
| | 616 | goto err; |
|---|
| | 617 | } |
|---|
| | 618 | } |
|---|
| | 619 | } |
|---|
| | 620 | qpol_iterator_destroy(&iter); |
|---|
| | 621 | |
|---|
| | 622 | /* repeat for roles */ |
|---|
| | 623 | if (qpol_policy_get_role_iter(policy, &iter)) { |
|---|
| | 624 | return 1; |
|---|
| | 625 | } |
|---|
| | 626 | for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { |
|---|
| | 627 | role_datum_t *role; |
|---|
| | 628 | if (qpol_iterator_get_item(iter, (void**)&role)) { |
|---|
| | 629 | error = errno; |
|---|
| | 630 | goto err; |
|---|
| | 631 | } |
|---|
| | 632 | const char *name; |
|---|
| | 633 | if (qpol_role_get_name(policy, (qpol_role_t*)role, &name)) { |
|---|
| | 634 | error = errno; |
|---|
| | 635 | goto err; |
|---|
| | 636 | } |
|---|
| | 637 | policydb_t *db = &policy->p->p; |
|---|
| | 638 | scope_datum_t* scope_datum = hashtab_search(db->scope[SYM_ROLES].table, (const hashtab_key_t)name); |
|---|
| | 639 | if (scope_datum == NULL) { |
|---|
| | 640 | ERR(policy, "could not find scope datum for role %s", name); |
|---|
| | 641 | error = ENOENT; |
|---|
| | 642 | goto err; |
|---|
| | 643 | } |
|---|
| | 644 | for (uint32_t i = 0; i < scope_datum->decl_ids_len; i++) |
|---|
| | 645 | { |
|---|
| | 646 | if (db->decl_val_to_struct[scope_datum->decl_ids[i] - 1]->enabled == 0) |
|---|
| | 647 | continue; /* block is disabled */ |
|---|
| | 648 | role_datum_t *internal_datum = hashtab_search(db->decl_val_to_struct[scope_datum->decl_ids[i] - 1]->symtab[SYM_ROLES].table, (const hashtab_key_t)name); |
|---|
| | 649 | if (internal_datum == NULL) { |
|---|
| | 650 | continue; /* not declared here */ |
|---|
| | 651 | } |
|---|
| | 652 | if (ebitmap_union(&role->types.types, &internal_datum->types.types) || ebitmap_union(&role->dominates, &internal_datum->dominates)) |
|---|
| | 653 | { |
|---|
| | 654 | error = errno; |
|---|
| | 655 | ERR(policy, "could not merge declarations for role %s", name); |
|---|
| | 656 | goto err; |
|---|
| | 657 | } |
|---|
| | 658 | } |
|---|
| | 659 | } |
|---|
| | 660 | qpol_iterator_destroy(&iter); |
|---|
| | 661 | |
|---|
| | 662 | /* repeat for users */ |
|---|
| | 663 | if (qpol_policy_get_user_iter(policy, &iter)) { |
|---|
| | 664 | return 1; |
|---|
| | 665 | } |
|---|
| | 666 | for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { |
|---|
| | 667 | user_datum_t *user; |
|---|
| | 668 | if (qpol_iterator_get_item(iter, (void**)&user)) { |
|---|
| | 669 | error = errno; |
|---|
| | 670 | goto err; |
|---|
| | 671 | } |
|---|
| | 672 | const char *name; |
|---|
| | 673 | if (qpol_user_get_name(policy, (qpol_user_t*)user, &name)) { |
|---|
| | 674 | error = errno; |
|---|
| | 675 | goto err; |
|---|
| | 676 | } |
|---|
| | 677 | policydb_t *db = &policy->p->p; |
|---|
| | 678 | scope_datum_t* scope_datum = hashtab_search(db->scope[SYM_USERS].table, (const hashtab_key_t)name); |
|---|
| | 679 | if (scope_datum == NULL) { |
|---|
| | 680 | ERR(policy, "could not find scope datum for user %s", name); |
|---|
| | 681 | error = ENOENT; |
|---|
| | 682 | goto err; |
|---|
| | 683 | } |
|---|
| | 684 | for (uint32_t i = 0; i < scope_datum->decl_ids_len; i++) |
|---|
| | 685 | { |
|---|
| | 686 | if (db->decl_val_to_struct[scope_datum->decl_ids[i] - 1]->enabled == 0) |
|---|
| | 687 | continue; /* block is disabled */ |
|---|
| | 688 | user_datum_t *internal_datum = hashtab_search(db->decl_val_to_struct[scope_datum->decl_ids[i] -1 ]->symtab[SYM_USERS].table, (const hashtab_key_t)name); |
|---|
| | 689 | if (internal_datum == NULL) { |
|---|
| | 690 | continue; /* not declared here */ |
|---|
| | 691 | } |
|---|
| | 692 | if (ebitmap_union(&user->roles.roles, &internal_datum->roles.roles)) |
|---|
| | 693 | { |
|---|
| | 694 | error = errno; |
|---|
| | 695 | ERR(policy, "could not merge declarations for user %s", name); |
|---|
| | 696 | goto err; |
|---|
| | 697 | } |
|---|
| | 698 | } |
|---|
| | 699 | } |
|---|
| | 700 | qpol_iterator_destroy(&iter); |
|---|
| | 701 | |
|---|
| | 702 | return 0; |
|---|
| | 703 | err: |
|---|
| | 704 | qpol_iterator_destroy(&iter); |
|---|
| | 705 | errno = error; |
|---|
| | 706 | return 1; |
|---|
| | 707 | } |
|---|
| | 708 | |
|---|