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: <200905072042.AFF10698.LJFHOOFFQtMOSV@I-love.SAKURA.ne.jp>
Date:	Thu, 7 May 2009 20:42:15 +0900
From:	Tetsuo Handa <penguin-kernel@...ove.SAKURA.ne.jp>
To:	pavel@....cz, jmorris@...ei.org
Cc:	linux-security-module@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: [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.

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.

  When a process finished reading list elements, a garbage collector function
  is called after the process released tomoyo_policy_lock.
  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.

  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.

  "struct tomoyo_io_buffer" remembers pointer to list elements.
  Thus, TOMOYO memorizes the address of "struct tomoyo_io_buffer"->read_var1,
  "struct tomoyo_io_buffer"->read_var2, "struct tomoyo_io_buffer"->write_var1
  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().

  tomoyo_update_cookie() is called with tomoyo_policy_lock held for reading
  when the pointer refers a different list element.

  tomoyo_used_by_cookie() is called with tomoyo_policy_lock held for writing
  to check whether the pointer is referenced by a cookie or not.


Now, TOMOYO can release memory. :-)

Attached patch is for security-testing-2.6#next.
James, it is possible to apply below commits to security-testing-2.6#next ?
I get a lot of warning messages in my environment.

39826a1e17c1957bd7b5cd7815b83940e5e3a230 tomoyo: version bump to 2.2.0. 
17a7b7b39056a82c5012539311850f202e6c3cd4 tomoyo: add Documentation/tomoyo.txt
05fa199d45c54a9bda7aa3ae6537253d6f097aa9 mm: pass correct mm when growing stack
05f54c13cd0c33694eec39a265475c5d6cf223cf Revert "kobject: don't block for each kobject_uevent".
a964e33c5d7c0ea46376d20c2f02edf01c9db251 x86: clean up old gcc warnings


Regards.
--------------------
Subject: [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.

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   |  259 ++++++++++++++++++++++++++++----------------
 security/tomoyo/common.h   |   37 ++++--
 security/tomoyo/domain.c   |  237 ++++++++++++++++++++++++----------------
 security/tomoyo/file.c     |  188 +++++++++++++++++++++++---------
 security/tomoyo/realpath.c |  264 ++++++++++++++++++++++++++-------------------
 security/tomoyo/realpath.h |   43 +++++--
 security/tomoyo/tomoyo.c   |   40 ++++--
 security/tomoyo/tomoyo.h   |   13 --
 8 files changed, 689 insertions(+), 392 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? */
@@ -326,13 +326,13 @@ 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); .
+ * Caller must hold tomoyo_policy_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;
@@ -340,11 +340,13 @@ struct tomoyo_domain_info *tomoyo_find_d
 	name.name = domainname;
 	tomoyo_fill_path_info(&name);
 	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;
+		tomoyo_update_cookie(cookie, domain);
+		return true;
 	}
-	return NULL;
+	return false;
 }
 
 /**
@@ -784,7 +786,7 @@ bool tomoyo_domain_quota_is_ok(struct to
 
 	if (!domain)
 		return true;
-	down_read(&tomoyo_domain_acl_info_list_lock);
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &domain->acl_info_list, list) {
 		if (ptr->type & TOMOYO_ACL_DELETED)
 			continue;
@@ -838,7 +840,7 @@ bool tomoyo_domain_quota_is_ok(struct to
 			break;
 		}
 	}
-	up_read(&tomoyo_domain_acl_info_list_lock);
+	up_read(&tomoyo_policy_lock);
 	if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY))
 		return true;
 	if (!domain->quota_warned) {
@@ -915,7 +917,10 @@ static int tomoyo_write_profile(struct t
 		return -EINVAL;
 	*cp = '\0';
 	if (!strcmp(data, "COMMENT")) {
+		down_write(&tomoyo_policy_lock);
+		tomoyo_del_name(profile->comment);
 		profile->comment = tomoyo_save_name(cp + 1);
+		up_write(&tomoyo_policy_lock);
 		return 0;
 	}
 	for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) {
@@ -973,9 +978,13 @@ static int tomoyo_read_profile(struct to
 		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;
+			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);
+			if (!done)
 				break;
 			continue;
 		}
@@ -1020,7 +1029,6 @@ struct tomoyo_policy_manager_entry {
 
 /* The list for "struct tomoyo_policy_manager_entry". */
 static LIST_HEAD(tomoyo_policy_manager_list);
-static DECLARE_RWSEM(tomoyo_policy_manager_list_lock);
 
 /**
  * tomoyo_update_manager_entry - Add a manager entry.
@@ -1051,7 +1059,7 @@ static int tomoyo_update_manager_entry(c
 	if (!saved_manager)
 		return -ENOMEM;
 	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_policy_manager_list_lock);
+	down_write(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
 		if (ptr->manager != saved_manager)
 			continue;
@@ -1067,11 +1075,13 @@ static int tomoyo_update_manager_entry(c
 	if (!new_entry)
 		goto out;
 	new_entry->manager = saved_manager;
+	saved_manager = NULL;
 	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);
+	tomoyo_del_name(saved_manager);
+	up_write(&tomoyo_policy_lock);
 	/***** EXCLUSIVE SECTION END *****/
 	return error;
 }
@@ -1095,6 +1105,23 @@ static int tomoyo_write_manager_policy(s
 	return tomoyo_update_manager_entry(data, is_delete);
 }
 
