diff options
Diffstat (limited to 'security/tomoyo')
-rw-r--r-- | security/tomoyo/common.c | 4 | ||||
-rw-r--r-- | security/tomoyo/common.h | 4 | ||||
-rw-r--r-- | security/tomoyo/condition.c | 50 | ||||
-rw-r--r-- | security/tomoyo/domain.c | 53 | ||||
-rw-r--r-- | security/tomoyo/file.c | 38 |
5 files changed, 137 insertions, 12 deletions
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 084018351b4..0994948f3ed 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -1203,6 +1203,10 @@ static bool tomoyo_print_condition(struct tomoyo_io_buffer *head, | |||
1203 | case 0: | 1203 | case 0: |
1204 | head->r.cond_index = 0; | 1204 | head->r.cond_index = 0; |
1205 | head->r.cond_step++; | 1205 | head->r.cond_step++; |
1206 | if (cond->transit) { | ||
1207 | tomoyo_set_space(head); | ||
1208 | tomoyo_set_string(head, cond->transit->name); | ||
1209 | } | ||
1206 | /* fall through */ | 1210 | /* fall through */ |
1207 | case 1: | 1211 | case 1: |
1208 | { | 1212 | { |
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 471c9f9afc1..a2bc33fc60b 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
@@ -615,6 +615,7 @@ struct tomoyo_execve { | |||
615 | struct tomoyo_request_info r; | 615 | struct tomoyo_request_info r; |
616 | struct tomoyo_obj_info obj; | 616 | struct tomoyo_obj_info obj; |
617 | struct linux_binprm *bprm; | 617 | struct linux_binprm *bprm; |
618 | const struct tomoyo_path_info *transition; | ||
618 | /* For dumping argv[] and envp[]. */ | 619 | /* For dumping argv[] and envp[]. */ |
619 | struct tomoyo_page_dump dump; | 620 | struct tomoyo_page_dump dump; |
620 | /* For temporary use. */ | 621 | /* For temporary use. */ |
@@ -650,6 +651,7 @@ struct tomoyo_condition { | |||
650 | u16 argc; /* Number of "struct tomoyo_argv". */ | 651 | u16 argc; /* Number of "struct tomoyo_argv". */ |
651 | u16 envc; /* Number of "struct tomoyo_envp". */ | 652 | u16 envc; /* Number of "struct tomoyo_envp". */ |
652 | u8 grant_log; /* One of values in "enum tomoyo_grant_log". */ | 653 | u8 grant_log; /* One of values in "enum tomoyo_grant_log". */ |
654 | const struct tomoyo_path_info *transit; /* Maybe NULL. */ | ||
653 | /* | 655 | /* |
654 | * struct tomoyo_condition_element condition[condc]; | 656 | * struct tomoyo_condition_element condition[condc]; |
655 | * struct tomoyo_number_union values[numbers_count]; | 657 | * struct tomoyo_number_union values[numbers_count]; |
@@ -956,6 +958,8 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | |||
956 | struct path *path, const int flag); | 958 | struct path *path, const int flag); |
957 | int tomoyo_close_control(struct tomoyo_io_buffer *head); | 959 | int tomoyo_close_control(struct tomoyo_io_buffer *head); |
958 | int tomoyo_env_perm(struct tomoyo_request_info *r, const char *env); | 960 | int tomoyo_env_perm(struct tomoyo_request_info *r, const char *env); |
961 | int tomoyo_execute_permission(struct tomoyo_request_info *r, | ||
962 | const struct tomoyo_path_info *filename); | ||
959 | int tomoyo_find_next_domain(struct linux_binprm *bprm); | 963 | int tomoyo_find_next_domain(struct linux_binprm *bprm); |
960 | int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile, | 964 | int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile, |
961 | const u8 index); | 965 | const u8 index); |
diff --git a/security/tomoyo/condition.c b/security/tomoyo/condition.c index 3a05eb3e2a6..b854959c0fd 100644 --- a/security/tomoyo/condition.c +++ b/security/tomoyo/condition.c | |||
@@ -348,7 +348,7 @@ static inline bool tomoyo_same_condition(const struct tomoyo_condition *a, | |||
348 | a->numbers_count == b->numbers_count && | 348 | a->numbers_count == b->numbers_count && |
349 | a->names_count == b->names_count && | 349 | a->names_count == b->names_count && |
350 | a->argc == b->argc && a->envc == b->envc && | 350 | a->argc == b->argc && a->envc == b->envc && |
351 | a->grant_log == b->grant_log && | 351 | a->grant_log == b->grant_log && a->transit == b->transit && |
352 | !memcmp(a + 1, b + 1, a->size - sizeof(*a)); | 352 | !memcmp(a + 1, b + 1, a->size - sizeof(*a)); |
353 | } | 353 | } |
354 | 354 | ||
@@ -429,6 +429,46 @@ out: | |||
429 | } | 429 | } |
430 | 430 | ||
431 | /** | 431 | /** |
432 | * tomoyo_get_transit_preference - Parse domain transition preference for execve(). | ||
433 | * | ||
434 | * @param: Pointer to "struct tomoyo_acl_param". | ||
435 | * @e: Pointer to "struct tomoyo_condition". | ||
436 | * | ||
437 | * Returns the condition string part. | ||
438 | */ | ||
439 | static char *tomoyo_get_transit_preference(struct tomoyo_acl_param *param, | ||
440 | struct tomoyo_condition *e) | ||
441 | { | ||
442 | char * const pos = param->data; | ||
443 | bool flag; | ||
444 | if (*pos == '<') { | ||
445 | e->transit = tomoyo_get_domainname(param); | ||
446 | goto done; | ||
447 | } | ||
448 | { | ||
449 | char *cp = strchr(pos, ' '); | ||
450 | if (cp) | ||
451 | *cp = '\0'; | ||
452 | flag = tomoyo_correct_path(pos) || !strcmp(pos, "keep") || | ||
453 | !strcmp(pos, "initialize") || !strcmp(pos, "reset") || | ||
454 | !strcmp(pos, "child") || !strcmp(pos, "parent"); | ||
455 | if (cp) | ||
456 | *cp = ' '; | ||
457 | } | ||
458 | if (!flag) | ||
459 | return pos; | ||
460 | e->transit = tomoyo_get_name(tomoyo_read_token(param)); | ||
461 | done: | ||
462 | if (e->transit) | ||
463 | return param->data; | ||
464 | /* | ||
465 | * Return a bad read-only condition string that will let | ||
466 | * tomoyo_get_condition() return NULL. | ||
467 | */ | ||
468 | return "/"; | ||
469 | } | ||
470 | |||
471 | /** | ||
432 | * tomoyo_get_condition - Parse condition part. | 472 | * tomoyo_get_condition - Parse condition part. |
433 | * | 473 | * |
434 | * @param: Pointer to "struct tomoyo_acl_param". | 474 | * @param: Pointer to "struct tomoyo_acl_param". |
@@ -444,7 +484,8 @@ struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param) | |||
444 | struct tomoyo_argv *argv = NULL; | 484 | struct tomoyo_argv *argv = NULL; |
445 | struct tomoyo_envp *envp = NULL; | 485 | struct tomoyo_envp *envp = NULL; |
446 | struct tomoyo_condition e = { }; | 486 | struct tomoyo_condition e = { }; |
447 | char * const start_of_string = param->data; | 487 | char * const start_of_string = |
488 | tomoyo_get_transit_preference(param, &e); | ||
448 | char * const end_of_string = start_of_string + strlen(start_of_string); | 489 | char * const end_of_string = start_of_string + strlen(start_of_string); |
449 | char *pos; | 490 | char *pos; |
450 | rerun: | 491 | rerun: |
@@ -608,8 +649,9 @@ store_value: | |||
608 | + e.envc * sizeof(struct tomoyo_envp); | 649 | + e.envc * sizeof(struct tomoyo_envp); |
609 | entry = kzalloc(e.size, GFP_NOFS); | 650 | entry = kzalloc(e.size, GFP_NOFS); |
610 | if (!entry) | 651 | if (!entry) |
611 | return NULL; | 652 | goto out2; |
612 | *entry = e; | 653 | *entry = e; |
654 | e.transit = NULL; | ||
613 | condp = (struct tomoyo_condition_element *) (entry + 1); | 655 | condp = (struct tomoyo_condition_element *) (entry + 1); |
614 | numbers_p = (struct tomoyo_number_union *) (condp + e.condc); | 656 | numbers_p = (struct tomoyo_number_union *) (condp + e.condc); |
615 | names_p = (struct tomoyo_name_union *) (numbers_p + e.numbers_count); | 657 | names_p = (struct tomoyo_name_union *) (numbers_p + e.numbers_count); |
@@ -636,6 +678,8 @@ out: | |||
636 | tomoyo_del_condition(&entry->head.list); | 678 | tomoyo_del_condition(&entry->head.list); |
637 | kfree(entry); | 679 | kfree(entry); |
638 | } | 680 | } |
681 | out2: | ||
682 | tomoyo_put_name(e.transit); | ||
639 | return NULL; | 683 | return NULL; |
640 | } | 684 | } |
641 | 685 | ||
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index a1fc6b5f612..860390ee1fb 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
@@ -102,6 +102,15 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, | |||
102 | new_entry->cond = tomoyo_get_condition(param); | 102 | new_entry->cond = tomoyo_get_condition(param); |
103 | if (!new_entry->cond) | 103 | if (!new_entry->cond) |
104 | return -EINVAL; | 104 | return -EINVAL; |
105 | /* | ||
106 | * Domain transition preference is allowed for only | ||
107 | * "file execute" entries. | ||
108 | */ | ||
109 | if (new_entry->cond->transit && | ||
110 | !(new_entry->type == TOMOYO_TYPE_PATH_ACL && | ||
111 | container_of(new_entry, struct tomoyo_path_acl, head) | ||
112 | ->perm == 1 << TOMOYO_TYPE_EXECUTE)) | ||
113 | goto out; | ||
105 | } | 114 | } |
106 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 115 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
107 | goto out; | 116 | goto out; |
@@ -707,8 +716,7 @@ retry: | |||
707 | } | 716 | } |
708 | 717 | ||
709 | /* Check execute permission. */ | 718 | /* Check execute permission. */ |
710 | retval = tomoyo_path_permission(&ee->r, TOMOYO_TYPE_EXECUTE, | 719 | retval = tomoyo_execute_permission(&ee->r, candidate); |
711 | candidate); | ||
712 | if (retval == TOMOYO_RETRY_REQUEST) | 720 | if (retval == TOMOYO_RETRY_REQUEST) |
713 | goto retry; | 721 | goto retry; |
714 | if (retval < 0) | 722 | if (retval < 0) |
@@ -722,10 +730,45 @@ retry: | |||
722 | if (ee->r.param.path.matched_path) | 730 | if (ee->r.param.path.matched_path) |
723 | candidate = ee->r.param.path.matched_path; | 731 | candidate = ee->r.param.path.matched_path; |
724 | 732 | ||
725 | /* Calculate domain to transit to. */ | 733 | /* |
734 | * Check for domain transition preference if "file execute" matched. | ||
735 | * If preference is given, make do_execve() fail if domain transition | ||
736 | * has failed, for domain transition preference should be used with | ||
737 | * destination domain defined. | ||
738 | */ | ||
739 | if (ee->transition) { | ||
740 | const char *domainname = ee->transition->name; | ||
741 | reject_on_transition_failure = true; | ||
742 | if (!strcmp(domainname, "keep")) | ||
743 | goto force_keep_domain; | ||
744 | if (!strcmp(domainname, "child")) | ||
745 | goto force_child_domain; | ||
746 | if (!strcmp(domainname, "reset")) | ||
747 | goto force_reset_domain; | ||
748 | if (!strcmp(domainname, "initialize")) | ||
749 | goto force_initialize_domain; | ||
750 | if (!strcmp(domainname, "parent")) { | ||
751 | char *cp; | ||
752 | strncpy(ee->tmp, old_domain->domainname->name, | ||
753 | TOMOYO_EXEC_TMPSIZE - 1); | ||
754 | cp = strrchr(ee->tmp, ' '); | ||
755 | if (cp) | ||
756 | *cp = '\0'; | ||
757 | } else if (*domainname == '<') | ||
758 | strncpy(ee->tmp, domainname, TOMOYO_EXEC_TMPSIZE - 1); | ||
759 | else | ||
760 | snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", | ||
761 | old_domain->domainname->name, domainname); | ||
762 | goto force_jump_domain; | ||
763 | } | ||
764 | /* | ||
765 | * No domain transition preference specified. | ||
766 | * Calculate domain to transit to. | ||
767 | */ | ||
726 | switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname, | 768 | switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname, |
727 | candidate)) { | 769 | candidate)) { |
728 | case TOMOYO_TRANSITION_CONTROL_RESET: | 770 | case TOMOYO_TRANSITION_CONTROL_RESET: |
771 | force_reset_domain: | ||
729 | /* Transit to the root of specified namespace. */ | 772 | /* Transit to the root of specified namespace. */ |
730 | snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", | 773 | snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", |
731 | candidate->name); | 774 | candidate->name); |
@@ -736,11 +779,13 @@ retry: | |||
736 | reject_on_transition_failure = true; | 779 | reject_on_transition_failure = true; |
737 | break; | 780 | break; |
738 | case TOMOYO_TRANSITION_CONTROL_INITIALIZE: | 781 | case TOMOYO_TRANSITION_CONTROL_INITIALIZE: |
782 | force_initialize_domain: | ||
739 | /* Transit to the child of current namespace's root. */ | 783 | /* Transit to the child of current namespace's root. */ |
740 | snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", | 784 | snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", |
741 | old_domain->ns->name, candidate->name); | 785 | old_domain->ns->name, candidate->name); |
742 | break; | 786 | break; |
743 | case TOMOYO_TRANSITION_CONTROL_KEEP: | 787 | case TOMOYO_TRANSITION_CONTROL_KEEP: |
788 | force_keep_domain: | ||
744 | /* Keep current domain. */ | 789 | /* Keep current domain. */ |
745 | domain = old_domain; | 790 | domain = old_domain; |
746 | break; | 791 | break; |
@@ -756,11 +801,13 @@ retry: | |||
756 | domain = old_domain; | 801 | domain = old_domain; |
757 | break; | 802 | break; |
758 | } | 803 | } |
804 | force_child_domain: | ||
759 | /* Normal domain transition. */ | 805 | /* Normal domain transition. */ |
760 | snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", | 806 | snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", |
761 | old_domain->domainname->name, candidate->name); | 807 | old_domain->domainname->name, candidate->name); |
762 | break; | 808 | break; |
763 | } | 809 | } |
810 | force_jump_domain: | ||
764 | if (!domain) | 811 | if (!domain) |
765 | domain = tomoyo_assign_domain(ee->tmp, true); | 812 | domain = tomoyo_assign_domain(ee->tmp, true); |
766 | if (domain) | 813 | if (domain) |
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 743c35f5084..b280c1bd652 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c | |||
@@ -570,16 +570,42 @@ int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, | |||
570 | do { | 570 | do { |
571 | tomoyo_check_acl(r, tomoyo_check_path_acl); | 571 | tomoyo_check_acl(r, tomoyo_check_path_acl); |
572 | error = tomoyo_audit_path_log(r); | 572 | error = tomoyo_audit_path_log(r); |
573 | /* | 573 | } while (error == TOMOYO_RETRY_REQUEST); |
574 | * Do not retry for execute request, for alias may have | ||
575 | * changed. | ||
576 | */ | ||
577 | } while (error == TOMOYO_RETRY_REQUEST && | ||
578 | operation != TOMOYO_TYPE_EXECUTE); | ||
579 | return error; | 574 | return error; |
580 | } | 575 | } |
581 | 576 | ||
582 | /** | 577 | /** |
578 | * tomoyo_execute_permission - Check permission for execute operation. | ||
579 | * | ||
580 | * @r: Pointer to "struct tomoyo_request_info". | ||
581 | * @filename: Filename to check. | ||
582 | * | ||
583 | * Returns 0 on success, negative value otherwise. | ||
584 | * | ||
585 | * Caller holds tomoyo_read_lock(). | ||
586 | */ | ||
587 | int tomoyo_execute_permission(struct tomoyo_request_info *r, | ||
588 | const struct tomoyo_path_info *filename) | ||
589 | { | ||
590 | /* | ||
591 | * Unlike other permission checks, this check is done regardless of | ||
592 | * profile mode settings in order to check for domain transition | ||
593 | * preference. | ||
594 | */ | ||
595 | r->type = TOMOYO_MAC_FILE_EXECUTE; | ||
596 | r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type); | ||
597 | r->param_type = TOMOYO_TYPE_PATH_ACL; | ||
598 | r->param.path.filename = filename; | ||
599 | r->param.path.operation = TOMOYO_TYPE_EXECUTE; | ||
600 | tomoyo_check_acl(r, tomoyo_check_path_acl); | ||
601 | r->ee->transition = r->matched_acl && r->matched_acl->cond ? | ||
602 | r->matched_acl->cond->transit : NULL; | ||
603 | if (r->mode != TOMOYO_CONFIG_DISABLED) | ||
604 | return tomoyo_audit_path_log(r); | ||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | /** | ||
583 | * tomoyo_same_path_number_acl - Check for duplicated "struct tomoyo_path_number_acl" entry. | 609 | * tomoyo_same_path_number_acl - Check for duplicated "struct tomoyo_path_number_acl" entry. |
584 | * | 610 | * |
585 | * @a: Pointer to "struct tomoyo_acl_info". | 611 | * @a: Pointer to "struct tomoyo_acl_info". |