Skip to content

Commit

Permalink
TOMOYO: Allow specifying domain transition preference.
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: James Morris <[email protected]>
  • Loading branch information
Tetsuo Handa authored and James Morris committed Sep 19, 2011
1 parent cc10055 commit 6bce98e
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 12 deletions.
4 changes: 4 additions & 0 deletions security/tomoyo/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -1203,6 +1203,10 @@ static bool tomoyo_print_condition(struct tomoyo_io_buffer *head,
case 0:
head->r.cond_index = 0;
head->r.cond_step++;
if (cond->transit) {
tomoyo_set_space(head);
tomoyo_set_string(head, cond->transit->name);
}
/* fall through */
case 1:
{
Expand Down
4 changes: 4 additions & 0 deletions security/tomoyo/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,7 @@ struct tomoyo_execve {
struct tomoyo_request_info r;
struct tomoyo_obj_info obj;
struct linux_binprm *bprm;
const struct tomoyo_path_info *transition;
/* For dumping argv[] and envp[]. */
struct tomoyo_page_dump dump;
/* For temporary use. */
Expand Down Expand Up @@ -650,6 +651,7 @@ struct tomoyo_condition {
u16 argc; /* Number of "struct tomoyo_argv". */
u16 envc; /* Number of "struct tomoyo_envp". */
u8 grant_log; /* One of values in "enum tomoyo_grant_log". */
const struct tomoyo_path_info *transit; /* Maybe NULL. */
/*
* struct tomoyo_condition_element condition[condc];
* struct tomoyo_number_union values[numbers_count];
Expand Down Expand Up @@ -956,6 +958,8 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
struct path *path, const int flag);
int tomoyo_close_control(struct tomoyo_io_buffer *head);
int tomoyo_env_perm(struct tomoyo_request_info *r, const char *env);
int tomoyo_execute_permission(struct tomoyo_request_info *r,
const struct tomoyo_path_info *filename);
int tomoyo_find_next_domain(struct linux_binprm *bprm);
int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile,
const u8 index);
Expand Down
50 changes: 47 additions & 3 deletions security/tomoyo/condition.c
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ static inline bool tomoyo_same_condition(const struct tomoyo_condition *a,
a->numbers_count == b->numbers_count &&
a->names_count == b->names_count &&
a->argc == b->argc && a->envc == b->envc &&
a->grant_log == b->grant_log &&
a->grant_log == b->grant_log && a->transit == b->transit &&
!memcmp(a + 1, b + 1, a->size - sizeof(*a));
}

Expand Down Expand Up @@ -428,6 +428,46 @@ static struct tomoyo_condition *tomoyo_commit_condition
return entry;
}

/**
* tomoyo_get_transit_preference - Parse domain transition preference for execve().
*
* @param: Pointer to "struct tomoyo_acl_param".
* @e: Pointer to "struct tomoyo_condition".
*
* Returns the condition string part.
*/
static char *tomoyo_get_transit_preference(struct tomoyo_acl_param *param,
struct tomoyo_condition *e)
{
char * const pos = param->data;
bool flag;
if (*pos == '<') {
e->transit = tomoyo_get_domainname(param);
goto done;
}
{
char *cp = strchr(pos, ' ');
if (cp)
*cp = '\0';
flag = tomoyo_correct_path(pos) || !strcmp(pos, "keep") ||
!strcmp(pos, "initialize") || !strcmp(pos, "reset") ||
!strcmp(pos, "child") || !strcmp(pos, "parent");
if (cp)
*cp = ' ';
}
if (!flag)
return pos;
e->transit = tomoyo_get_name(tomoyo_read_token(param));
done:
if (e->transit)
return param->data;
/*
* Return a bad read-only condition string that will let
* tomoyo_get_condition() return NULL.
*/
return "/";
}

/**
* tomoyo_get_condition - Parse condition part.
*
Expand All @@ -444,7 +484,8 @@ struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param)
struct tomoyo_argv *argv = NULL;
struct tomoyo_envp *envp = NULL;
struct tomoyo_condition e = { };
char * const start_of_string = param->data;
char * const start_of_string =
tomoyo_get_transit_preference(param, &e);
char * const end_of_string = start_of_string + strlen(start_of_string);
char *pos;
rerun:
Expand Down Expand Up @@ -608,8 +649,9 @@ struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param)
+ e.envc * sizeof(struct tomoyo_envp);
entry = kzalloc(e.size, GFP_NOFS);
if (!entry)
return NULL;
goto out2;
*entry = e;
e.transit = NULL;
condp = (struct tomoyo_condition_element *) (entry + 1);
numbers_p = (struct tomoyo_number_union *) (condp + e.condc);
names_p = (struct tomoyo_name_union *) (numbers_p + e.numbers_count);
Expand All @@ -636,6 +678,8 @@ struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param)
tomoyo_del_condition(&entry->head.list);
kfree(entry);
}
out2:
tomoyo_put_name(e.transit);
return NULL;
}

Expand Down
53 changes: 50 additions & 3 deletions security/tomoyo/domain.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,15 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
new_entry->cond = tomoyo_get_condition(param);
if (!new_entry->cond)
return -EINVAL;
/*
* Domain transition preference is allowed for only
* "file execute" entries.
*/
if (new_entry->cond->transit &&
!(new_entry->type == TOMOYO_TYPE_PATH_ACL &&
container_of(new_entry, struct tomoyo_path_acl, head)
->perm == 1 << TOMOYO_TYPE_EXECUTE))
goto out;
}
if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out;
Expand Down Expand Up @@ -707,8 +716,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
}

/* Check execute permission. */
retval = tomoyo_path_permission(&ee->r, TOMOYO_TYPE_EXECUTE,
candidate);
retval = tomoyo_execute_permission(&ee->r, candidate);
if (retval == TOMOYO_RETRY_REQUEST)
goto retry;
if (retval < 0)
Expand All @@ -722,10 +730,45 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
if (ee->r.param.path.matched_path)
candidate = ee->r.param.path.matched_path;

/* Calculate domain to transit to. */
/*
* Check for domain transition preference if "file execute" matched.
* If preference is given, make do_execve() fail if domain transition
* has failed, for domain transition preference should be used with
* destination domain defined.
*/
if (ee->transition) {
const char *domainname = ee->transition->name;
reject_on_transition_failure = true;
if (!strcmp(domainname, "keep"))
goto force_keep_domain;
if (!strcmp(domainname, "child"))
goto force_child_domain;
if (!strcmp(domainname, "reset"))
goto force_reset_domain;
if (!strcmp(domainname, "initialize"))
goto force_initialize_domain;
if (!strcmp(domainname, "parent")) {
char *cp;
strncpy(ee->tmp, old_domain->domainname->name,
TOMOYO_EXEC_TMPSIZE - 1);
cp = strrchr(ee->tmp, ' ');
if (cp)
*cp = '\0';
} else if (*domainname == '<')
strncpy(ee->tmp, domainname, TOMOYO_EXEC_TMPSIZE - 1);
else
snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
old_domain->domainname->name, domainname);
goto force_jump_domain;
}
/*
* No domain transition preference specified.
* Calculate domain to transit to.
*/
switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname,
candidate)) {
case TOMOYO_TRANSITION_CONTROL_RESET:
force_reset_domain:
/* Transit to the root of specified namespace. */
snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>",
candidate->name);
Expand All @@ -736,11 +779,13 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
reject_on_transition_failure = true;
break;
case TOMOYO_TRANSITION_CONTROL_INITIALIZE:
force_initialize_domain:
/* Transit to the child of current namespace's root. */
snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
old_domain->ns->name, candidate->name);
break;
case TOMOYO_TRANSITION_CONTROL_KEEP:
force_keep_domain:
/* Keep current domain. */
domain = old_domain;
break;
Expand All @@ -756,11 +801,13 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
domain = old_domain;
break;
}
force_child_domain:
/* Normal domain transition. */
snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
old_domain->domainname->name, candidate->name);
break;
}
force_jump_domain:
if (!domain)
domain = tomoyo_assign_domain(ee->tmp, true);
if (domain)
Expand Down
38 changes: 32 additions & 6 deletions security/tomoyo/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -570,15 +570,41 @@ int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
do {
tomoyo_check_acl(r, tomoyo_check_path_acl);
error = tomoyo_audit_path_log(r);
/*
* Do not retry for execute request, for alias may have
* changed.
*/
} while (error == TOMOYO_RETRY_REQUEST &&
operation != TOMOYO_TYPE_EXECUTE);
} while (error == TOMOYO_RETRY_REQUEST);
return error;
}

/**
* tomoyo_execute_permission - Check permission for execute operation.
*
* @r: Pointer to "struct tomoyo_request_info".
* @filename: Filename to check.
*
* Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/
int tomoyo_execute_permission(struct tomoyo_request_info *r,
const struct tomoyo_path_info *filename)
{
/*
* Unlike other permission checks, this check is done regardless of
* profile mode settings in order to check for domain transition
* preference.
*/
r->type = TOMOYO_MAC_FILE_EXECUTE;
r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type);
r->param_type = TOMOYO_TYPE_PATH_ACL;
r->param.path.filename = filename;
r->param.path.operation = TOMOYO_TYPE_EXECUTE;
tomoyo_check_acl(r, tomoyo_check_path_acl);
r->ee->transition = r->matched_acl && r->matched_acl->cond ?
r->matched_acl->cond->transit : NULL;
if (r->mode != TOMOYO_CONFIG_DISABLED)
return tomoyo_audit_path_log(r);
return 0;
}

/**
* tomoyo_same_path_number_acl - Check for duplicated "struct tomoyo_path_number_acl" entry.
*
Expand Down

0 comments on commit 6bce98e

Please sign in to comment.