+static void tomoyo_cleanup_manager(void)
+{
+	struct tomoyo_policy_manager_entry *ptr;
+	struct tomoyo_policy_manager_entry *tmp;
+	/***** EXCLUSIVE 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);
+		tomoyo_del_name(ptr->manager);
+		tomoyo_free_element(ptr);
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** EXCLUSIVE SECTION END *****/
+}
+
 /**
  * tomoyo_read_manager_policy - Read manager policy.
  *
@@ -1109,8 +1136,8 @@ 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,
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(pos, head->read_var2.u.list,
 			     &tomoyo_policy_manager_list) {
 		struct tomoyo_policy_manager_entry *ptr;
 		ptr = list_entry(pos, struct tomoyo_policy_manager_entry,
@@ -1122,8 +1149,10 @@ static int tomoyo_read_manager_policy(st
 			break;
 		}
 	}
-	up_read(&tomoyo_policy_manager_list_lock);
+	up_read(&tomoyo_policy_lock);
 	head->read_eof = done;
+	if (done)
+		tomoyo_cleanup_manager();
 	return 0;
 }
 
@@ -1145,7 +1174,7 @@ 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);
+	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 +1182,13 @@ static bool tomoyo_is_policy_manager(voi
 			break;
 		}
 	}
-	up_read(&tomoyo_policy_manager_list_lock);
+	up_read(&tomoyo_policy_lock);
 	if (found)
 		return true;
 	exe = tomoyo_get_exe();
 	if (!exe)
 		return false;
-	down_read(&tomoyo_policy_manager_list_lock);
+	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 +1196,7 @@ static bool tomoyo_is_policy_manager(voi
 			break;
 		}
 	}
-	up_read(&tomoyo_policy_manager_list_lock);
+	up_read(&tomoyo_policy_lock);
 	if (!found) { /* Reduce error messages. */
 		static pid_t last_pid;
 		const pid_t pid = current->pid;
@@ -1194,25 +1223,30 @@ static bool tomoyo_is_select_one(struct 
 {
 	unsigned int pid;
 	struct tomoyo_domain_info *domain = NULL;
+	struct tomoyo_cookie *cookie = &head->write_var1;
 
 	if (sscanf(data, "pid=%u", &pid) == 1) {
 		struct task_struct *p;
+		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);
+		rcu_read_unlock();
 		/***** CRITICAL SECTION END *****/
+		if (domain)
+			tomoyo_update_cookie(cookie, domain);
+		up_read(&tomoyo_policy_lock);
 	} 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);
+			down_read(&tomoyo_policy_lock);
+			if (tomoyo_find_domain(data + 7, cookie))
+				domain = cookie->u.domain;
+			up_read(&tomoyo_policy_lock);
 		}
 	} 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). */
@@ -1222,15 +1256,15 @@ static bool tomoyo_is_select_one(struct 
 	head->read_eof = !domain;
 	if (domain) {
 		struct tomoyo_domain_info *d;
-		head->read_var1 = NULL;
-		down_read(&tomoyo_domain_list_lock);
+		head->read_var1.u.domain = NULL;
+		down_read(&tomoyo_policy_lock);
 		list_for_each_entry(d, &tomoyo_domain_list, list) {
 			if (d == domain)
 				break;
-			head->read_var1 = &d->list;
+			head->read_var1.u.list = &d->list;
 		}
-		up_read(&tomoyo_domain_list_lock);
-		head->read_var2 = NULL;
+		up_read(&tomoyo_policy_lock);
+		head->read_var2.u.list = NULL;
 		head->read_bit = 0;
 		head->read_step = 0;
 		if (domain->is_deleted)
@@ -1249,7 +1283,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_domain_info *domain = head->write_var1.u.domain;
 	bool is_delete = false;
 	bool is_select = false;
 	unsigned int profile;
@@ -1264,16 +1298,16 @@ static int tomoyo_write_domain_policy(st
 	if (!tomoyo_is_policy_manager())
 		return -EPERM;
 	if (tomoyo_is_domain_def(data)) {
-		domain = NULL;
-		if (is_delete)
+		struct tomoyo_cookie *cookie = &head->write_var1;
+		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);
+			tomoyo_update_cookie(cookie, NULL);
+		} else if (is_select) {
+			down_read(&tomoyo_policy_lock);
+			tomoyo_find_domain(data, cookie);
+			up_read(&tomoyo_policy_lock);
 		} else
-			domain = tomoyo_find_or_assign_new_domain(data, 0);
-		head->write_var1 = domain;
+			tomoyo_find_or_assign_new_domain(data, 0, cookie);
 		return 0;
 	}
 	if (!domain)
@@ -1410,6 +1444,57 @@ static bool tomoyo_print_entry(struct to
 	return false;
 }
 
+static void tomoyo_cleanup_domain_policy(void)
+{
+	struct tomoyo_domain_info *domain;
+	struct tomoyo_domain_info *next_domain;
+	/***** EXCLUSIVE SECTION START *****/
+	down_write(&tomoyo_policy_lock);
+	list_for_each_entry_safe(domain, next_domain, &tomoyo_domain_list,
+				 list) {
+		struct tomoyo_acl_info *acl;
+		struct tomoyo_acl_info *next_acl;
+		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);
+			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_del_name(acl1->filename);
+				break;
+			case TOMOYO_TYPE_DOUBLE_PATH_ACL:
+				acl2 = container_of(acl,
+				    struct tomoyo_double_path_acl_record,
+						    head);
+				tomoyo_del_name(acl2->filename1);
+				tomoyo_del_name(acl2->filename2);
+				break;
+			}
+			tomoyo_free_element(acl);
+		}
+		if (can_delete_domain && list_empty(&domain->acl_info_list)) {
+			tomoyo_del_name(domain->domainname);
+			list_del(&domain->list);
+			tomoyo_free_element(domain);
+		}
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** EXCLUSIVE SECTION END *****/
+}
+
 /**
  * tomoyo_read_domain_policy - Read domain policy.
  *
@@ -1427,8 +1512,9 @@ 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) {
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(dpos, head->read_var1.u.list,
+			     &tomoyo_domain_list) {
 		struct tomoyo_domain_info *domain;
 		const char *quota_exceeded = "";
 		const char *transition_failed = "";
@@ -1461,18 +1547,16 @@ 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_var2.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;
@@ -1485,8 +1569,10 @@ tail_mark:
 		if (head->read_single_domain)
 			break;
 	}
-	up_read(&tomoyo_domain_list_lock);
+	up_read(&tomoyo_policy_lock);
 	head->read_eof = done;
+	if (done)
+		tomoyo_cleanup_domain_policy();
 	return 0;
 }
 
@@ -1496,30 +1582,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;
+	down_read(&tomoyo_policy_lock);
+	if (tomoyo_find_domain(cp + 1, &cookie) &&
+	    (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded))
+		cookie.u.domain->profile = (u8) profile;
+	up_read(&tomoyo_policy_lock);
 	return 0;
 }
 
@@ -1529,13 +1610,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,8 +1618,8 @@ 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) {
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(pos, head->read_var1.u.list, &tomoyo_domain_list) {
 		struct tomoyo_domain_info *domain;
 		domain = list_entry(pos, struct tomoyo_domain_info, list);
 		if (domain->is_deleted)
@@ -1556,7 +1630,7 @@ static int tomoyo_read_domain_profile(st
 			break;
 		}
 	}
-	up_read(&tomoyo_domain_list_lock);
+	up_read(&tomoyo_policy_lock);
 	head->read_eof = done;
 	return 0;
 }
@@ -1595,11 +1669,11 @@ static int tomoyo_read_pid(struct tomoyo
 		struct task_struct *p;
 		struct tomoyo_domain_info *domain = NULL;
 		/***** 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);
+		rcu_read_unlock();
 		/***** CRITICAL SECTION END *****/
 		if (domain)
 			tomoyo_io_printf(head, "%d %u %s", pid, domain->profile,
@@ -1655,43 +1729,43 @@ static int tomoyo_read_exception_policy(
 	if (!head->read_eof) {
 		switch (head->read_step) {
 		case 0:
-			head->read_var2 = NULL;
+			head->read_var2.u.list = NULL;
 			head->read_step = 1;
 		case 1:
 			if (!tomoyo_read_domain_keeper_policy(head))
 				break;
-			head->read_var2 = NULL;
+			head->read_var2.u.list = NULL;
 			head->read_step = 2;
 		case 2:
 			if (!tomoyo_read_globally_readable_policy(head))
 				break;
-			head->read_var2 = NULL;
+			head->read_var2.u.list = NULL;
 			head->read_step = 3;
 		case 3:
-			head->read_var2 = NULL;
+			head->read_var2.u.list = NULL;
 			head->read_step = 4;
 		case 4:
 			if (!tomoyo_read_domain_initializer_policy(head))
 				break;
-			head->read_var2 = NULL;
+			head->read_var2.u.list = NULL;
 			head->read_step = 5;
 		case 5:
 			if (!tomoyo_read_alias_policy(head))
 				break;
-			head->read_var2 = NULL;
+			head->read_var2.u.list = NULL;
 			head->read_step = 6;
 		case 6:
-			head->read_var2 = NULL;
+			head->read_var2.u.list = NULL;
 			head->read_step = 7;
 		case 7:
 			if (!tomoyo_read_file_pattern(head))
 				break;
-			head->read_var2 = NULL;
+			head->read_var2.u.list = NULL;
 			head->read_step = 8;
 		case 8:
 			if (!tomoyo_read_no_rewrite_policy(head))
 				break;
-			head->read_var2 = NULL;
+			head->read_var2.u.list = NULL;
 			head->read_step = 9;
 		case 9:
 			head->read_eof = true;
@@ -1778,7 +1852,7 @@ 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);
+		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 +1860,7 @@ 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);
 	}
 }
 
