lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <200905142108.JIF10080.OOFHJVFtOSQMFL@I-love.SAKURA.ne.jp>
Date:	Thu, 14 May 2009 21:08:15 +0900
From:	Tetsuo Handa <penguin-kernel@...ove.SAKURA.ne.jp>
To:	jmorris@...ei.org, linux-security-module@...r.kernel.org
Cc:	linux-kernel@...r.kernel.org
Subject: [PATCH] TOMOYO: Add garbage collector support. (v2)

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@...data.co.jp>
Signed-off-by: Tetsuo Handa <penguin-kernel@...ove.SAKURA.ne.jp>
Signed-off-by: Toshiharu Harada <haradats@...data.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;
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