[PATCH] TOMOYO: Add garbage collector support. (v2)

Tetsuo Handa
2009-05-14T12:08:39Z

A process who is reading/writing list elements has pointers which point to
(possibly marked-as-deleted) list elements and releases a lock when the process
leaves the kernel.

As of now, TOMOYO cannot release memory used by marked-as-deleted list elements
because TOMOYO does not manage list of pointers.

This patch makes TOMOYO to manage list of pointers and allows an administrator
release memory used by marked-as-deleted list elements.

Also, according to KOSAKI Motohiro's comment
( http://lkml.org/lkml/2009/5/10/176 ), I moved TOMOYO's
kmalloc(GFP_KERNEL)/kfree() calls to outside the rw_semaphore.

Attached patch is tested on security-testing-2.6#next.

Regards.
----------------------------------------
TOMOYO: Add garbage collector support.

A process who is reading/writing list elements has pointers which point to
(possibly marked-as-deleted) list elements and releases a lock when the process
leaves the kernel.

As of now, TOMOYO cannot release memory used by marked-as-deleted list elements
because TOMOYO does not manage list of pointers.

This patch makes TOMOYO to manage list of pointers and allows an administrator
release memory used by marked-as-deleted list elements.

Also, this patch makes TOMOYO's kmalloc(GFP_KERNEL)/kfree() calls go outside
the rw_semaphore.

Approach:

Define a cookie as

struct tomoyo_cookie {
struct list_head list;
union {
const void *ptr;
struct list_head *list;
struct tomoyo_domain_info *domain;
const struct tomoyo_path_info *path;
} u;
};

and add the cookie to the cookie's list using

void tomoyo_add_cookie(struct tomoyo_cookie *cookie, const void *ptr);

and delete the cookie from the cookie's list using

void tomoyo_del_cookie(struct tomoyo_cookie *cookie);

and update the "cookie->u.{ptr,list,domain,path}" between
down_read(&tomoyo_policy_lock); and up_read(&tomoyo_policy_lock); .

To keep the cookie's list up-to-date, tomoyo_add_cookie() and
tomoyo_del_cookie() take write lock of tomoyo_cookie_list_lock spinlock and
tomoyo_used_by_cookie() takes read lock of tomoyo_cookie_list_lock spinlock.

The garbage collector function scans the cookie's list using

bool tomoyo_used_by_cookie(const void *ptr);

between down_write(&tomoyo_policy_lock); and up_write(&tomoyo_policy_lock);
to determine whether "ptr" is kfree()able or not.

In this way, the garbage collector shall not release "ptr" stored in a cookie
in the cookie's list.

Memory Management Rules:

When reading list elements, a process takes tomoyo_policy_lock for reading.
When writing list elements, a process takes tomoyo_policy_lock for writing.

"struct tomoyo_io_buffer" remembers pointer to list elements.
Thus, TOMOYO memorizes the address of
"struct tomoyo_io_buffer"->read_cookie1
"struct tomoyo_io_buffer"->read_cookie2
"struct tomoyo_io_buffer"->write_cookie1
when a file in /sys/kernel/security/tomoyo/ interface is opened and forgets
them when that file is closed.

"struct task_struct"->cred->security also remembers pointer to list elements.
Thus, TOMOYO memorizes the address of cred->security at
security_cred_prepare() and forgets it at security_cred_free().

When /sys/kernel/security/tomoyo/ interface opened for writing is closed,
a garbage collector function is called. The garbage collector function takes
tomoyo_policy_lock for writing and traverses the lists and releases elements
if that element has is_deleted flag set and that element is no longer used.

Since strings are likely referenced by multiple list elements, this patch
assigns a refcounter to each string.
The policy add/del function increments the refcounter only if the element is
added to the list. The garbage collector function decrements the refcounter
only if the element is not referred by a process.
The garbage collector function releases memory of the string if the string's
refcounter becomes 0.

Signed-off-by: Kentaro Takeda <takedakn@nttdata.co.jp>
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: Toshiharu Harada <haradats@nttdata.co.jp>
---
security/tomoyo/common.c | 456 +++++++++++++++++++-----------------
security/tomoyo/common.h | 134 ++++++++--
security/tomoyo/domain.c | 437 +++++++++++++---------------------
security/tomoyo/file.c | 369 +++++++++++++++--------------
security/tomoyo/realpath.c | 567 ++++++++++++++++++++++++++++++++++-----------
security/tomoyo/realpath.h | 25 +
security/tomoyo/tomoyo.c | 40 +--
security/tomoyo/tomoyo.h | 13 -
8 files changed, 1190 insertions(+), 851 deletions(-)

--- security-testing-2.6.git.orig/security/tomoyo/common.c
+++ security-testing-2.6.git/security/tomoyo/common.c
@@ -12,8 +12,8 @@
#include <linux/uaccess.h>
#include <linux/security.h>
#include <linux/hardirq.h>
-#include "realpath.h"
#include "common.h"
+#include "realpath.h"
#include "tomoyo.h"

/* Has loading policy done? */
@@ -23,6 +23,7 @@ bool tomoyo_policy_loaded;
static const char *tomoyo_mode_4[4] = {
"disabled", "learning", "permissive", "enforcing"
};
+
/* String table for functionality that takes 2 modes. */
static const char *tomoyo_mode_2[4] = {
"disabled", "enabled", "enabled", "enabled"
@@ -52,11 +53,14 @@ static bool tomoyo_manage_by_non_root;

/* Open operation for /sys/kernel/security/tomoyo/ interface. */
static int tomoyo_open_control(const u8 type, struct file *file);
+
/* Close /sys/kernel/security/tomoyo/ interface. */
static int tomoyo_close_control(struct file *file);
+
/* Read operation for /sys/kernel/security/tomoyo/ interface. */
static int tomoyo_read_control(struct file *file, char __user *buffer,
const int buffer_len);
+
/* Write operation for /sys/kernel/security/tomoyo/ interface. */
static int tomoyo_write_control(struct file *file, const char __user *buffer,
const int buffer_len);
@@ -326,25 +330,30 @@ bool tomoyo_is_domain_def(const unsigned
* tomoyo_find_domain - Find a domain by the given name.
*
* @domainname: The domainname to find.
+ * @cookie: Pointer to "struct tomoyo_cookie".
*
- * Caller must call down_read(&tomoyo_domain_list_lock); or
- * down_write(&tomoyo_domain_list_lock); .
- *
- * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise.
+ * Returns true if found, false otherwise.
*/
-struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
+bool tomoyo_find_domain(const char *domainname, struct tomoyo_cookie *cookie)
{
struct tomoyo_domain_info *domain;
struct tomoyo_path_info name;

+ cookie->u.domain = NULL;
name.name = domainname;
tomoyo_fill_path_info(&name);
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
list_for_each_entry(domain, &tomoyo_domain_list, list) {
- if (!domain->is_deleted &&
- !tomoyo_pathcmp(&name, domain->domainname))
- return domain;
+ if (domain->is_deleted ||
+ tomoyo_pathcmp(&name, domain->domainname))
+ continue;
+ cookie->u.domain = domain;
+ break;
}
- return NULL;
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
+ return cookie->u.domain != NULL;
}

/**
@@ -421,7 +430,7 @@ static int tomoyo_const_part_length(cons
*
* @ptr: Pointer to "struct tomoyo_path_info" to fill in.
*
- * The caller sets "struct tomoyo_path_info"->name.
+ * The caller sets @ptr->name.
*/
void tomoyo_fill_path_info(struct tomoyo_path_info *ptr)
{
@@ -763,7 +772,7 @@ unsigned int tomoyo_check_flags(const st
* @domain: Pointer to "struct tomoyo_domain_info".
*
* Returns true if domain policy violation warning should be printed to
- * console.
+ * console, false otherwise.
*/
bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain)
{
@@ -784,7 +793,8 @@ bool tomoyo_domain_quota_is_ok(struct to

if (!domain)
return true;
- down_read(&tomoyo_domain_acl_info_list_lock);
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
list_for_each_entry(ptr, &domain->acl_info_list, list) {
if (ptr->type & TOMOYO_ACL_DELETED)
continue;
@@ -838,7 +848,13 @@ bool tomoyo_domain_quota_is_ok(struct to
break;
}
}
- up_read(&tomoyo_domain_acl_info_list_lock);
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
+ /*
+ * This is safe because domain is either
+ * ((struct tomoyo_cookie *) current->cred->security)->u.domain or
+ * ((struct tomoyo_cookie *) bprm->cred->security)->u.domain .
+ */
if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY))
return true;
if (!domain->quota_warned) {
@@ -860,27 +876,27 @@ bool tomoyo_domain_quota_is_ok(struct to
static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned
int profile)
{
- static DEFINE_MUTEX(lock);
- struct tomoyo_profile *ptr = NULL;
+ struct tomoyo_profile *entry;
+ struct tomoyo_profile *ptr;
int i;

if (profile >= TOMOYO_MAX_PROFILES)
return NULL;
- /***** EXCLUSIVE SECTION START *****/
- mutex_lock(&lock);
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_policy_lock);
ptr = tomoyo_profile_ptr[profile];
- if (ptr)
- goto ok;
- ptr = tomoyo_alloc_element(sizeof(*ptr));
- if (!ptr)
- goto ok;
- for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++)
- ptr->value[i] = tomoyo_control_array[i].current_value;
- mb(); /* Avoid out-of-order execution. */
- tomoyo_profile_ptr[profile] = ptr;
- ok:
- mutex_unlock(&lock);
- /***** EXCLUSIVE SECTION END *****/
+ if (!ptr && tomoyo_alloc_element(entry)) {
+ for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++)
+ entry->value[i] = tomoyo_control_array[i].current_value;
+ mb(); /* Avoid out-of-order execution. */
+ tomoyo_profile_ptr[profile] = entry;
+ ptr = entry;
+ entry = NULL;
+ }
+ up_write(&tomoyo_policy_lock);
+ /***** WRITER SECTION END *****/
+ kfree(entry);
return ptr;
}

@@ -915,7 +931,16 @@ static int tomoyo_write_profile(struct t
return -EINVAL;
*cp = '\0';
if (!strcmp(data, "COMMENT")) {
- profile->comment = tomoyo_save_name(cp + 1);
+ const struct tomoyo_path_info *new_comment
+ = tomoyo_get_name(cp + 1);
+ const struct tomoyo_path_info *old_comment;
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_policy_lock);
+ old_comment = profile->comment;
+ profile->comment = new_comment;
+ up_write(&tomoyo_policy_lock);
+ /***** WRITER SECTION END *****/
+ tomoyo_put_name(old_comment);
return 0;
}
for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) {
@@ -943,6 +968,7 @@ static int tomoyo_write_profile(struct t
} else if (value > tomoyo_control_array[i].max_value) {
value = tomoyo_control_array[i].max_value;
}
+ /* profile is not deleted. */
profile->value[i] = value;
return 0;
}
@@ -967,15 +993,22 @@ static int tomoyo_read_profile(struct to
step++) {
const u8 index = step / total;
u8 type = step % total;
+ /* profile is not deleted. */
const struct tomoyo_profile *profile
= tomoyo_profile_ptr[index];
head->read_step = step;
if (!profile)
continue;
if (!type) { /* Print profile' comment tag. */
- if (!tomoyo_io_printf(head, "%u-COMMENT=%s\n",
- index, profile->comment ?
- profile->comment->name : ""))
+ bool done;
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
+ done = tomoyo_io_printf(head, "%u-COMMENT=%s\n",
+ index, profile->comment ?
+ profile->comment->name : "");
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
+ if (!done)
break;
continue;
}
@@ -1009,18 +1042,8 @@ static int tomoyo_read_profile(struct to
return 0;
}

-/* Structure for policy manager. */
-struct tomoyo_policy_manager_entry {
- struct list_head list;
- /* A path to program or a domainname. */
- const struct tomoyo_path_info *manager;
- bool is_domain; /* True if manager is a domainname. */
- bool is_deleted; /* True if this entry is deleted. */
-};
-
/* The list for "struct tomoyo_policy_manager_entry". */
-static LIST_HEAD(tomoyo_policy_manager_list);
-static DECLARE_RWSEM(tomoyo_policy_manager_list_lock);
+LIST_HEAD(tomoyo_policy_manager_list);

/**
* tomoyo_update_manager_entry - Add a manager entry.
@@ -1033,10 +1056,10 @@ static DECLARE_RWSEM(tomoyo_policy_manag
static int tomoyo_update_manager_entry(const char *manager,
const bool is_delete)
{
- struct tomoyo_policy_manager_entry *new_entry;
+ struct tomoyo_policy_manager_entry *entry = NULL;
struct tomoyo_policy_manager_entry *ptr;
const struct tomoyo_path_info *saved_manager;
- int error = -ENOMEM;
+ int error = is_delete ? -ENOENT : -ENOMEM;
bool is_domain = false;

if (tomoyo_is_domain_def(manager)) {
@@ -1047,32 +1070,32 @@ static int tomoyo_update_manager_entry(c
if (!tomoyo_is_correct_path(manager, 1, -1, -1, __func__))
return -EINVAL;
}
- saved_manager = tomoyo_save_name(manager);
+ saved_manager = tomoyo_get_name(manager);
if (!saved_manager)
return -ENOMEM;
- /***** EXCLUSIVE SECTION START *****/
- down_write(&tomoyo_policy_manager_list_lock);
+ if (!is_delete)
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_policy_lock);
list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
if (ptr->manager != saved_manager)
continue;
ptr->is_deleted = is_delete;
error = 0;
- goto out;
+ break;
}
- if (is_delete) {
- error = -ENOENT;
- goto out;
+ if (!is_delete && error && tomoyo_alloc_element(entry)) {
+ entry->manager = saved_manager;
+ saved_manager = NULL;
+ entry->is_domain = is_domain;
+ list_add_tail(&entry->list, &tomoyo_policy_manager_list);
+ entry = NULL;
+ error = 0;
}
- new_entry = tomoyo_alloc_element(sizeof(*new_entry));
- if (!new_entry)
- goto out;
- new_entry->manager = saved_manager;
- new_entry->is_domain = is_domain;
- list_add_tail(&new_entry->list, &tomoyo_policy_manager_list);
- error = 0;
- out:
- up_write(&tomoyo_policy_manager_list_lock);
- /***** EXCLUSIVE SECTION END *****/
+ up_write(&tomoyo_policy_lock);
+ /***** WRITER SECTION END *****/
+ tomoyo_put_name(saved_manager);
+ kfree(entry);
return error;
}