@@ -1919,6 +1993,9 @@ static int tomoyo_open_control(const u8 
 			return -ENOMEM;
 		}
 	}
+	tomoyo_add_cookie(&head->read_var1, NULL);
+	tomoyo_add_cookie(&head->read_var2, NULL);
+	tomoyo_add_cookie(&head->write_var1, NULL);
 	file->private_data = head;
 	/*
 	 * Call the handler now if the file is
@@ -2043,6 +2120,9 @@ static int tomoyo_close_control(struct f
 	head->read_buf = NULL;
 	tomoyo_free(head->write_buf);
 	head->write_buf = NULL;
+	tomoyo_del_cookie(&head->read_var1);
+	tomoyo_del_cookie(&head->read_var2);
+	tomoyo_del_cookie(&head->write_var1);
 	tomoyo_free(head);
 	head = NULL;
 	file->private_data = NULL;
@@ -2171,9 +2251,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];
@@ -160,11 +172,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_var1;
 	/* Extra variables for reading.         */
-	struct list_head *read_var2;
+	struct tomoyo_cookie read_var2;
 	/* The position currently writing to.   */
-	struct tomoyo_domain_info *write_var1;
+	struct tomoyo_cookie write_var1;
 	/* The step for reading.                */
 	int read_step;
 	/* Buffer for reading.                  */
@@ -258,11 +270,10 @@ 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);
@@ -276,6 +287,11 @@ void tomoyo_load_policy(const char *file
 void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain,
 			    const bool is_delete, const u8 flags);
 
+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,
 				  const struct tomoyo_path_info *b)
@@ -319,12 +335,11 @@ 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;
 
 /* 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,7 +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);
+DECLARE_RWSEM(tomoyo_policy_lock);
 
 /* Structure for "initialize_domain" and "no_initialize_domain" keyword. */
 struct tomoyo_domain_initializer_entry {
@@ -96,7 +96,6 @@ 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);
 
 /**
  * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list.
@@ -133,10 +132,12 @@ static int tomoyo_update_domain_initiali
 			return -ENOMEM;
 	}
 	saved_program = tomoyo_save_name(program);
-	if (!saved_program)
+	if (!saved_program) {
+		tomoyo_del_name(saved_domainname);
 		return -ENOMEM;
+	}
 	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_domain_initializer_list_lock);
+	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 ||
@@ -154,17 +155,40 @@ static int tomoyo_update_domain_initiali
 	if (!new_entry)
 		goto out;
 	new_entry->domainname = saved_domainname;
+	saved_domainname = NULL;
 	new_entry->program = saved_program;
+	saved_program = NULL;
 	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;
  out:
-	up_write(&tomoyo_domain_initializer_list_lock);
+	tomoyo_del_name(saved_domainname);
+	tomoyo_del_name(saved_program);
+	up_write(&tomoyo_policy_lock);
 	/***** EXCLUSIVE SECTION END *****/
 	return error;
 }
 
