/*
* security/tomoyo/domain.c
*
- * Domain transition functions for TOMOYO.
- *
- * Copyright (C) 2005-2010 NTT DATA CORPORATION
+ * Copyright (C) 2005-2011 NTT DATA CORPORATION
*/
#include "common.h"
static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *a,
const struct tomoyo_acl_info *b)
{
- return a->type == b->type;
+ return a->type == b->type && a->cond == b->cond;
}
/**
struct tomoyo_acl_info *entry;
struct list_head * const list = param->list;
+ if (param->data[0]) {
+ new_entry->cond = tomoyo_get_condition(param);
+ if (!new_entry->cond)
+ return -EINVAL;
+ }
if (mutex_lock_interruptible(&tomoyo_policy_lock))
- return error;
+ goto out;
list_for_each_entry_rcu(entry, list, list) {
if (!tomoyo_same_acl_head(entry, new_entry) ||
!check_duplicate(entry, new_entry))
}
}
mutex_unlock(&tomoyo_policy_lock);
+out:
+ tomoyo_put_condition(new_entry->cond);
return error;
}
list_for_each_entry_rcu(ptr, list, list) {
if (ptr->is_deleted || ptr->type != r->param_type)
continue;
- if (check_entry(r, ptr)) {
- r->granted = true;
- return;
- }
+ if (!check_entry(r, ptr))
+ continue;
+ if (!tomoyo_condition(r, ptr->cond))
+ continue;
+ r->granted = true;
+ return;
}
if (!retried) {
retried = true;
*/
static const char *tomoyo_last_word(const char *name)
{
- const char *cp = strrchr(name, ' ');
- if (cp)
- return cp + 1;
- return name;
+ const char *cp = strrchr(name, ' ');
+ if (cp)
+ return cp + 1;
+ return name;
}
/**
*/
int tomoyo_find_next_domain(struct linux_binprm *bprm)
{
- struct tomoyo_request_info r;
- char *tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
struct tomoyo_domain_info *old_domain = tomoyo_domain();
struct tomoyo_domain_info *domain = NULL;
const char *original_name = bprm->filename;
- u8 mode;
- bool is_enforce;
int retval = -ENOMEM;
bool need_kfree = false;
bool reject_on_transition_failure = false;
struct tomoyo_path_info rn = { }; /* real name */
-
- mode = tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE);
- is_enforce = (mode == TOMOYO_CONFIG_ENFORCING);
- if (!tmp)
- goto out;
-
+ struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS);
+ if (!ee)
+ return -ENOMEM;
+ ee->tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
+ if (!ee->tmp) {
+ kfree(ee);
+ return -ENOMEM;
+ }
+ /* ee->dump->data is allocated by tomoyo_dump_page(). */
+ tomoyo_init_request_info(&ee->r, NULL, TOMOYO_MAC_FILE_EXECUTE);
+ ee->r.ee = ee;
+ ee->bprm = bprm;
+ ee->r.obj = &ee->obj;
+ ee->obj.path1 = bprm->file->f_path;
retry:
if (need_kfree) {
kfree(rn.name);
}
/* Check execute permission. */
- retval = tomoyo_path_permission(&r, TOMOYO_TYPE_EXECUTE, &rn);
+ retval = tomoyo_path_permission(&ee->r, TOMOYO_TYPE_EXECUTE, &rn);
if (retval == TOMOYO_RETRY_REQUEST)
goto retry;
if (retval < 0)
* wildcard) rather than the pathname passed to execve()
* (which never contains wildcard).
*/
- if (r.param.path.matched_path) {
+ if (ee->r.param.path.matched_path) {
if (need_kfree)
kfree(rn.name);
need_kfree = false;
/* This is OK because it is read only. */
- rn = *r.param.path.matched_path;
+ rn = *ee->r.param.path.matched_path;
}
/* Calculate domain to transit to. */
&rn)) {
case TOMOYO_TRANSITION_CONTROL_RESET:
/* Transit to the root of specified namespace. */
- snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", rn.name);
+ snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", rn.name);
/*
* Make do_execve() fail if domain transition across namespaces
* has failed.
break;
case TOMOYO_TRANSITION_CONTROL_INITIALIZE:
/* Transit to the child of current namespace's root. */
- snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
+ snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
old_domain->ns->name, rn.name);
break;
case TOMOYO_TRANSITION_CONTROL_KEEP:
domain = old_domain;
} else {
/* Normal domain transition. */
- snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
+ snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
old_domain->domainname->name, rn.name);
}
break;
}
if (!domain)
- domain = tomoyo_assign_domain(tmp, true);
+ domain = tomoyo_assign_domain(ee->tmp, true);
if (domain)
retval = 0;
else if (reject_on_transition_failure) {
- printk(KERN_WARNING "ERROR: Domain '%s' not ready.\n", tmp);
+ printk(KERN_WARNING "ERROR: Domain '%s' not ready.\n",
+ ee->tmp);
retval = -ENOMEM;
- } else if (r.mode == TOMOYO_CONFIG_ENFORCING)
+ } else if (ee->r.mode == TOMOYO_CONFIG_ENFORCING)
retval = -ENOMEM;
else {
retval = 0;
if (!old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED]) {
old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED] = true;
- r.granted = false;
- tomoyo_write_log(&r, "%s", tomoyo_dif
+ ee->r.granted = false;
+ tomoyo_write_log(&ee->r, "%s", tomoyo_dif
[TOMOYO_DIF_TRANSITION_FAILED]);
printk(KERN_WARNING
- "ERROR: Domain '%s' not defined.\n", tmp);
+ "ERROR: Domain '%s' not defined.\n", ee->tmp);
}
}
out:
bprm->cred->security = domain;
if (need_kfree)
kfree(rn.name);
- kfree(tmp);
+ kfree(ee->tmp);
+ kfree(ee->dump.data);
+ kfree(ee);
return retval;
}
+
+/**
+ * tomoyo_dump_page - Dump a page to buffer.
+ *
+ * @bprm: Pointer to "struct linux_binprm".
+ * @pos: Location to dump.
+ * @dump: Poiner to "struct tomoyo_page_dump".
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
+ struct tomoyo_page_dump *dump)
+{
+ struct page *page;
+ /* dump->data is released by tomoyo_finish_execve(). */
+ if (!dump->data) {
+ dump->data = kzalloc(PAGE_SIZE, GFP_NOFS);
+ if (!dump->data)
+ return false;
+ }
+ /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
+#ifdef CONFIG_MMU
+ if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
+ return false;
+#else
+ page = bprm->page[pos / PAGE_SIZE];
+#endif
+ if (page != dump->page) {
+ const unsigned int offset = pos % PAGE_SIZE;
+ /*
+ * Maybe kmap()/kunmap() should be used here.
+ * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic().
+ * So do I.
+ */
+ char *kaddr = kmap_atomic(page, KM_USER0);
+ dump->page = page;
+ memcpy(dump->data + offset, kaddr + offset,
+ PAGE_SIZE - offset);
+ kunmap_atomic(kaddr, KM_USER0);
+ }
+ /* Same with put_arg_page(page) in fs/exec.c */
+#ifdef CONFIG_MMU
+ put_page(page);
+#endif
+ return true;
+}