@@ -1109,20 +1132,21 @@ static int tomoyo_read_manager_policy(st

if (head->read_eof)
return 0;
- down_read(&tomoyo_policy_manager_list_lock);
- list_for_each_cookie(pos, head->read_var2,
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
+ list_for_each_cookie(pos, head->read_cookie2.u.list,
&tomoyo_policy_manager_list) {
struct tomoyo_policy_manager_entry *ptr;
ptr = list_entry(pos, struct tomoyo_policy_manager_entry,
list);
if (ptr->is_deleted)
continue;
- if (!tomoyo_io_printf(head, "%s\n", ptr->manager->name)) {
- done = false;
+ done = tomoyo_io_printf(head, "%s\n", ptr->manager->name);
+ if (!done)
break;
- }
}
- up_read(&tomoyo_policy_manager_list_lock);
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
head->read_eof = done;
return 0;
}
@@ -1145,7 +1169,8 @@ static bool tomoyo_is_policy_manager(voi
return true;
if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid))
return false;
- down_read(&tomoyo_policy_manager_list_lock);
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
if (!ptr->is_deleted && ptr->is_domain
&& !tomoyo_pathcmp(domainname, ptr->manager)) {
@@ -1153,13 +1178,15 @@ static bool tomoyo_is_policy_manager(voi
break;
}
}
- up_read(&tomoyo_policy_manager_list_lock);
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
if (found)
return true;
exe = tomoyo_get_exe();
if (!exe)
return false;
- down_read(&tomoyo_policy_manager_list_lock);
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
if (!ptr->is_deleted && !ptr->is_domain
&& !strcmp(exe, ptr->manager->name)) {
@@ -1167,7 +1194,8 @@ static bool tomoyo_is_policy_manager(voi
break;
}
}
- up_read(&tomoyo_policy_manager_list_lock);
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
if (!found) { /* Reduce error messages. */
static pid_t last_pid;
const pid_t pid = current->pid;
@@ -1182,6 +1210,35 @@ static bool tomoyo_is_policy_manager(voi
}

/**
+ * tomoyo_delete_domain - Delete a domain.
+ *
+ * @domainname: The name of domain.
+ */
+static void tomoyo_delete_domain(char *domainname)
+{
+ struct tomoyo_domain_info *domain;
+ struct tomoyo_path_info name;
+
+ name.name = domainname;
+ tomoyo_fill_path_info(&name);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_policy_lock);
+ /* Is there an active domain? */
+ list_for_each_entry(domain, &tomoyo_domain_list, list) {
+ /* Never delete tomoyo_kernel_domain */
+ if (domain == &tomoyo_kernel_domain)
+ continue;
+ if (domain->is_deleted ||
+ tomoyo_pathcmp(domain->domainname, &name))
+ continue;
+ domain->is_deleted = true;
+ break;
+ }
+ up_write(&tomoyo_policy_lock);
+ /***** WRITER SECTION END *****/
+}
+
+/**
* tomoyo_is_select_one - Parse select command.
*
* @head: Pointer to "struct tomoyo_io_buffer".
@@ -1193,49 +1250,46 @@ static bool tomoyo_is_select_one(struct
const char *data)
{
unsigned int pid;
- struct tomoyo_domain_info *domain = NULL;
+ struct tomoyo_cookie *cookie = &head->write_cookie1;

if (sscanf(data, "pid=%u", &pid) == 1) {
struct task_struct *p;
+ cookie->u.domain = NULL;
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
/***** CRITICAL SECTION START *****/
- read_lock(&tasklist_lock);
+ rcu_read_lock();
p = find_task_by_vpid(pid);
if (p)
- domain = tomoyo_real_domain(p);
- read_unlock(&tasklist_lock);
+ cookie->u.domain = tomoyo_real_domain(p);
+ rcu_read_unlock();
/***** CRITICAL SECTION END *****/
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
} else if (!strncmp(data, "domain=", 7)) {
- if (tomoyo_is_domain_def(data + 7)) {
- down_read(&tomoyo_domain_list_lock);
- domain = tomoyo_find_domain(data + 7);
- up_read(&tomoyo_domain_list_lock);
- }
+ cookie->u.domain = NULL;
+ if (tomoyo_is_domain_def(data + 7))
+ tomoyo_find_domain(data + 7, cookie);
} else
return false;
- head->write_var1 = domain;
/* Accessing read_buf is safe because head->io_sem is held. */
if (!head->read_buf)
return true; /* Do nothing if open(O_WRONLY). */
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
+ if (cookie->u.domain)
+ head->read_cookie1.u.list = cookie->u.domain->list.prev;
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
head->read_avail = 0;
tomoyo_io_printf(head, "# select %s\n", data);
head->read_single_domain = true;
- head->read_eof = !domain;
- if (domain) {
- struct tomoyo_domain_info *d;
- head->read_var1 = NULL;
- down_read(&tomoyo_domain_list_lock);
- list_for_each_entry(d, &tomoyo_domain_list, list) {
- if (d == domain)
- break;
- head->read_var1 = &d->list;
- }
- up_read(&tomoyo_domain_list_lock);
- head->read_var2 = NULL;
- head->read_bit = 0;
- head->read_step = 0;
- if (domain->is_deleted)
- tomoyo_io_printf(head, "# This is a deleted domain.\n");
- }
+ head->read_eof = !cookie->u.domain;
+ head->read_cookie2.u.list = NULL;
+ head->read_bit = 0;
+ head->read_step = 0;
+ if (cookie->u.domain && cookie->u.domain->is_deleted)
+ tomoyo_io_printf(head, "# This is a deleted domain.\n");
return true;
}

@@ -1249,7 +1303,7 @@ static bool tomoyo_is_select_one(struct
static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head)
{
char *data = head->write_buf;
- struct tomoyo_domain_info *domain = head->write_var1;
+ struct tomoyo_cookie *cookie = &head->write_cookie1;
bool is_delete = false;
bool is_select = false;
unsigned int profile;
@@ -1264,33 +1318,29 @@ static int tomoyo_write_domain_policy(st
if (!tomoyo_is_policy_manager())
return -EPERM;
if (tomoyo_is_domain_def(data)) {
- domain = NULL;
+ cookie->u.domain = NULL;
if (is_delete)
tomoyo_delete_domain(data);
- else if (is_select) {
- down_read(&tomoyo_domain_list_lock);
- domain = tomoyo_find_domain(data);
- up_read(&tomoyo_domain_list_lock);
- } else
- domain = tomoyo_find_or_assign_new_domain(data, 0);
- head->write_var1 = domain;
+ else if (is_select)
+ tomoyo_find_domain(data, cookie);
+ else
+ tomoyo_find_or_assign_new_domain(data, 0, cookie);
return 0;
}
- if (!domain)
+ if (!cookie->u.domain)
return -EINVAL;

if (sscanf(data, TOMOYO_KEYWORD_USE_PROFILE "%u", &profile) == 1
&& profile < TOMOYO_MAX_PROFILES) {
if (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded)
- domain->profile = (u8) profile;
+ cookie->u.domain->profile = (u8) profile;
return 0;
}
if (!strcmp(data, TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ)) {
- tomoyo_set_domain_flag(domain, is_delete,
- TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ);
+ cookie->u.domain->ignore_global_allow_read = !is_delete;
return 0;
}
- return tomoyo_write_file_policy(data, domain, is_delete);
+ return tomoyo_write_file_policy(data, cookie->u.domain, is_delete);
}

/**
@@ -1427,8 +1477,10 @@ static int tomoyo_read_domain_policy(str
return 0;
if (head->read_step == 0)
head->read_step = 1;
- down_read(&tomoyo_domain_list_lock);
- list_for_each_cookie(dpos, head->read_var1, &tomoyo_domain_list) {
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
+ list_for_each_cookie(dpos, head->read_cookie1.u.list,
+ &tomoyo_domain_list) {
struct tomoyo_domain_info *domain;
const char *quota_exceeded = "";
const char *transition_failed = "";
@@ -1441,51 +1493,47 @@ static int tomoyo_read_domain_policy(str
/* Print domainname and flags. */
if (domain->quota_warned)
quota_exceeded = "quota_exceeded\n";
- if (domain->flags & TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED)
+ if (domain->domain_transition_failed)
transition_failed = "transition_failed\n";
- if (domain->flags &
- TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ)
+ if (domain->ignore_global_allow_read)
ignore_global_allow_read
= TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n";
- if (!tomoyo_io_printf(head,
- "%s\n" TOMOYO_KEYWORD_USE_PROFILE "%u\n"
- "%s%s%s\n", domain->domainname->name,
- domain->profile, quota_exceeded,
- transition_failed,
- ignore_global_allow_read)) {
- done = false;
+ done = tomoyo_io_printf(head, "%s\n" TOMOYO_KEYWORD_USE_PROFILE
+ "%u\n%s%s%s\n",
+ domain->domainname->name,
+ domain->profile, quota_exceeded,
+ transition_failed,
+ ignore_global_allow_read);
+ if (!done)
break;
- }
head->read_step = 2;
acl_loop:
if (head->read_step == 3)
goto tail_mark;
/* Print ACL entries in the domain. */
- down_read(&tomoyo_domain_acl_info_list_lock);
- list_for_each_cookie(apos, head->read_var2,
- &domain->acl_info_list) {
+ list_for_each_cookie(apos, head->read_cookie2.u.list,
+ &domain->acl_info_list) {
struct tomoyo_acl_info *ptr
= list_entry(apos, struct tomoyo_acl_info,
- list);
+ list);
if (!tomoyo_print_entry(head, ptr)) {
done = false;
break;
}
}
- up_read(&tomoyo_domain_acl_info_list_lock);
if (!done)
break;
head->read_step = 3;
tail_mark:
- if (!tomoyo_io_printf(head, "\n")) {
- done = false;
+ done = tomoyo_io_printf(head, "\n");
+ if (!done)
break;
- }
head->read_step = 1;
if (head->read_single_domain)
break;
}
- up_read(&tomoyo_domain_list_lock);
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
head->read_eof = done;
return 0;
}
@@ -1496,30 +1544,25 @@ tail_mark:
* @head: Pointer to "struct tomoyo_io_buffer".
*
* Returns 0 on success, -EINVAL otherwise.
- *
- * This is equivalent to doing
- *
- * ( echo "select " $domainname; echo "use_profile " $profile ) |
- * /usr/lib/ccs/loadpolicy -d
*/
static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head)
{
char *data = head->write_buf;
char *cp = strchr(data, ' ');
- struct tomoyo_domain_info *domain;
unsigned long profile;
+ struct tomoyo_cookie cookie;

if (!cp)
return -EINVAL;
*cp = '\0';
- down_read(&tomoyo_domain_list_lock);
- domain = tomoyo_find_domain(cp + 1);
- up_read(&tomoyo_domain_list_lock);
- if (strict_strtoul(data, 10, &profile))
+ if (strict_strtoul(data, 10, &profile) ||
+ profile >= TOMOYO_MAX_PROFILES)
return -EINVAL;
- if (domain && profile < TOMOYO_MAX_PROFILES
- && (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded))
- domain->profile = (u8) profile;
+ tomoyo_add_cookie(&cookie, NULL);
+ if (tomoyo_find_domain(cp + 1, &cookie) &&
+ (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded))
+ cookie.u.domain->profile = (u8) profile;
+ tomoyo_del_cookie(&cookie);
return 0;
}

@@ -1529,13 +1572,6 @@ static int tomoyo_write_domain_profile(s
* @head: Pointer to "struct tomoyo_io_buffer".
*
* Returns list of profile number and domainname pairs.
- *
- * This is equivalent to doing
- *
- * grep -A 1 '^<kernel>' /sys/kernel/security/tomoyo/domain_policy |
- * awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" )
- * domainname = $0; } else if ( $1 == "use_profile" ) {
- * print $2 " " domainname; domainname = ""; } } ; '
*/
static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
{
@@ -1544,19 +1580,21 @@ static int tomoyo_read_domain_profile(st

if (head->read_eof)
return 0;
- down_read(&tomoyo_domain_list_lock);
- list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) {
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
+ list_for_each_cookie(pos, head->read_cookie1.u.list,
+ &tomoyo_domain_list) {
struct tomoyo_domain_info *domain;
domain = list_entry(pos, struct tomoyo_domain_info, list);
if (domain->is_deleted)
continue;
- if (!tomoyo_io_printf(head, "%u %s\n", domain->profile,
- domain->domainname->name)) {
- done = false;
+ done = tomoyo_io_printf(head, "%u %s\n", domain->profile,
+ domain->domainname->name);
+ if (!done)
break;
- }
}
- up_read(&tomoyo_domain_list_lock);
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
head->read_eof = done;
return 0;
}
@@ -1593,17 +1631,24 @@ static int tomoyo_read_pid(struct tomoyo
if (head->read_avail == 0 && !head->read_eof) {
const int pid = head->read_step;
struct task_struct *p;
- struct tomoyo_domain_info *domain = NULL;
+ struct tomoyo_cookie cookie;
+ tomoyo_add_cookie(&cookie, NULL);
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
/***** CRITICAL SECTION START *****/
- read_lock(&tasklist_lock);
+ rcu_read_lock();
p = find_task_by_vpid(pid);
if (p)
- domain = tomoyo_real_domain(p);
- read_unlock(&tasklist_lock);
+ cookie.u.domain = tomoyo_real_domain(p);
+ rcu_read_unlock();
/***** CRITICAL SECTION END *****/
- if (domain)
- tomoyo_io_printf(head, "%d %u %s", pid, domain->profile,
- domain->domainname->name);
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
+ if (cookie.u.domain)
+ tomoyo_io_printf(head, "%d %u %s", pid,
+ cookie.u.domain->profile,
+ cookie.u.domain->domainname->name);
+ tomoyo_del_cookie(&cookie);
head->read_eof = true;
}
return 0;
@@ -1655,43 +1700,43 @@ static int tomoyo_read_exception_policy(
if (!head->read_eof) {
switch (head->read_step) {
case 0:
- head->read_var2 = NULL;
+ head->read_cookie2.u.list = NULL;
head->read_step = 1;
case 1:
if (!tomoyo_read_domain_keeper_policy(head))
break;
- head->read_var2 = NULL;
+ head->read_cookie2.u.list = NULL;
head->read_step = 2;
case 2:
if (!tomoyo_read_globally_readable_policy(head))
break;
- head->read_var2 = NULL;
+ head->read_cookie2.u.list = NULL;
head->read_step = 3;
case 3:
- head->read_var2 = NULL;
+ head->read_cookie2.u.list = NULL;
head->read_step = 4;
case 4:
if (!tomoyo_read_domain_initializer_policy(head))
break;
- head->read_var2 = NULL;
+ head->read_cookie2.u.list = NULL;
head->read_step = 5;
case 5:
if (!tomoyo_read_alias_policy(head))
break;
- head->read_var2 = NULL;
+ head->read_cookie2.u.list = NULL;
head->read_step = 6;
case 6:
- head->read_var2 = NULL;
+ head->read_cookie2.u.list = NULL;
head->read_step = 7;
case 7:
if (!tomoyo_read_file_pattern(head))
break;
- head->read_var2 = NULL;
+ head->read_cookie2.u.list = NULL;
head->read_step = 8;
case 8:
if (!tomoyo_read_no_rewrite_policy(head))
break;
- head->read_var2 = NULL;
+ head->read_cookie2.u.list = NULL;
head->read_step = 9;
case 9:
head->read_eof = true;
@@ -1736,13 +1781,13 @@ static bool tomoyo_policy_loader_exists(
*
* @filename: The program about to start.
*
+ * Returns nothing.
+ *
* This function checks whether @filename is /sbin/init , and if so
* invoke /sbin/tomoyo-init and wait for the termination of /sbin/tomoyo-init
* and then continues invocation of /sbin/init.
* /sbin/tomoyo-init reads policy files in /etc/tomoyo/ directory and
* writes to /sys/kernel/security/tomoyo/ interfaces.
- *
- * Returns nothing.
*/
void tomoyo_load_policy(const char *filename)
{
@@ -1778,7 +1823,8 @@ void tomoyo_load_policy(const char *file
tomoyo_policy_loaded = true;
{ /* Check all profiles currently assigned to domains are defined. */
struct tomoyo_domain_info *domain;
- down_read(&tomoyo_domain_list_lock);
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
list_for_each_entry(domain, &tomoyo_domain_list, list) {
const u8 profile = domain->profile;
if (tomoyo_profile_ptr[profile])
@@ -1786,7 +1832,8 @@ void tomoyo_load_policy(const char *file
panic("Profile %u (used by '%s') not defined.\n",
profile, domain->domainname->name);
}
- up_read(&tomoyo_domain_list_lock);
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
}
}

@@ -1919,6 +1966,9 @@ static int tomoyo_open_control(const u8
return -ENOMEM;
}
}
+ tomoyo_add_cookie(&head->read_cookie1, NULL);
+ tomoyo_add_cookie(&head->read_cookie2, NULL);
+ tomoyo_add_cookie(&head->write_cookie1, NULL);
file->private_data = head;
/*
* Call the handler now if the file is
@@ -2037,48 +2087,25 @@ static int tomoyo_write_control(struct f
static int tomoyo_close_control(struct file *file)
{
struct tomoyo_io_buffer *head = file->private_data;
+ const bool write_mode = head->write_buf != NULL;

/* Release memory used for policy I/O. */
tomoyo_free(head->read_buf);
head->read_buf = NULL;
tomoyo_free(head->write_buf);
head->write_buf = NULL;
+ tomoyo_del_cookie(&head->read_cookie1);
+ tomoyo_del_cookie(&head->read_cookie2);
+ tomoyo_del_cookie(&head->write_cookie1);
tomoyo_free(head);
head = NULL;
file->private_data = NULL;
+ if (write_mode)
+ tomoyo_run_garbage_collector();
return 0;
}

/**
- * tomoyo_alloc_acl_element - Allocate permanent memory for ACL entry.
- *
- * @acl_type: Type of ACL entry.
- *
- * Returns pointer to the ACL entry on success, NULL otherwise.
- */
-void *tomoyo_alloc_acl_element(const u8 acl_type)
-{
- int len;
- struct tomoyo_acl_info *ptr;
-
- switch (acl_type) {
- case TOMOYO_TYPE_SINGLE_PATH_ACL:
- len = sizeof(struct tomoyo_single_path_acl_record);
- break;
- case TOMOYO_TYPE_DOUBLE_PATH_ACL:
- len = sizeof(struct tomoyo_double_path_acl_record);
- break;
- default:
- return NULL;
- }
- ptr = tomoyo_alloc_element(len);
- if (!ptr)
- return NULL;
- ptr->type = acl_type;
- return ptr;
-}
-
-/**
* tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface.
*
* @inode: Pointer to "struct inode".
@@ -2171,9 +2198,10 @@ static void __init tomoyo_create_entry(c
static int __init tomoyo_initerface_init(void)
{
struct dentry *tomoyo_dir;
+ struct tomoyo_cookie *cookie = current_cred()->security;

/* Don't create securityfs entries unless registered. */
- if (current_cred()->security != &tomoyo_kernel_domain)
+ if (!cookie || cookie->u.domain != &tomoyo_kernel_domain)
return 0;

tomoyo_dir = securityfs_create_dir("tomoyo", NULL);
--- security-testing-2.6.git.orig/security/tomoyo/common.h
+++ security-testing-2.6.git/security/tomoyo/common.h
@@ -26,6 +26,18 @@
struct dentry;
struct vfsmount;

+struct tomoyo_domain_info;
+struct tomoyo_path_info;
+struct tomoyo_cookie {
+ struct list_head list;
+ union {
+ const void *ptr;
+ struct list_head *list;
+ struct tomoyo_domain_info *domain;
+ const struct tomoyo_path_info *path;
+ } u;
+};
+
/* Temporary buffer for holding pathnames. */
struct tomoyo_page_buffer {
char buffer[4096];
@@ -90,23 +102,20 @@ struct tomoyo_domain_info {
u8 profile; /* Profile number to use. */
bool is_deleted; /* Delete flag. */
bool quota_warned; /* Quota warnning flag. */
- /* DOMAIN_FLAGS_*. Use tomoyo_set_domain_flag() to modify. */
- u8 flags;
+ /* Ignore "allow_read" directive in exception policy. */
+ bool ignore_global_allow_read;
+ /*
+ * This domain was unable to create a new domain at
+ * tomoyo_find_next_domain() because the name of the domain to be
+ * created was too long or it could not allocate memory.
+ * More than one process continued execve() without domain transition.
+ */
+ bool domain_transition_failed;
};

/* Profile number is an integer between 0 and 255. */
#define TOMOYO_MAX_PROFILES 256

-/* Ignore "allow_read" directive in exception policy. */
-#define TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ 1
-/*
- * This domain was unable to create a new domain at tomoyo_find_next_domain()
- * because the name of the domain to be created was too long or
- * it could not allocate memory.
- * More than one process continued execve() without domain transition.
- */
-#define TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED 2
-
/*
* Structure for "allow_read/write", "allow_execute", "allow_read",
* "allow_write", "allow_create", "allow_unlink", "allow_mkdir", "allow_rmdir",
@@ -160,11 +169,11 @@ struct tomoyo_io_buffer {
/* Exclusive lock for this structure. */
struct mutex io_sem;
/* The position currently reading from. */
- struct list_head *read_var1;
+ struct tomoyo_cookie read_cookie1;
/* Extra variables for reading. */
- struct list_head *read_var2;
+ struct tomoyo_cookie read_cookie2;
/* The position currently writing to. */
- struct tomoyo_domain_info *write_var1;
+ struct tomoyo_cookie write_cookie1;
/* The step for reading. */
int read_step;
/* Buffer for reading. */
@@ -187,6 +196,66 @@ struct tomoyo_io_buffer {
int writebuf_size;
};

+/* Structure for policy manager. */
+struct tomoyo_policy_manager_entry {
+ struct list_head list;
+ /* A path to program or a domainname. */
+ const struct tomoyo_path_info *manager;
+ bool is_domain; /* True if manager is a domainname. */
+ bool is_deleted; /* True if this entry is deleted. */
+};
+
+/* Structure for "initialize_domain" and "no_initialize_domain" keyword. */
+struct tomoyo_domain_initializer_entry {
+ struct list_head list;
+ const struct tomoyo_path_info *domainname; /* This may be NULL */
+ const struct tomoyo_path_info *program;
+ bool is_deleted;
+ bool is_not; /* True if this entry is "no_initialize_domain". */
+ /* True if the domainname is tomoyo_get_last_name(). */
+ bool is_last_name;
+};
+
+/* Structure for "keep_domain" and "no_keep_domain" keyword. */
+struct tomoyo_domain_keeper_entry {
+ struct list_head list;
+ const struct tomoyo_path_info *domainname;
+ const struct tomoyo_path_info *program; /* This may be NULL */
+ bool is_deleted;
+ bool is_not; /* True if this entry is "no_keep_domain". */
+ /* True if the domainname is tomoyo_get_last_name(). */
+ bool is_last_name;
+};
+
+/* Structure for "alias" keyword. */
+struct tomoyo_alias_entry {
+ struct list_head list;
+ const struct tomoyo_path_info *original_name;
+ const struct tomoyo_path_info *aliased_name;
+ bool is_deleted;
+};
+
+/* Structure for "allow_read" keyword. */
+struct tomoyo_globally_readable_file_entry {
+ struct list_head list;
+ const struct tomoyo_path_info *filename;
+ bool is_deleted;
+};
+
+/* Structure for "file_pattern" keyword. */
+struct tomoyo_pattern_entry {
+ struct list_head list;
+ const struct tomoyo_path_info *pattern;
+ bool is_deleted;
+};
+
+/* Structure for "deny_rewrite" keyword. */
+struct tomoyo_no_rewrite_entry {
+ struct list_head list;
+ const struct tomoyo_path_info *pattern;
+ bool is_deleted;
+};
+
/* Check whether the domain has too many ACL entries to hold. */
bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain);
/* Transactional sprintf() for policy dump. */
@@ -229,8 +298,6 @@ const char *tomoyo_get_last_name(const s
const char *tomoyo_get_msg(const bool is_enforce);
/* Convert single path operation to operation name. */
const char *tomoyo_sp2keyword(const u8 operation);
-/* Delete a domain. */
-int tomoyo_delete_domain(char *data);
/* Create "alias" entry in exception policy. */
int tomoyo_write_alias_policy(char *data, const bool is_delete);
/*
@@ -258,23 +325,24 @@ int tomoyo_write_no_rewrite_policy(char
/* Create "file_pattern" entry in exception policy. */
int tomoyo_write_pattern_policy(char *data, const bool is_delete);
/* Find a domain by the given name. */
-struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname);
+bool tomoyo_find_domain(const char *domainname, struct tomoyo_cookie *cookie);
/* Find or create a domain by the given name. */
-struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
- domainname,
- const u8 profile);
+bool tomoyo_find_or_assign_new_domain(const char *domainname, const u8 profile,
+ struct tomoyo_cookie *cookie);
/* Check mode for specified functionality. */
unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
const u8 index);
-/* Allocate memory for structures. */
-void *tomoyo_alloc_acl_element(const u8 acl_type);
/* Fill in "struct tomoyo_path_info" members. */
void tomoyo_fill_path_info(struct tomoyo_path_info *ptr);
/* Run policy loader when /sbin/init starts. */
void tomoyo_load_policy(const char *filename);
-/* Change "struct tomoyo_domain_info"->flags. */
-void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain,
- const bool is_delete, const u8 flags);
+/* Cleanup deleted entries. */
+void tomoyo_run_garbage_collector(void);
+
+static inline struct tomoyo_domain_info *tomoyo_domain(void)
+{
+ return ((struct tomoyo_cookie *) current_cred()->security)->u.domain;
+}

/* strcmp() for "struct tomoyo_path_info" structure. */
static inline bool tomoyo_pathcmp(const struct tomoyo_path_info *a,
@@ -319,12 +387,18 @@ static inline bool tomoyo_is_invalid(con
return c && (c <= ' ' || c >= 127);
}

+/* Lock for modifying policy. */
+extern struct rw_semaphore tomoyo_policy_lock;
+
/* The list for "struct tomoyo_domain_info". */
extern struct list_head tomoyo_domain_list;
-extern struct rw_semaphore tomoyo_domain_list_lock;
-
-/* Lock for domain->acl_info_list. */
-extern struct rw_semaphore tomoyo_domain_acl_info_list_lock;
+extern struct list_head tomoyo_policy_manager_list;
+extern struct list_head tomoyo_globally_readable_list;
+extern struct list_head tomoyo_pattern_list;
+extern struct list_head tomoyo_no_rewrite_list;
+extern struct list_head tomoyo_domain_initializer_list;
+extern struct list_head tomoyo_domain_keeper_list;
+extern struct list_head tomoyo_alias_list;

/* Has /sbin/init started? */
extern bool tomoyo_policy_loaded;
--- security-testing-2.6.git.orig/security/tomoyo/domain.c
+++ security-testing-2.6.git/security/tomoyo/domain.c
@@ -21,61 +21,7 @@ struct tomoyo_domain_info tomoyo_kernel_

/* The list for "struct tomoyo_domain_info". */
LIST_HEAD(tomoyo_domain_list);
-DECLARE_RWSEM(tomoyo_domain_list_lock);
-
-/* Structure for "initialize_domain" and "no_initialize_domain" keyword. */
-struct tomoyo_domain_initializer_entry {
- struct list_head list;
- const struct tomoyo_path_info *domainname; /* This may be NULL */
- const struct tomoyo_path_info *program;
- bool is_deleted;
- bool is_not; /* True if this entry is "no_initialize_domain". */
- /* True if the domainname is tomoyo_get_last_name(). */
- bool is_last_name;
-};
-
-/* Structure for "keep_domain" and "no_keep_domain" keyword. */
-struct tomoyo_domain_keeper_entry {
- struct list_head list;
- const struct tomoyo_path_info *domainname;
- const struct tomoyo_path_info *program; /* This may be NULL */
- bool is_deleted;
- bool is_not; /* True if this entry is "no_keep_domain". */
- /* True if the domainname is tomoyo_get_last_name(). */
- bool is_last_name;
-};
-
-/* Structure for "alias" keyword. */
-struct tomoyo_alias_entry {
- struct list_head list;
- const struct tomoyo_path_info *original_name;
- const struct tomoyo_path_info *aliased_name;
- bool is_deleted;
-};
-
-/**
- * tomoyo_set_domain_flag - Set or clear domain's attribute flags.
- *
- * @domain: Pointer to "struct tomoyo_domain_info".
- * @is_delete: True if it is a delete request.
- * @flags: Flags to set or clear.
- *
- * Returns nothing.
- */
-void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain,
- const bool is_delete, const u8 flags)
-{
- /* We need to serialize because this is bitfield operation. */
- static DEFINE_SPINLOCK(lock);
- /***** CRITICAL SECTION START *****/
- spin_lock(&lock);
- if (!is_delete)
- domain->flags |= flags;
- else
- domain->flags &= ~flags;
- spin_unlock(&lock);
- /***** CRITICAL SECTION END *****/
-}
+DECLARE_RWSEM(tomoyo_policy_lock);

/**
* tomoyo_get_last_name - Get last component of a domainname.
@@ -83,6 +29,8 @@ void tomoyo_set_domain_flag(struct tomoy
* @domain: Pointer to "struct tomoyo_domain_info".
*
* Returns the last component of the domainname.
+ *
+ * @domain must be either current domain or saved in the cookie list.
*/
const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain)
{
@@ -95,8 +43,7 @@ const char *tomoyo_get_last_name(const s
}

/* The list for "struct tomoyo_domain_initializer_entry". */
-static LIST_HEAD(tomoyo_domain_initializer_list);
-static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock);
+LIST_HEAD(tomoyo_domain_initializer_list);

/**
* tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list.
@@ -113,11 +60,11 @@ static int tomoyo_update_domain_initiali
const bool is_not,
const bool is_delete)
{
- struct tomoyo_domain_initializer_entry *new_entry;
+ struct tomoyo_domain_initializer_entry *entry = NULL;
struct tomoyo_domain_initializer_entry *ptr;
const struct tomoyo_path_info *saved_program;
const struct tomoyo_path_info *saved_domainname = NULL;
- int error = -ENOMEM;
+ int error = is_delete ? -ENOENT : -ENOMEM;
bool is_last_name = false;

if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__))
@@ -128,15 +75,17 @@ static int tomoyo_update_domain_initiali
is_last_name = true;
else if (!tomoyo_is_correct_domain(domainname, __func__))
return -EINVAL;
- saved_domainname = tomoyo_save_name(domainname);
+ saved_domainname = tomoyo_get_name(domainname);
if (!saved_domainname)
return -ENOMEM;
}
- saved_program = tomoyo_save_name(program);
+ saved_program = tomoyo_get_name(program);
if (!saved_program)
- return -ENOMEM;
- /***** EXCLUSIVE SECTION START *****/
- down_write(&tomoyo_domain_initializer_list_lock);
+ goto out;
+ if (!is_delete)
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_policy_lock);
list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) {
if (ptr->is_not != is_not ||
ptr->domainname != saved_domainname ||
@@ -144,24 +93,25 @@ static int tomoyo_update_domain_initiali
continue;
ptr->is_deleted = is_delete;
error = 0;
- goto out;
+ break;
}
- if (is_delete) {
- error = -ENOENT;
- goto out;
+ if (!is_delete && error && tomoyo_alloc_element(entry)) {
+ entry->domainname = saved_domainname;
+ saved_domainname = NULL;
+ entry->program = saved_program;
+ saved_program = NULL;
+ entry->is_not = is_not;
+ entry->is_last_name = is_last_name;
+ list_add_tail(&entry->list, &tomoyo_domain_initializer_list);
+ entry = NULL;
+ error = 0;
}
- new_entry = tomoyo_alloc_element(sizeof(*new_entry));
- if (!new_entry)
- goto out;
- new_entry->domainname = saved_domainname;
- new_entry->program = saved_program;
- new_entry->is_not = is_not;
- new_entry->is_last_name = is_last_name;
- list_add_tail(&new_entry->list, &tomoyo_domain_initializer_list);
- error = 0;
+ up_write(&tomoyo_policy_lock);
+ /***** WRITER SECTION END *****/
out:
- up_write(&tomoyo_domain_initializer_list_lock);
- /***** EXCLUSIVE SECTION END *****/
+ tomoyo_put_name(saved_domainname);
+ tomoyo_put_name(saved_program);
+ kfree(entry);
return error;
}

@@ -177,15 +127,16 @@ bool tomoyo_read_domain_initializer_poli
struct list_head *pos;
bool done = true;

- down_read(&tomoyo_domain_initializer_list_lock);
- list_for_each_cookie(pos, head->read_var2,
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
+ list_for_each_cookie(pos, head->read_cookie2.u.list,
&tomoyo_domain_initializer_list) {
const char *no;
const char *from = "";
const char *domain = "";
struct tomoyo_domain_initializer_entry *ptr;
ptr = list_entry(pos, struct tomoyo_domain_initializer_entry,
- list);
+ list);
if (ptr->is_deleted)
continue;
no = ptr->is_not ? "no_" : "";
@@ -193,15 +144,15 @@ bool tomoyo_read_domain_initializer_poli
from = " from ";
domain = ptr->domainname->name;
}
- if (!tomoyo_io_printf(head,
- "%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN
- "%s%s%s\n", no, ptr->program->name, from,
- domain)) {
- done = false;
+ done = tomoyo_io_printf(head,
+ "%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN
+ "%s%s%s\n", no, ptr->program->name,
+ from, domain);
+ if (!done)
break;
- }
}
- up_read(&tomoyo_domain_initializer_list_lock);
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
return done;
}