+static void tomoyo_cleanup_initializer(void)
+{
+	struct tomoyo_domain_initializer_entry *ptr;
+	struct tomoyo_domain_initializer_entry *tmp;
+	/***** EXCLUSIVE 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);
+		tomoyo_del_name(ptr->domainname);
+		tomoyo_del_name(ptr->program);
+		tomoyo_free_element(ptr);
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** EXCLUSIVE SECTION END *****/
+}
+
 /**
  * tomoyo_read_domain_initializer_policy - Read "struct tomoyo_domain_initializer_entry" list.
  *
@@ -177,8 +201,8 @@ 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,
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(pos, head->read_var2.u.list,
 			     &tomoyo_domain_initializer_list) {
 		const char *no;
 		const char *from = "";
@@ -201,7 +225,9 @@ bool tomoyo_read_domain_initializer_poli
 			break;
 		}
 	}
-	up_read(&tomoyo_domain_initializer_list_lock);
+	up_read(&tomoyo_policy_lock);
+	if (done)
+		tomoyo_cleanup_initializer();
 	return done;
 }
 
@@ -248,7 +274,7 @@ static bool tomoyo_is_domain_initializer
 	struct tomoyo_domain_initializer_entry *ptr;
 	bool flag = false;
 
-	down_read(&tomoyo_domain_initializer_list_lock);
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(ptr,  &tomoyo_domain_initializer_list, list) {
 		if (ptr->is_deleted)
 			continue;
@@ -269,13 +295,12 @@ static bool tomoyo_is_domain_initializer
 		}
 		flag = true;
 	}
-	up_read(&tomoyo_domain_initializer_list_lock);
+	up_read(&tomoyo_policy_lock);
 	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);
 
 /**
  * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list.
@@ -313,10 +338,12 @@ static int tomoyo_update_domain_keeper_e
 			return -ENOMEM;
 	}
 	saved_domainname = tomoyo_save_name(domainname);
-	if (!saved_domainname)
+	if (!saved_domainname) {
+		tomoyo_del_name(saved_program);
 		return -ENOMEM;
+	}
 	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_domain_keeper_list_lock);
+	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 ||
@@ -334,13 +361,17 @@ static int tomoyo_update_domain_keeper_e
 	if (!new_entry)
 		goto out;
 	new_entry->domainname = saved_domainname;
+	saved_domainname = NULL;
 	new_entry->program = saved_program;
+	saved_program = NULL;
 	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;
  out:
-	up_write(&tomoyo_domain_keeper_list_lock);
+	tomoyo_del_name(saved_domainname);
+	tomoyo_del_name(saved_program);
+	up_write(&tomoyo_policy_lock);
 	/***** EXCLUSIVE SECTION END *****/
 	return error;
 }
@@ -366,6 +397,24 @@ int tomoyo_write_domain_keeper_policy(ch
 	return tomoyo_update_domain_keeper_entry(data, NULL, is_not, is_delete);
 }
 
+static void tomoyo_cleanup_keep_domain(void)
+{
+	struct tomoyo_domain_keeper_entry *ptr;
+	struct tomoyo_domain_keeper_entry *tmp;
+	/***** EXCLUSIVE 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);
+		tomoyo_del_name(ptr->domainname);
+		tomoyo_del_name(ptr->program);
+		tomoyo_free_element(ptr);
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** EXCLUSIVE SECTION END *****/
+}
+
 /**
  * tomoyo_read_domain_keeper_policy - Read "struct tomoyo_domain_keeper_entry" list.
  *
@@ -378,8 +427,8 @@ 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,
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(pos, head->read_var2.u.list,
 			     &tomoyo_domain_keeper_list) {
 		struct tomoyo_domain_keeper_entry *ptr;
 		const char *no;
@@ -402,7 +451,9 @@ bool tomoyo_read_domain_keeper_policy(st
 			break;
 		}
 	}
-	up_read(&tomoyo_domain_keeper_list_lock);
+	up_read(&tomoyo_policy_lock);
+	if (done)
+		tomoyo_cleanup_keep_domain();
 	return done;
 }
 
@@ -423,7 +474,7 @@ static bool tomoyo_is_domain_keeper(cons
 	struct tomoyo_domain_keeper_entry *ptr;
 	bool flag = false;
 
-	down_read(&tomoyo_domain_keeper_list_lock);
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
 		if (ptr->is_deleted)
 			continue;
@@ -442,13 +493,12 @@ static bool tomoyo_is_domain_keeper(cons
 		}
 		flag = true;
 	}
-	up_read(&tomoyo_domain_keeper_list_lock);
+	up_read(&tomoyo_policy_lock);
 	return flag;
 }
 
 /* The list for "struct tomoyo_alias_entry". */
 static LIST_HEAD(tomoyo_alias_list);
-static DECLARE_RWSEM(tomoyo_alias_list_lock);
 
 /**
  * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list.
@@ -474,10 +524,13 @@ static int tomoyo_update_alias_entry(con
 		return -EINVAL; /* No patterns allowed. */
 	saved_original_name = tomoyo_save_name(original_name);
 	saved_aliased_name = tomoyo_save_name(aliased_name);
-	if (!saved_original_name || !saved_aliased_name)
+	if (!saved_original_name || !saved_aliased_name) {
+		tomoyo_del_name(saved_original_name);
+		tomoyo_del_name(saved_aliased_name);
 		return -ENOMEM;
+	}
 	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_alias_list_lock);
+	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)
@@ -494,15 +547,37 @@ static int tomoyo_update_alias_entry(con
 	if (!new_entry)
 		goto out;
 	new_entry->original_name = saved_original_name;
+	saved_original_name = NULL;
 	new_entry->aliased_name = saved_aliased_name;
+	saved_aliased_name = NULL;
 	list_add_tail(&new_entry->list, &tomoyo_alias_list);
 	error = 0;
  out:
-	up_write(&tomoyo_alias_list_lock);
+	tomoyo_del_name(saved_original_name);
+	tomoyo_del_name(saved_aliased_name);
+	up_write(&tomoyo_policy_lock);
 	/***** EXCLUSIVE SECTION END *****/
 	return error;
 }
 
