}
}
+static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = {
+ [TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE]
+ = TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN,
+ [TOMOYO_TRANSITION_CONTROL_INITIALIZE]
+ = TOMOYO_KEYWORD_INITIALIZE_DOMAIN,
+ [TOMOYO_TRANSITION_CONTROL_NO_KEEP] = TOMOYO_KEYWORD_NO_KEEP_DOMAIN,
+ [TOMOYO_TRANSITION_CONTROL_KEEP] = TOMOYO_KEYWORD_KEEP_DOMAIN
+};
+
/**
* tomoyo_write_exception_policy - Write exception policy.
*
{
char *data = head->write_buf;
bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE);
+ u8 i;
- if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_KEEP_DOMAIN))
- return tomoyo_write_domain_keeper_policy(data, false,
- is_delete);
- if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_KEEP_DOMAIN))
- return tomoyo_write_domain_keeper_policy(data, true, is_delete);
- if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_INITIALIZE_DOMAIN))
- return tomoyo_write_domain_initializer_policy(data, false,
- is_delete);
- if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN))
- return tomoyo_write_domain_initializer_policy(data, true,
- is_delete);
+ for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++) {
+ if (tomoyo_str_starts(&data, tomoyo_transition_type[i]))
+ return tomoyo_write_transition_control(data, is_delete,
+ i);
+ }
if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_AGGREGATOR))
return tomoyo_write_aggregator_policy(data, is_delete);
if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_READ))
if (acl->is_deleted)
continue;
switch (idx) {
- case TOMOYO_ID_DOMAIN_KEEPER:
+ case TOMOYO_ID_TRANSITION_CONTROL:
{
- struct tomoyo_domain_keeper_entry *ptr =
+ struct tomoyo_transition_control *ptr =
container_of(acl, typeof(*ptr), head);
- w[0] = ptr->is_not ?
- TOMOYO_KEYWORD_NO_KEEP_DOMAIN :
- TOMOYO_KEYWORD_KEEP_DOMAIN;
- if (ptr->program) {
+ w[0] = tomoyo_transition_type[ptr->type];
+ if (ptr->program)
w[1] = ptr->program->name;
- w[2] = " from ";
- }
- w[3] = ptr->domainname->name;
- }
- break;
- case TOMOYO_ID_DOMAIN_INITIALIZER:
- {
- struct tomoyo_domain_initializer_entry *ptr =
- container_of(acl, typeof(*ptr), head);
- w[0] = ptr->is_not ?
- TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN :
- TOMOYO_KEYWORD_INITIALIZE_DOMAIN;
- w[1] = ptr->program->name;
- if (ptr->domainname) {
- w[2] = " from ";
+ if (ptr->domainname)
w[3] = ptr->domainname->name;
- }
+ if (w[1][0] && w[3][0])
+ w[2] = " from ";
}
break;
case TOMOYO_ID_GLOBALLY_READABLE:
TOMOYO_ID_GROUP,
TOMOYO_ID_PATH_GROUP,
TOMOYO_ID_NUMBER_GROUP,
- TOMOYO_ID_DOMAIN_INITIALIZER,
- TOMOYO_ID_DOMAIN_KEEPER,
+ TOMOYO_ID_TRANSITION_CONTROL,
TOMOYO_ID_AGGREGATOR,
TOMOYO_ID_GLOBALLY_READABLE,
TOMOYO_ID_PATTERN,
#define TOMOYO_VALUE_TYPE_OCTAL 2
#define TOMOYO_VALUE_TYPE_HEXADECIMAL 3
+enum tomoyo_transition_type {
+ /* Do not change this order, */
+ TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE,
+ TOMOYO_TRANSITION_CONTROL_INITIALIZE,
+ TOMOYO_TRANSITION_CONTROL_NO_KEEP,
+ TOMOYO_TRANSITION_CONTROL_KEEP,
+ TOMOYO_MAX_TRANSITION_TYPE
+};
+
/* Index numbers for Access Controls. */
enum tomoyo_acl_entry_type_index {
TOMOYO_TYPE_PATH_ACL,
};
/*
- * tomoyo_domain_initializer_entry is a structure which is used for holding
- * "initialize_domain" and "no_initialize_domain" entries.
+ * tomoyo_transition_control is a structure which is used for holding
+ * "initialize_domain"/"no_initialize_domain"/"keep_domain"/"no_keep_domain"
+ * entries.
* It has following fields.
*
* (1) "head" is "struct tomoyo_acl_head".
- * (2) "is_not" is a bool which is true if "no_initialize_domain", false
- * otherwise.
- * (3) "is_last_name" is a bool which is true if "domainname" is "the last
- * component of a domainname", false otherwise.
- * (4) "domainname" which is "a domainname" or "the last component of a
- * domainname". This field is NULL if "from" clause is not specified.
- * (5) "program" which is a program's pathname.
- */
-struct tomoyo_domain_initializer_entry {
- struct tomoyo_acl_head head;
- bool is_not; /* True if this entry is "no_initialize_domain". */
- /* True if the domainname is tomoyo_get_last_name(). */
- bool is_last_name;
- const struct tomoyo_path_info *domainname; /* This may be NULL */
- const struct tomoyo_path_info *program;
-};
-
-/*
- * tomoyo_domain_keeper_entry is a structure which is used for holding
- * "keep_domain" and "no_keep_domain" entries.
- * It has following fields.
- *
- * (1) "head" is "struct tomoyo_acl_head".
- * (2) "is_not" is a bool which is true if "no_initialize_domain", false
- * otherwise.
+ * (2) "type" is type of this entry.
* (3) "is_last_name" is a bool which is true if "domainname" is "the last
* component of a domainname", false otherwise.
* (4) "domainname" which is "a domainname" or "the last component of a
* domainname".
* (5) "program" which is a program's pathname.
- * This field is NULL if "from" clause is not specified.
*/
-struct tomoyo_domain_keeper_entry {
+struct tomoyo_transition_control {
struct tomoyo_acl_head head;
- bool is_not; /* True if this entry is "no_keep_domain". */
+ u8 type; /* One of values in "enum tomoyo_transition_type". */
/* True if the domainname is tomoyo_get_last_name(). */
bool is_last_name;
- const struct tomoyo_path_info *domainname;
- const struct tomoyo_path_info *program; /* This may be NULL */
+ const struct tomoyo_path_info *domainname; /* Maybe NULL */
+ const struct tomoyo_path_info *program; /* Maybe NULL */
};
/*
unsigned long flags, void *data_page);
/* Create "aggregator" entry in exception policy. */
int tomoyo_write_aggregator_policy(char *data, const bool is_delete);
-/*
- * Create "initialize_domain" and "no_initialize_domain" entry
- * in exception policy.
- */
-int tomoyo_write_domain_initializer_policy(char *data, const bool is_not,
- const bool is_delete);
-/* Create "keep_domain" and "no_keep_domain" entry in exception policy. */
-int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
- const bool is_delete);
+int tomoyo_write_transition_control(char *data, const bool is_delete,
+ const u8 type);
/*
* Create "allow_read/write", "allow_execute", "allow_read", "allow_write",
* "allow_create", "allow_unlink", "allow_mkdir", "allow_rmdir",
void tomoyo_check_acl(struct tomoyo_request_info *r,
bool (*check_entry) (const struct tomoyo_request_info *,
const struct tomoyo_acl_info *));
+const char *tomoyo_last_word(const char *name);
/********** External variable definitions. **********/
return cp0;
}
-static bool tomoyo_same_domain_initializer_entry(const struct tomoyo_acl_head *
+static bool tomoyo_same_transition_control_entry(const struct tomoyo_acl_head *
a,
const struct tomoyo_acl_head *
b)
{
- const struct tomoyo_domain_initializer_entry *p1 =
- container_of(a, typeof(*p1), head);
- const struct tomoyo_domain_initializer_entry *p2 =
- container_of(b, typeof(*p2), head);
- return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name
+ const struct tomoyo_transition_control *p1 = container_of(a,
+ typeof(*p1),
+ head);
+ const struct tomoyo_transition_control *p2 = container_of(b,
+ typeof(*p2),
+ head);
+ return p1->type == p2->type && p1->is_last_name == p2->is_last_name
&& p1->domainname == p2->domainname
&& p1->program == p2->program;
}
/**
- * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list.
+ * tomoyo_update_transition_control_entry - Update "struct tomoyo_transition_control" list.
*
- * @domainname: The name of domain. May be NULL.
- * @program: The name of program.
- * @is_not: True if it is "no_initialize_domain" entry.
+ * @domainname: The name of domain. Maybe NULL.
+ * @program: The name of program. Maybe NULL.
+ * @type: Type of transition.
* @is_delete: True if it is a delete request.
*
* Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
*/
-static int tomoyo_update_domain_initializer_entry(const char *domainname,
+static int tomoyo_update_transition_control_entry(const char *domainname,
const char *program,
- const bool is_not,
+ const u8 type,
const bool is_delete)
{
- struct tomoyo_domain_initializer_entry e = { .is_not = is_not };
+ struct tomoyo_transition_control e = { .type = type };
int error = is_delete ? -ENOENT : -ENOMEM;
-
- if (!tomoyo_correct_path(program))
- return -EINVAL;
+ if (program) {
+ if (!tomoyo_correct_path(program))
+ return -EINVAL;
+ e.program = tomoyo_get_name(program);
+ if (!e.program)
+ goto out;
+ }
if (domainname) {
- if (!tomoyo_domain_def(domainname) &&
- tomoyo_correct_path(domainname))
+ if (!tomoyo_correct_domain(domainname)) {
+ if (!tomoyo_correct_path(domainname))
+ goto out;
e.is_last_name = true;
- else if (!tomoyo_correct_domain(domainname))
- return -EINVAL;
+ }
e.domainname = tomoyo_get_name(domainname);
if (!e.domainname)
goto out;
}
- e.program = tomoyo_get_name(program);
- if (!e.program)
- goto out;
error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
&tomoyo_policy_list
- [TOMOYO_ID_DOMAIN_INITIALIZER],
- tomoyo_same_domain_initializer_entry);
+ [TOMOYO_ID_TRANSITION_CONTROL],
+ tomoyo_same_transition_control_entry);
out:
tomoyo_put_name(e.domainname);
tomoyo_put_name(e.program);
}
/**
- * tomoyo_write_domain_initializer_policy - Write "struct tomoyo_domain_initializer_entry" list.
+ * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list.
*
* @data: String to parse.
- * @is_not: True if it is "no_initialize_domain" entry.
* @is_delete: True if it is a delete request.
+ * @type: Type of this entry.
*
* Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
*/
-int tomoyo_write_domain_initializer_policy(char *data, const bool is_not,
- const bool is_delete)
+int tomoyo_write_transition_control(char *data, const bool is_delete,
+ const u8 type)
{
- char *cp = strstr(data, " from ");
-
- if (cp) {
- *cp = '\0';
- return tomoyo_update_domain_initializer_entry(cp + 6, data,
- is_not,
- is_delete);
+ char *domainname = strstr(data, " from ");
+ if (domainname) {
+ *domainname = '\0';
+ domainname += 6;
+ } else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP ||
+ type == TOMOYO_TRANSITION_CONTROL_KEEP) {
+ domainname = data;
+ data = NULL;
}
- return tomoyo_update_domain_initializer_entry(NULL, data, is_not,
+ return tomoyo_update_transition_control_entry(domainname, data, type,
is_delete);
}
/**
- * tomoyo_domain_initializer - Check whether the given program causes domainname reinitialization.
+ * tomoyo_transition_type - Get domain transition type.
*
* @domainname: The name of domain.
* @program: The name of program.
- * @last_name: The last component of @domainname.
*
- * Returns true if executing @program reinitializes domain transition,
- * false otherwise.
+ * Returns TOMOYO_TRANSITION_CONTROL_INITIALIZE if executing @program
+ * reinitializes domain transition, TOMOYO_TRANSITION_CONTROL_KEEP if executing
+ * @program suppresses domain transition, others otherwise.
*
* Caller holds tomoyo_read_lock().
*/
-static bool tomoyo_domain_initializer(const struct tomoyo_path_info *
- domainname,
- const struct tomoyo_path_info *program,
- const struct tomoyo_path_info *
- last_name)
+static u8 tomoyo_transition_type(const struct tomoyo_path_info *domainname,
+ const struct tomoyo_path_info *program)
{
- struct tomoyo_domain_initializer_entry *ptr;
- bool flag = false;
-
- list_for_each_entry_rcu(ptr, &tomoyo_policy_list
- [TOMOYO_ID_DOMAIN_INITIALIZER], head.list) {
- if (ptr->head.is_deleted)
- continue;
- if (ptr->domainname) {
- if (!ptr->is_last_name) {
- if (ptr->domainname != domainname)
- continue;
- } else {
- if (tomoyo_pathcmp(ptr->domainname, last_name))
- continue;
- }
- }
- if (tomoyo_pathcmp(ptr->program, program))
- continue;
- if (ptr->is_not) {
- flag = false;
- break;
- }
- flag = true;
- }
- return flag;
-}
-
-static bool tomoyo_same_domain_keeper_entry(const struct tomoyo_acl_head *a,
- const struct tomoyo_acl_head *b)
-{
- const struct tomoyo_domain_keeper_entry *p1 =
- container_of(a, typeof(*p1), head);
- const struct tomoyo_domain_keeper_entry *p2 =
- container_of(b, typeof(*p2), head);
- return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name
- && p1->domainname == p2->domainname
- && p1->program == p2->program;
-}
-
-/**
- * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list.
- *
- * @domainname: The name of domain.
- * @program: The name of program. May be NULL.
- * @is_not: True if it is "no_keep_domain" entry.
- * @is_delete: True if it is a delete request.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_update_domain_keeper_entry(const char *domainname,
- const char *program,
- const bool is_not,
- const bool is_delete)
-{
- struct tomoyo_domain_keeper_entry e = { .is_not = is_not };
- int error = is_delete ? -ENOENT : -ENOMEM;
-
- if (!tomoyo_domain_def(domainname) &&
- tomoyo_correct_path(domainname))
- e.is_last_name = true;
- else if (!tomoyo_correct_domain(domainname))
- return -EINVAL;
- if (program) {
- if (!tomoyo_correct_path(program))
- return -EINVAL;
- e.program = tomoyo_get_name(program);
- if (!e.program)
- goto out;
- }
- e.domainname = tomoyo_get_name(domainname);
- if (!e.domainname)
- goto out;
- error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
- &tomoyo_policy_list
- [TOMOYO_ID_DOMAIN_KEEPER],
- tomoyo_same_domain_keeper_entry);
- out:
- tomoyo_put_name(e.domainname);
- tomoyo_put_name(e.program);
- return error;
-}
-
-/**
- * tomoyo_write_domain_keeper_policy - Write "struct tomoyo_domain_keeper_entry" list.
- *
- * @data: String to parse.
- * @is_not: True if it is "no_keep_domain" entry.
- * @is_delete: True if it is a delete request.
- *
- * Caller holds tomoyo_read_lock().
- */
-int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
- const bool is_delete)
-{
- char *cp = strstr(data, " from ");
-
- if (cp) {
- *cp = '\0';
- return tomoyo_update_domain_keeper_entry(cp + 6, data, is_not,
- is_delete);
- }
- return tomoyo_update_domain_keeper_entry(data, NULL, is_not, is_delete);
-}
-
-/**
- * tomoyo_domain_keeper - Check whether the given program causes domain transition suppression.
- *
- * @domainname: The name of domain.
- * @program: The name of program.
- * @last_name: The last component of @domainname.
- *
- * Returns true if executing @program supresses domain transition,
- * false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static bool tomoyo_domain_keeper(const struct tomoyo_path_info *domainname,
- const struct tomoyo_path_info *program,
- const struct tomoyo_path_info *last_name)
-{
- struct tomoyo_domain_keeper_entry *ptr;
- bool flag = false;
-
- list_for_each_entry_rcu(ptr,
- &tomoyo_policy_list[TOMOYO_ID_DOMAIN_KEEPER],
- head.list) {
- if (ptr->head.is_deleted)
- continue;
- if (!ptr->is_last_name) {
- if (ptr->domainname != domainname)
+ const struct tomoyo_transition_control *ptr;
+ const char *last_name = tomoyo_last_word(domainname->name);
+ u8 type;
+ for (type = 0; type < TOMOYO_MAX_TRANSITION_TYPE; type++) {
+ next:
+ list_for_each_entry_rcu(ptr, &tomoyo_policy_list
+ [TOMOYO_ID_TRANSITION_CONTROL],
+ head.list) {
+ if (ptr->head.is_deleted || ptr->type != type)
continue;
- } else {
- if (tomoyo_pathcmp(ptr->domainname, last_name))
+ if (ptr->domainname) {
+ if (!ptr->is_last_name) {
+ if (ptr->domainname != domainname)
+ continue;
+ } else {
+ /*
+ * Use direct strcmp() since this is
+ * unlikely used.
+ */
+ if (strcmp(ptr->domainname->name,
+ last_name))
+ continue;
+ }
+ }
+ if (ptr->program &&
+ tomoyo_pathcmp(ptr->program, program))
continue;
+ if (type == TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE) {
+ /*
+ * Do not check for initialize_domain if
+ * no_initialize_domain matched.
+ */
+ type = TOMOYO_TRANSITION_CONTROL_NO_KEEP;
+ goto next;
+ }
+ goto done;
}
- if (ptr->program && tomoyo_pathcmp(ptr->program, program))
- continue;
- if (ptr->is_not) {
- flag = false;
- break;
- }
- flag = true;
}
- return flag;
+ done:
+ return type;
}
static bool tomoyo_same_aggregator_entry(const struct tomoyo_acl_head *a,
char *tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
struct tomoyo_domain_info *old_domain = tomoyo_domain();
struct tomoyo_domain_info *domain = NULL;
- const char *old_domain_name = old_domain->domainname->name;
const char *original_name = bprm->filename;
u8 mode;
bool is_enforce;
if (retval < 0)
goto out;
- if (tomoyo_domain_initializer(old_domain->domainname, &rn, &ln)) {
+ /* Calculate domain to transit to. */
+ switch (tomoyo_transition_type(old_domain->domainname, &rn)) {
+ case TOMOYO_TRANSITION_CONTROL_INITIALIZE:
/* Transit to the child of tomoyo_kernel_domain domain. */
- snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1,
- TOMOYO_ROOT_NAME " " "%s", rn.name);
- } else if (old_domain == &tomoyo_kernel_domain &&
- !tomoyo_policy_loaded) {
- /*
- * Needn't to transit from kernel domain before starting
- * /sbin/init. But transit from kernel domain if executing
- * initializers because they might start before /sbin/init.
- */
- domain = old_domain;
- } else if (tomoyo_domain_keeper(old_domain->domainname, &rn, &ln)) {
+ snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, TOMOYO_ROOT_NAME " "
+ "%s", rn.name);
+ break;
+ case TOMOYO_TRANSITION_CONTROL_KEEP:
/* Keep current domain. */
domain = old_domain;
- } else {
- /* Normal domain transition. */
- snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1,
- "%s %s", old_domain_name, rn.name);
+ break;
+ default:
+ if (old_domain == &tomoyo_kernel_domain &&
+ !tomoyo_policy_loaded) {
+ /*
+ * Needn't to transit from kernel domain before
+ * starting /sbin/init. But transit from kernel domain
+ * if executing initializers because they might start
+ * before /sbin/init.
+ */
+ domain = old_domain;
+ } else {
+ /* Normal domain transition. */
+ snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
+ old_domain->domainname->name, rn.name);
+ }
+ break;
}
if (domain || strlen(tmp) >= TOMOYO_EXEC_TMPSIZE - 10)
goto done;