@@ -248,7 +199,8 @@ static bool tomoyo_is_domain_initializer
struct tomoyo_domain_initializer_entry *ptr;
bool flag = false;

- down_read(&tomoyo_domain_initializer_list_lock);
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) {
if (ptr->is_deleted)
continue;
@@ -269,13 +221,13 @@ static bool tomoyo_is_domain_initializer
}
flag = true;
}
- up_read(&tomoyo_domain_initializer_list_lock);
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
return flag;
}

/* The list for "struct tomoyo_domain_keeper_entry". */
-static LIST_HEAD(tomoyo_domain_keeper_list);
-static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock);
+LIST_HEAD(tomoyo_domain_keeper_list);

/**
* tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list.
@@ -292,12 +244,12 @@ static int tomoyo_update_domain_keeper_e
const bool is_not,
const bool is_delete)
{
- struct tomoyo_domain_keeper_entry *new_entry;
+ struct tomoyo_domain_keeper_entry *entry = NULL;
struct tomoyo_domain_keeper_entry *ptr;
const struct tomoyo_path_info *saved_domainname;
const struct tomoyo_path_info *saved_program = NULL;
static DEFINE_MUTEX(lock);
- int error = -ENOMEM;
+ int error = is_delete ? -ENOENT : -ENOMEM;
bool is_last_name = false;

if (!tomoyo_is_domain_def(domainname) &&
@@ -308,15 +260,17 @@ static int tomoyo_update_domain_keeper_e
if (program) {
if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__))
return -EINVAL;
- saved_program = tomoyo_save_name(program);
+ saved_program = tomoyo_get_name(program);
if (!saved_program)
return -ENOMEM;
}
- saved_domainname = tomoyo_save_name(domainname);
+ saved_domainname = tomoyo_get_name(domainname);
if (!saved_domainname)
- return -ENOMEM;
- /***** EXCLUSIVE SECTION START *****/
- down_write(&tomoyo_domain_keeper_list_lock);
+ goto out;
+ if (!is_delete)
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_policy_lock);
list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
if (ptr->is_not != is_not ||
ptr->domainname != saved_domainname ||
@@ -324,24 +278,25 @@ static int tomoyo_update_domain_keeper_e
continue;
ptr->is_deleted = is_delete;
error = 0;
- goto out;
+ break;
}
- if (is_delete) {
- error = -ENOENT;
- goto out;
+ if (!is_delete && error && tomoyo_alloc_element(entry)) {
+ entry->domainname = saved_domainname;
+ saved_domainname = NULL;
+ entry->program = saved_program;
+ saved_program = NULL;
+ entry->is_not = is_not;
+ entry->is_last_name = is_last_name;
+ list_add_tail(&entry->list, &tomoyo_domain_keeper_list);
+ entry = NULL;
+ error = 0;
}
- new_entry = tomoyo_alloc_element(sizeof(*new_entry));
- if (!new_entry)
- goto out;
- new_entry->domainname = saved_domainname;
- new_entry->program = saved_program;
- new_entry->is_not = is_not;
- new_entry->is_last_name = is_last_name;
- list_add_tail(&new_entry->list, &tomoyo_domain_keeper_list);
- error = 0;
+ up_write(&tomoyo_policy_lock);
+ /***** WRITER SECTION END *****/
out:
- up_write(&tomoyo_domain_keeper_list_lock);
- /***** EXCLUSIVE SECTION END *****/
+ tomoyo_put_name(saved_domainname);
+ tomoyo_put_name(saved_program);
+ kfree(entry);
return error;
}

@@ -378,8 +333,9 @@ bool tomoyo_read_domain_keeper_policy(st
struct list_head *pos;
bool done = true;

- down_read(&tomoyo_domain_keeper_list_lock);
- list_for_each_cookie(pos, head->read_var2,
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
+ list_for_each_cookie(pos, head->read_cookie2.u.list,
&tomoyo_domain_keeper_list) {
struct tomoyo_domain_keeper_entry *ptr;
const char *no;
@@ -394,15 +350,15 @@ bool tomoyo_read_domain_keeper_policy(st
from = " from ";
program = ptr->program->name;
}
- if (!tomoyo_io_printf(head,
- "%s" TOMOYO_KEYWORD_KEEP_DOMAIN
- "%s%s%s\n", no, program, from,
- ptr->domainname->name)) {
- done = false;
+ done = tomoyo_io_printf(head,
+ "%s" TOMOYO_KEYWORD_KEEP_DOMAIN
+ "%s%s%s\n", no, program, from,
+ ptr->domainname->name);
+ if (!done)
break;
- }
}
- up_read(&tomoyo_domain_keeper_list_lock);
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
return done;
}

@@ -423,7 +379,8 @@ static bool tomoyo_is_domain_keeper(cons
struct tomoyo_domain_keeper_entry *ptr;
bool flag = false;

- down_read(&tomoyo_domain_keeper_list_lock);
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
if (ptr->is_deleted)
continue;
@@ -442,13 +399,13 @@ static bool tomoyo_is_domain_keeper(cons
}
flag = true;
}
- up_read(&tomoyo_domain_keeper_list_lock);
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
return flag;
}

/* The list for "struct tomoyo_alias_entry". */
-static LIST_HEAD(tomoyo_alias_list);
-static DECLARE_RWSEM(tomoyo_alias_list_lock);
+LIST_HEAD(tomoyo_alias_list);

/**
* tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list.
@@ -463,43 +420,46 @@ static int tomoyo_update_alias_entry(con
const char *aliased_name,
const bool is_delete)
{
- struct tomoyo_alias_entry *new_entry;
+ struct tomoyo_alias_entry *entry = NULL;
struct tomoyo_alias_entry *ptr;
const struct tomoyo_path_info *saved_original_name;
const struct tomoyo_path_info *saved_aliased_name;
- int error = -ENOMEM;
+ int error = is_delete ? -ENOENT : -ENOMEM;

if (!tomoyo_is_correct_path(original_name, 1, -1, -1, __func__) ||
!tomoyo_is_correct_path(aliased_name, 1, -1, -1, __func__))
return -EINVAL; /* No patterns allowed. */
- saved_original_name = tomoyo_save_name(original_name);
- saved_aliased_name = tomoyo_save_name(aliased_name);
+ saved_original_name = tomoyo_get_name(original_name);
+ saved_aliased_name = tomoyo_get_name(aliased_name);
if (!saved_original_name || !saved_aliased_name)
- return -ENOMEM;
- /***** EXCLUSIVE SECTION START *****/
- down_write(&tomoyo_alias_list_lock);
+ goto out;
+ if (!is_delete)
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_policy_lock);
list_for_each_entry(ptr, &tomoyo_alias_list, list) {
if (ptr->original_name != saved_original_name ||
ptr->aliased_name != saved_aliased_name)
continue;
ptr->is_deleted = is_delete;
error = 0;
- goto out;
+ break;
}
- if (is_delete) {
- error = -ENOENT;
- goto out;
+ if (!is_delete && error && tomoyo_alloc_element(entry)) {
+ entry->original_name = saved_original_name;
+ saved_original_name = NULL;
+ entry->aliased_name = saved_aliased_name;
+ saved_aliased_name = NULL;
+ list_add_tail(&entry->list, &tomoyo_alias_list);
+ entry = NULL;
+ error = 0;
}
- new_entry = tomoyo_alloc_element(sizeof(*new_entry));
- if (!new_entry)
- goto out;
- new_entry->original_name = saved_original_name;
- new_entry->aliased_name = saved_aliased_name;
- list_add_tail(&new_entry->list, &tomoyo_alias_list);
- error = 0;
+ up_write(&tomoyo_policy_lock);
+ /***** WRITER SECTION END *****/
out:
- up_write(&tomoyo_alias_list_lock);
- /***** EXCLUSIVE SECTION END *****/
+ tomoyo_put_name(saved_original_name);
+ tomoyo_put_name(saved_aliased_name);
+ kfree(entry);
return error;
}

@@ -515,21 +475,23 @@ bool tomoyo_read_alias_policy(struct tom
struct list_head *pos;
bool done = true;

- down_read(&tomoyo_alias_list_lock);
- list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) {
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
+ list_for_each_cookie(pos, head->read_cookie2.u.list,
+ &tomoyo_alias_list) {
struct tomoyo_alias_entry *ptr;

ptr = list_entry(pos, struct tomoyo_alias_entry, list);
if (ptr->is_deleted)
continue;
- if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n",
- ptr->original_name->name,
- ptr->aliased_name->name)) {
- done = false;
+ done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n",
+ ptr->original_name->name,
+ ptr->aliased_name->name);
+ if (!done)
break;
- }
}
- up_read(&tomoyo_alias_list_lock);
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
return done;
}

@@ -551,120 +513,64 @@ int tomoyo_write_alias_policy(char *data
return tomoyo_update_alias_entry(data, cp, is_delete);
}

-/* Domain create/delete handler. */
-
-/**
- * tomoyo_delete_domain - Delete a domain.
- *
- * @domainname: The name of domain.
- *
- * Returns 0.
- */
-int tomoyo_delete_domain(char *domainname)
-{
- struct tomoyo_domain_info *domain;
- struct tomoyo_path_info name;
-
- name.name = domainname;
- tomoyo_fill_path_info(&name);
- /***** EXCLUSIVE SECTION START *****/
- down_write(&tomoyo_domain_list_lock);
- /* Is there an active domain? */
- list_for_each_entry(domain, &tomoyo_domain_list, list) {
- /* Never delete tomoyo_kernel_domain */
- if (domain == &tomoyo_kernel_domain)
- continue;
- if (domain->is_deleted ||
- tomoyo_pathcmp(domain->domainname, &name))
- continue;
- domain->is_deleted = true;
- break;
- }
- up_write(&tomoyo_domain_list_lock);
- /***** EXCLUSIVE SECTION END *****/
- return 0;
-}
+/* Domain create handler. */