+static void tomoyo_cleanup_alias(void)
+{
+	struct tomoyo_alias_entry *ptr;
+	struct tomoyo_alias_entry *tmp;
+	/***** EXCLUSIVE 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);
+		tomoyo_del_name(ptr->original_name);
+		tomoyo_del_name(ptr->aliased_name);
+		tomoyo_free_element(ptr);
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** EXCLUSIVE SECTION END *****/
+}
+
 /**
  * tomoyo_read_alias_policy - Read "struct tomoyo_alias_entry" list.
  *
@@ -515,8 +590,8 @@ 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) {
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(pos, head->read_var2.u.list, &tomoyo_alias_list) {
 		struct tomoyo_alias_entry *ptr;
 
 		ptr = list_entry(pos, struct tomoyo_alias_entry, list);
@@ -529,7 +604,9 @@ bool tomoyo_read_alias_policy(struct tom
 			break;
 		}
 	}
-	up_read(&tomoyo_alias_list_lock);
+	up_read(&tomoyo_policy_lock);
+	if (done)
+		tomoyo_cleanup_alias();
 	return done;
 }
 
@@ -568,7 +645,7 @@ int tomoyo_delete_domain(char *domainnam
 	name.name = domainname;
 	tomoyo_fill_path_info(&name);
 	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_domain_list_lock);
+	down_write(&tomoyo_policy_lock);
 	/* Is there an active domain? */
 	list_for_each_entry(domain, &tomoyo_domain_list, list) {
 		/* Never delete tomoyo_kernel_domain */
@@ -580,7 +657,7 @@ int tomoyo_delete_domain(char *domainnam
 		domain->is_deleted = true;
 		break;
 	}
-	up_write(&tomoyo_domain_list_lock);
+	up_write(&tomoyo_policy_lock);
 	/***** EXCLUSIVE SECTION END *****/
 	return 0;
 }
@@ -590,81 +667,49 @@ int tomoyo_delete_domain(char *domainnam
  *
  * @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;
-	const struct tomoyo_path_info *saved_domainname;
+	struct tomoyo_domain_info *domain;
+	const struct tomoyo_path_info *saved_domainname = NULL;
 
 	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_domain_list_lock);
-	domain = tomoyo_find_domain(domainname);
-	if (domain)
+	down_write(&tomoyo_policy_lock);
+	if (tomoyo_find_domain(domainname, cookie))
 		goto out;
 	if (!tomoyo_is_correct_domain(domainname, __func__))
 		goto out;
 	saved_domainname = tomoyo_save_name(domainname);
 	if (!saved_domainname)
 		goto out;
-	/* Can I reuse memory of deleted domain? */
-	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)
-			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;
+		saved_domainname = NULL;
 		domain->profile = profile;
 		list_add_tail(&domain->list, &tomoyo_domain_list);
+		tomoyo_update_cookie(cookie, domain);
 	}
  out:
-	up_write(&tomoyo_domain_list_lock);
+	tomoyo_del_name(saved_domainname);
+	up_write(&tomoyo_policy_lock);
 	/***** EXCLUSIVE SECTION END *****/
-	return domain;
+	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 +717,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 +729,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 +769,7 @@ 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);
+		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 +781,7 @@ int tomoyo_find_next_domain(struct linux
 			tomoyo_fill_path_info(&r);
 			break;
 		}
-		up_read(&tomoyo_alias_list_lock);
+		up_read(&tomoyo_policy_lock);
 	}
 
 	/* Check execute permission. */
@@ -755,28 +801,36 @@ 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;
+		/*
+		 * Since old_domain is already in cookie list,
+		 * tomoyo_policy_lock is not needed.
+		 */
+		tomoyo_update_cookie(cookie, old_domain);
 	} else if (tomoyo_is_domain_keeper(old_domain->domainname, &r, &l)) {
 		/* Keep current domain. */
-		domain = old_domain;
+		found = true;
+		/*
+		 * Since old_domain is already in cookie,
+		 * tomoyo_policy_lock is not needed.
+		 */
+		tomoyo_update_cookie(cookie, 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);
+	down_read(&tomoyo_policy_lock);
+	found = tomoyo_find_domain(new_domain_name, cookie);
+	up_read(&tomoyo_policy_lock);
+	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);
@@ -788,7 +842,6 @@ int tomoyo_find_next_domain(struct linux
  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
@@ -130,9 +130,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 *
@@ -143,7 +140,6 @@ static int tomoyo_update_single_path_acl
 
 /* The list for "struct tomoyo_globally_readable_file_entry". */
 static LIST_HEAD(tomoyo_globally_readable_list);
-static DECLARE_RWSEM(tomoyo_globally_readable_list_lock);
 
 /**
  * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list.
@@ -167,7 +163,7 @@ static int tomoyo_update_globally_readab
 	if (!saved_filename)
 		return -ENOMEM;
 	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_globally_readable_list_lock);
+	down_write(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
 		if (ptr->filename != saved_filename)
 			continue;
@@ -183,10 +179,12 @@ static int tomoyo_update_globally_readab
 	if (!new_entry)
 		goto out;
 	new_entry->filename = saved_filename;
+	saved_filename = NULL;
 	list_add_tail(&new_entry->list, &tomoyo_globally_readable_list);
 	error = 0;
  out:
-	up_write(&tomoyo_globally_readable_list_lock);
+	tomoyo_del_name(saved_filename);
+	up_write(&tomoyo_policy_lock);
 	/***** EXCLUSIVE SECTION END *****/
 	return error;
 }
@@ -203,7 +201,7 @@ static bool tomoyo_is_globally_readable_
 {
 	struct tomoyo_globally_readable_file_entry *ptr;
 	bool found = false;
-	down_read(&tomoyo_globally_readable_list_lock);
+	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 +209,7 @@ static bool tomoyo_is_globally_readable_
 			break;
 		}
 	}
-	up_read(&tomoyo_globally_readable_list_lock);
+	up_read(&tomoyo_policy_lock);
 	return found;
 }
 
