mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] TOMOYO: Use RCU primitives for list operation
@ 2009-12-11 13:53 Tetsuo Handa
  2009-12-14 16:39 ` Serge E. Hallyn
  0 siblings, 1 reply; 6+ messages in thread
From: Tetsuo Handa @ 2009-12-11 13:53 UTC (permalink / raw)
  To: linux-security-module; +Cc: linux-kernel

Can somebody please review?
----------
[PATCH] TOMOYO: Use RCU primitives for list operation

Currently, TOMOYO is using down_read() only for protecting ->prev member from
writers. If we convert list operation using RCU primitives so that readers don't
look at ->prev member, we can replace down_read() by srcu_read_lock().

tomoyo_read_lock()/tomoyo_read_unlock() (these are wrappers for
srcu_read_lock()/srcu_read_unlock()) protects the data against the garbage
collector (which will be added in the future). I call tomoyo_read_lock() when
/sys/kernel/security/tomoyo/ interface is open()ed and call
tomoyo_read_unlock() when /sys/kernel/security/tomoyo/ interface is close()d
rather than calling tomoyo_read_lock()/tomoyo_read_unlock() upon individual
read()/write() requests. In this way, the pointers saved in
"struct tomoyo_io_buffer" are guaranteed to be valid. Please ignore

  warning: context imbalance in 'tomoyo_open_control' - wrong count at exit
  warning: context imbalance in 'tomoyo_close_control' - unexpected unlock

messages when built with "C=1" option.

Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
 common.c   |   90 +++++++++++++++++++++++++++----------------------
 common.h   |   28 +++++++++++----
 domain.c   |   63 ++++++++++++++++++++--------------
 file.c     |  110 ++++++++++++++++++++++++++++++++++++++++++-------------------
 realpath.c |    8 ++--
 tomoyo.c   |   20 +++++++++--
 6 files changed, 207 insertions(+), 112 deletions(-)

diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c
index 6c60616..f01b936 100644
--- a/security/tomoyo/common.c
+++ b/security/tomoyo/common.c
@@ -365,10 +365,9 @@ bool tomoyo_is_domain_def(const unsigned char *buffer)
  *
  * @domainname: The domainname to find.
  *
- * 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.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
 {
@@ -377,7 +376,7 @@ struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
 
 	name.name = domainname;
 	tomoyo_fill_path_info(&name);
-	list_for_each_entry(domain, &tomoyo_domain_list, list) {
+	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
 		if (!domain->is_deleted &&
 		    !tomoyo_pathcmp(&name, domain->domainname))
 			return domain;
@@ -829,6 +828,8 @@ bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain)
  * @domain: Pointer to "struct tomoyo_domain_info".
  *
  * Returns true if the domain is not exceeded quota, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain)
 {
@@ -837,8 +838,7 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain)
 
 	if (!domain)
 		return true;
-	down_read(&tomoyo_domain_acl_info_list_lock);
-	list_for_each_entry(ptr, &domain->acl_info_list, list) {
+	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
 		if (ptr->type & TOMOYO_ACL_DELETED)
 			continue;
 		switch (tomoyo_acl_type2(ptr)) {
@@ -866,7 +866,6 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain)
 			break;
 		}
 	}
-	up_read(&tomoyo_domain_acl_info_list_lock);
 	if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY))
 		return true;
 	if (!domain->quota_warned) {
@@ -1096,6 +1095,8 @@ static DECLARE_RWSEM(tomoyo_policy_manager_list_lock);
  * @is_delete: True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_update_manager_entry(const char *manager,
 				       const bool is_delete)
@@ -1118,7 +1119,7 @@ static int tomoyo_update_manager_entry(const char *manager,
 	if (!saved_manager)
 		return -ENOMEM;
 	down_write(&tomoyo_policy_manager_list_lock);
-	list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
 		if (ptr->manager != saved_manager)
 			continue;
 		ptr->is_deleted = is_delete;
@@ -1134,7 +1135,7 @@ static int tomoyo_update_manager_entry(const char *manager,
 		goto out;
 	new_entry->manager = saved_manager;
 	new_entry->is_domain = is_domain;
-	list_add_tail(&new_entry->list, &tomoyo_policy_manager_list);
+	list_add_tail_rcu(&new_entry->list, &tomoyo_policy_manager_list);
 	error = 0;
  out:
 	up_write(&tomoyo_policy_manager_list_lock);
@@ -1147,6 +1148,8 @@ static int tomoyo_update_manager_entry(const char *manager,
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head)
 {
@@ -1166,6 +1169,8 @@ static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head)
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns 0.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head)
 {
@@ -1174,7 +1179,6 @@ static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head)
 
 	if (head->read_eof)
 		return 0;
-	down_read(&tomoyo_policy_manager_list_lock);
 	list_for_each_cookie(pos, head->read_var2,
 			     &tomoyo_policy_manager_list) {
 		struct tomoyo_policy_manager_entry *ptr;
@@ -1186,7 +1190,6 @@ static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head)
 		if (!done)
 			break;
 	}
-	up_read(&tomoyo_policy_manager_list_lock);
 	head->read_eof = done;
 	return 0;
 }
@@ -1196,6 +1199,8 @@ static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head)
  *
  * Returns true if the current process is permitted to modify policy
  * via /sys/kernel/security/tomoyo/ interface.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static bool tomoyo_is_policy_manager(void)
 {
@@ -1209,29 +1214,25 @@ static bool tomoyo_is_policy_manager(void)
 		return true;
 	if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid))
 		return false;
-	down_read(&tomoyo_policy_manager_list_lock);
-	list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
 		if (!ptr->is_deleted && ptr->is_domain
 		    && !tomoyo_pathcmp(domainname, ptr->manager)) {
 			found = true;
 			break;
 		}
 	}
-	up_read(&tomoyo_policy_manager_list_lock);
 	if (found)
 		return true;
 	exe = tomoyo_get_exe();
 	if (!exe)
 		return false;
-	down_read(&tomoyo_policy_manager_list_lock);
-	list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
 		if (!ptr->is_deleted && !ptr->is_domain
 		    && !strcmp(exe, ptr->manager->name)) {
 			found = true;
 			break;
 		}
 	}
-	up_read(&tomoyo_policy_manager_list_lock);
 	if (!found) { /* Reduce error messages. */
 		static pid_t last_pid;
 		const pid_t pid = current->pid;
@@ -1252,6 +1253,8 @@ static bool tomoyo_is_policy_manager(void)
  * @data: String to parse.
  *
  * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
 				 const char *data)
@@ -1267,11 +1270,8 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
 			domain = tomoyo_real_domain(p);
 		read_unlock(&tasklist_lock);
 	} else if (!strncmp(data, "domain=", 7)) {
-		if (tomoyo_is_domain_def(data + 7)) {
-			down_read(&tomoyo_domain_list_lock);
+		if (tomoyo_is_domain_def(data + 7))
 			domain = tomoyo_find_domain(data + 7);
-			up_read(&tomoyo_domain_list_lock);
-		}
 	} else
 		return false;
 	head->write_var1 = domain;
@@ -1285,13 +1285,11 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
 	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) {
+		list_for_each_entry_rcu(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;
@@ -1307,6 +1305,8 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
  * @domainname: The name of domain.
  *
  * Returns 0.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_delete_domain(char *domainname)
 {
@@ -1317,7 +1317,7 @@ static int tomoyo_delete_domain(char *domainname)
 	tomoyo_fill_path_info(&name);
 	down_write(&tomoyo_domain_list_lock);
 	/* Is there an active domain? */
-	list_for_each_entry(domain, &tomoyo_domain_list, list) {
+	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
 		/* Never delete tomoyo_kernel_domain */
 		if (domain == &tomoyo_kernel_domain)
 			continue;
@@ -1337,6 +1337,8 @@ static int tomoyo_delete_domain(char *domainname)
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head)
 {
@@ -1359,11 +1361,9 @@ static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head)
 		domain = NULL;
 		if (is_delete)
 			tomoyo_delete_domain(data);
-		else if (is_select) {
-			down_read(&tomoyo_domain_list_lock);
+		else if (is_select)
 			domain = tomoyo_find_domain(data);
-			up_read(&tomoyo_domain_list_lock);
-		} else
+		else
 			domain = tomoyo_find_or_assign_new_domain(data, 0);
 		head->write_var1 = domain;
 		return 0;
@@ -1508,6 +1508,8 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns 0.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head)
 {
@@ -1519,7 +1521,6 @@ static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head)
 		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) {
 		struct tomoyo_domain_info *domain;
 		const char *quota_exceeded = "";
@@ -1552,7 +1553,6 @@ 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) {
 			struct tomoyo_acl_info *ptr
@@ -1562,7 +1562,6 @@ acl_loop:
 			if (!done)
 				break;
 		}
-		up_read(&tomoyo_domain_acl_info_list_lock);
 		if (!done)
 			break;
 		head->read_step = 3;
@@ -1574,7 +1573,6 @@ tail_mark:
 		if (head->read_single_domain)
 			break;
 	}
-	up_read(&tomoyo_domain_list_lock);
 	head->read_eof = done;
 	return 0;
 }
@@ -1590,6 +1588,8 @@ tail_mark:
  *
  *     ( echo "select " $domainname; echo "use_profile " $profile ) |
  *     /usr/lib/ccs/loadpolicy -d
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head)
 {
@@ -1601,9 +1601,7 @@ static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head)
 	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))
 		return -EINVAL;
 	if (domain && profile < TOMOYO_MAX_PROFILES
@@ -1625,6 +1623,8 @@ static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head)
  *     awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" )
  *     domainname = $0; } else if ( $1 == "use_profile" ) {
  *     print $2 " " domainname; domainname = ""; } } ; '
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
 {
@@ -1633,7 +1633,6 @@ static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
 
 	if (head->read_eof)
 		return 0;
-	down_read(&tomoyo_domain_list_lock);
 	list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) {
 		struct tomoyo_domain_info *domain;
 		domain = list_entry(pos, struct tomoyo_domain_info, list);
@@ -1644,7 +1643,6 @@ static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
 		if (!done)
 			break;
 	}
-	up_read(&tomoyo_domain_list_lock);
 	head->read_eof = done;
 	return 0;
 }
@@ -1701,6 +1699,8 @@ static int tomoyo_read_pid(struct tomoyo_io_buffer *head)
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head)
 {
@@ -1735,6 +1735,8 @@ static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head)
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns 0 on success, -EINVAL otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head)
 {
@@ -1864,15 +1866,13 @@ void tomoyo_load_policy(const char *filename)
 	tomoyo_policy_loaded = true;
 	{ /* Check all profiles currently assigned to domains are defined. */
 		struct tomoyo_domain_info *domain;
-		down_read(&tomoyo_domain_list_lock);
-		list_for_each_entry(domain, &tomoyo_domain_list, list) {
+		list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
 			const u8 profile = domain->profile;
 			if (tomoyo_profile_ptr[profile])
 				continue;
 			panic("Profile %u (used by '%s') not defined.\n",
 			      profile, domain->domainname->name);
 		}
-		up_read(&tomoyo_domain_list_lock);
 	}
 }
 
@@ -1920,6 +1920,8 @@ static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head)
  * @file: Pointer to "struct file".
  *
  * Associates policy handler and returns 0 on success, -ENOMEM otherwise.
+ *
+ * Caller acquires tomoyo_read_lock().
  */
 static int tomoyo_open_control(const u8 type, struct file *file)
 {
@@ -2005,6 +2007,7 @@ static int tomoyo_open_control(const u8 type, struct file *file)
 			return -ENOMEM;
 		}
 	}
+	head->reader_idx = tomoyo_read_lock();
 	file->private_data = head;
 	/*
 	 * Call the handler now if the file is
@@ -2026,6 +2029,8 @@ static int tomoyo_open_control(const u8 type, struct file *file)
  * @buffer_len: Size of @buffer.
  *
  * Returns bytes read on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_read_control(struct file *file, char __user *buffer,
 			       const int buffer_len)
@@ -2069,6 +2074,8 @@ static int tomoyo_read_control(struct file *file, char __user *buffer,
  * @buffer_len: Size of @buffer.
  *
  * Returns @buffer_len on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_write_control(struct file *file, const char __user *buffer,
 				const int buffer_len)
@@ -2119,11 +2126,14 @@ static int tomoyo_write_control(struct file *file, const char __user *buffer,
  * @file: Pointer to "struct file".
  *
  * Releases memory and returns 0.
+ *
+ * Caller looses tomoyo_read_lock().
  */
 static int tomoyo_close_control(struct file *file)
 {
 	struct tomoyo_io_buffer *head = file->private_data;
 
+	tomoyo_read_unlock(head->reader_idx);
 	/* Release memory used for policy I/O. */
 	tomoyo_free(head->read_buf);
 	head->read_buf = NULL;
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
index bd10f9f..c6f1392 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -269,6 +269,8 @@ struct tomoyo_io_buffer {
 	int (*write) (struct tomoyo_io_buffer *);
 	/* Exclusive lock for this structure.   */
 	struct mutex io_sem;
+	/* Index returned by tomoyo_read_lock(). */
+	int reader_idx;
 	/* The position currently reading from. */
 	struct list_head *read_var1;
 	/* Extra variables for reading.         */
@@ -446,16 +448,28 @@ extern struct tomoyo_domain_info tomoyo_kernel_domain;
  * @cookie:     the &struct list_head to use as a cookie.
  * @head:       the head for your list.
  *
- * Same with list_for_each() except that this primitive uses @cookie
+ * Same with list_for_each_rcu() except that this primitive uses @cookie
  * so that we can continue iteration.
  * @cookie must be NULL when iteration starts, and @cookie will become
  * NULL when iteration finishes.
  */
-#define list_for_each_cookie(pos, cookie, head)                       \
-	for (({ if (!cookie)                                          \
-				     cookie = head; }),               \
-	     pos = (cookie)->next;                                    \
-	     prefetch(pos->next), pos != (head) || ((cookie) = NULL); \
-	     (cookie) = pos, pos = pos->next)
+#define list_for_each_cookie(pos, cookie, head)				\
+	for (({ if (!cookie)						\
+				     cookie = head; }),			\
+		     pos = rcu_dereference((cookie)->next);		\
+	     prefetch(pos->next), pos != (head) || ((cookie) = NULL);	\
+	     (cookie) = pos, pos = rcu_dereference(pos->next))
+
+extern struct srcu_struct tomoyo_ss;
+
+static inline int tomoyo_read_lock(void)
+{
+	return srcu_read_lock(&tomoyo_ss);
+}
+
+static inline void tomoyo_read_unlock(int idx)
+{
+	srcu_read_unlock(&tomoyo_ss, idx);
+}
 
 #endif /* !defined(_SECURITY_TOMOYO_COMMON_H) */
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
index fcf52ac..2fd1901 100644
--- a/security/tomoyo/domain.c
+++ b/security/tomoyo/domain.c
@@ -217,6 +217,8 @@ static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock);
  * @is_delete:  True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_update_domain_initializer_entry(const char *domainname,
 						  const char *program,
@@ -246,7 +248,7 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname,
 	if (!saved_program)
 		return -ENOMEM;
 	down_write(&tomoyo_domain_initializer_list_lock);
-	list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
 		if (ptr->is_not != is_not ||
 		    ptr->domainname != saved_domainname ||
 		    ptr->program != saved_program)
@@ -266,7 +268,7 @@ static int tomoyo_update_domain_initializer_entry(const char *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);
+	list_add_tail_rcu(&new_entry->list, &tomoyo_domain_initializer_list);
 	error = 0;
  out:
 	up_write(&tomoyo_domain_initializer_list_lock);
@@ -279,13 +281,14 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname,
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head)
 {
 	struct list_head *pos;
 	bool done = true;
 
-	down_read(&tomoyo_domain_initializer_list_lock);
 	list_for_each_cookie(pos, head->read_var2,
 			     &tomoyo_domain_initializer_list) {
 		const char *no;
@@ -308,7 +311,6 @@ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head)
 		if (!done)
 			break;
 	}
-	up_read(&tomoyo_domain_initializer_list_lock);
 	return done;
 }
 
@@ -320,6 +322,8 @@ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head)
  * @is_delete: True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 int tomoyo_write_domain_initializer_policy(char *data, const bool is_not,
 					   const bool is_delete)
@@ -345,6 +349,8 @@ int tomoyo_write_domain_initializer_policy(char *data, const bool is_not,
  *
  * Returns true if executing @program reinitializes domain transition,
  * false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info *
 					 domainname,
@@ -355,8 +361,7 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info *
 	struct tomoyo_domain_initializer_entry *ptr;
 	bool flag = false;
 
-	down_read(&tomoyo_domain_initializer_list_lock);
-	list_for_each_entry(ptr,  &tomoyo_domain_initializer_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
 		if (ptr->is_deleted)
 			continue;
 		if (ptr->domainname) {
@@ -376,7 +381,6 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info *
 		}
 		flag = true;
 	}
-	up_read(&tomoyo_domain_initializer_list_lock);
 	return flag;
 }
 
@@ -430,6 +434,8 @@ static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock);
  * @is_delete:  True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_update_domain_keeper_entry(const char *domainname,
 					     const char *program,
@@ -459,7 +465,7 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname,
 	if (!saved_domainname)
 		return -ENOMEM;
 	down_write(&tomoyo_domain_keeper_list_lock);
-	list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
 		if (ptr->is_not != is_not ||
 		    ptr->domainname != saved_domainname ||
 		    ptr->program != saved_program)
@@ -479,7 +485,7 @@ static int tomoyo_update_domain_keeper_entry(const char *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);
+	list_add_tail_rcu(&new_entry->list, &tomoyo_domain_keeper_list);
 	error = 0;
  out:
 	up_write(&tomoyo_domain_keeper_list_lock);
@@ -493,6 +499,7 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname,
  * @is_not:    True if it is "no_keep_domain" entry.
  * @is_delete: True if it is a delete request.
  *
+ * Caller holds tomoyo_read_lock().
  */
 int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
 				      const bool is_delete)
@@ -513,13 +520,14 @@ int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head)
 {
 	struct list_head *pos;
 	bool done = true;
 
-	down_read(&tomoyo_domain_keeper_list_lock);
 	list_for_each_cookie(pos, head->read_var2,
 			     &tomoyo_domain_keeper_list) {
 		struct tomoyo_domain_keeper_entry *ptr;
@@ -542,7 +550,6 @@ bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head)
 		if (!done)
 			break;
 	}
-	up_read(&tomoyo_domain_keeper_list_lock);
 	return done;
 }
 
@@ -555,6 +562,8 @@ bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head)
  *
  * Returns true if executing @program supresses domain transition,
  * false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
 				    const struct tomoyo_path_info *program,
@@ -563,8 +572,7 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
 	struct tomoyo_domain_keeper_entry *ptr;
 	bool flag = false;
 
-	down_read(&tomoyo_domain_keeper_list_lock);
-	list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
 		if (ptr->is_deleted)
 			continue;
 		if (!ptr->is_last_name) {
@@ -582,7 +590,6 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
 		}
 		flag = true;
 	}
-	up_read(&tomoyo_domain_keeper_list_lock);
 	return flag;
 }
 
@@ -627,6 +634,8 @@ static DECLARE_RWSEM(tomoyo_alias_list_lock);
  * @is_delete:     True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_update_alias_entry(const char *original_name,
 				     const char *aliased_name,
@@ -646,7 +655,7 @@ static int tomoyo_update_alias_entry(const char *original_name,
 	if (!saved_original_name || !saved_aliased_name)
 		return -ENOMEM;
 	down_write(&tomoyo_alias_list_lock);
-	list_for_each_entry(ptr, &tomoyo_alias_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
 		if (ptr->original_name != saved_original_name ||
 		    ptr->aliased_name != saved_aliased_name)
 			continue;
@@ -663,7 +672,7 @@ static int tomoyo_update_alias_entry(const char *original_name,
 		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);
+	list_add_tail_rcu(&new_entry->list, &tomoyo_alias_list);
 	error = 0;
  out:
 	up_write(&tomoyo_alias_list_lock);
@@ -676,13 +685,14 @@ static int tomoyo_update_alias_entry(const char *original_name,
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
 {
 	struct list_head *pos;
 	bool done = true;
 
-	down_read(&tomoyo_alias_list_lock);
 	list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) {
 		struct tomoyo_alias_entry *ptr;
 
@@ -695,7 +705,6 @@ bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
 		if (!done)
 			break;
 	}
-	up_read(&tomoyo_alias_list_lock);
 	return done;
 }
 
@@ -706,6 +715,8 @@ bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
  * @is_delete: True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 int tomoyo_write_alias_policy(char *data, const bool is_delete)
 {
@@ -724,6 +735,8 @@ int tomoyo_write_alias_policy(char *data, const bool is_delete)
  * @profile:    Profile number to assign if the domain was newly created.
  *
  * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
 							    domainname,
@@ -742,7 +755,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
 	if (!saved_domainname)
 		goto out;
 	/* Can I reuse memory of deleted domain? */
-	list_for_each_entry(domain, &tomoyo_domain_list, list) {
+	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
 		struct task_struct *p;
 		struct tomoyo_acl_info *ptr;
 		bool flag;
@@ -760,7 +773,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
 		read_unlock(&tasklist_lock);
 		if (flag)
 			continue;
-		list_for_each_entry(ptr, &domain->acl_info_list, list) {
+		list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
 			ptr->type |= TOMOYO_ACL_DELETED;
 		}
 		tomoyo_set_domain_flag(domain, true, domain->flags);
@@ -776,7 +789,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
 		INIT_LIST_HEAD(&domain->acl_info_list);
 		domain->domainname = saved_domainname;
 		domain->profile = profile;
-		list_add_tail(&domain->list, &tomoyo_domain_list);
+		list_add_tail_rcu(&domain->list, &tomoyo_domain_list);
 	}
  out:
 	up_write(&tomoyo_domain_list_lock);
@@ -789,6 +802,8 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
  * @bprm: Pointer to "struct linux_binprm".
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 int tomoyo_find_next_domain(struct linux_binprm *bprm)
 {
@@ -849,8 +864,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
 	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);
-		list_for_each_entry(ptr, &tomoyo_alias_list, list) {
+		list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
 			if (ptr->is_deleted ||
 			    tomoyo_pathcmp(&r, ptr->original_name) ||
 			    tomoyo_pathcmp(&s, ptr->aliased_name))
@@ -861,7 +875,6 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
 			tomoyo_fill_path_info(&r);
 			break;
 		}
-		up_read(&tomoyo_alias_list_lock);
 	}
 
 	/* Check execute permission. */
@@ -892,9 +905,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
 	}
 	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)
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c
index 482f0e7..3c47286 100644
--- a/security/tomoyo/file.c
+++ b/security/tomoyo/file.c
@@ -213,6 +213,8 @@ static DECLARE_RWSEM(tomoyo_globally_readable_list_lock);
  * @is_delete: True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_update_globally_readable_entry(const char *filename,
 						 const bool is_delete)
@@ -228,7 +230,7 @@ static int tomoyo_update_globally_readable_entry(const char *filename,
 	if (!saved_filename)
 		return -ENOMEM;
 	down_write(&tomoyo_globally_readable_list_lock);
-	list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) {
 		if (ptr->filename != saved_filename)
 			continue;
 		ptr->is_deleted = is_delete;
@@ -243,7 +245,7 @@ static int tomoyo_update_globally_readable_entry(const char *filename,
 	if (!new_entry)
 		goto out;
 	new_entry->filename = saved_filename;
-	list_add_tail(&new_entry->list, &tomoyo_globally_readable_list);
+	list_add_tail_rcu(&new_entry->list, &tomoyo_globally_readable_list);
 	error = 0;
  out:
 	up_write(&tomoyo_globally_readable_list_lock);
@@ -256,21 +258,22 @@ static int tomoyo_update_globally_readable_entry(const char *filename,
  * @filename: The filename to check.
  *
  * Returns true if any domain can open @filename for reading, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info *
 					     filename)
 {
 	struct tomoyo_globally_readable_file_entry *ptr;
 	bool found = false;
-	down_read(&tomoyo_globally_readable_list_lock);
-	list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
+
+	list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) {
 		if (!ptr->is_deleted &&
 		    tomoyo_path_matches_pattern(filename, ptr->filename)) {
 			found = true;
 			break;
 		}
 	}
-	up_read(&tomoyo_globally_readable_list_lock);
 	return found;
 }
 
@@ -281,6 +284,8 @@ static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info *
  * @is_delete: True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 int tomoyo_write_globally_readable_policy(char *data, const bool is_delete)
 {
@@ -293,13 +298,14 @@ int tomoyo_write_globally_readable_policy(char *data, const bool is_delete)
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head)
 {
 	struct list_head *pos;
 	bool done = true;
 
-	down_read(&tomoyo_globally_readable_list_lock);
 	list_for_each_cookie(pos, head->read_var2,
 			     &tomoyo_globally_readable_list) {
 		struct tomoyo_globally_readable_file_entry *ptr;
@@ -313,7 +319,6 @@ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head)
 		if (!done)
 			break;
 	}
-	up_read(&tomoyo_globally_readable_list_lock);
 	return done;
 }
 
@@ -356,6 +361,8 @@ static DECLARE_RWSEM(tomoyo_pattern_list_lock);
  * @is_delete: True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_update_file_pattern_entry(const char *pattern,
 					    const bool is_delete)
@@ -371,7 +378,7 @@ static int tomoyo_update_file_pattern_entry(const char *pattern,
 	if (!saved_pattern)
 		return -ENOMEM;
 	down_write(&tomoyo_pattern_list_lock);
-	list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
 		if (saved_pattern != ptr->pattern)
 			continue;
 		ptr->is_deleted = is_delete;
@@ -386,7 +393,7 @@ static int tomoyo_update_file_pattern_entry(const char *pattern,
 	if (!new_entry)
 		goto out;
 	new_entry->pattern = saved_pattern;
-	list_add_tail(&new_entry->list, &tomoyo_pattern_list);
+	list_add_tail_rcu(&new_entry->list, &tomoyo_pattern_list);
 	error = 0;
  out:
 	up_write(&tomoyo_pattern_list_lock);
@@ -399,6 +406,8 @@ static int tomoyo_update_file_pattern_entry(const char *pattern,
  * @filename: The filename to find patterned pathname.
  *
  * Returns pointer to pathname pattern if matched, @filename otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static const struct tomoyo_path_info *
 tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
@@ -406,8 +415,7 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
 	struct tomoyo_pattern_entry *ptr;
 	const struct tomoyo_path_info *pattern = NULL;
 
-	down_read(&tomoyo_pattern_list_lock);
-	list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
 		if (ptr->is_deleted)
 			continue;
 		if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
@@ -420,7 +428,6 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
 			break;
 		}
 	}
-	up_read(&tomoyo_pattern_list_lock);
 	if (pattern)
 		filename = pattern;
 	return filename;
@@ -433,6 +440,8 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
  * @is_delete: True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 int tomoyo_write_pattern_policy(char *data, const bool is_delete)
 {
@@ -445,13 +454,14 @@ int tomoyo_write_pattern_policy(char *data, const bool is_delete)
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head)
 {
 	struct list_head *pos;
 	bool done = true;
 
-	down_read(&tomoyo_pattern_list_lock);
 	list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) {
 		struct tomoyo_pattern_entry *ptr;
 		ptr = list_entry(pos, struct tomoyo_pattern_entry, list);
@@ -462,7 +472,6 @@ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head)
 		if (!done)
 			break;
 	}
-	up_read(&tomoyo_pattern_list_lock);
 	return done;
 }
 
@@ -505,6 +514,8 @@ static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock);
  * @is_delete: True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_update_no_rewrite_entry(const char *pattern,
 					  const bool is_delete)
@@ -519,7 +530,7 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern,
 	if (!saved_pattern)
 		return -ENOMEM;
 	down_write(&tomoyo_no_rewrite_list_lock);
-	list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
 		if (ptr->pattern != saved_pattern)
 			continue;
 		ptr->is_deleted = is_delete;
@@ -534,7 +545,7 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern,
 	if (!new_entry)
 		goto out;
 	new_entry->pattern = saved_pattern;
-	list_add_tail(&new_entry->list, &tomoyo_no_rewrite_list);
+	list_add_tail_rcu(&new_entry->list, &tomoyo_no_rewrite_list);
 	error = 0;
  out:
 	up_write(&tomoyo_no_rewrite_list_lock);
@@ -548,14 +559,15 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern,
  *
  * Returns true if @filename is specified by "deny_rewrite" directive,
  * false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename)
 {
 	struct tomoyo_no_rewrite_entry *ptr;
 	bool found = false;
 
-	down_read(&tomoyo_no_rewrite_list_lock);
-	list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
 		if (ptr->is_deleted)
 			continue;
 		if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
@@ -563,7 +575,6 @@ static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename)
 		found = true;
 		break;
 	}
-	up_read(&tomoyo_no_rewrite_list_lock);
 	return found;
 }
 
@@ -574,6 +585,8 @@ static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename)
  * @is_delete: True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete)
 {
@@ -586,13 +599,14 @@ int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete)
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
 {
 	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) {
 		struct tomoyo_no_rewrite_entry *ptr;
 		ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list);
@@ -603,7 +617,6 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
 		if (!done)
 			break;
 	}
-	up_read(&tomoyo_no_rewrite_list_lock);
 	return done;
 }
 
@@ -621,6 +634,8 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
  * Current policy syntax uses "allow_read/write" instead of "6",
  * "allow_read" instead of "4", "allow_write" instead of "2",
  * "allow_execute" instead of "1".
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_update_file_acl(const char *filename, u8 perm,
 				  struct tomoyo_domain_info * const domain,
@@ -658,6 +673,8 @@ static int tomoyo_update_file_acl(const char *filename, u8 perm,
  * @may_use_pattern: True if patterned ACL is permitted.
  *
  * Returns 0 on success, -EPERM otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info *
 					 domain,
@@ -669,8 +686,7 @@ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info *
 	struct tomoyo_acl_info *ptr;
 	int error = -EPERM;
 
-	down_read(&tomoyo_domain_acl_info_list_lock);
-	list_for_each_entry(ptr, &domain->acl_info_list, list) {
+	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
 		struct tomoyo_single_path_acl_record *acl;
 		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
 			continue;
@@ -693,7 +709,6 @@ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info *
 		error = 0;
 		break;
 	}
-	up_read(&tomoyo_domain_acl_info_list_lock);
 	return error;
 }
 
@@ -705,6 +720,8 @@ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info *
  * @operation: Mode ("read" or "write" or "read/write" or "execute").
  *
  * Returns 0 on success, -EPERM otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain,
 				 const struct tomoyo_path_info *filename,
@@ -738,6 +755,8 @@ static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain,
  * @mode:      Access control mode.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain,
 				   const struct tomoyo_path_info *filename,
@@ -791,6 +810,8 @@ static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain,
  * @is_delete: True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
 			     const bool is_delete)
@@ -838,6 +859,8 @@ int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
  * @is_delete: True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
 					 struct tomoyo_domain_info *
@@ -861,7 +884,7 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
 	down_write(&tomoyo_domain_acl_info_list_lock);
 	if (is_delete)
 		goto delete;
-	list_for_each_entry(ptr, &domain->acl_info_list, list) {
+	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
 		if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
 			continue;
 		acl = container_of(ptr, struct tomoyo_single_path_acl_record,
@@ -894,12 +917,12 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
 	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);
+	list_add_tail_rcu(&acl->head.list, &domain->acl_info_list);
 	error = 0;
 	goto out;
  delete:
 	error = -ENOENT;
-	list_for_each_entry(ptr, &domain->acl_info_list, list) {
+	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
 		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
 			continue;
 		acl = container_of(ptr, struct tomoyo_single_path_acl_record,
@@ -934,6 +957,8 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
  * @is_delete: True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
 					 const char *filename2,
@@ -959,7 +984,7 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
 	down_write(&tomoyo_domain_acl_info_list_lock);
 	if (is_delete)
 		goto delete;
-	list_for_each_entry(ptr, &domain->acl_info_list, list) {
+	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
 		if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
 			continue;
 		acl = container_of(ptr, struct tomoyo_double_path_acl_record,
@@ -982,12 +1007,12 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
 	acl->perm = perm;
 	acl->filename1 = saved_filename1;
 	acl->filename2 = saved_filename2;
-	list_add_tail(&acl->head.list, &domain->acl_info_list);
+	list_add_tail_rcu(&acl->head.list, &domain->acl_info_list);
 	error = 0;
 	goto out;
  delete:
 	error = -ENOENT;
-	list_for_each_entry(ptr, &domain->acl_info_list, list) {
+	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
 		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
 			continue;
 		acl = container_of(ptr, struct tomoyo_double_path_acl_record,
@@ -1014,6 +1039,8 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
  * @filename: Filename to check.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain,
 					const u8 type,
@@ -1033,6 +1060,8 @@ static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain,
  * @filename2: Second filename to check.
  *
  * Returns 0 on success, -EPERM otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain,
 					const u8 type,
@@ -1047,8 +1076,7 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain,
 
 	if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
 		return 0;
-	down_read(&tomoyo_domain_acl_info_list_lock);
-	list_for_each_entry(ptr, &domain->acl_info_list, list) {
+	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
 		struct tomoyo_double_path_acl_record *acl;
 		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
 			continue;
@@ -1063,7 +1091,6 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain,
 		error = 0;
 		break;
 	}
-	up_read(&tomoyo_domain_acl_info_list_lock);
 	return error;
 }
 
@@ -1076,6 +1103,8 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain,
  * @mode:      Access control mode.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info *
 						const domain, u8 operation,
@@ -1124,6 +1153,8 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info *
  * @filename: Check permission for "execute".
  *
  * Returns 0 on success, negativevalue otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
 			   const struct tomoyo_path_info *filename)
@@ -1152,6 +1183,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
 	struct tomoyo_path_info *buf;
 	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
 	const bool is_enforce = (mode == 3);
+	int idx;
 
 	if (!mode || !path->mnt)
 		return 0;
@@ -1163,6 +1195,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
 		 * don't call me.
 		 */
 		return 0;
+	idx = tomoyo_read_lock();
 	buf = tomoyo_get_path(path);
 	if (!buf)
 		goto out;
@@ -1188,6 +1221,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
 							     buf, mode);
  out:
 	tomoyo_free(buf);
+	tomoyo_read_unlock(idx);
 	if (!is_enforce)
 		error = 0;
 	return error;
@@ -1209,9 +1243,11 @@ int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain,
 	struct tomoyo_path_info *buf;
 	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
 	const bool is_enforce = (mode == 3);
+	int idx;
 
 	if (!mode || !path->mnt)
 		return 0;
+	idx = tomoyo_read_lock();
 	buf = tomoyo_get_path(path);
 	if (!buf)
 		goto out;
@@ -1231,6 +1267,7 @@ int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain,
 						     mode);
  out:
 	tomoyo_free(buf);
+	tomoyo_read_unlock(idx);
 	if (!is_enforce)
 		error = 0;
 	return error;
@@ -1251,9 +1288,12 @@ int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain,
 	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
 	const bool is_enforce = (mode == 3);
 	struct tomoyo_path_info *buf;
+	int idx;
 
 	if (!mode || !filp->f_path.mnt)
 		return 0;
+
+	idx = tomoyo_read_lock();
 	buf = tomoyo_get_path(&filp->f_path);
 	if (!buf)
 		goto out;
@@ -1266,6 +1306,7 @@ int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain,
 						     buf, mode);
  out:
 	tomoyo_free(buf);
+	tomoyo_read_unlock(idx);
 	if (!is_enforce)
 		error = 0;
 	return error;
@@ -1290,9 +1331,11 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain,
 	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
 	const bool is_enforce = (mode == 3);
 	const char *msg;
+	int idx;
 
 	if (!mode || !path1->mnt || !path2->mnt)
 		return 0;
+	idx = tomoyo_read_lock();
 	buf1 = tomoyo_get_path(path1);
 	buf2 = tomoyo_get_path(path2);
 	if (!buf1 || !buf2)
@@ -1331,6 +1374,7 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain,
  out:
 	tomoyo_free(buf1);
 	tomoyo_free(buf2);
+	tomoyo_read_unlock(idx);
 	if (!is_enforce)
 		error = 0;
 	return error;
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c
index e3c7aa0..62363b3 100644
--- a/security/tomoyo/realpath.c
+++ b/security/tomoyo/realpath.c
@@ -402,11 +402,13 @@ void __init tomoyo_realpath_init(void)
 		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);
-	list_add_tail(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
-	down_read(&tomoyo_domain_list_lock);
+	/*
+	 * tomoyo_read_lock() is not needed because this function is
+	 * called before the first "delete" request.
+	 */
+	list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
 	if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
 		panic("Can't register tomoyo_kernel_domain");
-	up_read(&tomoyo_domain_list_lock);
 }
 
 /* Memory allocated for temporary purpose. */
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index ad9555f..714daa3 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -76,8 +76,18 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
 	 * Execute permission is checked against pathname passed to do_execve()
 	 * using current domain.
 	 */
-	if (!domain)
-		return tomoyo_find_next_domain(bprm);
+	if (!domain) {
+		/*
+		 * We will need to protect whole execve() operation when GC
+		 * starts kfree()ing "struct tomoyo_domain_info" because
+		 * bprm->cred->security points to "struct tomoyo_domain_info"
+		 * but "struct tomoyo_domain_info" does not have a refcounter.
+		 */
+		const int idx = tomoyo_read_lock();
+		const int err = tomoyo_find_next_domain(bprm);
+		tomoyo_read_unlock(idx);
+		return err;
+	}
 	/*
 	 * Read permission is checked against interpreters using next domain.
 	 * '1' is the result of open_to_namei_flags(O_RDONLY).
@@ -278,6 +288,9 @@ static struct security_operations tomoyo_security_ops = {
 	.sb_pivotroot        = tomoyo_sb_pivotroot,
 };
 
+/* Lock for GC. */
+struct srcu_struct tomoyo_ss;
+
 static int __init tomoyo_init(void)
 {
 	struct cred *cred = (struct cred *) current_cred();
@@ -285,7 +298,8 @@ static int __init tomoyo_init(void)
 	if (!security_module_enable(&tomoyo_security_ops))
 		return 0;
 	/* register ourselves with the security framework */
-	if (register_security(&tomoyo_security_ops))
+	if (register_security(&tomoyo_security_ops) ||
+	    init_srcu_struct(&tomoyo_ss))
 		panic("Failure registering TOMOYO Linux");
 	printk(KERN_INFO "TOMOYO Linux initialized\n");
 	cred->security = &tomoyo_kernel_domain;

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] TOMOYO: Use RCU primitives for list operation
  2009-12-11 13:53 [PATCH] TOMOYO: Use RCU primitives for list operation Tetsuo Handa
@ 2009-12-14 16:39 ` Serge E. Hallyn
  2009-12-15  1:39   ` Tetsuo Handa
  0 siblings, 1 reply; 6+ messages in thread
From: Serge E. Hallyn @ 2009-12-14 16:39 UTC (permalink / raw)
  To: Tetsuo Handa; +Cc: linux-security-module, linux-kernel

Quoting Tetsuo Handa (penguin-kernel@I-love.SAKURA.ne.jp):
> Can somebody please review?

Thanks, Tetsuo!

Just out of curiosity (and bc I'm personally much more familiar with plain old
rcu), I assume you have a list of places where sleeping under rcu is necessary
or greatly simplifies/cleans up the code?

Acked-by: Serge Hallyn <serue@us.ibm.com>

-serge

> ----------
> [PATCH] TOMOYO: Use RCU primitives for list operation
> 
> Currently, TOMOYO is using down_read() only for protecting ->prev member from
> writers. If we convert list operation using RCU primitives so that readers don't
> look at ->prev member, we can replace down_read() by srcu_read_lock().
> 
> tomoyo_read_lock()/tomoyo_read_unlock() (these are wrappers for
> srcu_read_lock()/srcu_read_unlock()) protects the data against the garbage
> collector (which will be added in the future). I call tomoyo_read_lock() when
> /sys/kernel/security/tomoyo/ interface is open()ed and call
> tomoyo_read_unlock() when /sys/kernel/security/tomoyo/ interface is close()d
> rather than calling tomoyo_read_lock()/tomoyo_read_unlock() upon individual
> read()/write() requests. In this way, the pointers saved in
> "struct tomoyo_io_buffer" are guaranteed to be valid. Please ignore
> 
>   warning: context imbalance in 'tomoyo_open_control' - wrong count at exit
>   warning: context imbalance in 'tomoyo_close_control' - unexpected unlock
> 
> messages when built with "C=1" option.
> 
> Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
> ---
>  common.c   |   90 +++++++++++++++++++++++++++----------------------
>  common.h   |   28 +++++++++++----
>  domain.c   |   63 ++++++++++++++++++++--------------
>  file.c     |  110 ++++++++++++++++++++++++++++++++++++++++++-------------------
>  realpath.c |    8 ++--
>  tomoyo.c   |   20 +++++++++--
>  6 files changed, 207 insertions(+), 112 deletions(-)
> 
> diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c
> index 6c60616..f01b936 100644
> --- a/security/tomoyo/common.c
> +++ b/security/tomoyo/common.c
> @@ -365,10 +365,9 @@ bool tomoyo_is_domain_def(const unsigned char *buffer)
>   *
>   * @domainname: The domainname to find.
>   *
> - * 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.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
>  {
> @@ -377,7 +376,7 @@ struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
> 
>  	name.name = domainname;
>  	tomoyo_fill_path_info(&name);
> -	list_for_each_entry(domain, &tomoyo_domain_list, list) {
> +	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
>  		if (!domain->is_deleted &&
>  		    !tomoyo_pathcmp(&name, domain->domainname))
>  			return domain;
> @@ -829,6 +828,8 @@ bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain)
>   * @domain: Pointer to "struct tomoyo_domain_info".
>   *
>   * Returns true if the domain is not exceeded quota, false otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain)
>  {
> @@ -837,8 +838,7 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain)
> 
>  	if (!domain)
>  		return true;
> -	down_read(&tomoyo_domain_acl_info_list_lock);
> -	list_for_each_entry(ptr, &domain->acl_info_list, list) {
> +	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
>  		if (ptr->type & TOMOYO_ACL_DELETED)
>  			continue;
>  		switch (tomoyo_acl_type2(ptr)) {
> @@ -866,7 +866,6 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain)
>  			break;
>  		}
>  	}
> -	up_read(&tomoyo_domain_acl_info_list_lock);
>  	if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY))
>  		return true;
>  	if (!domain->quota_warned) {
> @@ -1096,6 +1095,8 @@ static DECLARE_RWSEM(tomoyo_policy_manager_list_lock);
>   * @is_delete: True if it is a delete request.
>   *
>   * Returns 0 on success, negative value otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_update_manager_entry(const char *manager,
>  				       const bool is_delete)
> @@ -1118,7 +1119,7 @@ static int tomoyo_update_manager_entry(const char *manager,
>  	if (!saved_manager)
>  		return -ENOMEM;
>  	down_write(&tomoyo_policy_manager_list_lock);
> -	list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
> +	list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
>  		if (ptr->manager != saved_manager)
>  			continue;
>  		ptr->is_deleted = is_delete;
> @@ -1134,7 +1135,7 @@ static int tomoyo_update_manager_entry(const char *manager,
>  		goto out;
>  	new_entry->manager = saved_manager;
>  	new_entry->is_domain = is_domain;
> -	list_add_tail(&new_entry->list, &tomoyo_policy_manager_list);
> +	list_add_tail_rcu(&new_entry->list, &tomoyo_policy_manager_list);
>  	error = 0;
>   out:
>  	up_write(&tomoyo_policy_manager_list_lock);
> @@ -1147,6 +1148,8 @@ static int tomoyo_update_manager_entry(const char *manager,
>   * @head: Pointer to "struct tomoyo_io_buffer".
>   *
>   * Returns 0 on success, negative value otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head)
>  {
> @@ -1166,6 +1169,8 @@ static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head)
>   * @head: Pointer to "struct tomoyo_io_buffer".
>   *
>   * Returns 0.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head)
>  {
> @@ -1174,7 +1179,6 @@ static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head)
> 
>  	if (head->read_eof)
>  		return 0;
> -	down_read(&tomoyo_policy_manager_list_lock);
>  	list_for_each_cookie(pos, head->read_var2,
>  			     &tomoyo_policy_manager_list) {
>  		struct tomoyo_policy_manager_entry *ptr;
> @@ -1186,7 +1190,6 @@ static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head)
>  		if (!done)
>  			break;
>  	}
> -	up_read(&tomoyo_policy_manager_list_lock);
>  	head->read_eof = done;
>  	return 0;
>  }
> @@ -1196,6 +1199,8 @@ static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head)
>   *
>   * Returns true if the current process is permitted to modify policy
>   * via /sys/kernel/security/tomoyo/ interface.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static bool tomoyo_is_policy_manager(void)
>  {
> @@ -1209,29 +1214,25 @@ static bool tomoyo_is_policy_manager(void)
>  		return true;
>  	if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid))
>  		return false;
> -	down_read(&tomoyo_policy_manager_list_lock);
> -	list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
> +	list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
>  		if (!ptr->is_deleted && ptr->is_domain
>  		    && !tomoyo_pathcmp(domainname, ptr->manager)) {
>  			found = true;
>  			break;
>  		}
>  	}
> -	up_read(&tomoyo_policy_manager_list_lock);
>  	if (found)
>  		return true;
>  	exe = tomoyo_get_exe();
>  	if (!exe)
>  		return false;
> -	down_read(&tomoyo_policy_manager_list_lock);
> -	list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
> +	list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
>  		if (!ptr->is_deleted && !ptr->is_domain
>  		    && !strcmp(exe, ptr->manager->name)) {
>  			found = true;
>  			break;
>  		}
>  	}
> -	up_read(&tomoyo_policy_manager_list_lock);
>  	if (!found) { /* Reduce error messages. */
>  		static pid_t last_pid;
>  		const pid_t pid = current->pid;
> @@ -1252,6 +1253,8 @@ static bool tomoyo_is_policy_manager(void)
>   * @data: String to parse.
>   *
>   * Returns true on success, false otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
>  				 const char *data)
> @@ -1267,11 +1270,8 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
>  			domain = tomoyo_real_domain(p);
>  		read_unlock(&tasklist_lock);
>  	} else if (!strncmp(data, "domain=", 7)) {
> -		if (tomoyo_is_domain_def(data + 7)) {
> -			down_read(&tomoyo_domain_list_lock);
> +		if (tomoyo_is_domain_def(data + 7))
>  			domain = tomoyo_find_domain(data + 7);
> -			up_read(&tomoyo_domain_list_lock);
> -		}
>  	} else
>  		return false;
>  	head->write_var1 = domain;
> @@ -1285,13 +1285,11 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
>  	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) {
> +		list_for_each_entry_rcu(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;
> @@ -1307,6 +1305,8 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
>   * @domainname: The name of domain.
>   *
>   * Returns 0.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_delete_domain(char *domainname)
>  {
> @@ -1317,7 +1317,7 @@ static int tomoyo_delete_domain(char *domainname)
>  	tomoyo_fill_path_info(&name);
>  	down_write(&tomoyo_domain_list_lock);
>  	/* Is there an active domain? */
> -	list_for_each_entry(domain, &tomoyo_domain_list, list) {
> +	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
>  		/* Never delete tomoyo_kernel_domain */
>  		if (domain == &tomoyo_kernel_domain)
>  			continue;
> @@ -1337,6 +1337,8 @@ static int tomoyo_delete_domain(char *domainname)
>   * @head: Pointer to "struct tomoyo_io_buffer".
>   *
>   * Returns 0 on success, negative value otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head)
>  {
> @@ -1359,11 +1361,9 @@ static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head)
>  		domain = NULL;
>  		if (is_delete)
>  			tomoyo_delete_domain(data);
> -		else if (is_select) {
> -			down_read(&tomoyo_domain_list_lock);
> +		else if (is_select)
>  			domain = tomoyo_find_domain(data);
> -			up_read(&tomoyo_domain_list_lock);
> -		} else
> +		else
>  			domain = tomoyo_find_or_assign_new_domain(data, 0);
>  		head->write_var1 = domain;
>  		return 0;
> @@ -1508,6 +1508,8 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
>   * @head: Pointer to "struct tomoyo_io_buffer".
>   *
>   * Returns 0.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head)
>  {
> @@ -1519,7 +1521,6 @@ static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head)
>  		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) {
>  		struct tomoyo_domain_info *domain;
>  		const char *quota_exceeded = "";
> @@ -1552,7 +1553,6 @@ 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) {
>  			struct tomoyo_acl_info *ptr
> @@ -1562,7 +1562,6 @@ acl_loop:
>  			if (!done)
>  				break;
>  		}
> -		up_read(&tomoyo_domain_acl_info_list_lock);
>  		if (!done)
>  			break;
>  		head->read_step = 3;
> @@ -1574,7 +1573,6 @@ tail_mark:
>  		if (head->read_single_domain)
>  			break;
>  	}
> -	up_read(&tomoyo_domain_list_lock);
>  	head->read_eof = done;
>  	return 0;
>  }
> @@ -1590,6 +1588,8 @@ tail_mark:
>   *
>   *     ( echo "select " $domainname; echo "use_profile " $profile ) |
>   *     /usr/lib/ccs/loadpolicy -d
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head)
>  {
> @@ -1601,9 +1601,7 @@ static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head)
>  	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))
>  		return -EINVAL;
>  	if (domain && profile < TOMOYO_MAX_PROFILES
> @@ -1625,6 +1623,8 @@ static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head)
>   *     awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" )
>   *     domainname = $0; } else if ( $1 == "use_profile" ) {
>   *     print $2 " " domainname; domainname = ""; } } ; '
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
>  {
> @@ -1633,7 +1633,6 @@ static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
> 
>  	if (head->read_eof)
>  		return 0;
> -	down_read(&tomoyo_domain_list_lock);
>  	list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) {
>  		struct tomoyo_domain_info *domain;
>  		domain = list_entry(pos, struct tomoyo_domain_info, list);
> @@ -1644,7 +1643,6 @@ static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
>  		if (!done)
>  			break;
>  	}
> -	up_read(&tomoyo_domain_list_lock);
>  	head->read_eof = done;
>  	return 0;
>  }
> @@ -1701,6 +1699,8 @@ static int tomoyo_read_pid(struct tomoyo_io_buffer *head)
>   * @head: Pointer to "struct tomoyo_io_buffer".
>   *
>   * Returns 0 on success, negative value otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head)
>  {
> @@ -1735,6 +1735,8 @@ static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head)
>   * @head: Pointer to "struct tomoyo_io_buffer".
>   *
>   * Returns 0 on success, -EINVAL otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head)
>  {
> @@ -1864,15 +1866,13 @@ void tomoyo_load_policy(const char *filename)
>  	tomoyo_policy_loaded = true;
>  	{ /* Check all profiles currently assigned to domains are defined. */
>  		struct tomoyo_domain_info *domain;
> -		down_read(&tomoyo_domain_list_lock);
> -		list_for_each_entry(domain, &tomoyo_domain_list, list) {
> +		list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
>  			const u8 profile = domain->profile;
>  			if (tomoyo_profile_ptr[profile])
>  				continue;
>  			panic("Profile %u (used by '%s') not defined.\n",
>  			      profile, domain->domainname->name);
>  		}
> -		up_read(&tomoyo_domain_list_lock);
>  	}
>  }
> 
> @@ -1920,6 +1920,8 @@ static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head)
>   * @file: Pointer to "struct file".
>   *
>   * Associates policy handler and returns 0 on success, -ENOMEM otherwise.
> + *
> + * Caller acquires tomoyo_read_lock().
>   */
>  static int tomoyo_open_control(const u8 type, struct file *file)
>  {
> @@ -2005,6 +2007,7 @@ static int tomoyo_open_control(const u8 type, struct file *file)
>  			return -ENOMEM;
>  		}
>  	}
> +	head->reader_idx = tomoyo_read_lock();
>  	file->private_data = head;
>  	/*
>  	 * Call the handler now if the file is
> @@ -2026,6 +2029,8 @@ static int tomoyo_open_control(const u8 type, struct file *file)
>   * @buffer_len: Size of @buffer.
>   *
>   * Returns bytes read on success, negative value otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_read_control(struct file *file, char __user *buffer,
>  			       const int buffer_len)
> @@ -2069,6 +2074,8 @@ static int tomoyo_read_control(struct file *file, char __user *buffer,
>   * @buffer_len: Size of @buffer.
>   *
>   * Returns @buffer_len on success, negative value otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_write_control(struct file *file, const char __user *buffer,
>  				const int buffer_len)
> @@ -2119,11 +2126,14 @@ static int tomoyo_write_control(struct file *file, const char __user *buffer,
>   * @file: Pointer to "struct file".
>   *
>   * Releases memory and returns 0.
> + *
> + * Caller looses tomoyo_read_lock().
>   */
>  static int tomoyo_close_control(struct file *file)
>  {
>  	struct tomoyo_io_buffer *head = file->private_data;
> 
> +	tomoyo_read_unlock(head->reader_idx);
>  	/* Release memory used for policy I/O. */
>  	tomoyo_free(head->read_buf);
>  	head->read_buf = NULL;
> diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
> index bd10f9f..c6f1392 100644
> --- a/security/tomoyo/common.h
> +++ b/security/tomoyo/common.h
> @@ -269,6 +269,8 @@ struct tomoyo_io_buffer {
>  	int (*write) (struct tomoyo_io_buffer *);
>  	/* Exclusive lock for this structure.   */
>  	struct mutex io_sem;
> +	/* Index returned by tomoyo_read_lock(). */
> +	int reader_idx;
>  	/* The position currently reading from. */
>  	struct list_head *read_var1;
>  	/* Extra variables for reading.         */
> @@ -446,16 +448,28 @@ extern struct tomoyo_domain_info tomoyo_kernel_domain;
>   * @cookie:     the &struct list_head to use as a cookie.
>   * @head:       the head for your list.
>   *
> - * Same with list_for_each() except that this primitive uses @cookie
> + * Same with list_for_each_rcu() except that this primitive uses @cookie
>   * so that we can continue iteration.
>   * @cookie must be NULL when iteration starts, and @cookie will become
>   * NULL when iteration finishes.
>   */
> -#define list_for_each_cookie(pos, cookie, head)                       \
> -	for (({ if (!cookie)                                          \
> -				     cookie = head; }),               \
> -	     pos = (cookie)->next;                                    \
> -	     prefetch(pos->next), pos != (head) || ((cookie) = NULL); \
> -	     (cookie) = pos, pos = pos->next)
> +#define list_for_each_cookie(pos, cookie, head)				\
> +	for (({ if (!cookie)						\
> +				     cookie = head; }),			\
> +		     pos = rcu_dereference((cookie)->next);		\
> +	     prefetch(pos->next), pos != (head) || ((cookie) = NULL);	\
> +	     (cookie) = pos, pos = rcu_dereference(pos->next))
> +
> +extern struct srcu_struct tomoyo_ss;
> +
> +static inline int tomoyo_read_lock(void)
> +{
> +	return srcu_read_lock(&tomoyo_ss);
> +}
> +
> +static inline void tomoyo_read_unlock(int idx)
> +{
> +	srcu_read_unlock(&tomoyo_ss, idx);
> +}
> 
>  #endif /* !defined(_SECURITY_TOMOYO_COMMON_H) */
> diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
> index fcf52ac..2fd1901 100644
> --- a/security/tomoyo/domain.c
> +++ b/security/tomoyo/domain.c
> @@ -217,6 +217,8 @@ static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock);
>   * @is_delete:  True if it is a delete request.
>   *
>   * Returns 0 on success, negative value otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_update_domain_initializer_entry(const char *domainname,
>  						  const char *program,
> @@ -246,7 +248,7 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname,
>  	if (!saved_program)
>  		return -ENOMEM;
>  	down_write(&tomoyo_domain_initializer_list_lock);
> -	list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) {
> +	list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
>  		if (ptr->is_not != is_not ||
>  		    ptr->domainname != saved_domainname ||
>  		    ptr->program != saved_program)
> @@ -266,7 +268,7 @@ static int tomoyo_update_domain_initializer_entry(const char *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);
> +	list_add_tail_rcu(&new_entry->list, &tomoyo_domain_initializer_list);
>  	error = 0;
>   out:
>  	up_write(&tomoyo_domain_initializer_list_lock);
> @@ -279,13 +281,14 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname,
>   * @head: Pointer to "struct tomoyo_io_buffer".
>   *
>   * Returns true on success, false otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head)
>  {
>  	struct list_head *pos;
>  	bool done = true;
> 
> -	down_read(&tomoyo_domain_initializer_list_lock);
>  	list_for_each_cookie(pos, head->read_var2,
>  			     &tomoyo_domain_initializer_list) {
>  		const char *no;
> @@ -308,7 +311,6 @@ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head)
>  		if (!done)
>  			break;
>  	}
> -	up_read(&tomoyo_domain_initializer_list_lock);
>  	return done;
>  }
> 
> @@ -320,6 +322,8 @@ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head)
>   * @is_delete: True if it is a delete request.
>   *
>   * Returns 0 on success, negative value otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  int tomoyo_write_domain_initializer_policy(char *data, const bool is_not,
>  					   const bool is_delete)
> @@ -345,6 +349,8 @@ int tomoyo_write_domain_initializer_policy(char *data, const bool is_not,
>   *
>   * Returns true if executing @program reinitializes domain transition,
>   * false otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info *
>  					 domainname,
> @@ -355,8 +361,7 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info *
>  	struct tomoyo_domain_initializer_entry *ptr;
>  	bool flag = false;
> 
> -	down_read(&tomoyo_domain_initializer_list_lock);
> -	list_for_each_entry(ptr,  &tomoyo_domain_initializer_list, list) {
> +	list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
>  		if (ptr->is_deleted)
>  			continue;
>  		if (ptr->domainname) {
> @@ -376,7 +381,6 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info *
>  		}
>  		flag = true;
>  	}
> -	up_read(&tomoyo_domain_initializer_list_lock);
>  	return flag;
>  }
> 
> @@ -430,6 +434,8 @@ static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock);
>   * @is_delete:  True if it is a delete request.
>   *
>   * Returns 0 on success, negative value otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_update_domain_keeper_entry(const char *domainname,
>  					     const char *program,
> @@ -459,7 +465,7 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname,
>  	if (!saved_domainname)
>  		return -ENOMEM;
>  	down_write(&tomoyo_domain_keeper_list_lock);
> -	list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
> +	list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
>  		if (ptr->is_not != is_not ||
>  		    ptr->domainname != saved_domainname ||
>  		    ptr->program != saved_program)
> @@ -479,7 +485,7 @@ static int tomoyo_update_domain_keeper_entry(const char *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);
> +	list_add_tail_rcu(&new_entry->list, &tomoyo_domain_keeper_list);
>  	error = 0;
>   out:
>  	up_write(&tomoyo_domain_keeper_list_lock);
> @@ -493,6 +499,7 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname,
>   * @is_not:    True if it is "no_keep_domain" entry.
>   * @is_delete: True if it is a delete request.
>   *
> + * Caller holds tomoyo_read_lock().
>   */
>  int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
>  				      const bool is_delete)
> @@ -513,13 +520,14 @@ int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
>   * @head: Pointer to "struct tomoyo_io_buffer".
>   *
>   * Returns true on success, false otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head)
>  {
>  	struct list_head *pos;
>  	bool done = true;
> 
> -	down_read(&tomoyo_domain_keeper_list_lock);
>  	list_for_each_cookie(pos, head->read_var2,
>  			     &tomoyo_domain_keeper_list) {
>  		struct tomoyo_domain_keeper_entry *ptr;
> @@ -542,7 +550,6 @@ bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head)
>  		if (!done)
>  			break;
>  	}
> -	up_read(&tomoyo_domain_keeper_list_lock);
>  	return done;
>  }
> 
> @@ -555,6 +562,8 @@ bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head)
>   *
>   * Returns true if executing @program supresses domain transition,
>   * false otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
>  				    const struct tomoyo_path_info *program,
> @@ -563,8 +572,7 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
>  	struct tomoyo_domain_keeper_entry *ptr;
>  	bool flag = false;
> 
> -	down_read(&tomoyo_domain_keeper_list_lock);
> -	list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
> +	list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
>  		if (ptr->is_deleted)
>  			continue;
>  		if (!ptr->is_last_name) {
> @@ -582,7 +590,6 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
>  		}
>  		flag = true;
>  	}
> -	up_read(&tomoyo_domain_keeper_list_lock);
>  	return flag;
>  }
> 
> @@ -627,6 +634,8 @@ static DECLARE_RWSEM(tomoyo_alias_list_lock);
>   * @is_delete:     True if it is a delete request.
>   *
>   * Returns 0 on success, negative value otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_update_alias_entry(const char *original_name,
>  				     const char *aliased_name,
> @@ -646,7 +655,7 @@ static int tomoyo_update_alias_entry(const char *original_name,
>  	if (!saved_original_name || !saved_aliased_name)
>  		return -ENOMEM;
>  	down_write(&tomoyo_alias_list_lock);
> -	list_for_each_entry(ptr, &tomoyo_alias_list, list) {
> +	list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
>  		if (ptr->original_name != saved_original_name ||
>  		    ptr->aliased_name != saved_aliased_name)
>  			continue;
> @@ -663,7 +672,7 @@ static int tomoyo_update_alias_entry(const char *original_name,
>  		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);
> +	list_add_tail_rcu(&new_entry->list, &tomoyo_alias_list);
>  	error = 0;
>   out:
>  	up_write(&tomoyo_alias_list_lock);
> @@ -676,13 +685,14 @@ static int tomoyo_update_alias_entry(const char *original_name,
>   * @head: Pointer to "struct tomoyo_io_buffer".
>   *
>   * Returns true on success, false otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
>  {
>  	struct list_head *pos;
>  	bool done = true;
> 
> -	down_read(&tomoyo_alias_list_lock);
>  	list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) {
>  		struct tomoyo_alias_entry *ptr;
> 
> @@ -695,7 +705,6 @@ bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
>  		if (!done)
>  			break;
>  	}
> -	up_read(&tomoyo_alias_list_lock);
>  	return done;
>  }
> 
> @@ -706,6 +715,8 @@ bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
>   * @is_delete: True if it is a delete request.
>   *
>   * Returns 0 on success, negative value otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  int tomoyo_write_alias_policy(char *data, const bool is_delete)
>  {
> @@ -724,6 +735,8 @@ int tomoyo_write_alias_policy(char *data, const bool is_delete)
>   * @profile:    Profile number to assign if the domain was newly created.
>   *
>   * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
>  							    domainname,
> @@ -742,7 +755,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
>  	if (!saved_domainname)
>  		goto out;
>  	/* Can I reuse memory of deleted domain? */
> -	list_for_each_entry(domain, &tomoyo_domain_list, list) {
> +	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
>  		struct task_struct *p;
>  		struct tomoyo_acl_info *ptr;
>  		bool flag;
> @@ -760,7 +773,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
>  		read_unlock(&tasklist_lock);
>  		if (flag)
>  			continue;
> -		list_for_each_entry(ptr, &domain->acl_info_list, list) {
> +		list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
>  			ptr->type |= TOMOYO_ACL_DELETED;
>  		}
>  		tomoyo_set_domain_flag(domain, true, domain->flags);
> @@ -776,7 +789,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
>  		INIT_LIST_HEAD(&domain->acl_info_list);
>  		domain->domainname = saved_domainname;
>  		domain->profile = profile;
> -		list_add_tail(&domain->list, &tomoyo_domain_list);
> +		list_add_tail_rcu(&domain->list, &tomoyo_domain_list);
>  	}
>   out:
>  	up_write(&tomoyo_domain_list_lock);
> @@ -789,6 +802,8 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
>   * @bprm: Pointer to "struct linux_binprm".
>   *
>   * Returns 0 on success, negative value otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  int tomoyo_find_next_domain(struct linux_binprm *bprm)
>  {
> @@ -849,8 +864,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
>  	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);
> -		list_for_each_entry(ptr, &tomoyo_alias_list, list) {
> +		list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
>  			if (ptr->is_deleted ||
>  			    tomoyo_pathcmp(&r, ptr->original_name) ||
>  			    tomoyo_pathcmp(&s, ptr->aliased_name))
> @@ -861,7 +875,6 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
>  			tomoyo_fill_path_info(&r);
>  			break;
>  		}
> -		up_read(&tomoyo_alias_list_lock);
>  	}
> 
>  	/* Check execute permission. */
> @@ -892,9 +905,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
>  	}
>  	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)
> diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c
> index 482f0e7..3c47286 100644
> --- a/security/tomoyo/file.c
> +++ b/security/tomoyo/file.c
> @@ -213,6 +213,8 @@ static DECLARE_RWSEM(tomoyo_globally_readable_list_lock);
>   * @is_delete: True if it is a delete request.
>   *
>   * Returns 0 on success, negative value otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_update_globally_readable_entry(const char *filename,
>  						 const bool is_delete)
> @@ -228,7 +230,7 @@ static int tomoyo_update_globally_readable_entry(const char *filename,
>  	if (!saved_filename)
>  		return -ENOMEM;
>  	down_write(&tomoyo_globally_readable_list_lock);
> -	list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
> +	list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) {
>  		if (ptr->filename != saved_filename)
>  			continue;
>  		ptr->is_deleted = is_delete;
> @@ -243,7 +245,7 @@ static int tomoyo_update_globally_readable_entry(const char *filename,
>  	if (!new_entry)
>  		goto out;
>  	new_entry->filename = saved_filename;
> -	list_add_tail(&new_entry->list, &tomoyo_globally_readable_list);
> +	list_add_tail_rcu(&new_entry->list, &tomoyo_globally_readable_list);
>  	error = 0;
>   out:
>  	up_write(&tomoyo_globally_readable_list_lock);
> @@ -256,21 +258,22 @@ static int tomoyo_update_globally_readable_entry(const char *filename,
>   * @filename: The filename to check.
>   *
>   * Returns true if any domain can open @filename for reading, false otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info *
>  					     filename)
>  {
>  	struct tomoyo_globally_readable_file_entry *ptr;
>  	bool found = false;
> -	down_read(&tomoyo_globally_readable_list_lock);
> -	list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
> +
> +	list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) {
>  		if (!ptr->is_deleted &&
>  		    tomoyo_path_matches_pattern(filename, ptr->filename)) {
>  			found = true;
>  			break;
>  		}
>  	}
> -	up_read(&tomoyo_globally_readable_list_lock);
>  	return found;
>  }
> 
> @@ -281,6 +284,8 @@ static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info *
>   * @is_delete: True if it is a delete request.
>   *
>   * Returns 0 on success, negative value otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  int tomoyo_write_globally_readable_policy(char *data, const bool is_delete)
>  {
> @@ -293,13 +298,14 @@ int tomoyo_write_globally_readable_policy(char *data, const bool is_delete)
>   * @head: Pointer to "struct tomoyo_io_buffer".
>   *
>   * Returns true on success, false otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head)
>  {
>  	struct list_head *pos;
>  	bool done = true;
> 
> -	down_read(&tomoyo_globally_readable_list_lock);
>  	list_for_each_cookie(pos, head->read_var2,
>  			     &tomoyo_globally_readable_list) {
>  		struct tomoyo_globally_readable_file_entry *ptr;
> @@ -313,7 +319,6 @@ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head)
>  		if (!done)
>  			break;
>  	}
> -	up_read(&tomoyo_globally_readable_list_lock);
>  	return done;
>  }
> 
> @@ -356,6 +361,8 @@ static DECLARE_RWSEM(tomoyo_pattern_list_lock);
>   * @is_delete: True if it is a delete request.
>   *
>   * Returns 0 on success, negative value otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_update_file_pattern_entry(const char *pattern,
>  					    const bool is_delete)
> @@ -371,7 +378,7 @@ static int tomoyo_update_file_pattern_entry(const char *pattern,
>  	if (!saved_pattern)
>  		return -ENOMEM;
>  	down_write(&tomoyo_pattern_list_lock);
> -	list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
> +	list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
>  		if (saved_pattern != ptr->pattern)
>  			continue;
>  		ptr->is_deleted = is_delete;
> @@ -386,7 +393,7 @@ static int tomoyo_update_file_pattern_entry(const char *pattern,
>  	if (!new_entry)
>  		goto out;
>  	new_entry->pattern = saved_pattern;
> -	list_add_tail(&new_entry->list, &tomoyo_pattern_list);
> +	list_add_tail_rcu(&new_entry->list, &tomoyo_pattern_list);
>  	error = 0;
>   out:
>  	up_write(&tomoyo_pattern_list_lock);
> @@ -399,6 +406,8 @@ static int tomoyo_update_file_pattern_entry(const char *pattern,
>   * @filename: The filename to find patterned pathname.
>   *
>   * Returns pointer to pathname pattern if matched, @filename otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static const struct tomoyo_path_info *
>  tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
> @@ -406,8 +415,7 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
>  	struct tomoyo_pattern_entry *ptr;
>  	const struct tomoyo_path_info *pattern = NULL;
> 
> -	down_read(&tomoyo_pattern_list_lock);
> -	list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
> +	list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
>  		if (ptr->is_deleted)
>  			continue;
>  		if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
> @@ -420,7 +428,6 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
>  			break;
>  		}
>  	}
> -	up_read(&tomoyo_pattern_list_lock);
>  	if (pattern)
>  		filename = pattern;
>  	return filename;
> @@ -433,6 +440,8 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
>   * @is_delete: True if it is a delete request.
>   *
>   * Returns 0 on success, negative value otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  int tomoyo_write_pattern_policy(char *data, const bool is_delete)
>  {
> @@ -445,13 +454,14 @@ int tomoyo_write_pattern_policy(char *data, const bool is_delete)
>   * @head: Pointer to "struct tomoyo_io_buffer".
>   *
>   * Returns true on success, false otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head)
>  {
>  	struct list_head *pos;
>  	bool done = true;
> 
> -	down_read(&tomoyo_pattern_list_lock);
>  	list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) {
>  		struct tomoyo_pattern_entry *ptr;
>  		ptr = list_entry(pos, struct tomoyo_pattern_entry, list);
> @@ -462,7 +472,6 @@ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head)
>  		if (!done)
>  			break;
>  	}
> -	up_read(&tomoyo_pattern_list_lock);
>  	return done;
>  }
> 
> @@ -505,6 +514,8 @@ static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock);
>   * @is_delete: True if it is a delete request.
>   *
>   * Returns 0 on success, negative value otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_update_no_rewrite_entry(const char *pattern,
>  					  const bool is_delete)
> @@ -519,7 +530,7 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern,
>  	if (!saved_pattern)
>  		return -ENOMEM;
>  	down_write(&tomoyo_no_rewrite_list_lock);
> -	list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
> +	list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
>  		if (ptr->pattern != saved_pattern)
>  			continue;
>  		ptr->is_deleted = is_delete;
> @@ -534,7 +545,7 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern,
>  	if (!new_entry)
>  		goto out;
>  	new_entry->pattern = saved_pattern;
> -	list_add_tail(&new_entry->list, &tomoyo_no_rewrite_list);
> +	list_add_tail_rcu(&new_entry->list, &tomoyo_no_rewrite_list);
>  	error = 0;
>   out:
>  	up_write(&tomoyo_no_rewrite_list_lock);
> @@ -548,14 +559,15 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern,
>   *
>   * Returns true if @filename is specified by "deny_rewrite" directive,
>   * false otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename)
>  {
>  	struct tomoyo_no_rewrite_entry *ptr;
>  	bool found = false;
> 
> -	down_read(&tomoyo_no_rewrite_list_lock);
> -	list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
> +	list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
>  		if (ptr->is_deleted)
>  			continue;
>  		if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
> @@ -563,7 +575,6 @@ static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename)
>  		found = true;
>  		break;
>  	}
> -	up_read(&tomoyo_no_rewrite_list_lock);
>  	return found;
>  }
> 
> @@ -574,6 +585,8 @@ static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename)
>   * @is_delete: True if it is a delete request.
>   *
>   * Returns 0 on success, negative value otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete)
>  {
> @@ -586,13 +599,14 @@ int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete)
>   * @head: Pointer to "struct tomoyo_io_buffer".
>   *
>   * Returns true on success, false otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
>  {
>  	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) {
>  		struct tomoyo_no_rewrite_entry *ptr;
>  		ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list);
> @@ -603,7 +617,6 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
>  		if (!done)
>  			break;
>  	}
> -	up_read(&tomoyo_no_rewrite_list_lock);
>  	return done;
>  }
> 
> @@ -621,6 +634,8 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
>   * Current policy syntax uses "allow_read/write" instead of "6",
>   * "allow_read" instead of "4", "allow_write" instead of "2",
>   * "allow_execute" instead of "1".
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_update_file_acl(const char *filename, u8 perm,
>  				  struct tomoyo_domain_info * const domain,
> @@ -658,6 +673,8 @@ static int tomoyo_update_file_acl(const char *filename, u8 perm,
>   * @may_use_pattern: True if patterned ACL is permitted.
>   *
>   * Returns 0 on success, -EPERM otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info *
>  					 domain,
> @@ -669,8 +686,7 @@ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info *
>  	struct tomoyo_acl_info *ptr;
>  	int error = -EPERM;
> 
> -	down_read(&tomoyo_domain_acl_info_list_lock);
> -	list_for_each_entry(ptr, &domain->acl_info_list, list) {
> +	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
>  		struct tomoyo_single_path_acl_record *acl;
>  		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
>  			continue;
> @@ -693,7 +709,6 @@ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info *
>  		error = 0;
>  		break;
>  	}
> -	up_read(&tomoyo_domain_acl_info_list_lock);
>  	return error;
>  }
> 
> @@ -705,6 +720,8 @@ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info *
>   * @operation: Mode ("read" or "write" or "read/write" or "execute").
>   *
>   * Returns 0 on success, -EPERM otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain,
>  				 const struct tomoyo_path_info *filename,
> @@ -738,6 +755,8 @@ static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain,
>   * @mode:      Access control mode.
>   *
>   * Returns 0 on success, negative value otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain,
>  				   const struct tomoyo_path_info *filename,
> @@ -791,6 +810,8 @@ static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain,
>   * @is_delete: True if it is a delete request.
>   *
>   * Returns 0 on success, negative value otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
>  			     const bool is_delete)
> @@ -838,6 +859,8 @@ int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
>   * @is_delete: True if it is a delete request.
>   *
>   * Returns 0 on success, negative value otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
>  					 struct tomoyo_domain_info *
> @@ -861,7 +884,7 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
>  	down_write(&tomoyo_domain_acl_info_list_lock);
>  	if (is_delete)
>  		goto delete;
> -	list_for_each_entry(ptr, &domain->acl_info_list, list) {
> +	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
>  		if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
>  			continue;
>  		acl = container_of(ptr, struct tomoyo_single_path_acl_record,
> @@ -894,12 +917,12 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
>  	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);
> +	list_add_tail_rcu(&acl->head.list, &domain->acl_info_list);
>  	error = 0;
>  	goto out;
>   delete:
>  	error = -ENOENT;
> -	list_for_each_entry(ptr, &domain->acl_info_list, list) {
> +	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
>  		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
>  			continue;
>  		acl = container_of(ptr, struct tomoyo_single_path_acl_record,
> @@ -934,6 +957,8 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
>   * @is_delete: True if it is a delete request.
>   *
>   * Returns 0 on success, negative value otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
>  					 const char *filename2,
> @@ -959,7 +984,7 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
>  	down_write(&tomoyo_domain_acl_info_list_lock);
>  	if (is_delete)
>  		goto delete;
> -	list_for_each_entry(ptr, &domain->acl_info_list, list) {
> +	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
>  		if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
>  			continue;
>  		acl = container_of(ptr, struct tomoyo_double_path_acl_record,
> @@ -982,12 +1007,12 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
>  	acl->perm = perm;
>  	acl->filename1 = saved_filename1;
>  	acl->filename2 = saved_filename2;
> -	list_add_tail(&acl->head.list, &domain->acl_info_list);
> +	list_add_tail_rcu(&acl->head.list, &domain->acl_info_list);
>  	error = 0;
>  	goto out;
>   delete:
>  	error = -ENOENT;
> -	list_for_each_entry(ptr, &domain->acl_info_list, list) {
> +	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
>  		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
>  			continue;
>  		acl = container_of(ptr, struct tomoyo_double_path_acl_record,
> @@ -1014,6 +1039,8 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
>   * @filename: Filename to check.
>   *
>   * Returns 0 on success, negative value otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain,
>  					const u8 type,
> @@ -1033,6 +1060,8 @@ static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain,
>   * @filename2: Second filename to check.
>   *
>   * Returns 0 on success, -EPERM otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain,
>  					const u8 type,
> @@ -1047,8 +1076,7 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain,
> 
>  	if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
>  		return 0;
> -	down_read(&tomoyo_domain_acl_info_list_lock);
> -	list_for_each_entry(ptr, &domain->acl_info_list, list) {
> +	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
>  		struct tomoyo_double_path_acl_record *acl;
>  		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
>  			continue;
> @@ -1063,7 +1091,6 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain,
>  		error = 0;
>  		break;
>  	}
> -	up_read(&tomoyo_domain_acl_info_list_lock);
>  	return error;
>  }
> 
> @@ -1076,6 +1103,8 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain,
>   * @mode:      Access control mode.
>   *
>   * Returns 0 on success, negative value otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info *
>  						const domain, u8 operation,
> @@ -1124,6 +1153,8 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info *
>   * @filename: Check permission for "execute".
>   *
>   * Returns 0 on success, negativevalue otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
>   */
>  int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
>  			   const struct tomoyo_path_info *filename)
> @@ -1152,6 +1183,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
>  	struct tomoyo_path_info *buf;
>  	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
>  	const bool is_enforce = (mode == 3);
> +	int idx;
> 
>  	if (!mode || !path->mnt)
>  		return 0;
> @@ -1163,6 +1195,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
>  		 * don't call me.
>  		 */
>  		return 0;
> +	idx = tomoyo_read_lock();
>  	buf = tomoyo_get_path(path);
>  	if (!buf)
>  		goto out;
> @@ -1188,6 +1221,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
>  							     buf, mode);
>   out:
>  	tomoyo_free(buf);
> +	tomoyo_read_unlock(idx);
>  	if (!is_enforce)
>  		error = 0;
>  	return error;
> @@ -1209,9 +1243,11 @@ int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain,
>  	struct tomoyo_path_info *buf;
>  	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
>  	const bool is_enforce = (mode == 3);
> +	int idx;
> 
>  	if (!mode || !path->mnt)
>  		return 0;
> +	idx = tomoyo_read_lock();
>  	buf = tomoyo_get_path(path);
>  	if (!buf)
>  		goto out;
> @@ -1231,6 +1267,7 @@ int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain,
>  						     mode);
>   out:
>  	tomoyo_free(buf);
> +	tomoyo_read_unlock(idx);
>  	if (!is_enforce)
>  		error = 0;
>  	return error;
> @@ -1251,9 +1288,12 @@ int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain,
>  	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
>  	const bool is_enforce = (mode == 3);
>  	struct tomoyo_path_info *buf;
> +	int idx;
> 
>  	if (!mode || !filp->f_path.mnt)
>  		return 0;
> +
> +	idx = tomoyo_read_lock();
>  	buf = tomoyo_get_path(&filp->f_path);
>  	if (!buf)
>  		goto out;
> @@ -1266,6 +1306,7 @@ int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain,
>  						     buf, mode);
>   out:
>  	tomoyo_free(buf);
> +	tomoyo_read_unlock(idx);
>  	if (!is_enforce)
>  		error = 0;
>  	return error;
> @@ -1290,9 +1331,11 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain,
>  	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
>  	const bool is_enforce = (mode == 3);
>  	const char *msg;
> +	int idx;
> 
>  	if (!mode || !path1->mnt || !path2->mnt)
>  		return 0;
> +	idx = tomoyo_read_lock();
>  	buf1 = tomoyo_get_path(path1);
>  	buf2 = tomoyo_get_path(path2);
>  	if (!buf1 || !buf2)
> @@ -1331,6 +1374,7 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain,
>   out:
>  	tomoyo_free(buf1);
>  	tomoyo_free(buf2);
> +	tomoyo_read_unlock(idx);
>  	if (!is_enforce)
>  		error = 0;
>  	return error;
> diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c
> index e3c7aa0..62363b3 100644
> --- a/security/tomoyo/realpath.c
> +++ b/security/tomoyo/realpath.c
> @@ -402,11 +402,13 @@ void __init tomoyo_realpath_init(void)
>  		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);
> -	list_add_tail(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
> -	down_read(&tomoyo_domain_list_lock);
> +	/*
> +	 * tomoyo_read_lock() is not needed because this function is
> +	 * called before the first "delete" request.
> +	 */
> +	list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
>  	if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
>  		panic("Can't register tomoyo_kernel_domain");
> -	up_read(&tomoyo_domain_list_lock);
>  }
> 
>  /* Memory allocated for temporary purpose. */
> diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
> index ad9555f..714daa3 100644
> --- a/security/tomoyo/tomoyo.c
> +++ b/security/tomoyo/tomoyo.c
> @@ -76,8 +76,18 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
>  	 * Execute permission is checked against pathname passed to do_execve()
>  	 * using current domain.
>  	 */
> -	if (!domain)
> -		return tomoyo_find_next_domain(bprm);
> +	if (!domain) {
> +		/*
> +		 * We will need to protect whole execve() operation when GC
> +		 * starts kfree()ing "struct tomoyo_domain_info" because
> +		 * bprm->cred->security points to "struct tomoyo_domain_info"
> +		 * but "struct tomoyo_domain_info" does not have a refcounter.
> +		 */
> +		const int idx = tomoyo_read_lock();
> +		const int err = tomoyo_find_next_domain(bprm);
> +		tomoyo_read_unlock(idx);
> +		return err;
> +	}
>  	/*
>  	 * Read permission is checked against interpreters using next domain.
>  	 * '1' is the result of open_to_namei_flags(O_RDONLY).
> @@ -278,6 +288,9 @@ static struct security_operations tomoyo_security_ops = {
>  	.sb_pivotroot        = tomoyo_sb_pivotroot,
>  };
> 
> +/* Lock for GC. */
> +struct srcu_struct tomoyo_ss;
> +
>  static int __init tomoyo_init(void)
>  {
>  	struct cred *cred = (struct cred *) current_cred();
> @@ -285,7 +298,8 @@ static int __init tomoyo_init(void)
>  	if (!security_module_enable(&tomoyo_security_ops))
>  		return 0;
>  	/* register ourselves with the security framework */
> -	if (register_security(&tomoyo_security_ops))
> +	if (register_security(&tomoyo_security_ops) ||
> +	    init_srcu_struct(&tomoyo_ss))
>  		panic("Failure registering TOMOYO Linux");
>  	printk(KERN_INFO "TOMOYO Linux initialized\n");
>  	cred->security = &tomoyo_kernel_domain;
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] TOMOYO: Use RCU primitives for list operation
  2009-12-14 16:39 ` Serge E. Hallyn