/**
* tomoyo_find_or_assign_new_domain - Create a domain.
*
* @domainname: The name of domain.
* @profile: Profile number to assign if the domain was newly created.
+ * @cookie: Pointer to "struct tomoyo_cookie".
*
- * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
+ * Returns true on success, false otherwise.
*/
-struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
- domainname,
- const u8 profile)
+bool tomoyo_find_or_assign_new_domain(const char *domainname, const u8 profile,
+ struct tomoyo_cookie *cookie)
{
- struct tomoyo_domain_info *domain = NULL;
+ struct tomoyo_domain_info *entry;
+ struct tomoyo_domain_info *domain;
const struct tomoyo_path_info *saved_domainname;

- /***** EXCLUSIVE SECTION START *****/
- down_write(&tomoyo_domain_list_lock);
- domain = tomoyo_find_domain(domainname);
- if (domain)
- goto out;
+ cookie->u.domain = NULL;
if (!tomoyo_is_correct_domain(domainname, __func__))
- goto out;
- saved_domainname = tomoyo_save_name(domainname);
+ return false;
+ saved_domainname = tomoyo_get_name(domainname);
if (!saved_domainname)
- goto out;
- /* Can I reuse memory of deleted domain? */
+ return false;
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_policy_lock);
list_for_each_entry(domain, &tomoyo_domain_list, list) {
- struct task_struct *p;
- struct tomoyo_acl_info *ptr;
- bool flag;
- if (!domain->is_deleted ||
- domain->domainname != saved_domainname)
- continue;
- flag = false;
- /***** CRITICAL SECTION START *****/
- read_lock(&tasklist_lock);
- for_each_process(p) {
- if (tomoyo_real_domain(p) != domain)
- continue;
- flag = true;
- break;
- }
- read_unlock(&tasklist_lock);
- /***** CRITICAL SECTION END *****/
- if (flag)
+ if (domain->is_deleted ||
+ tomoyo_pathcmp(saved_domainname, domain->domainname))
continue;
- list_for_each_entry(ptr, &domain->acl_info_list, list) {
- ptr->type |= TOMOYO_ACL_DELETED;
- }
- tomoyo_set_domain_flag(domain, true, domain->flags);
- domain->profile = profile;
- domain->quota_warned = false;
- mb(); /* Avoid out-of-order execution. */
- domain->is_deleted = false;
- goto out;
- }
- /* No memory reusable. Create using new memory. */
- domain = tomoyo_alloc_element(sizeof(*domain));
- if (domain) {
- INIT_LIST_HEAD(&domain->acl_info_list);
- domain->domainname = saved_domainname;
- domain->profile = profile;
- list_add_tail(&domain->list, &tomoyo_domain_list);
+ cookie->u.domain = domain;
+ break;
}
- out:
- up_write(&tomoyo_domain_list_lock);
- /***** EXCLUSIVE SECTION END *****/
- return domain;
+ if (!cookie->u.domain && tomoyo_alloc_element(entry)) {
+ INIT_LIST_HEAD(&entry->acl_info_list);
+ entry->domainname = saved_domainname;
+ saved_domainname = NULL;
+ entry->profile = profile;
+ list_add_tail(&entry->list, &tomoyo_domain_list);
+ cookie->u.domain = entry;
+ entry = NULL;
+ }
+ up_write(&tomoyo_policy_lock);
+ /***** WRITER SECTION END *****/
+ tomoyo_put_name(saved_domainname);
+ kfree(entry);
+ return cookie->u.domain != NULL;
}

/**
* tomoyo_find_next_domain - Find a domain.
*
- * @bprm: Pointer to "struct linux_binprm".
- * @next_domain: Pointer to pointer to "struct tomoyo_domain_info".
+ * @bprm: Pointer to "struct linux_binprm".
*
* Returns 0 on success, negative value otherwise.
*/
-int tomoyo_find_next_domain(struct linux_binprm *bprm,
- struct tomoyo_domain_info **next_domain)
+int tomoyo_find_next_domain(struct linux_binprm *bprm)
{
/*
* This function assumes that the size of buffer returned by
@@ -672,7 +578,6 @@ int tomoyo_find_next_domain(struct linux
*/
struct tomoyo_page_buffer *tmp = tomoyo_alloc(sizeof(*tmp));
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;
char *new_domain_name = NULL;
@@ -685,6 +590,8 @@ int tomoyo_find_next_domain(struct linux
struct tomoyo_path_info s; /* symlink name */
struct tomoyo_path_info l; /* last name */
static bool initialized;
+ struct tomoyo_cookie *cookie = bprm->cred->security;
+ bool found = false;

if (!tmp)
goto out;
@@ -723,7 +630,8 @@ int tomoyo_find_next_domain(struct linux
if (tomoyo_pathcmp(&r, &s)) {
struct tomoyo_alias_entry *ptr;
/* Is this program allowed to be called via symbolic links? */
- down_read(&tomoyo_alias_list_lock);
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
list_for_each_entry(ptr, &tomoyo_alias_list, list) {
if (ptr->is_deleted ||
tomoyo_pathcmp(&r, ptr->original_name) ||
@@ -735,7 +643,8 @@ int tomoyo_find_next_domain(struct linux
tomoyo_fill_path_info(&r);
break;
}
- up_read(&tomoyo_alias_list_lock);
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
}

/* Check execute permission. */
@@ -755,40 +664,38 @@ int tomoyo_find_next_domain(struct linux
* /sbin/init. But transit from kernel domain if executing
* initializers because they might start before /sbin/init.
*/
- domain = old_domain;
+ found = true;
+ /* This is safe because old_domain is already in cookie list. */
+ cookie->u.domain = old_domain;
} else if (tomoyo_is_domain_keeper(old_domain->domainname, &r, &l)) {
/* Keep current domain. */
- domain = old_domain;
+ found = true;
+ /* This is safe because old_domain is already in cookie list. */
+ cookie->u.domain = old_domain;
} else {
/* Normal domain transition. */
snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
"%s %s", old_domain_name, real_program_name);
}
- if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN)
- goto done;
- down_read(&tomoyo_domain_list_lock);
- domain = tomoyo_find_domain(new_domain_name);
- up_read(&tomoyo_domain_list_lock);
- if (domain)
- goto done;
- if (is_enforce)
+ if (found || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN)
goto done;
- domain = tomoyo_find_or_assign_new_domain(new_domain_name,
- old_domain->profile);
+ found = tomoyo_find_domain(new_domain_name, cookie);
+ if (!found && !is_enforce)
+ found = tomoyo_find_or_assign_new_domain(new_domain_name,
+ old_domain->profile,
+ cookie);
done:
- if (domain)
+ if (found)
goto out;
printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
new_domain_name);
if (is_enforce)
retval = -EPERM;
else
- tomoyo_set_domain_flag(old_domain, false,
- TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED);
+ old_domain->domain_transition_failed = true;
out:
tomoyo_free(real_program_name);
tomoyo_free(symlink_program_name);
- *next_domain = domain ? domain : old_domain;
tomoyo_free(tmp);
return retval;
}
--- security-testing-2.6.git.orig/security/tomoyo/file.c
+++ security-testing-2.6.git/security/tomoyo/file.c
@@ -14,27 +14,6 @@
#include "realpath.h"
#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])

-/* Structure for "allow_read" keyword. */
-struct tomoyo_globally_readable_file_entry {
- struct list_head list;
- const struct tomoyo_path_info *filename;
- bool is_deleted;
-};
-
-/* Structure for "file_pattern" keyword. */
-struct tomoyo_pattern_entry {
- struct list_head list;
- const struct tomoyo_path_info *pattern;
- bool is_deleted;
-};
-
-/* Structure for "deny_rewrite" keyword. */
-struct tomoyo_no_rewrite_entry {
- struct list_head list;
- const struct tomoyo_path_info *pattern;
- bool is_deleted;
-};
-
/* Keyword array for single path operations. */
static const char *tomoyo_sp_keyword[TOMOYO_MAX_SINGLE_PATH_OPERATION] = {
[TOMOYO_TYPE_READ_WRITE_ACL] = "read/write",
@@ -130,9 +109,6 @@ static struct tomoyo_path_info *tomoyo_g
return NULL;
}

-/* Lock for domain->acl_info_list. */
-DECLARE_RWSEM(tomoyo_domain_acl_info_list_lock);
-
static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
const char *filename2,
struct tomoyo_domain_info *
@@ -142,8 +118,7 @@ static int tomoyo_update_single_path_acl
const domain, const bool is_delete);

/* The list for "struct tomoyo_globally_readable_file_entry". */
-static LIST_HEAD(tomoyo_globally_readable_list);
-static DECLARE_RWSEM(tomoyo_globally_readable_list_lock);
+LIST_HEAD(tomoyo_globally_readable_list);

/**
* tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list.
@@ -156,38 +131,38 @@ static DECLARE_RWSEM(tomoyo_globally_rea
static int tomoyo_update_globally_readable_entry(const char *filename,
const bool is_delete)
{
- struct tomoyo_globally_readable_file_entry *new_entry;
+ struct tomoyo_globally_readable_file_entry *entry = NULL;
struct tomoyo_globally_readable_file_entry *ptr;
const struct tomoyo_path_info *saved_filename;
- int error = -ENOMEM;
+ int error = is_delete ? -ENOENT : -ENOMEM;

if (!tomoyo_is_correct_path(filename, 1, 0, -1, __func__))
return -EINVAL;
- saved_filename = tomoyo_save_name(filename);
+ saved_filename = tomoyo_get_name(filename);
if (!saved_filename)
return -ENOMEM;
- /***** EXCLUSIVE SECTION START *****/
- down_write(&tomoyo_globally_readable_list_lock);
+ if (!is_delete)
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_policy_lock);
list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
if (ptr->filename != saved_filename)
continue;
ptr->is_deleted = is_delete;
error = 0;
- goto out;
+ break;
}
- if (is_delete) {
- error = -ENOENT;
- goto out;
+ if (!is_delete && error && tomoyo_alloc_element(entry)) {
+ entry->filename = saved_filename;
+ saved_filename = NULL;
+ list_add_tail(&entry->list, &tomoyo_globally_readable_list);
+ entry = NULL;
+ error = 0;
}
- new_entry = tomoyo_alloc_element(sizeof(*new_entry));
- if (!new_entry)
- goto out;
- new_entry->filename = saved_filename;
- list_add_tail(&new_entry->list, &tomoyo_globally_readable_list);
- error = 0;
- out:
- up_write(&tomoyo_globally_readable_list_lock);
- /***** EXCLUSIVE SECTION END *****/
+ up_write(&tomoyo_policy_lock);
+ /***** WRITER SECTION END *****/
+ tomoyo_put_name(saved_filename);
+ kfree(entry);
return error;
}

@@ -203,7 +178,9 @@ static bool tomoyo_is_globally_readable_
{
struct tomoyo_globally_readable_file_entry *ptr;
bool found = false;
- down_read(&tomoyo_globally_readable_list_lock);
+
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
if (!ptr->is_deleted &&
tomoyo_path_matches_pattern(filename, ptr->filename)) {
@@ -211,7 +188,8 @@ static bool tomoyo_is_globally_readable_
break;
}
}
- up_read(&tomoyo_globally_readable_list_lock);
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
return found;
}

@@ -240,8 +218,9 @@ bool tomoyo_read_globally_readable_polic
struct list_head *pos;
bool done = true;

- down_read(&tomoyo_globally_readable_list_lock);
- list_for_each_cookie(pos, head->read_var2,
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
+ list_for_each_cookie(pos, head->read_cookie2.u.list,
&tomoyo_globally_readable_list) {
struct tomoyo_globally_readable_file_entry *ptr;
ptr = list_entry(pos,
@@ -249,19 +228,18 @@ bool tomoyo_read_globally_readable_polic
list);
if (ptr->is_deleted)
continue;
- if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n",
- ptr->filename->name)) {
- done = false;
+ done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n",
+ ptr->filename->name);
+ if (!done)
break;
- }
}
- up_read(&tomoyo_globally_readable_list_lock);
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
return done;
}

/* The list for "struct tomoyo_pattern_entry". */
-static LIST_HEAD(tomoyo_pattern_list);
-static DECLARE_RWSEM(tomoyo_pattern_list_lock);
+LIST_HEAD(tomoyo_pattern_list);

/**
* tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list.
@@ -274,55 +252,55 @@ static DECLARE_RWSEM(tomoyo_pattern_list
static int tomoyo_update_file_pattern_entry(const char *pattern,
const bool is_delete)
{
- struct tomoyo_pattern_entry *new_entry;
+ struct tomoyo_pattern_entry *entry = NULL;
struct tomoyo_pattern_entry *ptr;
const struct tomoyo_path_info *saved_pattern;
- int error = -ENOMEM;
+ int error = is_delete ? -ENOENT : -ENOMEM;

if (!tomoyo_is_correct_path(pattern, 0, 1, 0, __func__))
return -EINVAL;
- saved_pattern = tomoyo_save_name(pattern);
+ saved_pattern = tomoyo_get_name(pattern);
if (!saved_pattern)
return -ENOMEM;
- /***** EXCLUSIVE SECTION START *****/
- down_write(&tomoyo_pattern_list_lock);
+ if (!is_delete)
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_policy_lock);
list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
if (saved_pattern != ptr->pattern)
continue;
ptr->is_deleted = is_delete;
error = 0;
- goto out;
+ break;
}
- if (is_delete) {
- error = -ENOENT;
- goto out;
+ if (!is_delete && error && tomoyo_alloc_element(entry)) {
+ entry->pattern = saved_pattern;
+ saved_pattern = NULL;
+ list_add_tail(&entry->list, &tomoyo_pattern_list);
+ entry = NULL;
+ error = 0;
}
- new_entry = tomoyo_alloc_element(sizeof(*new_entry));
- if (!new_entry)
- goto out;
- new_entry->pattern = saved_pattern;
- list_add_tail(&new_entry->list, &tomoyo_pattern_list);
- error = 0;
- out:
- up_write(&tomoyo_pattern_list_lock);
- /***** EXCLUSIVE SECTION END *****/
+ up_write(&tomoyo_policy_lock);
+ /***** WRITER SECTION END *****/
+ tomoyo_put_name(saved_pattern);
+ kfree(entry);
return error;
}

/**
* tomoyo_get_file_pattern - Get patterned pathname.
*
- * @filename: The filename to find patterned pathname.
- *
- * Returns pointer to pathname pattern if matched, @filename otherwise.
+ * @cookie: Pointer to "struct tomoyo_cookie".
*/
-static const struct tomoyo_path_info *
-tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
+static void tomoyo_get_file_pattern(struct tomoyo_cookie *cookie)
{
struct tomoyo_pattern_entry *ptr;
const struct tomoyo_path_info *pattern = NULL;
+ /* This is safe because cookie->u.path is not in policy. */
+ const struct tomoyo_path_info *filename = cookie->u.path;

- down_read(&tomoyo_pattern_list_lock);
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
if (ptr->is_deleted)
continue;
@@ -336,10 +314,10 @@ tomoyo_get_file_pattern(const struct tom
break;
}
}
- up_read(&tomoyo_pattern_list_lock);
if (pattern)
- filename = pattern;
- return filename;
+ cookie->u.path = pattern;
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
}

/**
@@ -367,25 +345,26 @@ bool tomoyo_read_file_pattern(struct tom
struct list_head *pos;
bool done = true;

- down_read(&tomoyo_pattern_list_lock);
- list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) {
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
+ list_for_each_cookie(pos, head->read_cookie2.u.list,
+ &tomoyo_pattern_list) {
struct tomoyo_pattern_entry *ptr;
ptr = list_entry(pos, struct tomoyo_pattern_entry, list);
if (ptr->is_deleted)
continue;
- if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN "%s\n",
- ptr->pattern->name)) {
- done = false;
+ done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN
+ "%s\n", ptr->pattern->name);
+ if (!done)
break;
- }
}
- up_read(&tomoyo_pattern_list_lock);
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
return done;
}

/* The list for "struct tomoyo_no_rewrite_entry". */
-static LIST_HEAD(tomoyo_no_rewrite_list);
-static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock);
+LIST_HEAD(tomoyo_no_rewrite_list);

/**
* tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list.
@@ -398,37 +377,38 @@ static DECLARE_RWSEM(tomoyo_no_rewrite_l
static int tomoyo_update_no_rewrite_entry(const char *pattern,
const bool is_delete)
{
- struct tomoyo_no_rewrite_entry *new_entry, *ptr;
+ struct tomoyo_no_rewrite_entry *entry = NULL;
+ struct tomoyo_no_rewrite_entry *ptr;
const struct tomoyo_path_info *saved_pattern;
- int error = -ENOMEM;
+ int error = is_delete ? -ENOENT : -ENOMEM;

if (!tomoyo_is_correct_path(pattern, 0, 0, 0, __func__))
return -EINVAL;
- saved_pattern = tomoyo_save_name(pattern);
+ saved_pattern = tomoyo_get_name(pattern);
if (!saved_pattern)
return -ENOMEM;
- /***** EXCLUSIVE SECTION START *****/
- down_write(&tomoyo_no_rewrite_list_lock);
+ if (!is_delete)
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_policy_lock);
list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
if (ptr->pattern != saved_pattern)
continue;
ptr->is_deleted = is_delete;
error = 0;
- goto out;
+ break;
}
- if (is_delete) {
- error = -ENOENT;
- goto out;
+ if (!is_delete && error && tomoyo_alloc_element(entry)) {
+ entry->pattern = saved_pattern;
+ saved_pattern = NULL;
+ list_add_tail(&entry->list, &tomoyo_no_rewrite_list);
+ entry = NULL;
+ error = 0;
}
- new_entry = tomoyo_alloc_element(sizeof(*new_entry));
- if (!new_entry)
- goto out;
- new_entry->pattern = saved_pattern;
- list_add_tail(&new_entry->list, &tomoyo_no_rewrite_list);
- error = 0;
- out:
- up_write(&tomoyo_no_rewrite_list_lock);
- /***** EXCLUSIVE SECTION END *****/
+ up_write(&tomoyo_policy_lock);
+ /***** WRITER SECTION END *****/
+ tomoyo_put_name(saved_pattern);
+ kfree(entry);
return error;
}

@@ -445,7 +425,8 @@ static bool tomoyo_is_no_rewrite_file(co
struct tomoyo_no_rewrite_entry *ptr;
bool found = false;

- down_read(&tomoyo_no_rewrite_list_lock);
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
if (ptr->is_deleted)
continue;
@@ -454,7 +435,8 @@ static bool tomoyo_is_no_rewrite_file(co
found = true;
break;
}
- up_read(&tomoyo_no_rewrite_list_lock);
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
return found;
}

@@ -483,19 +465,21 @@ bool tomoyo_read_no_rewrite_policy(struc
struct list_head *pos;
bool done = true;

- down_read(&tomoyo_no_rewrite_list_lock);
- list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) {
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
+ list_for_each_cookie(pos, head->read_cookie2.u.list,
+ &tomoyo_no_rewrite_list) {
struct tomoyo_no_rewrite_entry *ptr;
ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list);
if (ptr->is_deleted)
continue;
- if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE "%s\n",
- ptr->pattern->name)) {
- done = false;
+ done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE
+ "%s\n", ptr->pattern->name);
+ if (!done)
break;
- }
}
- up_read(&tomoyo_no_rewrite_list_lock);
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
return done;
}

@@ -561,7 +545,8 @@ static int tomoyo_check_single_path_acl2
struct tomoyo_acl_info *ptr;
int error = -EPERM;

- down_read(&tomoyo_domain_acl_info_list_lock);
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
list_for_each_entry(ptr, &domain->acl_info_list, list) {
struct tomoyo_single_path_acl_record *acl;
if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
@@ -580,7 +565,8 @@ static int tomoyo_check_single_path_acl2
error = 0;
break;
}
- up_read(&tomoyo_domain_acl_info_list_lock);
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
return error;
}

@@ -638,8 +624,7 @@ static int tomoyo_check_file_perm2(struc
if (!filename)
return 0;
error = tomoyo_check_file_acl(domain, filename, perm);
- if (error && perm == 4 &&
- (domain->flags & TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) == 0
+ if (error && perm == 4 && !domain->ignore_global_allow_read
&& tomoyo_is_globally_readable_file(filename))
error = 0;
if (perm == 6)
@@ -662,10 +647,17 @@ static int tomoyo_check_file_perm2(struc
return error;
if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
/* Don't use patterns for execute permission. */
- const struct tomoyo_path_info *patterned_file = (perm != 1) ?
- tomoyo_get_file_pattern(filename) : filename;
- tomoyo_update_file_acl(patterned_file->name, perm,
- domain, false);
+ if (perm == 1) {
+ tomoyo_update_file_acl(filename->name, perm, domain,
+ false);
+ } else {
+ struct tomoyo_cookie cookie;
+ tomoyo_add_cookie(&cookie, filename);
+ tomoyo_get_file_pattern(&cookie);
+ tomoyo_update_file_acl(cookie.u.path->name, perm,
+ domain, false);
+ tomoyo_del_cookie(&cookie);
+ }
}
return 0;
}
@@ -734,22 +726,24 @@ static int tomoyo_update_single_path_acl
(1 << TOMOYO_TYPE_READ_ACL) | (1 << TOMOYO_TYPE_WRITE_ACL);
const struct tomoyo_path_info *saved_filename;
struct tomoyo_acl_info *ptr;
- struct tomoyo_single_path_acl_record *acl;
- int error = -ENOMEM;
+ struct tomoyo_single_path_acl_record *entry = NULL;
+ int error = is_delete ? -ENOENT : -ENOMEM;
const u16 perm = 1 << type;

if (!domain)
return -EINVAL;
if (!tomoyo_is_correct_path(filename, 0, 0, 0, __func__))
return -EINVAL;
- saved_filename = tomoyo_save_name(filename);
+ saved_filename = tomoyo_get_name(filename);
if (!saved_filename)
return -ENOMEM;
- /***** EXCLUSIVE SECTION START *****/
- down_write(&tomoyo_domain_acl_info_list_lock);
if (is_delete)
goto delete;
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_policy_lock);
list_for_each_entry(ptr, &domain->acl_info_list, list) {
+ struct tomoyo_single_path_acl_record *acl;
if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
continue;
acl = container_of(ptr, struct tomoyo_single_path_acl_record,
@@ -766,22 +760,27 @@ static int tomoyo_update_single_path_acl
acl->perm |= rw_mask;
ptr->type &= ~TOMOYO_ACL_DELETED;
error = 0;
- goto out;
+ break;
}
- /* Not found. Append it to the tail. */
- acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_SINGLE_PATH_ACL);
- if (!acl)
- goto out;
- acl->perm = perm;
- if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL))
- acl->perm |= rw_mask;
- acl->filename = saved_filename;
- list_add_tail(&acl->head.list, &domain->acl_info_list);
- error = 0;
+ if (error && tomoyo_alloc_element(entry)) {
+ entry->head.type = TOMOYO_TYPE_SINGLE_PATH_ACL;
+ entry->perm = perm;
+ if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL))
+ entry->perm |= rw_mask;
+ entry->filename = saved_filename;
+ saved_filename = NULL;
+ list_add_tail(&entry->head.list, &domain->acl_info_list);
+ entry = NULL;
+ error = 0;
+ }
+ up_write(&tomoyo_policy_lock);
+ /***** WRITER SECTION END *****/
goto out;
delete:
- error = -ENOENT;
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_policy_lock);
list_for_each_entry(ptr, &domain->acl_info_list, list) {
+ struct tomoyo_single_path_acl_record *acl;
if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
continue;
acl = container_of(ptr, struct tomoyo_single_path_acl_record,
@@ -798,9 +797,11 @@ static int tomoyo_update_single_path_acl
error = 0;
break;
}
+ up_write(&tomoyo_policy_lock);
+ /***** WRITER SECTION END *****/
out:
- up_write(&tomoyo_domain_acl_info_list_lock);
- /***** EXCLUSIVE SECTION END *****/
+ tomoyo_put_name(saved_filename);
+ kfree(entry);
return error;
}

@@ -823,8 +824,8 @@ static int tomoyo_update_double_path_acl
const struct tomoyo_path_info *saved_filename1;
const struct tomoyo_path_info *saved_filename2;
struct tomoyo_acl_info *ptr;
- struct tomoyo_double_path_acl_record *acl;
- int error = -ENOMEM;
+ struct tomoyo_double_path_acl_record *entry = NULL;
+ int error = is_delete ? -ENOENT : -ENOMEM;
const u8 perm = 1 << type;

if (!domain)
@@ -832,15 +833,17 @@ static int tomoyo_update_double_path_acl
if (!tomoyo_is_correct_path(filename1, 0, 0, 0, __func__) ||
!tomoyo_is_correct_path(filename2, 0, 0, 0, __func__))
return -EINVAL;
- saved_filename1 = tomoyo_save_name(filename1);
- saved_filename2 = tomoyo_save_name(filename2);
+ saved_filename1 = tomoyo_get_name(filename1);
+ saved_filename2 = tomoyo_get_name(filename2);
if (!saved_filename1 || !saved_filename2)
- return -ENOMEM;
- /***** EXCLUSIVE SECTION START *****/
- down_write(&tomoyo_domain_acl_info_list_lock);
+ goto out;
if (is_delete)
goto delete;
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_policy_lock);
list_for_each_entry(ptr, &domain->acl_info_list, list) {
+ struct tomoyo_double_path_acl_record *acl;
if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
continue;
acl = container_of(ptr, struct tomoyo_double_path_acl_record,
@@ -854,21 +857,27 @@ static int tomoyo_update_double_path_acl
acl->perm |= perm;
ptr->type &= ~TOMOYO_ACL_DELETED;
error = 0;
- goto out;
+ break;
}
- /* Not found. Append it to the tail. */
- acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_DOUBLE_PATH_ACL);
- if (!acl)
- goto out;
- acl->perm = perm;
- acl->filename1 = saved_filename1;
- acl->filename2 = saved_filename2;
- list_add_tail(&acl->head.list, &domain->acl_info_list);
- error = 0;
+ if (error && tomoyo_alloc_element(entry)) {
+ entry->head.type = TOMOYO_TYPE_DOUBLE_PATH_ACL;
+ entry->perm = perm;
+ entry->filename1 = saved_filename1;
+ saved_filename1 = NULL;
+ entry->filename2 = saved_filename2;
+ saved_filename2 = NULL;
+ list_add_tail(&entry->head.list, &domain->acl_info_list);
+ entry = NULL;
+ error = 0;
+ }
+ up_write(&tomoyo_policy_lock);
+ /***** WRITER SECTION END *****/
goto out;
delete:
- error = -ENOENT;
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_policy_lock);
list_for_each_entry(ptr, &domain->acl_info_list, list) {
+ struct tomoyo_double_path_acl_record *acl;
if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
continue;
acl = container_of(ptr, struct tomoyo_double_path_acl_record,
@@ -882,9 +891,12 @@ static int tomoyo_update_double_path_acl
error = 0;
break;
}
+ up_write(&tomoyo_policy_lock);
+ /***** WRITER SECTION END *****/
out:
- up_write(&tomoyo_domain_acl_info_list_lock);
- /***** EXCLUSIVE SECTION END *****/
+ tomoyo_put_name(saved_filename1);
+ tomoyo_put_name(saved_filename2);
+ kfree(entry);
return error;
}

@@ -929,7 +941,8 @@ static int tomoyo_check_double_path_acl(

if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
return 0;
- down_read(&tomoyo_domain_acl_info_list_lock);
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_policy_lock);
list_for_each_entry(ptr, &domain->acl_info_list, list) {
struct tomoyo_double_path_acl_record *acl;
if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
@@ -945,7 +958,8 @@ static int tomoyo_check_double_path_acl(
error = 0;
break;
}
- up_read(&tomoyo_domain_acl_info_list_lock);
+ up_read(&tomoyo_policy_lock);
+ /***** READER SECTION END *****/
return error;
}

@@ -980,8 +994,12 @@ static int tomoyo_check_single_path_perm
tomoyo_get_msg(is_enforce), msg, filename->name,
tomoyo_get_last_name(domain));
if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
- const char *name = tomoyo_get_file_pattern(filename)->name;
- tomoyo_update_single_path_acl(operation, name, domain, false);
+ struct tomoyo_cookie cookie;
+ tomoyo_add_cookie(&cookie, filename);
+ tomoyo_get_file_pattern(&cookie);
+ tomoyo_update_single_path_acl(operation, cookie.u.path->name,
+ domain, false);
+ tomoyo_del_cookie(&cookie);
}
if (!is_enforce)
error = 0;
@@ -1227,10 +1245,17 @@ int tomoyo_check_2path_perm(struct tomoy
msg, buf1->name, buf2->name,
tomoyo_get_last_name(domain));
if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
- const char *name1 = tomoyo_get_file_pattern(buf1)->name;
- const char *name2 = tomoyo_get_file_pattern(buf2)->name;
- tomoyo_update_double_path_acl(operation, name1, name2, domain,
+ struct tomoyo_cookie cookie1;
+ struct tomoyo_cookie cookie2;
+ tomoyo_add_cookie(&cookie1, buf1);
+ tomoyo_add_cookie(&cookie2, buf2);
+ tomoyo_get_file_pattern(&cookie1);
+ tomoyo_get_file_pattern(&cookie2);
+ tomoyo_update_double_path_acl(operation, cookie1.u.path->name,
+ cookie2.u.path->name, domain,
false);
+ tomoyo_del_cookie(&cookie1);
+ tomoyo_del_cookie(&cookie2);
}
out:
tomoyo_free(buf1);
--- security-testing-2.6.git.orig/security/tomoyo/realpath.c
+++ security-testing-2.6.git/security/tomoyo/realpath.c
@@ -14,6 +14,7 @@
#include <linux/mnt_namespace.h>
#include <linux/fs_struct.h>
#include "common.h"
+#include "tomoyo.h"
#include "realpath.h"

/**
@@ -195,70 +196,49 @@ char *tomoyo_realpath_nofollow(const cha
}

/* Memory allocated for non-string data. */
-static unsigned int tomoyo_allocated_memory_for_elements;
+static atomic_t tomoyo_private_memory_size;
/* Quota for holding non-string data. */
-static unsigned int tomoyo_quota_for_elements;
+static unsigned int tomoyo_private_memory_quota;

/**
- * tomoyo_alloc_element - Allocate permanent memory for structures.
+ * tomoyo_alloc_element - Commit memory for elements.
*
- * @size: Size in bytes.
+ * @ptr: Pointer to allocated memory. Maybe NULL.
*
- * Returns pointer to allocated memory on success, NULL otherwise.
+ * Returns true if @ptr is not NULL and quota not exceeded, false otherwise.
*
- * Memory has to be zeroed.
- * The RAM is chunked, so NEVER try to kfree() the returned pointer.
+ * Caller must add @ptr to an appropriate list if this function returned true.
*/
-void *tomoyo_alloc_element(const unsigned int size)
+bool tomoyo_alloc_element(const void *ptr)
{
- static char *buf;
- static DEFINE_MUTEX(lock);
- static unsigned int buf_used_len = PATH_MAX;
- char *ptr = NULL;
- /*Assumes sizeof(void *) >= sizeof(long) is true. */
- const unsigned int word_aligned_size
- = roundup(size, max(sizeof(void *), sizeof(long)));
- if (word_aligned_size > PATH_MAX)
- return NULL;
- /***** EXCLUSIVE SECTION START *****/
- mutex_lock(&lock);
- if (buf_used_len + word_aligned_size > PATH_MAX) {
- if (!tomoyo_quota_for_elements ||
- tomoyo_allocated_memory_for_elements
- + PATH_MAX <= tomoyo_quota_for_elements)
- ptr = kzalloc(PATH_MAX, GFP_KERNEL);
- if (!ptr) {
- printk(KERN_WARNING "ERROR: Out of memory "
- "for tomoyo_alloc_element().\n");
- if (!tomoyo_policy_loaded)
- panic("MAC Initialization failed.\n");
- } else {
- buf = ptr;
- tomoyo_allocated_memory_for_elements += PATH_MAX;
- buf_used_len = word_aligned_size;
- ptr = buf;
- }
- } else if (word_aligned_size) {
- int i;
- ptr = buf + buf_used_len;
- buf_used_len += word_aligned_size;
- for (i = 0; i < word_aligned_size; i++) {
- if (!ptr[i])
- continue;
- printk(KERN_ERR "WARNING: Reserved memory was tainted! "
- "The system might go wrong.\n");
- ptr[i] = '\0';
- }
- }
- mutex_unlock(&lock);
- /***** EXCLUSIVE SECTION END *****/
- return ptr;
+ const int len = ptr ? ksize(ptr) : 0;
+ atomic_add(len, &tomoyo_private_memory_size);
+ if (len && (!tomoyo_private_memory_quota ||
+ atomic_read(&tomoyo_private_memory_size)
+ <= tomoyo_private_memory_quota))
+ return true;
+ atomic_sub(len, &tomoyo_private_memory_size);
+ printk(KERN_WARNING "ERROR: Out of memory. (%s)\n", __func__);
+ if (!tomoyo_policy_loaded)
+ panic("MAC Initialization failed.\n");
+ return false;
+}
+
+/**
+ * tomoyo_free_element - Free memory for elements.
+ *
+ * @ptr: Pointer to allocated memory.
+ */
+static void tomoyo_free_element(const void *ptr)
+{
+ atomic_sub(ksize(ptr), &tomoyo_private_memory_size);
+ kfree(ptr);
}

/* Memory allocated for string data in bytes. */
-static unsigned int tomoyo_allocated_memory_for_savename;
+static atomic_t tomoyo_shared_memory_size;
/* Quota for holding string data in bytes. */
-static unsigned int tomoyo_quota_for_savename;
+static unsigned int tomoyo_shared_memory_quota;

/*
* TOMOYO uses this hash only when appending a string into the string
@@ -270,104 +250,102 @@ static unsigned int tomoyo_quota_for_sav
/* Structure for string data. */
struct tomoyo_name_entry {
struct list_head list;
+ atomic_t users;
struct tomoyo_path_info entry;
};

-/* Structure for available memory region. */
-struct tomoyo_free_memory_block_list {
- struct list_head list;
- char *ptr; /* Pointer to a free area. */
- int len; /* Length of the area. */
-};
-
-/*
- * The list for "struct tomoyo_name_entry".
- *
- * This list is updated only inside tomoyo_save_name(), thus
- * no global mutex exists.
- */
+/* The list for "struct tomoyo_name_entry". */
static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
+static DEFINE_MUTEX(tomoyo_name_list_lock);

/**
- * tomoyo_save_name - Allocate permanent memory for string data.
+ * tomoyo_get_name - Allocate shared memory for string data.
*
- * @name: The string to store into the permernent memory.
+ * @name: The string to add.
*
* Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
- *
- * The RAM is shared, so NEVER try to modify or kfree() the returned name.
*/
-const struct tomoyo_path_info *tomoyo_save_name(const char *name)
+const struct tomoyo_path_info *tomoyo_get_name(const char *name)
{
- static LIST_HEAD(fmb_list);
- static DEFINE_MUTEX(lock);
+ struct tomoyo_name_entry *entry;
struct tomoyo_name_entry *ptr;
unsigned int hash;
- /* fmb contains available size in bytes.
- fmb is removed from the fmb_list when fmb->len becomes 0. */
- struct tomoyo_free_memory_block_list *fmb;
int len;
- char *cp;
+ int allocated_len;
+ int error = -ENOMEM;

if (!name)
return NULL;
len = strlen(name) + 1;
if (len > TOMOYO_MAX_PATHNAME_LEN) {
- printk(KERN_WARNING "ERROR: Name too long "
- "for tomoyo_save_name().\n");
+ printk(KERN_WARNING "ERROR: Name too long. (%s)\n", __func__);
return NULL;
}
hash = full_name_hash((const unsigned char *) name, len - 1);
+ entry = kmalloc(sizeof(*entry) + len, GFP_KERNEL);
+ allocated_len = entry ? ksize(entry) : 0;
/***** EXCLUSIVE SECTION START *****/
- mutex_lock(&lock);
+ mutex_lock(&tomoyo_name_list_lock);
list_for_each_entry(ptr, &tomoyo_name_list[hash % TOMOYO_MAX_HASH],
- list) {
- if (hash == ptr->entry.hash && !strcmp(name, ptr->entry.name))
- goto out;
- }
- list_for_each_entry(fmb, &fmb_list, list) {
- if (len <= fmb->len)
- goto ready;
- }
- if (!tomoyo_quota_for_savename ||
- tomoyo_allocated_memory_for_savename + PATH_MAX
- <= tomoyo_quota_for_savename)
- cp = kzalloc(PATH_MAX, GFP_KERNEL);
- else
- cp = NULL;
- fmb = kzalloc(sizeof(*fmb), GFP_KERNEL);
- if (!cp || !fmb) {
- kfree(cp);
- kfree(fmb);
- printk(KERN_WARNING "ERROR: Out of memory "
- "for tomoyo_save_name().\n");
+ list) {
+ if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
+ continue;
+ atomic_inc(&ptr->users);
+ error = 0;
+ break;
+ }
+ if (error && entry &&
+ (!tomoyo_shared_memory_quota ||
+ atomic_read(&tomoyo_shared_memory_size) + allocated_len
+ <= tomoyo_shared_memory_quota)) {
+ atomic_add(allocated_len, &tomoyo_shared_memory_size);
+ ptr = entry;
+ memset(ptr, 0, sizeof(*ptr));
+ ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
+ memmove((char *) ptr->entry.name, name, len);
+ atomic_set(&ptr->users, 1);
+ tomoyo_fill_path_info(&ptr->entry);
+ list_add_tail(&ptr->list,
+ &tomoyo_name_list[hash % TOMOYO_MAX_HASH]);
+ entry = NULL;
+ error = 0;
+ }
+ mutex_unlock(&tomoyo_name_list_lock);
+ /***** EXCLUSIVE SECTION END *****/
+ if (error) {
+ printk(KERN_WARNING "ERROR: Out of memory. (%s)\n", __func__);
if (!tomoyo_policy_loaded)
panic("MAC Initialization failed.\n");
- ptr = NULL;
- goto out;
}
- tomoyo_allocated_memory_for_savename += PATH_MAX;
- list_add(&fmb->list, &fmb_list);
- fmb->ptr = cp;
- fmb->len = PATH_MAX;
- ready:
- ptr = tomoyo_alloc_element(sizeof(*ptr));
- if (!ptr)
- goto out;
- ptr->entry.name = fmb->ptr;
- memmove(fmb->ptr, name, len);
- tomoyo_fill_path_info(&ptr->entry);
- fmb->ptr += len;
- fmb->len -= len;
- list_add_tail(&ptr->list, &tomoyo_name_list[hash % TOMOYO_MAX_HASH]);
- if (fmb->len == 0) {
- list_del(&fmb->list);
- kfree(fmb);
+ kfree(entry);
+ return ptr ? &ptr->entry : NULL;
+}
+
+/**
+ * tomoyo_put_name - Delete shared memory for string data.
+ *
+ * @ptr: Pointer to "struct tomoyo_path_info".
+ */
+void tomoyo_put_name(const struct tomoyo_path_info *name)
+{
+ struct tomoyo_name_entry *ptr;
+ bool can_delete = false;
+
+ if (!name)
+ return;
+ ptr = container_of(name, struct tomoyo_name_entry, entry);
+ /***** EXCLUSIVE SECTION START *****/
+ mutex_lock(&tomoyo_name_list_lock);
+ if (atomic_dec_and_test(&ptr->users)) {
+ list_del(&ptr->list);
+ can_delete = true;
}
- out:
- mutex_unlock(&lock);
+ mutex_unlock(&tomoyo_name_list_lock);
/***** EXCLUSIVE SECTION END *****/
- return ptr ? &ptr->entry : NULL;
+ if (can_delete) {
+ atomic_sub(ksize(ptr), &tomoyo_shared_memory_size);
+ kfree(ptr);
+ }
}

/**
@@ -376,17 +354,18 @@ const struct tomoyo_path_info *tomoyo_sa
void __init tomoyo_realpath_init(void)
{
int i;
+ struct tomoyo_cookie cookie;

BUILD_BUG_ON(TOMOYO_MAX_PATHNAME_LEN > PATH_MAX);
for (i = 0; i < TOMOYO_MAX_HASH; i++)
INIT_LIST_HEAD(&tomoyo_name_list[i]);
INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list);
- tomoyo_kernel_domain.domainname = tomoyo_save_name(TOMOYO_ROOT_NAME);
+ /* No lock needed because this is security_initcall() phase. */
+ tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME);
list_add_tail(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
- down_read(&tomoyo_domain_list_lock);
- if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
+ if (!tomoyo_find_domain(TOMOYO_ROOT_NAME, &cookie) ||
+ cookie.u.domain != &tomoyo_kernel_domain)
panic("Can't register tomoyo_kernel_domain");
- up_read(&tomoyo_domain_list_lock);
}