@@ -228,6 +226,24 @@ int tomoyo_write_globally_readable_polic
 	return tomoyo_update_globally_readable_entry(data, is_delete);
 }
 
+static void tomoyo_cleanup_allow_read(void)
+{
+	struct tomoyo_globally_readable_file_entry *ptr;
+	struct tomoyo_globally_readable_file_entry *tmp;
+	/***** EXCLUSIVE 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);
+		tomoyo_del_name(ptr->filename);
+		tomoyo_free_element(ptr);
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** EXCLUSIVE SECTION END *****/
+}
+
 /**
  * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list.
  *
@@ -240,8 +256,8 @@ 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,
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(pos, head->read_var2.u.list,
 			     &tomoyo_globally_readable_list) {
 		struct tomoyo_globally_readable_file_entry *ptr;
 		ptr = list_entry(pos,
@@ -255,13 +271,14 @@ bool tomoyo_read_globally_readable_polic
 			break;
 		}
 	}
-	up_read(&tomoyo_globally_readable_list_lock);
+	up_read(&tomoyo_policy_lock);
+	if (done)
+		tomoyo_cleanup_allow_read();
 	return done;
 }
 
 /* The list for "struct tomoyo_pattern_entry". */
 static LIST_HEAD(tomoyo_pattern_list);
-static DECLARE_RWSEM(tomoyo_pattern_list_lock);
 
 /**
  * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list.
@@ -285,7 +302,7 @@ static int tomoyo_update_file_pattern_en
 	if (!saved_pattern)
 		return -ENOMEM;
 	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_pattern_list_lock);
+	down_write(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
 		if (saved_pattern != ptr->pattern)
 			continue;
@@ -301,10 +318,12 @@ static int tomoyo_update_file_pattern_en
 	if (!new_entry)
 		goto out;
 	new_entry->pattern = saved_pattern;
+	saved_pattern = NULL;
 	list_add_tail(&new_entry->list, &tomoyo_pattern_list);
 	error = 0;
  out:
-	up_write(&tomoyo_pattern_list_lock);
+	tomoyo_del_name(saved_pattern);
+	up_write(&tomoyo_policy_lock);
 	/***** EXCLUSIVE SECTION END *****/
 	return error;
 }
@@ -312,17 +331,15 @@ static int tomoyo_update_file_pattern_en
 /**
  * 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;
+	const struct tomoyo_path_info *filename = cookie->u.path;
 
-	down_read(&tomoyo_pattern_list_lock);
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
 		if (ptr->is_deleted)
 			continue;
@@ -336,10 +353,9 @@ tomoyo_get_file_pattern(const struct tom
 			break;
 		}
 	}
-	up_read(&tomoyo_pattern_list_lock);
 	if (pattern)
-		filename = pattern;
-	return filename;
+		tomoyo_update_cookie(cookie, pattern);
+	up_read(&tomoyo_policy_lock);
 }
 
 /**
@@ -355,6 +371,23 @@ int tomoyo_write_pattern_policy(char *da
 	return tomoyo_update_file_pattern_entry(data, is_delete);
 }
 
+static void tomoyo_cleanup_file_pattern(void)
+{
+	struct tomoyo_pattern_entry *ptr;
+	struct tomoyo_pattern_entry *tmp;
+	/***** EXCLUSIVE 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);
+		tomoyo_del_name(ptr->pattern);
+		tomoyo_free_element(ptr);
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** EXCLUSIVE SECTION END *****/
+}
+
 /**
  * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list.
  *
@@ -367,8 +400,9 @@ 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) {
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(pos, head->read_var2.u.list,
+			     &tomoyo_pattern_list) {
 		struct tomoyo_pattern_entry *ptr;
 		ptr = list_entry(pos, struct tomoyo_pattern_entry, list);
 		if (ptr->is_deleted)
@@ -379,13 +413,14 @@ bool tomoyo_read_file_pattern(struct tom
 			break;
 		}
 	}
-	up_read(&tomoyo_pattern_list_lock);
+	up_read(&tomoyo_policy_lock);
+	if (done)
+		tomoyo_cleanup_file_pattern();
 	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);
 
 /**
  * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list.
@@ -408,7 +443,7 @@ static int tomoyo_update_no_rewrite_entr
 	if (!saved_pattern)
 		return -ENOMEM;
 	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_no_rewrite_list_lock);
+	down_write(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
 		if (ptr->pattern != saved_pattern)
 			continue;
@@ -424,10 +459,12 @@ static int tomoyo_update_no_rewrite_entr
 	if (!new_entry)
 		goto out;
 	new_entry->pattern = saved_pattern;
+	saved_pattern = NULL;
 	list_add_tail(&new_entry->list, &tomoyo_no_rewrite_list);
 	error = 0;
  out:
-	up_write(&tomoyo_no_rewrite_list_lock);
+	tomoyo_del_name(saved_pattern);
+	up_write(&tomoyo_policy_lock);
 	/***** EXCLUSIVE SECTION END *****/
 	return error;
 }
@@ -445,7 +482,7 @@ static bool tomoyo_is_no_rewrite_file(co
 	struct tomoyo_no_rewrite_entry *ptr;
 	bool found = false;
 
-	down_read(&tomoyo_no_rewrite_list_lock);
+	down_read(&tomoyo_policy_lock);
 	list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
 		if (ptr->is_deleted)
 			continue;
@@ -454,7 +491,7 @@ static bool tomoyo_is_no_rewrite_file(co
 		found = true;
 		break;
 	}
-	up_read(&tomoyo_no_rewrite_list_lock);
+	up_read(&tomoyo_policy_lock);
 	return found;
 }
 
@@ -471,6 +508,23 @@ int tomoyo_write_no_rewrite_policy(char 
 	return tomoyo_update_no_rewrite_entry(data, is_delete);
 }
 