@ 2009-12-15  1:39   ` Tetsuo Handa
  0 siblings, 0 replies; 6+ messages in thread
From: Tetsuo Handa @ 2009-12-15  1:39 UTC (permalink / raw)
  To: serue; +Cc: linux-security-module, linux-kernel

Hello.

Serge E. Hallyn wrote:
> Just out of curiosity (and bc I'm personally much more familiar with plain old
> rcu), I assume you have a list of places where sleeping under rcu is necessary
> or greatly simplifies/cleans up the code?

Yes.

TOMOYO checks operations which are permitted to sleep so that we can load
policy like call_usermodehelper("/sbin/modprobe"). I tried to use non-sleeping
RCU while implementing garbage collector support. But that attempt resulted in
messing up the code with full of atomic_inc()/atomic_dec() calls.
Thus, I decided to use sleeping RCU.

I tested garbage collector support using sleeping RCU with non-LSM version of
TOMOYO. It is working well. Thus, I started breaking non-LSM version of TOMOYO
into smaller pieces and proposing for LSM version of TOMOYO.

Thank you for reviewing. I'll send next patches.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] TOMOYO: Use RCU primitives for list operation
  2009-10-29  5:40           ` Serge E. Hallyn
@ 2009-12-04 12:34             ` Tetsuo Handa
  0 siblings, 0 replies; 6+ messages in thread
From: Tetsuo Handa @ 2009-12-04 12:34 UTC (permalink / raw)
  To: serue; +Cc: linux-security-module, linux-kernel

Hello.

Serge E. Hallyn wrote:
> If you'll be adding gc eventually anyway, is it really worthwhile
> to 'violate the rules' now by calling list_for_each_entry_rcu()
> without being inside rcu_read_lock() now?  I fear it'll only serve
> to confuse readers, especially those looking for rcu users to serve
> as examples.

You are right. I modified to call srcu_read_lock().

I don't modify tomoyo_file_permission() because it will be removed by
applying commit: c656ae95d1c5c8ed5763356263ace2d03087efec
(security/tomoyo: Remove now unnecessary handling of security_sysctl.).

Regards.
----------
[PATCH] TOMOYO: Use RCU primitives for list operation

Replace list operation with RCU primitives and replace
down_read()/up_read() with srcu_read_lock()/srcu_read_unlock().

Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
 security/tomoyo/common.c   |   90 ++++++++++++++++++++----------------
 security/tomoyo/common.h   |   28 ++++++++---
 security/tomoyo/domain.c   |   63 +++++++++++++++----------
 security/tomoyo/file.c     |  110 +++++++++++++++++++++++++++++++--------------
 security/tomoyo/realpath.c |    8 ++-
 security/tomoyo/tomoyo.c   |   20 ++++++--
 6 files changed, 207 insertions(+), 112 deletions(-)

--- security-testing-2.6.orig/security/tomoyo/common.c
+++ security-testing-2.6/security/tomoyo/common.c
@@ -365,10 +365,9 @@ bool tomoyo_is_domain_def(const unsigned
  *
  * @domainname: The domainname to find.
  *
- * 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.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
 {
@@ -377,7 +376,7 @@ struct tomoyo_domain_info *tomoyo_find_d
 
 	name.name = domainname;
 	tomoyo_fill_path_info(&name);
-	list_for_each_entry(domain, &tomoyo_domain_list, list) {
+	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
 		if (!domain->is_deleted &&
 		    !tomoyo_pathcmp(&name, domain->domainname))
 			return domain;
@@ -829,6 +828,8 @@ bool tomoyo_verbose_mode(const struct to
  * @domain: Pointer to "struct tomoyo_domain_info".
  *
  * Returns true if the domain is not exceeded quota, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain)
 {
@@ -837,8 +838,7 @@ bool tomoyo_domain_quota_is_ok(struct to
 
 	if (!domain)
 		return true;
-	down_read(&tomoyo_domain_acl_info_list_lock);
-	list_for_each_entry(ptr, &domain->acl_info_list, list) {
+	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
 		if (ptr->type & TOMOYO_ACL_DELETED)
 			continue;
 		switch (tomoyo_acl_type2(ptr)) {
@@ -891,7 +891,6 @@ bool tomoyo_domain_quota_is_ok(struct to
 			break;
 		}
 	}
-	up_read(&tomoyo_domain_acl_info_list_lock);
 	if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY))
 		return true;
 	if (!domain->quota_warned) {
@@ -1121,6 +1120,8 @@ static DECLARE_RWSEM(tomoyo_policy_manag
  * @is_delete: True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_update_manager_entry(const char *manager,
 				       const bool is_delete)
@@ -1143,7 +1144,7 @@ static int tomoyo_update_manager_entry(c
 	if (!saved_manager)
 		return -ENOMEM;
 	down_write(&tomoyo_policy_manager_list_lock);
-	list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
 		if (ptr->manager != saved_manager)
 			continue;
 		ptr->is_deleted = is_delete;
@@ -1159,7 +1160,7 @@ static int tomoyo_update_manager_entry(c
 		goto out;
 	new_entry->manager = saved_manager;
 	new_entry->is_domain = is_domain;
-	list_add_tail(&new_entry->list, &tomoyo_policy_manager_list);
+	list_add_tail_rcu(&new_entry->list, &tomoyo_policy_manager_list);
 	error = 0;
  out:
 	up_write(&tomoyo_policy_manager_list_lock);
@@ -1172,6 +1173,8 @@ static int tomoyo_update_manager_entry(c
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head)
 {
@@ -1191,6 +1194,8 @@ static int tomoyo_write_manager_policy(s
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns 0.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head)
 {
@@ -1199,7 +1204,6 @@ 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,
 			     &tomoyo_policy_manager_list) {
 		struct tomoyo_policy_manager_entry *ptr;
@@ -1211,7 +1215,6 @@ static int tomoyo_read_manager_policy(st
 		if (!done)
 			break;
 	}
-	up_read(&tomoyo_policy_manager_list_lock);
 	head->read_eof = done;
 	return 0;
 }
@@ -1221,6 +1224,8 @@ static int tomoyo_read_manager_policy(st
  *
  * Returns true if the current process is permitted to modify policy
  * via /sys/kernel/security/tomoyo/ interface.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static bool tomoyo_is_policy_manager(void)
 {
@@ -1234,29 +1239,25 @@ 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);
-	list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
 		if (!ptr->is_deleted && ptr->is_domain
 		    && !tomoyo_pathcmp(domainname, ptr->manager)) {
 			found = true;
 			break;
 		}
 	}
-	up_read(&tomoyo_policy_manager_list_lock);
 	if (found)
 		return true;
 	exe = tomoyo_get_exe();
 	if (!exe)
 		return false;
-	down_read(&tomoyo_policy_manager_list_lock);
-	list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
 		if (!ptr->is_deleted && !ptr->is_domain
 		    && !strcmp(exe, ptr->manager->name)) {
 			found = true;
 			break;
 		}
 	}
-	up_read(&tomoyo_policy_manager_list_lock);
 	if (!found) { /* Reduce error messages. */
 		static pid_t last_pid;
 		const pid_t pid = current->pid;
@@ -1277,6 +1278,8 @@ static bool tomoyo_is_policy_manager(voi
  * @data: String to parse.
  *
  * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
 				 const char *data)
@@ -1292,11 +1295,8 @@ static bool tomoyo_is_select_one(struct 
 			domain = tomoyo_real_domain(p);
 		read_unlock(&tasklist_lock);
 	} else if (!strncmp(data, "domain=", 7)) {
-		if (tomoyo_is_domain_def(data + 7)) {
-			down_read(&tomoyo_domain_list_lock);
+		if (tomoyo_is_domain_def(data + 7))
 			domain = tomoyo_find_domain(data + 7);
-			up_read(&tomoyo_domain_list_lock);
-		}
 	} else
 		return false;
 	head->write_var1 = domain;
@@ -1310,13 +1310,11 @@ static bool tomoyo_is_select_one(struct 
 	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) {
+		list_for_each_entry_rcu(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;
@@ -1332,6 +1330,8 @@ static bool tomoyo_is_select_one(struct 
  * @domainname: The name of domain.
  *
  * Returns 0.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_delete_domain(char *domainname)
 {
@@ -1342,7 +1342,7 @@ static int tomoyo_delete_domain(char *do
 	tomoyo_fill_path_info(&name);
 	down_write(&tomoyo_domain_list_lock);
 	/* Is there an active domain? */
-	list_for_each_entry(domain, &tomoyo_domain_list, list) {
+	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
 		/* Never delete tomoyo_kernel_domain */
 		if (domain == &tomoyo_kernel_domain)
 			continue;
@@ -1362,6 +1362,8 @@ static int tomoyo_delete_domain(char *do
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head)
 {
@@ -1384,11 +1386,9 @@ static int tomoyo_write_domain_policy(st
 		domain = NULL;
 		if (is_delete)
 			tomoyo_delete_domain(data);
-		else if (is_select) {
-			down_read(&tomoyo_domain_list_lock);
+		else if (is_select)
 			domain = tomoyo_find_domain(data);
-			up_read(&tomoyo_domain_list_lock);
-		} else
+		else
 			domain = tomoyo_find_or_assign_new_domain(data, 0);
 		head->write_var1 = domain;
 		return 0;
@@ -1533,6 +1533,8 @@ static bool tomoyo_print_entry(struct to
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns 0.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head)
 {
@@ -1544,7 +1546,6 @@ 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) {
 		struct tomoyo_domain_info *domain;
 		const char *quota_exceeded = "";
@@ -1577,7 +1578,6 @@ 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) {
 			struct tomoyo_acl_info *ptr
@@ -1587,7 +1587,6 @@ acl_loop:
 			if (!done)
 				break;
 		}
-		up_read(&tomoyo_domain_acl_info_list_lock);
 		if (!done)
 			break;
 		head->read_step = 3;
@@ -1599,7 +1598,6 @@ tail_mark:
 		if (head->read_single_domain)
 			break;
 	}
-	up_read(&tomoyo_domain_list_lock);
 	head->read_eof = done;
 	return 0;
 }
@@ -1615,6 +1613,8 @@ tail_mark:
  *
  *     ( echo "select " $domainname; echo "use_profile " $profile ) |
  *     /usr/lib/ccs/loadpolicy -d
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head)
 {
@@ -1626,9 +1626,7 @@ static int tomoyo_write_domain_profile(s
 	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))
 		return -EINVAL;
 	if (domain && profile < TOMOYO_MAX_PROFILES
@@ -1650,6 +1648,8 @@ static int tomoyo_write_domain_profile(s
  *     awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" )
  *     domainname = $0; } else if ( $1 == "use_profile" ) {
  *     print $2 " " domainname; domainname = ""; } } ; '
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
 {
@@ -1658,7 +1658,6 @@ 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) {
 		struct tomoyo_domain_info *domain;
 		domain = list_entry(pos, struct tomoyo_domain_info, list);
@@ -1669,7 +1668,6 @@ static int tomoyo_read_domain_profile(st
 		if (!done)
 			break;
 	}
-	up_read(&tomoyo_domain_list_lock);
 	head->read_eof = done;
 	return 0;
 }
@@ -1726,6 +1724,8 @@ static int tomoyo_read_pid(struct tomoyo
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head)
 {
@@ -1760,6 +1760,8 @@ static int tomoyo_write_exception_policy
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns 0 on success, -EINVAL otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head)
 {
@@ -1889,15 +1891,13 @@ 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);
-		list_for_each_entry(domain, &tomoyo_domain_list, list) {
+		list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
 			const u8 profile = domain->profile;
 			if (tomoyo_profile_ptr[profile])
 				continue;
 			panic("Profile %u (used by '%s') not defined.\n",
 			      profile, domain->domainname->name);
 		}
-		up_read(&tomoyo_domain_list_lock);
 	}
 }
 
@@ -1945,6 +1945,8 @@ static int tomoyo_read_self_domain(struc
  * @file: Pointer to "struct file".
  *
  * Associates policy handler and returns 0 on success, -ENOMEM otherwise.
+ *
+ * Caller acquires tomoyo_read_lock().
  */
 static int tomoyo_open_control(const u8 type, struct file *file)
 {
@@ -2030,6 +2032,7 @@ static int tomoyo_open_control(const u8 
 			return -ENOMEM;
 		}
 	}
+	head->reader_idx = tomoyo_read_lock();
 	file->private_data = head;
 	/*
 	 * Call the handler now if the file is
@@ -2051,6 +2054,8 @@ static int tomoyo_open_control(const u8 
  * @buffer_len: Size of @buffer.
  *
  * Returns bytes read on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_read_control(struct file *file, char __user *buffer,
 			       const int buffer_len)
@@ -2094,6 +2099,8 @@ static int tomoyo_read_control(struct fi
  * @buffer_len: Size of @buffer.
  *
  * Returns @buffer_len on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_write_control(struct file *file, const char __user *buffer,
 				const int buffer_len)
@@ -2144,11 +2151,14 @@ static int tomoyo_write_control(struct f
  * @file: Pointer to "struct file".
  *
  * Releases memory and returns 0.
+ *
+ * Caller looses tomoyo_read_lock().
  */
 static int tomoyo_close_control(struct file *file)
 {
 	struct tomoyo_io_buffer *head = file->private_data;
 
+	tomoyo_read_unlock(head->reader_idx);
 	/* Release memory used for policy I/O. */
 	tomoyo_free(head->read_buf);
 	head->read_buf = NULL;
--- security-testing-2.6.orig/security/tomoyo/common.h
+++ security-testing-2.6/security/tomoyo/common.h
@@ -265,6 +265,8 @@ struct tomoyo_io_buffer {
 	int (*write) (struct tomoyo_io_buffer *);
 	/* Exclusive lock for this structure.   */
 	struct mutex io_sem;
+	/* Index returned by tomoyo_read_lock(). */
+	int reader_idx;
 	/* The position currently reading from. */
 	struct list_head *read_var1;
 	/* Extra variables for reading.         */
@@ -442,16 +444,28 @@ extern struct tomoyo_domain_info tomoyo_
  * @cookie:     the &struct list_head to use as a cookie.
  * @head:       the head for your list.
  *
- * Same with list_for_each() except that this primitive uses @cookie
+ * Same with list_for_each_rcu() except that this primitive uses @cookie
  * so that we can continue iteration.
  * @cookie must be NULL when iteration starts, and @cookie will become
  * NULL when iteration finishes.
  */
-#define list_for_each_cookie(pos, cookie, head)                       \
-	for (({ if (!cookie)                                          \
-				     cookie = head; }),               \
-	     pos = (cookie)->next;                                    \
-	     prefetch(pos->next), pos != (head) || ((cookie) = NULL); \
-	     (cookie) = pos, pos = pos->next)
+#define list_for_each_cookie(pos, cookie, head)				\
+	for (({ if (!cookie)						\
+				     cookie = head; }),			\
+		     pos = rcu_dereference((cookie)->next);		\
+	     prefetch(pos->next), pos != (head) || ((cookie) = NULL);	\
+	     (cookie) = pos, pos = rcu_dereference(pos->next))
+
+extern struct srcu_struct tomoyo_ss;
+
+static inline int tomoyo_read_lock(void)
+{
+	return srcu_read_lock(&tomoyo_ss);
+}
+
+static inline void tomoyo_read_unlock(int idx)
+{
+	srcu_read_unlock(&tomoyo_ss, idx);
+}
 
 #endif /* !defined(_SECURITY_TOMOYO_COMMON_H) */
--- security-testing-2.6.orig/security/tomoyo/domain.c
+++ security-testing-2.6/security/tomoyo/domain.c
@@ -217,6 +217,8 @@ static DECLARE_RWSEM(tomoyo_domain_initi
  * @is_delete:  True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_update_domain_initializer_entry(const char *domainname,
 						  const char *program,
@@ -246,7 +248,7 @@ static int tomoyo_update_domain_initiali
 	if (!saved_program)
 		return -ENOMEM;
 	down_write(&tomoyo_domain_initializer_list_lock);
-	list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
 		if (ptr->is_not != is_not ||
 		    ptr->domainname != saved_domainname ||
 		    ptr->program != saved_program)
@@ -266,7 +268,7 @@ static int tomoyo_update_domain_initiali
 	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);
+	list_add_tail_rcu(&new_entry->list, &tomoyo_domain_initializer_list);
 	error = 0;
  out:
 	up_write(&tomoyo_domain_initializer_list_lock);
@@ -279,13 +281,14 @@ static int tomoyo_update_domain_initiali
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head)
 {
 	struct list_head *pos;
 	bool done = true;
 
-	down_read(&tomoyo_domain_initializer_list_lock);
 	list_for_each_cookie(pos, head->read_var2,
 			     &tomoyo_domain_initializer_list) {
 		const char *no;
@@ -308,7 +311,6 @@ bool tomoyo_read_domain_initializer_poli
 		if (!done)
 			break;
 	}
-	up_read(&tomoyo_domain_initializer_list_lock);
 	return done;
 }
 
@@ -320,6 +322,8 @@ bool tomoyo_read_domain_initializer_poli
  * @is_delete: True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 int tomoyo_write_domain_initializer_policy(char *data, const bool is_not,
 					   const bool is_delete)
@@ -345,6 +349,8 @@ int tomoyo_write_domain_initializer_poli
  *
  * Returns true if executing @program reinitializes domain transition,
  * false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info *
 					 domainname,
@@ -355,8 +361,7 @@ static bool tomoyo_is_domain_initializer
 	struct tomoyo_domain_initializer_entry *ptr;
 	bool flag = false;
 
-	down_read(&tomoyo_domain_initializer_list_lock);
-	list_for_each_entry(ptr,  &tomoyo_domain_initializer_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
 		if (ptr->is_deleted)
 			continue;
 		if (ptr->domainname) {
@@ -376,7 +381,6 @@ static bool tomoyo_is_domain_initializer
 		}
 		flag = true;
 	}
-	up_read(&tomoyo_domain_initializer_list_lock);
 	return flag;
 }
 
@@ -430,6 +434,8 @@ static DECLARE_RWSEM(tomoyo_domain_keepe
  * @is_delete:  True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_update_domain_keeper_entry(const char *domainname,
 					     const char *program,
@@ -459,7 +465,7 @@ static int tomoyo_update_domain_keeper_e
 	if (!saved_domainname)
 		return -ENOMEM;
 	down_write(&tomoyo_domain_keeper_list_lock);
-	list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
 		if (ptr->is_not != is_not ||
 		    ptr->domainname != saved_domainname ||
 		    ptr->program != saved_program)
@@ -479,7 +485,7 @@ static int tomoyo_update_domain_keeper_e
 	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);
+	list_add_tail_rcu(&new_entry->list, &tomoyo_domain_keeper_list);
 	error = 0;
  out:
 	up_write(&tomoyo_domain_keeper_list_lock);
@@ -493,6 +499,7 @@ static int tomoyo_update_domain_keeper_e
  * @is_not:    True if it is "no_keep_domain" entry.
  * @is_delete: True if it is a delete request.
  *
+ * Caller holds tomoyo_read_lock().
  */
 int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
 				      const bool is_delete)
@@ -513,13 +520,14 @@ int tomoyo_write_domain_keeper_policy(ch
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head)
 {
 	struct list_head *pos;
 	bool done = true;
 
-	down_read(&tomoyo_domain_keeper_list_lock);
 	list_for_each_cookie(pos, head->read_var2,
 			     &tomoyo_domain_keeper_list) {
 		struct tomoyo_domain_keeper_entry *ptr;
@@ -542,7 +550,6 @@ bool tomoyo_read_domain_keeper_policy(st
 		if (!done)
 			break;
 	}
-	up_read(&tomoyo_domain_keeper_list_lock);
 	return done;
 }
 
@@ -555,6 +562,8 @@ bool tomoyo_read_domain_keeper_policy(st
  *
  * Returns true if executing @program supresses domain transition,
  * false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
 				    const struct tomoyo_path_info *program,
@@ -563,8 +572,7 @@ static bool tomoyo_is_domain_keeper(cons
 	struct tomoyo_domain_keeper_entry *ptr;
 	bool flag = false;
 
-	down_read(&tomoyo_domain_keeper_list_lock);
-	list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
 		if (ptr->is_deleted)
 			continue;
 		if (!ptr->is_last_name) {
@@ -582,7 +590,6 @@ static bool tomoyo_is_domain_keeper(cons
 		}
 		flag = true;
 	}
-	up_read(&tomoyo_domain_keeper_list_lock);
 	return flag;
 }
 
@@ -627,6 +634,8 @@ static DECLARE_RWSEM(tomoyo_alias_list_l
  * @is_delete:     True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_update_alias_entry(const char *original_name,
 				     const char *aliased_name,
@@ -646,7 +655,7 @@ static int tomoyo_update_alias_entry(con
 	if (!saved_original_name || !saved_aliased_name)
 		return -ENOMEM;
 	down_write(&tomoyo_alias_list_lock);
-	list_for_each_entry(ptr, &tomoyo_alias_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
 		if (ptr->original_name != saved_original_name ||
 		    ptr->aliased_name != saved_aliased_name)
 			continue;
@@ -663,7 +672,7 @@ static int tomoyo_update_alias_entry(con
 		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);
+	list_add_tail_rcu(&new_entry->list, &tomoyo_alias_list);
 	error = 0;
  out:
 	up_write(&tomoyo_alias_list_lock);
@@ -676,13 +685,14 @@ static int tomoyo_update_alias_entry(con
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
 {
 	struct list_head *pos;
 	bool done = true;
 
-	down_read(&tomoyo_alias_list_lock);
 	list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) {
 		struct tomoyo_alias_entry *ptr;
 
@@ -695,7 +705,6 @@ bool tomoyo_read_alias_policy(struct tom
 		if (!done)
 			break;
 	}
-	up_read(&tomoyo_alias_list_lock);
 	return done;
 }
 
@@ -706,6 +715,8 @@ bool tomoyo_read_alias_policy(struct tom
  * @is_delete: True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 int tomoyo_write_alias_policy(char *data, const bool is_delete)
 {
@@ -724,6 +735,8 @@ int tomoyo_write_alias_policy(char *data
  * @profile:    Profile number to assign if the domain was newly created.
  *
  * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
 							    domainname,
@@ -742,7 +755,7 @@ struct tomoyo_domain_info *tomoyo_find_o
 	if (!saved_domainname)
 		goto out;
 	/* Can I reuse memory of deleted domain? */
-	list_for_each_entry(domain, &tomoyo_domain_list, list) {
+	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
 		struct task_struct *p;
 		struct tomoyo_acl_info *ptr;
 		bool flag;
@@ -760,7 +773,7 @@ struct tomoyo_domain_info *tomoyo_find_o
 		read_unlock(&tasklist_lock);
 		if (flag)
 			continue;
-		list_for_each_entry(ptr, &domain->acl_info_list, list) {
+		list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
 			ptr->type |= TOMOYO_ACL_DELETED;
 		}
 		tomoyo_set_domain_flag(domain, true, domain->flags);
@@ -776,7 +789,7 @@ struct tomoyo_domain_info *tomoyo_find_o
 		INIT_LIST_HEAD(&domain->acl_info_list);
 		domain->domainname = saved_domainname;
 		domain->profile = profile;
-		list_add_tail(&domain->list, &tomoyo_domain_list);
+		list_add_tail_rcu(&domain->list, &tomoyo_domain_list);
 	}
  out:
 	up_write(&tomoyo_domain_list_lock);
@@ -789,6 +802,8 @@ struct tomoyo_domain_info *tomoyo_find_o
  * @bprm: Pointer to "struct linux_binprm".
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 int tomoyo_find_next_domain(struct linux_binprm *bprm)
 {
@@ -849,8 +864,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);
-		list_for_each_entry(ptr, &tomoyo_alias_list, list) {
+		list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
 			if (ptr->is_deleted ||
 			    tomoyo_pathcmp(&r, ptr->original_name) ||
 			    tomoyo_pathcmp(&s, ptr->aliased_name))
@@ -861,7 +875,6 @@ int tomoyo_find_next_domain(struct linux
 			tomoyo_fill_path_info(&r);
 			break;
 		}
-		up_read(&tomoyo_alias_list_lock);
 	}
 
 	/* Check execute permission. */
@@ -892,9 +905,7 @@ int tomoyo_find_next_domain(struct linux
 	}
 	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)
--- security-testing-2.6.orig/security/tomoyo/file.c
+++ security-testing-2.6/security/tomoyo/file.c
@@ -205,6 +205,8 @@ static DECLARE_RWSEM(tomoyo_globally_rea
  * @is_delete: True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_update_globally_readable_entry(const char *filename,
 						 const bool is_delete)
@@ -220,7 +222,7 @@ static int tomoyo_update_globally_readab
 	if (!saved_filename)
 		return -ENOMEM;
 	down_write(&tomoyo_globally_readable_list_lock);
-	list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) {
 		if (ptr->filename != saved_filename)
 			continue;
 		ptr->is_deleted = is_delete;
@@ -235,7 +237,7 @@ static int tomoyo_update_globally_readab
 	if (!new_entry)
 		goto out;
 	new_entry->filename = saved_filename;
-	list_add_tail(&new_entry->list, &tomoyo_globally_readable_list);
+	list_add_tail_rcu(&new_entry->list, &tomoyo_globally_readable_list);
 	error = 0;
  out:
 	up_write(&tomoyo_globally_readable_list_lock);
@@ -248,21 +250,22 @@ static int tomoyo_update_globally_readab
  * @filename: The filename to check.
  *
  * Returns true if any domain can open @filename for reading, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info *
 					     filename)
 {
 	struct tomoyo_globally_readable_file_entry *ptr;
 	bool found = false;
-	down_read(&tomoyo_globally_readable_list_lock);
-	list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
+
+	list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) {
 		if (!ptr->is_deleted &&
 		    tomoyo_path_matches_pattern(filename, ptr->filename)) {
 			found = true;
 			break;
 		}
 	}
-	up_read(&tomoyo_globally_readable_list_lock);
 	return found;
 }
 
@@ -273,6 +276,8 @@ static bool tomoyo_is_globally_readable_
  * @is_delete: True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 int tomoyo_write_globally_readable_policy(char *data, const bool is_delete)
 {
@@ -285,13 +290,14 @@ int tomoyo_write_globally_readable_polic
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head)
 {
 	struct list_head *pos;
 	bool done = true;
 
-	down_read(&tomoyo_globally_readable_list_lock);
 	list_for_each_cookie(pos, head->read_var2,
 			     &tomoyo_globally_readable_list) {
 		struct tomoyo_globally_readable_file_entry *ptr;
@@ -305,7 +311,6 @@ bool tomoyo_read_globally_readable_polic
 		if (!done)
 			break;
 	}
-	up_read(&tomoyo_globally_readable_list_lock);
 	return done;
 }
 
@@ -348,6 +353,8 @@ static DECLARE_RWSEM(tomoyo_pattern_list
  * @is_delete: True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_update_file_pattern_entry(const char *pattern,
 					    const bool is_delete)
@@ -363,7 +370,7 @@ static int tomoyo_update_file_pattern_en
 	if (!saved_pattern)
 		return -ENOMEM;
 	down_write(&tomoyo_pattern_list_lock);
-	list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
 		if (saved_pattern != ptr->pattern)
 			continue;
 		ptr->is_deleted = is_delete;
@@ -378,7 +385,7 @@ static int tomoyo_update_file_pattern_en
 	if (!new_entry)
 		goto out;
 	new_entry->pattern = saved_pattern;
-	list_add_tail(&new_entry->list, &tomoyo_pattern_list);
+	list_add_tail_rcu(&new_entry->list, &tomoyo_pattern_list);
 	error = 0;
  out:
 	up_write(&tomoyo_pattern_list_lock);
@@ -391,6 +398,8 @@ static int tomoyo_update_file_pattern_en
  * @filename: The filename to find patterned pathname.
  *
  * Returns pointer to pathname pattern if matched, @filename otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static const struct tomoyo_path_info *
 tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
@@ -398,8 +407,7 @@ tomoyo_get_file_pattern(const struct tom
 	struct tomoyo_pattern_entry *ptr;
 	const struct tomoyo_path_info *pattern = NULL;
 
-	down_read(&tomoyo_pattern_list_lock);
-	list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
 		if (ptr->is_deleted)
 			continue;
 		if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
@@ -412,7 +420,6 @@ tomoyo_get_file_pattern(const struct tom
 			break;
 		}
 	}
-	up_read(&tomoyo_pattern_list_lock);
 	if (pattern)
 		filename = pattern;
 	return filename;
@@ -425,6 +432,8 @@ tomoyo_get_file_pattern(const struct tom
  * @is_delete: True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 int tomoyo_write_pattern_policy(char *data, const bool is_delete)
 {
@@ -437,13 +446,14 @@ int tomoyo_write_pattern_policy(char *da
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head)
 {
 	struct list_head *pos;
 	bool done = true;
 
-	down_read(&tomoyo_pattern_list_lock);
 	list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) {
 		struct tomoyo_pattern_entry *ptr;
 		ptr = list_entry(pos, struct tomoyo_pattern_entry, list);
@@ -454,7 +464,6 @@ bool tomoyo_read_file_pattern(struct tom
 		if (!done)
 			break;
 	}
-	up_read(&tomoyo_pattern_list_lock);
 	return done;
 }
 
@@ -497,6 +506,8 @@ static DECLARE_RWSEM(tomoyo_no_rewrite_l
  * @is_delete: True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_update_no_rewrite_entry(const char *pattern,
 					  const bool is_delete)
@@ -511,7 +522,7 @@ static int tomoyo_update_no_rewrite_entr
 	if (!saved_pattern)
 		return -ENOMEM;
 	down_write(&tomoyo_no_rewrite_list_lock);
-	list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
 		if (ptr->pattern != saved_pattern)
 			continue;
 		ptr->is_deleted = is_delete;
@@ -526,7 +537,7 @@ static int tomoyo_update_no_rewrite_entr
 	if (!new_entry)
 		goto out;
 	new_entry->pattern = saved_pattern;
-	list_add_tail(&new_entry->list, &tomoyo_no_rewrite_list);
+	list_add_tail_rcu(&new_entry->list, &tomoyo_no_rewrite_list);
 	error = 0;
  out:
 	up_write(&tomoyo_no_rewrite_list_lock);
@@ -540,14 +551,15 @@ static int tomoyo_update_no_rewrite_entr
  *
  * Returns true if @filename is specified by "deny_rewrite" directive,
  * false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename)
 {
 	struct tomoyo_no_rewrite_entry *ptr;
 	bool found = false;
 
-	down_read(&tomoyo_no_rewrite_list_lock);
-	list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
 		if (ptr->is_deleted)
 			continue;
 		if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
@@ -555,7 +567,6 @@ static bool tomoyo_is_no_rewrite_file(co
 		found = true;
 		break;
 	}
-	up_read(&tomoyo_no_rewrite_list_lock);
 	return found;
 }
 
@@ -566,6 +577,8 @@ static bool tomoyo_is_no_rewrite_file(co
  * @is_delete: True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete)
 {
@@ -578,13 +591,14 @@ int tomoyo_write_no_rewrite_policy(char 
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
  * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
 {
 	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) {
 		struct tomoyo_no_rewrite_entry *ptr;
 		ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list);
@@ -595,7 +609,6 @@ bool tomoyo_read_no_rewrite_policy(struc
 		if (!done)
 			break;
 	}
-	up_read(&tomoyo_no_rewrite_list_lock);
 	return done;
 }
 
@@ -613,6 +626,8 @@ bool tomoyo_read_no_rewrite_policy(struc
  * Current policy syntax uses "allow_read/write" instead of "6",
  * "allow_read" instead of "4", "allow_write" instead of "2",
  * "allow_execute" instead of "1".
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_update_file_acl(const char *filename, u8 perm,
 				  struct tomoyo_domain_info * const domain,
@@ -650,6 +665,8 @@ static int tomoyo_update_file_acl(const 
  * @may_use_pattern: True if patterned ACL is permitted.
  *
  * Returns 0 on success, -EPERM otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info *
 					 domain,
@@ -661,8 +678,7 @@ static int tomoyo_check_single_path_acl2
 	struct tomoyo_acl_info *ptr;
 	int error = -EPERM;
 
-	down_read(&tomoyo_domain_acl_info_list_lock);
-	list_for_each_entry(ptr, &domain->acl_info_list, list) {
+	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
 		struct tomoyo_single_path_acl_record *acl;
 		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
 			continue;
@@ -680,7 +696,6 @@ static int tomoyo_check_single_path_acl2
 		error = 0;
 		break;
 	}
-	up_read(&tomoyo_domain_acl_info_list_lock);
 	return error;
 }
 
@@ -692,6 +707,8 @@ static int tomoyo_check_single_path_acl2
  * @operation: Mode ("read" or "write" or "read/write" or "execute").
  *
  * Returns 0 on success, -EPERM otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain,
 				 const struct tomoyo_path_info *filename,
@@ -725,6 +742,8 @@ static int tomoyo_check_file_acl(const s
  * @mode:      Access control mode.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain,
 				   const struct tomoyo_path_info *filename,
@@ -778,6 +797,8 @@ static int tomoyo_check_file_perm2(struc
  * @is_delete: True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
 			     const bool is_delete)
@@ -825,6 +846,8 @@ int tomoyo_write_file_policy(char *data,
  * @is_delete: True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
 					 struct tomoyo_domain_info *
@@ -848,7 +871,7 @@ static int tomoyo_update_single_path_acl
 	down_write(&tomoyo_domain_acl_info_list_lock);
 	if (is_delete)
 		goto delete;
-	list_for_each_entry(ptr, &domain->acl_info_list, list) {
+	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
 		if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
 			continue;
 		acl = container_of(ptr, struct tomoyo_single_path_acl_record,
@@ -875,12 +898,12 @@ static int tomoyo_update_single_path_acl
 	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);
+	list_add_tail_rcu(&acl->head.list, &domain->acl_info_list);
 	error = 0;
 	goto out;
  delete:
 	error = -ENOENT;
-	list_for_each_entry(ptr, &domain->acl_info_list, list) {
+	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
 		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
 			continue;
 		acl = container_of(ptr, struct tomoyo_single_path_acl_record,
@@ -912,6 +935,8 @@ static int tomoyo_update_single_path_acl
  * @is_delete: True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
 					 const char *filename2,
@@ -937,7 +962,7 @@ static int tomoyo_update_double_path_acl
 	down_write(&tomoyo_domain_acl_info_list_lock);
 	if (is_delete)
 		goto delete;
-	list_for_each_entry(ptr, &domain->acl_info_list, list) {
+	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
 		if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
 			continue;
 		acl = container_of(ptr, struct tomoyo_double_path_acl_record,
@@ -960,12 +985,12 @@ static int tomoyo_update_double_path_acl
 	acl->perm = perm;
 	acl->filename1 = saved_filename1;
 	acl->filename2 = saved_filename2;
-	list_add_tail(&acl->head.list, &domain->acl_info_list);
+	list_add_tail_rcu(&acl->head.list, &domain->acl_info_list);
 	error = 0;
 	goto out;
  delete:
 	error = -ENOENT;
-	list_for_each_entry(ptr, &domain->acl_info_list, list) {
+	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
 		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
 			continue;
 		acl = container_of(ptr, struct tomoyo_double_path_acl_record,
@@ -992,6 +1017,8 @@ static int tomoyo_update_double_path_acl
  * @filename: Filename to check.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain,
 					const u8 type,
@@ -1011,6 +1038,8 @@ static int tomoyo_check_single_path_acl(
  * @filename2: Second filename to check.
  *
  * Returns 0 on success, -EPERM otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain,
 					const u8 type,
@@ -1025,8 +1054,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);
-	list_for_each_entry(ptr, &domain->acl_info_list, list) {
+	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
 		struct tomoyo_double_path_acl_record *acl;
 		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
 			continue;
@@ -1041,7 +1069,6 @@ static int tomoyo_check_double_path_acl(
 		error = 0;
 		break;
 	}
-	up_read(&tomoyo_domain_acl_info_list_lock);
 	return error;
 }
 
@@ -1054,6 +1081,8 @@ static int tomoyo_check_double_path_acl(
  * @mode:      Access control mode.
  *
  * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info *
 						const domain, u8 operation,
@@ -1123,6 +1152,8 @@ int tomoyo_check_file_perm(struct tomoyo
  * @filename: Check permission for "execute".
  *
  * Returns 0 on success, negativevalue otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
 int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
 			   const struct tomoyo_path_info *filename)
@@ -1151,6 +1182,7 @@ int tomoyo_check_open_permission(struct 
 	struct tomoyo_path_info *buf;
 	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
 	const bool is_enforce = (mode == 3);
+	int idx;
 
 	if (!mode || !path->mnt)
 		return 0;
@@ -1162,6 +1194,7 @@ int tomoyo_check_open_permission(struct 
 		 * don't call me.
 		 */
 		return 0;
+	idx = tomoyo_read_lock();
 	buf = tomoyo_get_path(path);
 	if (!buf)
 		goto out;
@@ -1187,6 +1220,7 @@ int tomoyo_check_open_permission(struct 
 							     buf, mode);
  out:
 	tomoyo_free(buf);
+	tomoyo_read_unlock(idx);
 	if (!is_enforce)
 		error = 0;
 	return error;
@@ -1208,9 +1242,11 @@ int tomoyo_check_1path_perm(struct tomoy
 	struct tomoyo_path_info *buf;
 	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
 	const bool is_enforce = (mode == 3);
+	int idx;
 
 	if (!mode || !path->mnt)
 		return 0;
+	idx = tomoyo_read_lock();
 	buf = tomoyo_get_path(path);
 	if (!buf)
 		goto out;
@@ -1229,6 +1265,7 @@ int tomoyo_check_1path_perm(struct tomoy
 						     mode);
  out:
 	tomoyo_free(buf);
+	tomoyo_read_unlock(idx);
 	if (!is_enforce)
 		error = 0;
 	return error;
@@ -1249,9 +1286,12 @@ int tomoyo_check_rewrite_permission(stru
 	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
 	const bool is_enforce = (mode == 3);
 	struct tomoyo_path_info *buf;
+	int idx;
 
 	if (!mode || !filp->f_path.mnt)
 		return 0;
+
+	idx = tomoyo_read_lock();
 	buf = tomoyo_get_path(&filp->f_path);
 	if (!buf)
 		goto out;
@@ -1264,6 +1304,7 @@ int tomoyo_check_rewrite_permission(stru
 						     buf, mode);
  out:
 	tomoyo_free(buf);
+	tomoyo_read_unlock(idx);
 	if (!is_enforce)
 		error = 0;
 	return error;
@@ -1288,9 +1329,11 @@ int tomoyo_check_2path_perm(struct tomoy
 	const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
 	const bool is_enforce = (mode == 3);
 	const char *msg;
+	int idx;
 
 	if (!mode || !path1->mnt || !path2->mnt)
 		return 0;
+	idx = tomoyo_read_lock();
 	buf1 = tomoyo_get_path(path1);
 	buf2 = tomoyo_get_path(path2);
 	if (!buf1 || !buf2)
@@ -1329,6 +1372,7 @@ int tomoyo_check_2path_perm(struct tomoy
  out:
 	tomoyo_free(buf1);
 	tomoyo_free(buf2);
+	tomoyo_read_unlock(idx);
 	if (!is_enforce)
 		error = 0;
 	return error;
--- security-testing-2.6.orig/security/tomoyo/realpath.c
+++ security-testing-2.6/security/tomoyo/realpath.c
@@ -392,11 +392,13 @@ void __init tomoyo_realpath_init(void)
 		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);
-	list_add_tail(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
-	down_read(&tomoyo_domain_list_lock);
+	/*
+	 * tomoyo_read_lock() is not needed because this function is
+	 * called before the first "delete" request.
+	 */
+	list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
 	if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
 		panic("Can't register tomoyo_kernel_domain");
-	up_read(&tomoyo_domain_list_lock);
 }
 
 /* Memory allocated for temporary purpose. */
--- security-testing-2.6.orig/security/tomoyo/tomoyo.c
+++ security-testing-2.6/security/tomoyo/tomoyo.c
@@ -76,8 +76,18 @@ static int tomoyo_bprm_check_security(st
 	 * Execute permission is checked against pathname passed to do_execve()
 	 * using current domain.
 	 */
-	if (!domain)
-		return tomoyo_find_next_domain(bprm);
+	if (!domain) {
+		/*
+		 * We will need to protect whole execve() operation when GC
+		 * starts kfree()ing "struct tomoyo_domain_info" because
+		 * bprm->cred->security points to "struct tomoyo_domain_info"
+		 * but "struct tomoyo_domain_info" does not have a refcounter.
+		 */
+		const int idx = tomoyo_read_lock();
+		const int err = tomoyo_find_next_domain(bprm);
+		tomoyo_read_unlock(idx);
+		return err;
+	}
 	/*
 	 * Read permission is checked against interpreters using next domain.
 	 * '1' is the result of open_to_namei_flags(O_RDONLY).
@@ -297,6 +307,9 @@ static struct security_operations tomoyo
 	.path_rename         = tomoyo_path_rename,
 };
 
+/* Lock for GC. */
+struct srcu_struct tomoyo_ss;
+
 static int __init tomoyo_init(void)
 {
 	struct cred *cred = (struct cred *) current_cred();
@@ -304,7 +317,8 @@ static int __init tomoyo_init(void)
 	if (!security_module_enable(&tomoyo_security_ops))
 		return 0;
 	/* register ourselves with the security framework */
-	if (register_security(&tomoyo_security_ops))
+	if (register_security(&tomoyo_security_ops) ||
+	    init_srcu_struct(&tomoyo_ss))
 		panic("Failure registering TOMOYO Linux");
 	printk(KERN_INFO "TOMOYO Linux initialized\n");
 	cred->security = &tomoyo_kernel_domain;

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] TOMOYO: Use RCU primitives for list operation
  2009-10-13 11:39         ` [PATCH] TOMOYO: Use RCU primitives for list operation Tetsuo Handa