/* Memory allocated for temporary purpose. */
@@ -433,25 +412,25 @@ int tomoyo_read_memory_counter(struct to
{
if (!head->read_eof) {
const unsigned int shared
- = tomoyo_allocated_memory_for_savename;
+ = atomic_read(&tomoyo_shared_memory_size);
const unsigned int private
- = tomoyo_allocated_memory_for_elements;
+ = atomic_read(&tomoyo_private_memory_size);
const unsigned int dynamic
= atomic_read(&tomoyo_dynamic_memory_size);
char buffer[64];

memset(buffer, 0, sizeof(buffer));
- if (tomoyo_quota_for_savename)
+ if (tomoyo_shared_memory_quota)
snprintf(buffer, sizeof(buffer) - 1,
" (Quota: %10u)",
- tomoyo_quota_for_savename);
+ tomoyo_shared_memory_quota);
else
buffer[0] = '\0';
tomoyo_io_printf(head, "Shared: %10u%s\n", shared, buffer);
- if (tomoyo_quota_for_elements)
+ if (tomoyo_private_memory_quota)
snprintf(buffer, sizeof(buffer) - 1,
" (Quota: %10u)",
- tomoyo_quota_for_elements);
+ tomoyo_private_memory_quota);
else
buffer[0] = '\0';
tomoyo_io_printf(head, "Private: %10u%s\n", private, buffer);
@@ -476,8 +455,330 @@ int tomoyo_write_memory_quota(struct tom
unsigned int size;

if (sscanf(data, "Shared: %u", &size) == 1)
- tomoyo_quota_for_savename = size;
+ tomoyo_shared_memory_quota = size;
else if (sscanf(data, "Private: %u", &size) == 1)
- tomoyo_quota_for_elements = size;
+ tomoyo_private_memory_quota = size;
return 0;
}
+
+/* List of pointers referenced by cookies. */
+static LIST_HEAD(tomoyo_cookie_list);
+static DEFINE_RWLOCK(tomoyo_cookie_list_lock);
+
+/**
+ * tomoyo_add_cookie - Add a cookie to cookie list.
+ *
+ * @cookie: Pointer to "struct tomoyo_cookie".
+ * @ptr: Pointer to assign. Maybe NULL.
+ */
+void tomoyo_add_cookie(struct tomoyo_cookie *cookie, const void *ptr)
+{
+ unsigned long flags;
+ if (!cookie)
+ return;
+ cookie->u.ptr = ptr;
+ write_lock_irqsave(&tomoyo_cookie_list_lock, flags);
+ list_add_tail(&cookie->list, &tomoyo_cookie_list);
+ write_unlock_irqrestore(&tomoyo_cookie_list_lock, flags);
+}
+
+/**
+ * tomoyo_del_cookie - Delete a cookie from cookie list.
+ *
+ * @cookie: Pointer to "struct tomoyo_cookie".
+ */
+void tomoyo_del_cookie(struct tomoyo_cookie *cookie)
+{
+ unsigned long flags;
+ if (!cookie)
+ return;
+ write_lock_irqsave(&tomoyo_cookie_list_lock, flags);
+ list_del(&cookie->list);
+ write_unlock_irqrestore(&tomoyo_cookie_list_lock, flags);
+}
+
+/**
+ * tomoyo_used_by_cookie - Check whether the given pointer is referenced by a cookie or not.
+ *
+ * @ptr: Pointer to check.
+ *
+ * Returns true if @ptr is in use, false otherwise.
+ *
+ * Caller must hold tomoyo_policy_lock for writing.
+ */
+static bool tomoyo_used_by_cookie(const void *ptr)
+{
+ /***** WRITER SECTION START *****/
+ unsigned long flags;
+ struct tomoyo_cookie *cookie;
+ bool in_use = false;
+ read_lock_irqsave(&tomoyo_cookie_list_lock, flags);
+ list_for_each_entry(cookie, &tomoyo_cookie_list, list) {
+ if (ptr != cookie->u.ptr)
+ continue;
+ in_use = true;
+ break;
+ }
+ read_unlock_irqrestore(&tomoyo_cookie_list_lock, flags);
+ return in_use;
+ /***** WRITER SECTION END *****/
+}
+
+/**
+ * tomoyo_cleanup_allow_read - Clean up deleted "struct tomoyo_globally_readable_file_entry".
+ */
+static void tomoyo_cleanup_allow_read(void)
+{
+ struct tomoyo_globally_readable_file_entry *ptr;
+ struct tomoyo_globally_readable_file_entry *tmp;
+ LIST_HEAD(q);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_policy_lock);
+ list_for_each_entry_safe(ptr, tmp, &tomoyo_globally_readable_list,
+ list) {
+ if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
+ continue;
+ list_del(&ptr->list);
+ list_add(&ptr->list, &q);
+ }
+ up_write(&tomoyo_policy_lock);
+ /***** WRITER SECTION END *****/
+ list_for_each_entry_safe(ptr, tmp, &q, list) {
+ tomoyo_put_name(ptr->filename);
+ list_del(&ptr->list);
+ tomoyo_free_element(ptr);
+ }
+}
+
+/**
+ * tomoyo_cleanup_file_pattern - Clean up deleted "struct tomoyo_pattern_entry".
+ */
+static void tomoyo_cleanup_file_pattern(void)
+{
+ struct tomoyo_pattern_entry *ptr;
+ struct tomoyo_pattern_entry *tmp;
+ LIST_HEAD(q);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_policy_lock);
+ list_for_each_entry_safe(ptr, tmp, &tomoyo_pattern_list, list) {
+ if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
+ continue;
+ list_del(&ptr->list);
+ list_add(&ptr->list, &q);
+ }
+ up_write(&tomoyo_policy_lock);
+ /***** WRITER SECTION END *****/
+ list_for_each_entry_safe(ptr, tmp, &q, list) {
+ tomoyo_put_name(ptr->pattern);
+ list_del(&ptr->list);
+ tomoyo_free_element(ptr);
+ }
+}
+
+/**
+ * tomoyo_cleanup_no_rewrite - Clean up deleted "struct tomoyo_no_rewrite_entry".
+ */
+static void tomoyo_cleanup_no_rewrite(void)
+{
+ struct tomoyo_no_rewrite_entry *ptr;
+ struct tomoyo_no_rewrite_entry *tmp;
+ LIST_HEAD(q);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_policy_lock);
+ list_for_each_entry_safe(ptr, tmp, &tomoyo_no_rewrite_list, list) {
+ if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
+ continue;
+ list_del(&ptr->list);
+ list_add(&ptr->list, &q);
+ }
+ up_write(&tomoyo_policy_lock);
+ /***** WRITER SECTION END *****/
+ list_for_each_entry_safe(ptr, tmp, &q, list) {
+ tomoyo_put_name(ptr->pattern);
+ list_del(&ptr->list);
+ tomoyo_free_element(ptr);
+ }
+}
+
+/**
+ * tomoyo_cleanup_initializer - Clean up deleted "struct tomoyo_domain_initializer_entry".
+ */
+static void tomoyo_cleanup_initializer(void)
+{
+ struct tomoyo_domain_initializer_entry *ptr;
+ struct tomoyo_domain_initializer_entry *tmp;
+ LIST_HEAD(q);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_policy_lock);
+ list_for_each_entry_safe(ptr, tmp, &tomoyo_domain_initializer_list,
+ list) {
+ if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
+ continue;
+ list_del(&ptr->list);
+ list_add(&ptr->list, &q);
+ }
+ up_write(&tomoyo_policy_lock);
+ /***** WRITER SECTION END *****/
+ list_for_each_entry_safe(ptr, tmp, &q, list) {
+ tomoyo_put_name(ptr->domainname);
+ tomoyo_put_name(ptr->program);
+ list_del(&ptr->list);
+ tomoyo_free_element(ptr);
+ }
+}
+
+/**
+ * tomoyo_cleanup_keep_domain - Clean up deleted "struct tomoyo_domain_keeper_entry".
+ */
+static void tomoyo_cleanup_keep_domain(void)
+{
+ struct tomoyo_domain_keeper_entry *ptr;
+ struct tomoyo_domain_keeper_entry *tmp;
+ LIST_HEAD(q);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_policy_lock);
+ list_for_each_entry_safe(ptr, tmp, &tomoyo_domain_keeper_list, list) {
+ if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
+ continue;
+ list_del(&ptr->list);
+ list_add(&ptr->list, &q);
+ }
+ up_write(&tomoyo_policy_lock);
+ /***** WRITER SECTION END *****/
+ list_for_each_entry_safe(ptr, tmp, &q, list) {
+ tomoyo_put_name(ptr->domainname);
+ tomoyo_put_name(ptr->program);
+ list_del(&ptr->list);
+ tomoyo_free_element(ptr);
+ }
+}
+
+/**
+ * tomoyo_cleanup_alias - Clean up deleted "struct tomoyo_alias_entry".
+ */
+static void tomoyo_cleanup_alias(void)
+{
+ struct tomoyo_alias_entry *ptr;
+ struct tomoyo_alias_entry *tmp;
+ LIST_HEAD(q);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_policy_lock);
+ list_for_each_entry_safe(ptr, tmp, &tomoyo_alias_list, list) {
+ if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
+ continue;
+ list_del(&ptr->list);
+ list_add(&ptr->list, &q);
+ }
+ up_write(&tomoyo_policy_lock);
+ /***** WRITER SECTION END *****/
+ list_for_each_entry_safe(ptr, tmp, &q, list) {
+ tomoyo_put_name(ptr->original_name);
+ tomoyo_put_name(ptr->aliased_name);
+ list_del(&ptr->list);
+ tomoyo_free_element(ptr);
+ }
+}
+
+/**
+ * tomoyo_cleanup_manager - Clean up deleted "struct tomoyo_policy_manager_entry".
+ */
+static void tomoyo_cleanup_manager(void)
+{
+ struct tomoyo_policy_manager_entry *ptr;
+ struct tomoyo_policy_manager_entry *tmp;
+ LIST_HEAD(q);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_policy_lock);
+ list_for_each_entry_safe(ptr, tmp, &tomoyo_policy_manager_list, list) {
+ if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
+ continue;
+ list_del(&ptr->list);
+ list_add(&ptr->list, &q);
+ }
+ up_write(&tomoyo_policy_lock);
+ /***** WRITER SECTION END *****/
+ list_for_each_entry_safe(ptr, tmp, &q, list) {
+ tomoyo_put_name(ptr->manager);
+ list_del(&ptr->list);
+ tomoyo_free_element(ptr);
+ }
+}
+
+/**
+ * tomoyo_cleanup_domain_policy - Clean up deleted domain policy.
+ */
+static void tomoyo_cleanup_domain_policy(void)
+{
+ struct tomoyo_domain_info *domain;
+ struct tomoyo_domain_info *next_domain;
+ struct tomoyo_acl_info *acl;
+ struct tomoyo_acl_info *next_acl;
+ LIST_HEAD(q_domain);
+ LIST_HEAD(q_acl);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_policy_lock);
+ list_for_each_entry_safe(domain, next_domain, &tomoyo_domain_list,
+ list) {
+ const bool can_delete_domain = domain->is_deleted &&
+ !tomoyo_used_by_cookie(domain);
+ if (can_delete_domain) {
+ list_for_each_entry(acl, &domain->acl_info_list, list)
+ acl->type |= TOMOYO_ACL_DELETED;
+ }
+ list_for_each_entry_safe(acl, next_acl, &domain->acl_info_list,
+ list) {
+ if (!(acl->type & TOMOYO_ACL_DELETED)
+ || tomoyo_used_by_cookie(acl))
+ continue;
+ list_del(&acl->list);
+ list_add(&acl->list, &q_acl);
+ }
+ if (can_delete_domain && list_empty(&domain->acl_info_list)) {
+ list_del(&domain->list);
+ list_add(&domain->list, &q_domain);
+ }
+ }
+ up_write(&tomoyo_policy_lock);
+ /***** WRITER SECTION END *****/
+ list_for_each_entry_safe(acl, next_acl, &q_acl, list) {
+ switch (tomoyo_acl_type1(acl)) {
+ struct tomoyo_single_path_acl_record *acl1;
+ struct tomoyo_double_path_acl_record *acl2;
+ case TOMOYO_TYPE_SINGLE_PATH_ACL:
+ acl1 = container_of(acl,
+ struct tomoyo_single_path_acl_record,
+ head);
+ tomoyo_put_name(acl1->filename);
+ break;
+ case TOMOYO_TYPE_DOUBLE_PATH_ACL:
+ acl2 = container_of(acl,
+ struct tomoyo_double_path_acl_record,
+ head);
+ tomoyo_put_name(acl2->filename1);
+ tomoyo_put_name(acl2->filename2);
+ break;
+ }
+ list_del(&acl->list);
+ tomoyo_free_element(acl);
+ }
+ list_for_each_entry_safe(domain, next_domain, &q_domain, list) {
+ tomoyo_put_name(domain->domainname);
+ list_del(&domain->list);
+ tomoyo_free_element(domain);
+ }
+}
+
+/**
+ * tomoyo_run_garbage_collector - Run garbage collector.
+ */
+void tomoyo_run_garbage_collector(void)
+{
+ tomoyo_cleanup_allow_read();
+ tomoyo_cleanup_file_pattern();
+ tomoyo_cleanup_no_rewrite();
+ tomoyo_cleanup_initializer();
+ tomoyo_cleanup_keep_domain();
+ tomoyo_cleanup_alias();
+ tomoyo_cleanup_manager();
+ tomoyo_cleanup_domain_policy();
+}
--- security-testing-2.6.git.orig/security/tomoyo/realpath.h
+++ security-testing-2.6.git/security/tomoyo/realpath.h
@@ -36,18 +36,6 @@ char *tomoyo_realpath_nofollow(const cha
/* Same with tomoyo_realpath() except that the pathname is already solved. */
char *tomoyo_realpath_from_path(struct path *path);

-/*
- * Allocate memory for ACL entry.
- * The RAM is chunked, so NEVER try to kfree() the returned pointer.
- */
-void *tomoyo_alloc_element(const unsigned int size);
-
-/*
- * Keep the given name on the RAM.
- * The RAM is shared, so NEVER try to modify or kfree() the returned name.
- */
-const struct tomoyo_path_info *tomoyo_save_name(const char *name);
-
/* Allocate memory for temporary use (e.g. permission checks). */
void *tomoyo_alloc(const size_t size);

@@ -63,4 +51,17 @@ int tomoyo_write_memory_quota(struct tom
/* Initialize realpath related code. */
void __init tomoyo_realpath_init(void);

+/* Check memory quota. */
+bool tomoyo_alloc_element(const void *ptr);
+
+/* Allocate memory for the given name. */
+const struct tomoyo_path_info *tomoyo_get_name(const char *name);
+/* Delete memory for the given name. */
+void tomoyo_put_name(const struct tomoyo_path_info *name);
+
+/* Add a cookie to cookie list. */
+void tomoyo_add_cookie(struct tomoyo_cookie *cookie, const void *ptr);
+/* Delete a cookie from cookie list. */
+void tomoyo_del_cookie(struct tomoyo_cookie *cookie);
+
#endif /* !defined(_SECURITY_TOMOYO_REALPATH_H) */
--- security-testing-2.6.git.orig/security/tomoyo/tomoyo.c
+++ security-testing-2.6.git/security/tomoyo/tomoyo.c
@@ -17,14 +17,23 @@
static int tomoyo_cred_prepare(struct cred *new, const struct cred *old,
gfp_t gfp)
{
- /*
- * Since "struct tomoyo_domain_info *" is a sharable pointer,
- * we don't need to duplicate.
- */
- new->security = old->security;
+ struct tomoyo_cookie *cookie = kzalloc(sizeof(*cookie), gfp);
+
+ if (!cookie)
+ return -ENOMEM;
+ tomoyo_add_cookie(cookie,
+ ((struct tomoyo_cookie *) old->security)->u.ptr);
+ new->security = cookie;
return 0;
}

+static void tomoyo_cred_free(struct cred *cred)
+{
+ struct tomoyo_cookie *cookie = cred->security;
+ tomoyo_del_cookie(cookie);
+ kfree(cookie);
+}
+
static int tomoyo_bprm_set_creds(struct linux_binprm *bprm)
{
/*
@@ -43,26 +52,21 @@ static int tomoyo_bprm_set_creds(struct
* Tell tomoyo_bprm_check_security() is called for the first time of an
* execve operation.
*/
- bprm->cred->security = NULL;
+ ((struct tomoyo_cookie *) bprm->cred->security)->u.domain = NULL;
return 0;
}

static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
{
- struct tomoyo_domain_info *domain = bprm->cred->security;
+ struct tomoyo_domain_info *domain = ((struct tomoyo_cookie *)
+ bprm->cred->security)->u.domain;

/*
* Execute permission is checked against pathname passed to do_execve()
* using current domain.
*/
- if (!domain) {
- struct tomoyo_domain_info *next_domain = NULL;
- int retval = tomoyo_find_next_domain(bprm, &next_domain);
-
- if (!retval)
- bprm->cred->security = next_domain;
- return retval;
- }
+ if (!domain)
+ return tomoyo_find_next_domain(bprm);
/*
* Read permission is checked against interpreters using next domain.
* '1' is the result of open_to_namei_flags(O_RDONLY).
@@ -259,6 +263,7 @@ static int tomoyo_dentry_open(struct fil
static struct security_operations tomoyo_security_ops = {
.name = "tomoyo",
.cred_prepare = tomoyo_cred_prepare,
+ .cred_free = tomoyo_cred_free,
.bprm_set_creds = tomoyo_bprm_set_creds,
.bprm_check_security = tomoyo_bprm_check_security,
#ifdef CONFIG_SYSCTL
@@ -279,6 +284,7 @@ static struct security_operations tomoyo
static int __init tomoyo_init(void)
{
struct cred *cred = (struct cred *) current_cred();
+ struct tomoyo_cookie *cookie;

if (!security_module_enable(&tomoyo_security_ops))
return 0;
@@ -286,7 +292,9 @@ static int __init tomoyo_init(void)
if (register_security(&tomoyo_security_ops))
panic("Failure registering TOMOYO Linux");
printk(KERN_INFO "TOMOYO Linux initialized\n");
- cred->security = &tomoyo_kernel_domain;
+ cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
+ tomoyo_add_cookie(cookie, &tomoyo_kernel_domain);
+ cred->security = cookie;
tomoyo_realpath_init();
return 0;
}
--- security-testing-2.6.git.orig/security/tomoyo/tomoyo.h
+++ security-testing-2.6.git/security/tomoyo/tomoyo.h
@@ -33,8 +33,7 @@ int tomoyo_check_2path_perm(struct tomoy
struct path *path2);
int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain,
struct file *filp);
-int tomoyo_find_next_domain(struct linux_binprm *bprm,
- struct tomoyo_domain_info **next_domain);
+int tomoyo_find_next_domain(struct linux_binprm *bprm);

/* Index numbers for Access Controls. */

@@ -85,18 +84,14 @@ int tomoyo_find_next_domain(struct linux

extern struct tomoyo_domain_info tomoyo_kernel_domain;

-static inline struct tomoyo_domain_info *tomoyo_domain(void)
-{
- return current_cred()->security;
-}
-
-/* Caller holds tasklist_lock spinlock. */
+/* Caller calls rcu_read_lock()/rcu_read_unlock(). */
static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct
*task)
{
/***** CRITICAL SECTION START *****/
const struct cred *cred = get_task_cred(task);
- struct tomoyo_domain_info *domain = cred->security;
+ struct tomoyo_domain_info *domain = ((struct tomoyo_cookie *)
+ cred->security)->u.domain;

put_cred(cred);
return domain;