+static void tomoyo_cleanup_no_rewrite(void)
+{
+	struct tomoyo_no_rewrite_entry *ptr;
+	struct tomoyo_no_rewrite_entry *tmp;
+	/***** EXCLUSIVE 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);
+		tomoyo_del_name(ptr->pattern);
+		tomoyo_free_element(ptr);
+	}
+	up_write(&tomoyo_policy_lock);
+	/***** EXCLUSIVE SECTION END *****/
+}
+
 /**
  * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list.
  *
@@ -483,8 +537,9 @@ 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) {
+	down_read(&tomoyo_policy_lock);
+	list_for_each_cookie(pos, head->read_var2.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)
@@ -495,7 +550,9 @@ bool tomoyo_read_no_rewrite_policy(struc
 			break;
 		}
 	}
-	up_read(&tomoyo_no_rewrite_list_lock);
+	up_read(&tomoyo_policy_lock);
+	if (done)
+		tomoyo_cleanup_no_rewrite();
 	return done;
 }
 
@@ -561,7 +618,7 @@ static int tomoyo_check_single_path_acl2
 	struct tomoyo_acl_info *ptr;
 	int error = -EPERM;
 
-	down_read(&tomoyo_domain_acl_info_list_lock);
+	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 +637,7 @@ static int tomoyo_check_single_path_acl2
 		error = 0;
 		break;
 	}
-	up_read(&tomoyo_domain_acl_info_list_lock);
+	up_read(&tomoyo_policy_lock);
 	return error;
 }
 
@@ -662,10 +719,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;
 }
@@ -746,7 +810,7 @@ static int tomoyo_update_single_path_acl
 	if (!saved_filename)
 		return -ENOMEM;
 	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_domain_acl_info_list_lock);
+	down_write(&tomoyo_policy_lock);
 	if (is_delete)
 		goto delete;
 	list_for_each_entry(ptr, &domain->acl_info_list, list) {
@@ -776,6 +840,7 @@ static int tomoyo_update_single_path_acl
 	if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL))
 		acl->perm |= rw_mask;
 	acl->filename = saved_filename;
+	saved_filename = NULL;
 	list_add_tail(&acl->head.list, &domain->acl_info_list);
 	error = 0;
 	goto out;
@@ -799,7 +864,8 @@ static int tomoyo_update_single_path_acl
 		break;
 	}
  out:
-	up_write(&tomoyo_domain_acl_info_list_lock);
+	tomoyo_del_name(saved_filename);
+	up_write(&tomoyo_policy_lock);
 	/***** EXCLUSIVE SECTION END *****/
 	return error;
 }
@@ -834,10 +900,13 @@ static int tomoyo_update_double_path_acl
 		return -EINVAL;
 	saved_filename1 = tomoyo_save_name(filename1);
 	saved_filename2 = tomoyo_save_name(filename2);
-	if (!saved_filename1 || !saved_filename2)
+	if (!saved_filename1 || !saved_filename2) {
+		tomoyo_del_name(saved_filename1);
+		tomoyo_del_name(saved_filename2);
 		return -ENOMEM;
+	}
 	/***** EXCLUSIVE SECTION START *****/
-	down_write(&tomoyo_domain_acl_info_list_lock);
+	down_write(&tomoyo_policy_lock);
 	if (is_delete)
 		goto delete;
 	list_for_each_entry(ptr, &domain->acl_info_list, list) {
@@ -862,7 +931,9 @@ static int tomoyo_update_double_path_acl
 		goto out;
 	acl->perm = perm;
 	acl->filename1 = saved_filename1;
+	saved_filename1 = NULL;
 	acl->filename2 = saved_filename2;
+	saved_filename2 = NULL;
 	list_add_tail(&acl->head.list, &domain->acl_info_list);
 	error = 0;
 	goto out;
@@ -883,7 +954,9 @@ static int tomoyo_update_double_path_acl
 		break;
 	}
  out:
-	up_write(&tomoyo_domain_acl_info_list_lock);
+	tomoyo_del_name(saved_filename1);
+	tomoyo_del_name(saved_filename2);
+	up_write(&tomoyo_policy_lock);
 	/***** EXCLUSIVE SECTION END *****/
 	return error;
 }
@@ -929,7 +1002,7 @@ 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);
+	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 +1018,7 @@ static int tomoyo_check_double_path_acl(
 		error = 0;
 		break;
 	}
-	up_read(&tomoyo_domain_acl_info_list_lock);
+	up_read(&tomoyo_policy_lock);
 	return error;
 }
 
@@ -980,8 +1053,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 +1304,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
@@ -194,68 +194,51 @@ char *tomoyo_realpath_nofollow(const cha
 }
 
 /* Memory allocated for non-string data. */
-static unsigned int tomoyo_allocated_memory_for_elements;
+static atomic_t tomoyo_allocated_memory_for_elements;
 /* Quota for holding non-string data. */
 static unsigned int tomoyo_quota_for_elements;
 
 /**
- * tomoyo_alloc_element - Allocate permanent memory for structures.
+ * tomoyo_alloc_element - Allocate memory for structures.
  *
  * @size: Size in bytes.
  *
  * Returns pointer to allocated memory on success, NULL otherwise.
  *
- * Memory has to be zeroed.
- * The RAM is chunked, so NEVER try to kfree() the returned pointer.
+ * Memory are zeroed.
  */
 void *tomoyo_alloc_element(const unsigned int size)
 {
-	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';
-		}
+	char *ptr = kzalloc(size, GFP_KERNEL);
+	int len = ptr ? ksize(ptr) : 0;
+	atomic_add(len, &tomoyo_allocated_memory_for_elements);
+	if (!len ||
+	    (tomoyo_quota_for_elements &&
+	     atomic_read(&tomoyo_allocated_memory_for_elements)
+	     > tomoyo_quota_for_elements)) {
+		kfree(ptr);
+		ptr = NULL;
+		atomic_sub(len, &tomoyo_allocated_memory_for_elements);
+		printk(KERN_WARNING "ERROR: Out of memory for %s().\n",
+		       __func__);
+		if (!tomoyo_policy_loaded)
+			panic("MAC Initialization failed.\n");
 	}
-	mutex_unlock(&lock);
-	/***** EXCLUSIVE SECTION END *****/
 	return ptr;
 }
 