@ 2009-10-29  5:40           ` Serge E. Hallyn
  2009-12-04 12:34             ` Tetsuo Handa
  0 siblings, 1 reply; 6+ messages in thread
From: Serge E. Hallyn @ 2009-10-29  5:40 UTC (permalink / raw)
  To: Tetsuo Handa; +Cc: linux-security-module, linux-kernel

Quoting Tetsuo Handa (penguin-kernel@I-love.SAKURA.ne.jp):
> [PATCH] TOMOYO: Use RCU primitives for list operation
> 
> Remove down_read()/up_read() by replacing with RCU primitives.
> SRCU based garbage collector will be added in the future.
> 
> Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
> ---
>  security/tomoyo/common.c   |   52 ++++++++++-----------------------------------
>  security/tomoyo/common.h   |   14 ++++++------
>  security/tomoyo/domain.c   |   38 ++++++++++----------------------
>  security/tomoyo/file.c     |   50 ++++++++++++++-----------------------------
>  security/tomoyo/realpath.c |    4 ---
>  5 files changed, 49 insertions(+), 109 deletions(-)
> 
> --- security-testing-2.6.orig/security/tomoyo/common.c
> +++ security-testing-2.6/security/tomoyo/common.c
> @@ -365,9 +365,6 @@ bool tomoyo_is_domain_def(const unsigned
>   *
>   * @domainname: The domainname to find.
>   *
> - * 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.
>   */
>  struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
> @@ -377,7 +374,7 @@ struct tomoyo_domain_info *tomoyo_find_d
> 
>  	name.name = domainname;
>  	tomoyo_fill_path_info(&name);
> -	list_for_each_entry(domain, &tomoyo_domain_list, list) {
> +	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
>  		if (!domain->is_deleted &&
>  		    !tomoyo_pathcmp(&name, domain->domainname))
>  			return domain;
> @@ -837,8 +834,7 @@ bool tomoyo_domain_quota_is_ok(struct to
> 
>  	if (!domain)
>  		return true;
> -	down_read(&tomoyo_domain_acl_info_list_lock);
> -	list_for_each_entry(ptr, &domain->acl_info_list, list) {
> +	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
>  		if (ptr->type & TOMOYO_ACL_DELETED)
>  			continue;
>  		switch (tomoyo_acl_type2(ptr)) {

You are removing the down_read()s, but not replacing them with
rcu_read_lock()s.  I assume this is based on the same discussions
you had with Paul awhile ago about the safety of walking the list
bc you only append to the end (which I trust must have concluded
in your favor)?

If you'll be adding gc eventually anyway, is it really worthwhile
to 'violate the rules' now by calling list_for_each_entry_rcu()
without being inside rcu_read_lock() now?  I fear it'll only serve
to confuse readers, especially those looking for rcu users to serve
as examples.

-serge

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH] TOMOYO: Use RCU primitives for list operation
  2009-10-13 11:37       ` [PATCH] TOMOYO: Add recursive directory matching operator support Tetsuo Handa
@ 2009-10-13 11:39         ` Tetsuo Handa
  2009-10-29  5:40           ` Serge E. Hallyn
  0 siblings, 1 reply; 6+ messages in thread
From: Tetsuo Handa @ 2009-10-13 11:39 UTC (permalink / raw)
  To: linux-security-module; +Cc: linux-kernel

[PATCH] TOMOYO: Use RCU primitives for list operation

Remove down_read()/up_read() by replacing with RCU primitives.
SRCU based garbage collector will be added in the future.

Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
 security/tomoyo/common.c   |   52 ++++++++++-----------------------------------
 security/tomoyo/common.h   |   14 ++++++------
 security/tomoyo/domain.c   |   38 ++++++++++----------------------
 security/tomoyo/file.c     |   50 ++++++++++++++-----------------------------
 security/tomoyo/realpath.c |    4 ---
 5 files changed, 49 insertions(+), 109 deletions(-)

--- security-testing-2.6.orig/security/tomoyo/common.c
+++ security-testing-2.6/security/tomoyo/common.c
@@ -365,9 +365,6 @@ bool tomoyo_is_domain_def(const unsigned
  *
  * @domainname: The domainname to find.
  *
- * 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.
  */
 struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
@@ -377,7 +374,7 @@ struct tomoyo_domain_info *tomoyo_find_d
 
 	name.name = domainname;
 	tomoyo_fill_path_info(&name);
-	list_for_each_entry(domain, &tomoyo_domain_list, list) {
+	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
 		if (!domain->is_deleted &&
 		    !tomoyo_pathcmp(&name, domain->domainname))
 			return domain;
@@ -837,8 +834,7 @@ bool tomoyo_domain_quota_is_ok(struct to
 
 	if (!domain)
 		return true;
-	down_read(&tomoyo_domain_acl_info_list_lock);
-	list_for_each_entry(ptr, &domain->acl_info_list, list) {
+	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
 		if (ptr->type & TOMOYO_ACL_DELETED)
 			continue;
 		switch (tomoyo_acl_type2(ptr)) {
@@ -891,7 +887,6 @@ bool tomoyo_domain_quota_is_ok(struct to
 			break;
 		}
 	}
-	up_read(&tomoyo_domain_acl_info_list_lock);
 	if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY))
 		return true;
 	if (!domain->quota_warned) {
@@ -1143,7 +1138,7 @@ static int tomoyo_update_manager_entry(c
 	if (!saved_manager)
 		return -ENOMEM;
 	down_write(&tomoyo_policy_manager_list_lock);
-	list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
 		if (ptr->manager != saved_manager)
 			continue;
 		ptr->is_deleted = is_delete;
@@ -1159,7 +1154,7 @@ static int tomoyo_update_manager_entry(c
 		goto out;
 	new_entry->manager = saved_manager;
 	new_entry->is_domain = is_domain;
-	list_add_tail(&new_entry->list, &tomoyo_policy_manager_list);
+	list_add_tail_rcu(&new_entry->list, &tomoyo_policy_manager_list);
 	error = 0;
  out:
 	up_write(&tomoyo_policy_manager_list_lock);
@@ -1199,7 +1194,6 @@ 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,
 			     &tomoyo_policy_manager_list) {
 		struct tomoyo_policy_manager_entry *ptr;
@@ -1211,7 +1205,6 @@ static int tomoyo_read_manager_policy(st
 		if (!done)
 			break;
 	}
-	up_read(&tomoyo_policy_manager_list_lock);
 	head->read_eof = done;
 	return 0;
 }
@@ -1234,29 +1227,25 @@ 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);
-	list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
 		if (!ptr->is_deleted && ptr->is_domain
 		    && !tomoyo_pathcmp(domainname, ptr->manager)) {
 			found = true;
 			break;
 		}
 	}
-	up_read(&tomoyo_policy_manager_list_lock);
 	if (found)
 		return true;
 	exe = tomoyo_get_exe();
 	if (!exe)
 		return false;
-	down_read(&tomoyo_policy_manager_list_lock);
-	list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
 		if (!ptr->is_deleted && !ptr->is_domain
 		    && !strcmp(exe, ptr->manager->name)) {
 			found = true;
 			break;
 		}
 	}
-	up_read(&tomoyo_policy_manager_list_lock);
 	if (!found) { /* Reduce error messages. */
 		static pid_t last_pid;
 		const pid_t pid = current->pid;
@@ -1292,11 +1281,8 @@ static bool tomoyo_is_select_one(struct 
 			domain = tomoyo_real_domain(p);
 		read_unlock(&tasklist_lock);
 	} else if (!strncmp(data, "domain=", 7)) {
-		if (tomoyo_is_domain_def(data + 7)) {
-			down_read(&tomoyo_domain_list_lock);
+		if (tomoyo_is_domain_def(data + 7))
 			domain = tomoyo_find_domain(data + 7);
-			up_read(&tomoyo_domain_list_lock);
-		}
 	} else
 		return false;
 	head->write_var1 = domain;
@@ -1310,13 +1296,11 @@ static bool tomoyo_is_select_one(struct 
 	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) {
+		list_for_each_entry_rcu(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;
@@ -1342,7 +1326,7 @@ static int tomoyo_delete_domain(char *do
 	tomoyo_fill_path_info(&name);
 	down_write(&tomoyo_domain_list_lock);
 	/* Is there an active domain? */
-	list_for_each_entry(domain, &tomoyo_domain_list, list) {
+	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
 		/* Never delete tomoyo_kernel_domain */
 		if (domain == &tomoyo_kernel_domain)
 			continue;
@@ -1384,11 +1368,9 @@ static int tomoyo_write_domain_policy(st
 		domain = NULL;
 		if (is_delete)
 			tomoyo_delete_domain(data);
-		else if (is_select) {
-			down_read(&tomoyo_domain_list_lock);
+		else if (is_select)
 			domain = tomoyo_find_domain(data);
-			up_read(&tomoyo_domain_list_lock);
-		} else
+		else
 			domain = tomoyo_find_or_assign_new_domain(data, 0);
 		head->write_var1 = domain;
 		return 0;
@@ -1544,7 +1526,6 @@ 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) {
 		struct tomoyo_domain_info *domain;
 		const char *quota_exceeded = "";
@@ -1577,7 +1558,6 @@ 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) {
 			struct tomoyo_acl_info *ptr
@@ -1587,7 +1567,6 @@ acl_loop:
 			if (!done)
 				break;
 		}
-		up_read(&tomoyo_domain_acl_info_list_lock);
 		if (!done)
 			break;
 		head->read_step = 3;
@@ -1599,7 +1578,6 @@ tail_mark:
 		if (head->read_single_domain)
 			break;
 	}
-	up_read(&tomoyo_domain_list_lock);
 	head->read_eof = done;
 	return 0;
 }
@@ -1626,9 +1604,7 @@ static int tomoyo_write_domain_profile(s
 	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))
 		return -EINVAL;
 	if (domain && profile < TOMOYO_MAX_PROFILES
@@ -1658,7 +1634,6 @@ 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) {
 		struct tomoyo_domain_info *domain;
 		domain = list_entry(pos, struct tomoyo_domain_info, list);
@@ -1669,7 +1644,6 @@ static int tomoyo_read_domain_profile(st
 		if (!done)
 			break;
 	}
-	up_read(&tomoyo_domain_list_lock);
 	head->read_eof = done;
 	return 0;
 }
@@ -1889,15 +1863,13 @@ 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);
-		list_for_each_entry(domain, &tomoyo_domain_list, list) {
+		list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
 			const u8 profile = domain->profile;
 			if (tomoyo_profile_ptr[profile])
 				continue;
 			panic("Profile %u (used by '%s') not defined.\n",
 			      profile, domain->domainname->name);
 		}
-		up_read(&tomoyo_domain_list_lock);
 	}
 }
 
--- security-testing-2.6.orig/security/tomoyo/common.h
+++ security-testing-2.6/security/tomoyo/common.h
@@ -442,16 +442,16 @@ extern struct tomoyo_domain_info tomoyo_
  * @cookie:     the &struct list_head to use as a cookie.
  * @head:       the head for your list.
  *
- * Same with list_for_each() except that this primitive uses @cookie
+ * Same with list_for_each_rcu() except that this primitive uses @cookie
  * so that we can continue iteration.
  * @cookie must be NULL when iteration starts, and @cookie will become
  * NULL when iteration finishes.
  */
-#define list_for_each_cookie(pos, cookie, head)                       \
-	for (({ if (!cookie)                                          \
-				     cookie = head; }),               \
-	     pos = (cookie)->next;                                    \
-	     prefetch(pos->next), pos != (head) || ((cookie) = NULL); \
-	     (cookie) = pos, pos = pos->next)
+#define list_for_each_cookie(pos, cookie, head)				\
+	for (({ if (!cookie)						\
+				     cookie = head; }),			\
+		     pos = rcu_dereference((cookie)->next);		\
+	     prefetch(pos->next), pos != (head) || ((cookie) = NULL);	\
+	     (cookie) = pos, pos = rcu_dereference(pos->next))
 
 #endif /* !defined(_SECURITY_TOMOYO_COMMON_H) */
--- security-testing-2.6.orig/security/tomoyo/domain.c
+++ security-testing-2.6/security/tomoyo/domain.c
@@ -246,7 +246,7 @@ static int tomoyo_update_domain_initiali
 	if (!saved_program)
 		return -ENOMEM;
 	down_write(&tomoyo_domain_initializer_list_lock);
-	list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
 		if (ptr->is_not != is_not ||
 		    ptr->domainname != saved_domainname ||
 		    ptr->program != saved_program)
@@ -266,7 +266,7 @@ static int tomoyo_update_domain_initiali
 	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);
+	list_add_tail_rcu(&new_entry->list, &tomoyo_domain_initializer_list);
 	error = 0;
  out:
 	up_write(&tomoyo_domain_initializer_list_lock);
@@ -285,7 +285,6 @@ 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,
 			     &tomoyo_domain_initializer_list) {
 		const char *no;
@@ -308,7 +307,6 @@ bool tomoyo_read_domain_initializer_poli
 		if (!done)
 			break;
 	}
-	up_read(&tomoyo_domain_initializer_list_lock);
 	return done;
 }
 
@@ -355,8 +353,7 @@ static bool tomoyo_is_domain_initializer
 	struct tomoyo_domain_initializer_entry *ptr;
 	bool flag = false;
 
-	down_read(&tomoyo_domain_initializer_list_lock);
-	list_for_each_entry(ptr,  &tomoyo_domain_initializer_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
 		if (ptr->is_deleted)
 			continue;
 		if (ptr->domainname) {
@@ -376,7 +373,6 @@ static bool tomoyo_is_domain_initializer
 		}
 		flag = true;
 	}
-	up_read(&tomoyo_domain_initializer_list_lock);
 	return flag;
 }
 
@@ -459,7 +455,7 @@ static int tomoyo_update_domain_keeper_e
 	if (!saved_domainname)
 		return -ENOMEM;
 	down_write(&tomoyo_domain_keeper_list_lock);
-	list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
 		if (ptr->is_not != is_not ||
 		    ptr->domainname != saved_domainname ||
 		    ptr->program != saved_program)
@@ -479,7 +475,7 @@ static int tomoyo_update_domain_keeper_e
 	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);
+	list_add_tail_rcu(&new_entry->list, &tomoyo_domain_keeper_list);
 	error = 0;
  out:
 	up_write(&tomoyo_domain_keeper_list_lock);
@@ -519,7 +515,6 @@ 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,
 			     &tomoyo_domain_keeper_list) {
 		struct tomoyo_domain_keeper_entry *ptr;
@@ -542,7 +537,6 @@ bool tomoyo_read_domain_keeper_policy(st
 		if (!done)
 			break;
 	}
-	up_read(&tomoyo_domain_keeper_list_lock);
 	return done;
 }
 
@@ -563,8 +557,7 @@ static bool tomoyo_is_domain_keeper(cons
 	struct tomoyo_domain_keeper_entry *ptr;
 	bool flag = false;
 
-	down_read(&tomoyo_domain_keeper_list_lock);
-	list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
 		if (ptr->is_deleted)
 			continue;
 		if (!ptr->is_last_name) {
@@ -582,7 +575,6 @@ static bool tomoyo_is_domain_keeper(cons
 		}
 		flag = true;
 	}
-	up_read(&tomoyo_domain_keeper_list_lock);
 	return flag;
 }
 
@@ -646,7 +638,7 @@ static int tomoyo_update_alias_entry(con
 	if (!saved_original_name || !saved_aliased_name)
 		return -ENOMEM;
 	down_write(&tomoyo_alias_list_lock);
-	list_for_each_entry(ptr, &tomoyo_alias_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
 		if (ptr->original_name != saved_original_name ||
 		    ptr->aliased_name != saved_aliased_name)
 			continue;
@@ -663,7 +655,7 @@ static int tomoyo_update_alias_entry(con
 		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);
+	list_add_tail_rcu(&new_entry->list, &tomoyo_alias_list);
 	error = 0;
  out:
 	up_write(&tomoyo_alias_list_lock);
@@ -682,7 +674,6 @@ 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) {
 		struct tomoyo_alias_entry *ptr;
 
@@ -695,7 +686,6 @@ bool tomoyo_read_alias_policy(struct tom
 		if (!done)
 			break;
 	}
-	up_read(&tomoyo_alias_list_lock);
 	return done;
 }
 
@@ -742,7 +732,7 @@ struct tomoyo_domain_info *tomoyo_find_o
 	if (!saved_domainname)
 		goto out;
 	/* Can I reuse memory of deleted domain? */
-	list_for_each_entry(domain, &tomoyo_domain_list, list) {
+	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
 		struct task_struct *p;
 		struct tomoyo_acl_info *ptr;
 		bool flag;
@@ -760,7 +750,7 @@ struct tomoyo_domain_info *tomoyo_find_o
 		read_unlock(&tasklist_lock);
 		if (flag)
 			continue;
-		list_for_each_entry(ptr, &domain->acl_info_list, list) {
+		list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
 			ptr->type |= TOMOYO_ACL_DELETED;
 		}
 		tomoyo_set_domain_flag(domain, true, domain->flags);
@@ -776,7 +766,7 @@ struct tomoyo_domain_info *tomoyo_find_o
 		INIT_LIST_HEAD(&domain->acl_info_list);
 		domain->domainname = saved_domainname;
 		domain->profile = profile;
-		list_add_tail(&domain->list, &tomoyo_domain_list);
+		list_add_tail_rcu(&domain->list, &tomoyo_domain_list);
 	}
  out:
 	up_write(&tomoyo_domain_list_lock);
@@ -849,8 +839,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);
-		list_for_each_entry(ptr, &tomoyo_alias_list, list) {
+		list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
 			if (ptr->is_deleted ||
 			    tomoyo_pathcmp(&r, ptr->original_name) ||
 			    tomoyo_pathcmp(&s, ptr->aliased_name))
@@ -861,7 +850,6 @@ int tomoyo_find_next_domain(struct linux
 			tomoyo_fill_path_info(&r);
 			break;
 		}
-		up_read(&tomoyo_alias_list_lock);
 	}
 
 	/* Check execute permission. */
@@ -892,9 +880,7 @@ int tomoyo_find_next_domain(struct linux
 	}
 	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)
--- security-testing-2.6.orig/security/tomoyo/file.c
+++ security-testing-2.6/security/tomoyo/file.c
@@ -220,7 +220,7 @@ static int tomoyo_update_globally_readab
 	if (!saved_filename)
 		return -ENOMEM;
 	down_write(&tomoyo_globally_readable_list_lock);
-	list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) {
 		if (ptr->filename != saved_filename)
 			continue;
 		ptr->is_deleted = is_delete;
@@ -235,7 +235,7 @@ static int tomoyo_update_globally_readab
 	if (!new_entry)
 		goto out;
 	new_entry->filename = saved_filename;
-	list_add_tail(&new_entry->list, &tomoyo_globally_readable_list);
+	list_add_tail_rcu(&new_entry->list, &tomoyo_globally_readable_list);
 	error = 0;
  out:
 	up_write(&tomoyo_globally_readable_list_lock);
@@ -254,15 +254,13 @@ static bool tomoyo_is_globally_readable_
 {
 	struct tomoyo_globally_readable_file_entry *ptr;
 	bool found = false;
-	down_read(&tomoyo_globally_readable_list_lock);
-	list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) {
 		if (!ptr->is_deleted &&
 		    tomoyo_path_matches_pattern(filename, ptr->filename)) {
 			found = true;
 			break;
 		}
 	}
-	up_read(&tomoyo_globally_readable_list_lock);
 	return found;
 }
 
@@ -291,7 +289,6 @@ 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,
 			     &tomoyo_globally_readable_list) {
 		struct tomoyo_globally_readable_file_entry *ptr;
@@ -305,7 +302,6 @@ bool tomoyo_read_globally_readable_polic
 		if (!done)
 			break;
 	}
-	up_read(&tomoyo_globally_readable_list_lock);
 	return done;
 }
 
@@ -363,7 +359,7 @@ static int tomoyo_update_file_pattern_en
 	if (!saved_pattern)
 		return -ENOMEM;
 	down_write(&tomoyo_pattern_list_lock);
-	list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
 		if (saved_pattern != ptr->pattern)
 			continue;
 		ptr->is_deleted = is_delete;
@@ -378,7 +374,7 @@ static int tomoyo_update_file_pattern_en
 	if (!new_entry)
 		goto out;
 	new_entry->pattern = saved_pattern;
-	list_add_tail(&new_entry->list, &tomoyo_pattern_list);
+	list_add_tail_rcu(&new_entry->list, &tomoyo_pattern_list);
 	error = 0;
  out:
 	up_write(&tomoyo_pattern_list_lock);
@@ -398,8 +394,7 @@ tomoyo_get_file_pattern(const struct tom
 	struct tomoyo_pattern_entry *ptr;
 	const struct tomoyo_path_info *pattern = NULL;
 
-	down_read(&tomoyo_pattern_list_lock);
-	list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
 		if (ptr->is_deleted)
 			continue;
 		if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
@@ -412,7 +407,6 @@ tomoyo_get_file_pattern(const struct tom
 			break;
 		}
 	}
-	up_read(&tomoyo_pattern_list_lock);
 	if (pattern)
 		filename = pattern;
 	return filename;
@@ -443,7 +437,6 @@ 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) {
 		struct tomoyo_pattern_entry *ptr;
 		ptr = list_entry(pos, struct tomoyo_pattern_entry, list);
@@ -454,7 +447,6 @@ bool tomoyo_read_file_pattern(struct tom
 		if (!done)
 			break;
 	}
-	up_read(&tomoyo_pattern_list_lock);
 	return done;
 }
 
@@ -511,7 +503,7 @@ static int tomoyo_update_no_rewrite_entr
 	if (!saved_pattern)
 		return -ENOMEM;
 	down_write(&tomoyo_no_rewrite_list_lock);
-	list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
 		if (ptr->pattern != saved_pattern)
 			continue;
 		ptr->is_deleted = is_delete;
@@ -526,7 +518,7 @@ static int tomoyo_update_no_rewrite_entr
 	if (!new_entry)
 		goto out;
 	new_entry->pattern = saved_pattern;
-	list_add_tail(&new_entry->list, &tomoyo_no_rewrite_list);
+	list_add_tail_rcu(&new_entry->list, &tomoyo_no_rewrite_list);
 	error = 0;
  out:
 	up_write(&tomoyo_no_rewrite_list_lock);
@@ -546,8 +538,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);
-	list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
+	list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
 		if (ptr->is_deleted)
 			continue;
 		if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
@@ -555,7 +546,6 @@ static bool tomoyo_is_no_rewrite_file(co
 		found = true;
 		break;
 	}
-	up_read(&tomoyo_no_rewrite_list_lock);
 	return found;
 }
 
@@ -584,7 +574,6 @@ 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) {
 		struct tomoyo_no_rewrite_entry *ptr;
 		ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list);
@@ -595,7 +584,6 @@ bool tomoyo_read_no_rewrite_policy(struc
 		if (!done)
 			break;
 	}
-	up_read(&tomoyo_no_rewrite_list_lock);
 	return done;
 }
 
@@ -661,8 +649,7 @@ static int tomoyo_check_single_path_acl2
 	struct tomoyo_acl_info *ptr;
 	int error = -EPERM;
 
-	down_read(&tomoyo_domain_acl_info_list_lock);
-	list_for_each_entry(ptr, &domain->acl_info_list, list) {
+	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
 		struct tomoyo_single_path_acl_record *acl;
 		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
 			continue;
@@ -680,7 +667,6 @@ static int tomoyo_check_single_path_acl2
 		error = 0;
 		break;
 	}
-	up_read(&tomoyo_domain_acl_info_list_lock);
 	return error;
 }
 
@@ -848,7 +834,7 @@ static int tomoyo_update_single_path_acl
 	down_write(&tomoyo_domain_acl_info_list_lock);
 	if (is_delete)
 		goto delete;
-	list_for_each_entry(ptr, &domain->acl_info_list, list) {
+	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
 		if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
 			continue;
 		acl = container_of(ptr, struct tomoyo_single_path_acl_record,
@@ -875,12 +861,12 @@ static int tomoyo_update_single_path_acl
 	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);
+	list_add_tail_rcu(&acl->head.list, &domain->acl_info_list);
 	error = 0;
 	goto out;
  delete:
 	error = -ENOENT;
-	list_for_each_entry(ptr, &domain->acl_info_list, list) {
+	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
 		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
 			continue;
 		acl = container_of(ptr, struct tomoyo_single_path_acl_record,
@@ -937,7 +923,7 @@ static int tomoyo_update_double_path_acl
 	down_write(&tomoyo_domain_acl_info_list_lock);
 	if (is_delete)
 		goto delete;
-	list_for_each_entry(ptr, &domain->acl_info_list, list) {
+	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
 		if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
 			continue;
 		acl = container_of(ptr, struct tomoyo_double_path_acl_record,
@@ -960,12 +946,12 @@ static int tomoyo_update_double_path_acl
 	acl->perm = perm;
 	acl->filename1 = saved_filename1;
 	acl->filename2 = saved_filename2;
-	list_add_tail(&acl->head.list, &domain->acl_info_list);
+	list_add_tail_rcu(&acl->head.list, &domain->acl_info_list);
 	error = 0;
 	goto out;
  delete:
 	error = -ENOENT;
-	list_for_each_entry(ptr, &domain->acl_info_list, list) {
+	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
 		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
 			continue;
 		acl = container_of(ptr, struct tomoyo_double_path_acl_record,
@@ -1025,8 +1011,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);
-	list_for_each_entry(ptr, &domain->acl_info_list, list) {
+	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
 		struct tomoyo_double_path_acl_record *acl;
 		if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
 			continue;
@@ -1041,7 +1026,6 @@ static int tomoyo_check_double_path_acl(
 		error = 0;
 		break;
 	}
-	up_read(&tomoyo_domain_acl_info_list_lock);
 	return error;
 }
 
--- security-testing-2.6.orig/security/tomoyo/realpath.c
+++ security-testing-2.6/security/tomoyo/realpath.c
@@ -387,11 +387,9 @@ void __init tomoyo_realpath_init(void)
 		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);
-	list_add_tail(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
-	down_read(&tomoyo_domain_list_lock);
+	list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
 	if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
 		panic("Can't register tomoyo_kernel_domain");
-	up_read(&tomoyo_domain_list_lock);
 }
 
 /* Memory allocated for temporary purpose. */

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2009-12-15  1:39 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-12-11 13:53 [PATCH] TOMOYO: Use RCU primitives for list operation Tetsuo Handa
2009-12-14 16:39 ` Serge E. Hallyn
2009-12-15  1:39   ` Tetsuo Handa
  -- strict thread matches above, loose matches on Subject: below --
2009-10-04 12:49 [TOMOYO #16 01/25] LSM: Add security_path_chmod() and security_path_chown() Tetsuo Handa
2009-10-08 17:10 ` John Johansen
2009-10-12  1:04   ` James Morris
2009-10-13 11:34     ` [TOMOYO #16 01/25] LSM: Add security_path_chmod() andsecurity_path_chown() Tetsuo Handa
2009-10-13 11:37       ` [PATCH] TOMOYO: Add recursive directory matching operator support Tetsuo Handa
2009-10-13 11:39         ` [PATCH] TOMOYO: Use RCU primitives for list operation Tetsuo Handa
2009-10-29  5:40           ` Serge E. Hallyn
2009-12-04 12:34             ` Tetsuo Handa

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome