aboutsummaryrefslogtreecommitdiffstats
path: root/security/tomoyo
diff options
context:
space:
mode:
authorTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>2011-09-16 09:54:25 -0400
committerJames Morris <jmorris@namei.org>2011-09-18 20:09:59 -0400
commit6bce98edc3365a8f780ff3944ac7992544c194fe (patch)
treeee10abf2345f651d65d7f10fd385c01e0dc891b3 /security/tomoyo
parentcc100551b4d92f47abebfa7c7918b2be71263b4a (diff)
TOMOYO: Allow specifying domain transition preference.
I got an opinion that it is difficult to use exception policy's domain transition control directives because they need to match the pathname specified to "file execute" directives. For example, if "file execute /bin/\*\-ls\-cat" is given, corresponding domain transition control directive needs to be like "no_keep_domain /bin/\*\-ls\-cat from any". If we can specify like below, it will become more convenient. file execute /bin/ls keep exec.realpath="/bin/ls" exec.argv[0]="ls" file execute /bin/cat keep exec.realpath="/bin/cat" exec.argv[0]="cat" file execute /bin/\*\-ls\-cat child file execute /usr/sbin/httpd <apache> exec.realpath="/usr/sbin/httpd" exec.argv[0]="/usr/sbin/httpd" In above examples, "keep" works as if keep_domain is specified, "child" works as if "no_reset_domain" and "no_initialize_domain" and "no_keep_domain" are specified, "<apache>" causes domain transition to <apache> domain upon successful execve() operation. Moreover, we can also allow transition to different domains based on conditions like below example. <kernel> /usr/sbin/sshd file execute /bin/bash <kernel> /usr/sbin/sshd //batch-session exec.argc=2 exec.argv[1]="-c" file execute /bin/bash <kernel> /usr/sbin/sshd //root-session task.uid=0 file execute /bin/bash <kernel> /usr/sbin/sshd //nonroot-session task.uid!=0 Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/tomoyo')
-rw-r--r--security/tomoyo/common.c4
-rw-r--r--security/tomoyo/common.h4
-rw-r--r--security/tomoyo/condition.c50
-rw-r--r--security/tomoyo/domain.c53
-rw-r--r--security/tomoyo/file.c38
5 files changed, 137 insertions, 12 deletions
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c
index 084018351b4f..0994948f3edc 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 471c9f9afc18..a2bc33fc60b6 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);
957int tomoyo_close_control(struct tomoyo_io_buffer *head); 959int tomoyo_close_control(struct tomoyo_io_buffer *head);
958int tomoyo_env_perm(struct tomoyo_request_info *r, const char *env); 960int tomoyo_env_perm(struct tomoyo_request_info *r, const char *env);
961int tomoyo_execute_permission(struct tomoyo_request_info *r,
962 const struct tomoyo_path_info *filename);
959int tomoyo_find_next_domain(struct linux_binprm *bprm); 963int tomoyo_find_next_domain(struct linux_binprm *bprm);
960int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile, 964int 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 3a05eb3e2a64..b854959c0fd4 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 */
439static 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));
461done:
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;
450rerun: 491rerun:
@@ -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 }
681out2:
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 a1fc6b5f6125..860390ee1fbe 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:
771force_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:
782force_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:
788force_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 }
804force_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 }
810force_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 743c35f5084a..b280c1bd652d 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 */
587int 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".