+void tomoyo_free_element(void *ptr)
+{
+	int len;
+	if (!ptr)
+		return;
+	len = ksize(ptr);
+	kfree(ptr);
+	atomic_sub(len, &tomoyo_allocated_memory_for_elements);
+}
+
 /* Memory allocated for string data in bytes. */
-static unsigned int tomoyo_allocated_memory_for_savename;
+static atomic_t tomoyo_allocated_memory_for_savename;
 /* Quota for holding string data in bytes. */
 static unsigned int tomoyo_quota_for_savename;
 
@@ -269,44 +252,27 @@ 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_save_name - Allocate shared memory for string data.
  *
- * @name: The string to store into the permernent memory.
+ * @name: The string to add or find.
  *
  * 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)
 {
-	static LIST_HEAD(fmb_list);
-	static DEFINE_MUTEX(lock);
 	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;
 
 	if (!name)
 		return NULL;
@@ -318,74 +284,89 @@ const struct tomoyo_path_info *tomoyo_sa
 	}
 	hash = full_name_hash((const unsigned char *) name, len - 1);
 	/***** 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;
+			    list) {
+		if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
+			continue;
+		atomic_inc(&ptr->users);
+		goto out;
 	}
-	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");
+	ptr = kmalloc(sizeof(*ptr) + len, GFP_KERNEL);
+	allocated_len = ptr ? ksize(ptr) : 0;
+	if (!allocated_len ||
+	    (tomoyo_quota_for_savename &&
+	     atomic_read(&tomoyo_allocated_memory_for_savename)
+	     + allocated_len > tomoyo_quota_for_savename)) {
+		kfree(ptr);
+		ptr = NULL;
+		printk(KERN_WARNING "ERROR: Out of memory for %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);
+	atomic_add(allocated_len, &tomoyo_allocated_memory_for_savename);
+	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);
-	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);
-	}
  out:
-	mutex_unlock(&lock);
+	mutex_unlock(&tomoyo_name_list_lock);
 	/***** EXCLUSIVE SECTION END *****/
 	return ptr ? &ptr->entry : NULL;
 }
 
 /**
+ * tomoyo_del_name - Delete shared memory for string data.
+ *
+ * @name: Pointer to "struct tomoyo_path_info".
+ */
+void tomoyo_del_name(const struct tomoyo_path_info *name)
+{
+	struct tomoyo_name_entry *ptr;
+
+	if (!name)
+		return;
+	/***** EXCLUSIVE SECTION START *****/
+	mutex_lock(&tomoyo_name_list_lock);
+	list_for_each_entry(ptr, &tomoyo_name_list[name->hash %
+						   TOMOYO_MAX_HASH], list) {
+		if (tomoyo_pathcmp(name, &ptr->entry))
+			continue;
+		if (atomic_dec_and_test(&ptr->users)) {
+			int len = ksize(ptr);
+			list_del(&ptr->list);
+			kfree(ptr);
+			atomic_sub(len, &tomoyo_allocated_memory_for_savename);
+		}
+		break;
+	}
+	mutex_unlock(&tomoyo_name_list_lock);
+	/***** EXCLUSIVE SECTION END *****/
+}
+
+/**
  * tomoyo_realpath_init - Initialize realpath related code.
  */
 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);
+	/* No lock because this domain is not deletable. */
 	tomoyo_kernel_domain.domainname = tomoyo_save_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)
+	down_read(&tomoyo_policy_lock);
+	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);
+	up_read(&tomoyo_policy_lock);
 }
 
 /* Memory allocated for temporary purpose. */
@@ -432,9 +413,9 @@ int tomoyo_read_memory_counter(struct to
 {
 	if (!head->read_eof) {
 		const unsigned int shared
-			= tomoyo_allocated_memory_for_savename;
+			= atomic_read(&tomoyo_allocated_memory_for_savename);
 		const unsigned int private
-			= tomoyo_allocated_memory_for_elements;
+			= atomic_read(&tomoyo_allocated_memory_for_elements);
 		const unsigned int dynamic
 			= atomic_read(&tomoyo_dynamic_memory_size);
 		char buffer[64];
@@ -480,3 +461,64 @@ int tomoyo_write_memory_quota(struct tom
 		tomoyo_quota_for_elements = 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.
+ */
+void tomoyo_add_cookie(struct tomoyo_cookie *cookie, const void *ptr)
+{
+	unsigned long flags;
+	if (!cookie)
+		return;
+	tomoyo_update_cookie(cookie, 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.
+ */
+bool tomoyo_used_by_cookie(const void *ptr)
+{
+	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;
+}
--- 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,35 @@ int tomoyo_write_memory_quota(struct tom
 /* Initialize realpath related code. */
 void __init tomoyo_realpath_init(void);
 
+/* Allocate memory for ACL entry. */
+void *tomoyo_alloc_element(const unsigned int size);
+/* Delete memory for ACL entry. */
+void tomoyo_free_element(void *ptr);
+
+/* Allocate memory for the given name. */
+const struct tomoyo_path_info *tomoyo_save_name(const char *name);
+/* Delete memory for the given name. */
+void tomoyo_del_name(const struct tomoyo_path_info *name);
+
+/* Add a cookie to cookie list. */
+void tomoyo_add_cookie(struct tomoyo_cookie *cookie, const void *ptr);
+/**
+ * tomoyo_update_cookie - Assign the given pointer to a cookie.
+ *
+ * @cookie: Pointer to "struct tomoyo_cookie".
+ * @ptr:    Pointer to assign.
+ *
+ * Caller must hold tomoyo_policy_lock for writing unless @ptr is NULL or
+ * @ptr is already in cookie list.
+ */
+static inline void tomoyo_update_cookie(struct tomoyo_cookie *cookie,
+					const void *ptr)
+{
+	cookie->u.ptr = ptr;
+}
+/* Delete a cookie from cookie list. */
+void tomoyo_del_cookie(struct tomoyo_cookie *cookie);
+/* Check whether the given pointer is referenced by a cookie or not. */
+bool tomoyo_used_by_cookie(const void *ptr);
+
 #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