Merge branch 'next' into for-linus
[safe/jmp/linux-2.6] / security / tomoyo / file.c
index 9a6c588..1b24304 100644 (file)
  */
 
 #include "common.h"
-#include "tomoyo.h"
-#include "realpath.h"
-
-/*
- * tomoyo_globally_readable_file_entry is a structure which is used for holding
- * "allow_read" entries.
- * It has following fields.
- *
- *  (1) "list" which is linked to tomoyo_globally_readable_list .
- *  (2) "filename" is a pathname which is allowed to open(O_RDONLY).
- *  (3) "is_deleted" is a bool which is true if marked as deleted, false
- *      otherwise.
- */
-struct tomoyo_globally_readable_file_entry {
-       struct list_head list;
-       const struct tomoyo_path_info *filename;
-       bool is_deleted;
-};
-
-/*
- * tomoyo_pattern_entry is a structure which is used for holding
- * "tomoyo_pattern_list" entries.
- * It has following fields.
- *
- *  (1) "list" which is linked to tomoyo_pattern_list .
- *  (2) "pattern" is a pathname pattern which is used for converting pathnames
- *      to pathname patterns during learning mode.
- *  (3) "is_deleted" is a bool which is true if marked as deleted, false
- *      otherwise.
- */
-struct tomoyo_pattern_entry {
-       struct list_head list;
-       const struct tomoyo_path_info *pattern;
-       bool is_deleted;
-};
-
-/*
- * tomoyo_no_rewrite_entry is a structure which is used for holding
- * "deny_rewrite" entries.
- * It has following fields.
- *
- *  (1) "list" which is linked to tomoyo_no_rewrite_list .
- *  (2) "pattern" is a pathname which is by default not permitted to modify
- *      already existing content.
- *  (3) "is_deleted" is a bool which is true if marked as deleted, false
- *      otherwise.
- */
-struct tomoyo_no_rewrite_entry {
-       struct list_head list;
-       const struct tomoyo_path_info *pattern;
-       bool is_deleted;
-};
 
 /* Keyword array for single path operations. */
-static const char *tomoyo_sp_keyword[TOMOYO_MAX_SINGLE_PATH_OPERATION] = {
-       [TOMOYO_TYPE_READ_WRITE_ACL] = "read/write",
-       [TOMOYO_TYPE_EXECUTE_ACL]    = "execute",
-       [TOMOYO_TYPE_READ_ACL]       = "read",
-       [TOMOYO_TYPE_WRITE_ACL]      = "write",
-       [TOMOYO_TYPE_CREATE_ACL]     = "create",
-       [TOMOYO_TYPE_UNLINK_ACL]     = "unlink",
-       [TOMOYO_TYPE_MKDIR_ACL]      = "mkdir",
-       [TOMOYO_TYPE_RMDIR_ACL]      = "rmdir",
-       [TOMOYO_TYPE_MKFIFO_ACL]     = "mkfifo",
-       [TOMOYO_TYPE_MKSOCK_ACL]     = "mksock",
-       [TOMOYO_TYPE_MKBLOCK_ACL]    = "mkblock",
-       [TOMOYO_TYPE_MKCHAR_ACL]     = "mkchar",
-       [TOMOYO_TYPE_TRUNCATE_ACL]   = "truncate",
-       [TOMOYO_TYPE_SYMLINK_ACL]    = "symlink",
-       [TOMOYO_TYPE_REWRITE_ACL]    = "rewrite",
+static const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = {
+       [TOMOYO_TYPE_READ_WRITE] = "read/write",
+       [TOMOYO_TYPE_EXECUTE]    = "execute",
+       [TOMOYO_TYPE_READ]       = "read",
+       [TOMOYO_TYPE_WRITE]      = "write",
+       [TOMOYO_TYPE_CREATE]     = "create",
+       [TOMOYO_TYPE_UNLINK]     = "unlink",
+       [TOMOYO_TYPE_MKDIR]      = "mkdir",
+       [TOMOYO_TYPE_RMDIR]      = "rmdir",
+       [TOMOYO_TYPE_MKFIFO]     = "mkfifo",
+       [TOMOYO_TYPE_MKSOCK]     = "mksock",
+       [TOMOYO_TYPE_MKBLOCK]    = "mkblock",
+       [TOMOYO_TYPE_MKCHAR]     = "mkchar",
+       [TOMOYO_TYPE_TRUNCATE]   = "truncate",
+       [TOMOYO_TYPE_SYMLINK]    = "symlink",
+       [TOMOYO_TYPE_REWRITE]    = "rewrite",
+       [TOMOYO_TYPE_IOCTL]      = "ioctl",
+       [TOMOYO_TYPE_CHMOD]      = "chmod",
+       [TOMOYO_TYPE_CHOWN]      = "chown",
+       [TOMOYO_TYPE_CHGRP]      = "chgrp",
+       [TOMOYO_TYPE_CHROOT]     = "chroot",
+       [TOMOYO_TYPE_MOUNT]      = "mount",
+       [TOMOYO_TYPE_UMOUNT]     = "unmount",
 };
 
 /* Keyword array for double path operations. */
-static const char *tomoyo_dp_keyword[TOMOYO_MAX_DOUBLE_PATH_OPERATION] = {
-       [TOMOYO_TYPE_LINK_ACL]    = "link",
-       [TOMOYO_TYPE_RENAME_ACL]  = "rename",
+static const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = {
+       [TOMOYO_TYPE_LINK]    = "link",
+       [TOMOYO_TYPE_RENAME]  = "rename",
+       [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root",
 };
 
 /**
- * tomoyo_sp2keyword - Get the name of single path operation.
+ * tomoyo_path2keyword - Get the name of single path operation.
  *
  * @operation: Type of operation.
  *
  * Returns the name of single path operation.
  */
-const char *tomoyo_sp2keyword(const u8 operation)
+const char *tomoyo_path2keyword(const u8 operation)
 {
-       return (operation < TOMOYO_MAX_SINGLE_PATH_OPERATION)
-               ? tomoyo_sp_keyword[operation] : NULL;
+       return (operation < TOMOYO_MAX_PATH_OPERATION)
+               ? tomoyo_path_keyword[operation] : NULL;
 }
 
 /**
- * tomoyo_dp2keyword - Get the name of double path operation.
+ * tomoyo_path22keyword - Get the name of double path operation.
  *
  * @operation: Type of operation.
  *
  * Returns the name of double path operation.
  */
-const char *tomoyo_dp2keyword(const u8 operation)
+const char *tomoyo_path22keyword(const u8 operation)
 {
-       return (operation < TOMOYO_MAX_DOUBLE_PATH_OPERATION)
-               ? tomoyo_dp_keyword[operation] : NULL;
+       return (operation < TOMOYO_MAX_PATH2_OPERATION)
+               ? tomoyo_path2_keyword[operation] : NULL;
 }
 
 /**
@@ -142,7 +98,8 @@ static bool tomoyo_strendswith(const char *name, const char *tail)
 static struct tomoyo_path_info *tomoyo_get_path(struct path *path)
 {
        int error;
-       struct tomoyo_path_info_with_data *buf = tomoyo_alloc(sizeof(*buf));
+       struct tomoyo_path_info_with_data *buf = kzalloc(sizeof(*buf),
+                                                        GFP_KERNEL);
 
        if (!buf)
                return NULL;
@@ -154,20 +111,17 @@ static struct tomoyo_path_info *tomoyo_get_path(struct path *path)
                tomoyo_fill_path_info(&buf->head);
                return &buf->head;
        }
-       tomoyo_free(buf);
+       kfree(buf);
        return NULL;
 }
 
-/* Lock for domain->acl_info_list. */
-DECLARE_RWSEM(tomoyo_domain_acl_info_list_lock);
-
-static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
-                                        const char *filename2,
-                                        struct tomoyo_domain_info *
-                                        const domain, const bool is_delete);
-static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
-                                        struct tomoyo_domain_info *
-                                        const domain, const bool is_delete);
+static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
+                                  const char *filename2,
+                                  struct tomoyo_domain_info *const domain,
+                                  const bool is_delete);
+static int tomoyo_update_path_acl(const u8 type, const char *filename,
+                                 struct tomoyo_domain_info *const domain,
+                                 const bool is_delete);
 
 /*
  * tomoyo_globally_readable_list is used for holding list of pathnames which
@@ -194,8 +148,7 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
  * given "allow_read /lib/libc-2.5.so" to the domain which current process
  * belongs to.
  */
-static LIST_HEAD(tomoyo_globally_readable_list);
-static DECLARE_RWSEM(tomoyo_globally_readable_list_lock);
+LIST_HEAD(tomoyo_globally_readable_list);
 
 /**
  * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list.
@@ -204,40 +157,42 @@ 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)
 {
-       struct tomoyo_globally_readable_file_entry *new_entry;
+       struct tomoyo_globally_readable_file_entry *entry = NULL;
        struct tomoyo_globally_readable_file_entry *ptr;
        const struct tomoyo_path_info *saved_filename;
-       int error = -ENOMEM;
+       int error = is_delete ? -ENOENT : -ENOMEM;
 
-       if (!tomoyo_is_correct_path(filename, 1, 0, -1, __func__))
+       if (!tomoyo_is_correct_path(filename, 1, 0, -1))
                return -EINVAL;
-       saved_filename = tomoyo_save_name(filename);
+       saved_filename = tomoyo_get_name(filename);
        if (!saved_filename)
                return -ENOMEM;
-       down_write(&tomoyo_globally_readable_list_lock);
-       list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
+       if (!is_delete)
+               entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+       mutex_lock(&tomoyo_policy_lock);
+       list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) {
                if (ptr->filename != saved_filename)
                        continue;
                ptr->is_deleted = is_delete;
                error = 0;
-               goto out;
+               break;
        }
-       if (is_delete) {
-               error = -ENOENT;
-               goto out;
+       if (!is_delete && error && tomoyo_memory_ok(entry)) {
+               entry->filename = saved_filename;
+               saved_filename = NULL;
+               list_add_tail_rcu(&entry->list, &tomoyo_globally_readable_list);
+               entry = NULL;
+               error = 0;
        }
-       new_entry = tomoyo_alloc_element(sizeof(*new_entry));
-       if (!new_entry)
-               goto out;
-       new_entry->filename = saved_filename;
-       list_add_tail(&new_entry->list, &tomoyo_globally_readable_list);
-       error = 0;
- out:
-       up_write(&tomoyo_globally_readable_list_lock);
+       mutex_unlock(&tomoyo_policy_lock);
+       tomoyo_put_name(saved_filename);
+       kfree(entry);
        return error;
 }
 
@@ -247,21 +202,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;
 }
 
@@ -272,6 +228,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)
 {
@@ -284,13 +242,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;
@@ -304,7 +263,6 @@ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head)
                if (!done)
                        break;
        }
-       up_read(&tomoyo_globally_readable_list_lock);
        return done;
 }
 
@@ -337,8 +295,7 @@ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head)
  * which pretends as if /proc/self/ is not a symlink; so that we can forbid
  * current process from accessing other process's information.
  */
-static LIST_HEAD(tomoyo_pattern_list);
-static DECLARE_RWSEM(tomoyo_pattern_list_lock);
+LIST_HEAD(tomoyo_pattern_list);
 
 /**
  * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list.
@@ -347,40 +304,43 @@ 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)
 {
-       struct tomoyo_pattern_entry *new_entry;
+       struct tomoyo_pattern_entry *entry = NULL;
        struct tomoyo_pattern_entry *ptr;
        const struct tomoyo_path_info *saved_pattern;
-       int error = -ENOMEM;
+       int error = is_delete ? -ENOENT : -ENOMEM;
 
-       if (!tomoyo_is_correct_path(pattern, 0, 1, 0, __func__))
-               return -EINVAL;
-       saved_pattern = tomoyo_save_name(pattern);
+       saved_pattern = tomoyo_get_name(pattern);
        if (!saved_pattern)
-               return -ENOMEM;
-       down_write(&tomoyo_pattern_list_lock);
-       list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
+               return error;
+       if (!saved_pattern->is_patterned)
+               goto out;
+       if (!is_delete)
+               entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+       mutex_lock(&tomoyo_policy_lock);
+       list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
                if (saved_pattern != ptr->pattern)
                        continue;
                ptr->is_deleted = is_delete;
                error = 0;
-               goto out;
+               break;
        }
-       if (is_delete) {
-               error = -ENOENT;
-               goto out;
+       if (!is_delete && error && tomoyo_memory_ok(entry)) {
+               entry->pattern = saved_pattern;
+               saved_pattern = NULL;
+               list_add_tail_rcu(&entry->list, &tomoyo_pattern_list);
+               entry = NULL;
+               error = 0;
        }
-       new_entry = tomoyo_alloc_element(sizeof(*new_entry));
-       if (!new_entry)
-               goto out;
-       new_entry->pattern = saved_pattern;
-       list_add_tail(&new_entry->list, &tomoyo_pattern_list);
-       error = 0;
+       mutex_unlock(&tomoyo_policy_lock);
  out:
-       up_write(&tomoyo_pattern_list_lock);
+       kfree(entry);
+       tomoyo_put_name(saved_pattern);
        return error;
 }
 
@@ -390,6 +350,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)
@@ -397,8 +359,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))
@@ -411,7 +372,6 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
                        break;
                }
        }
-       up_read(&tomoyo_pattern_list_lock);
        if (pattern)
                filename = pattern;
        return filename;
@@ -424,6 +384,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)
 {
@@ -436,13 +398,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);
@@ -453,7 +416,6 @@ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head)
                if (!done)
                        break;
        }
-       up_read(&tomoyo_pattern_list_lock);
        return done;
 }
 
@@ -486,8 +448,7 @@ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head)
  * " (deleted)" suffix if the file is already unlink()ed; so that we don't
  * need to worry whether the file is already unlink()ed or not.
  */
-static LIST_HEAD(tomoyo_no_rewrite_list);
-static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock);
+LIST_HEAD(tomoyo_no_rewrite_list);
 
 /**
  * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list.
@@ -496,39 +457,42 @@ 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)
 {
-       struct tomoyo_no_rewrite_entry *new_entry, *ptr;
+       struct tomoyo_no_rewrite_entry *entry = NULL;
+       struct tomoyo_no_rewrite_entry *ptr;
        const struct tomoyo_path_info *saved_pattern;
-       int error = -ENOMEM;
+       int error = is_delete ? -ENOENT : -ENOMEM;
 
-       if (!tomoyo_is_correct_path(pattern, 0, 0, 0, __func__))
+       if (!tomoyo_is_correct_path(pattern, 0, 0, 0))
                return -EINVAL;
-       saved_pattern = tomoyo_save_name(pattern);
+       saved_pattern = tomoyo_get_name(pattern);
        if (!saved_pattern)
-               return -ENOMEM;
-       down_write(&tomoyo_no_rewrite_list_lock);
-       list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
+               return error;
+       if (!is_delete)
+               entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+       mutex_lock(&tomoyo_policy_lock);
+       list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
                if (ptr->pattern != saved_pattern)
                        continue;
                ptr->is_deleted = is_delete;
                error = 0;
-               goto out;
+               break;
        }
-       if (is_delete) {
-               error = -ENOENT;
-               goto out;
+       if (!is_delete && error && tomoyo_memory_ok(entry)) {
+               entry->pattern = saved_pattern;
+               saved_pattern = NULL;
+               list_add_tail_rcu(&entry->list, &tomoyo_no_rewrite_list);
+               entry = NULL;
+               error = 0;
        }
-       new_entry = tomoyo_alloc_element(sizeof(*new_entry));
-       if (!new_entry)
-               goto out;
-       new_entry->pattern = saved_pattern;
-       list_add_tail(&new_entry->list, &tomoyo_no_rewrite_list);
-       error = 0;
- out:
-       up_write(&tomoyo_no_rewrite_list_lock);
+       mutex_unlock(&tomoyo_policy_lock);
+       tomoyo_put_name(saved_pattern);
+       kfree(entry);
        return error;
 }
 
@@ -539,14 +503,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))
@@ -554,7 +519,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;
 }
 
@@ -565,6 +529,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)
 {
@@ -577,13 +543,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);
@@ -594,7 +561,6 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
                if (!done)
                        break;
        }
-       up_read(&tomoyo_no_rewrite_list_lock);
        return done;
 }
 
@@ -612,6 +578,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,
@@ -629,19 +597,19 @@ static int tomoyo_update_file_acl(const char *filename, u8 perm,
                 */
                return 0;
        if (perm & 4)
-               tomoyo_update_single_path_acl(TOMOYO_TYPE_READ_ACL, filename,
-                                             domain, is_delete);
+               tomoyo_update_path_acl(TOMOYO_TYPE_READ, filename, domain,
+                                      is_delete);
        if (perm & 2)
-               tomoyo_update_single_path_acl(TOMOYO_TYPE_WRITE_ACL, filename,
-                                             domain, is_delete);
+               tomoyo_update_path_acl(TOMOYO_TYPE_WRITE, filename, domain,
+                                      is_delete);
        if (perm & 1)
-               tomoyo_update_single_path_acl(TOMOYO_TYPE_EXECUTE_ACL,
-                                             filename, domain, is_delete);
+               tomoyo_update_path_acl(TOMOYO_TYPE_EXECUTE, filename, domain,
+                                      is_delete);
        return 0;
 }
 
 /**
- * tomoyo_check_single_path_acl2 - Check permission for single path operation.
+ * tomoyo_path_acl2 - Check permission for single path operation.
  *
  * @domain:          Pointer to "struct tomoyo_domain_info".
  * @filename:        Filename to check.
@@ -649,26 +617,28 @@ 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,
-                                        const struct tomoyo_path_info *
-                                        filename,
-                                        const u16 perm,
-                                        const bool may_use_pattern)
+static int tomoyo_path_acl2(const struct tomoyo_domain_info *domain,
+                           const struct tomoyo_path_info *filename,
+                           const u32 perm, const bool may_use_pattern)
 {
        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) {
-               struct tomoyo_single_path_acl_record *acl;
-               if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
-                       continue;
-               acl = container_of(ptr, struct tomoyo_single_path_acl_record,
-                                  head);
-               if (!(acl->perm & perm))
+       list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
+               struct tomoyo_path_acl *acl;
+               if (ptr->type != TOMOYO_TYPE_PATH_ACL)
                        continue;
+               acl = container_of(ptr, struct tomoyo_path_acl, head);
+               if (perm <= 0xFFFF) {
+                       if (!(acl->perm & perm))
+                               continue;
+               } else {
+                       if (!(acl->perm_high & (perm >> 16)))
+                               continue;
+               }
                if (may_use_pattern || !acl->filename->is_patterned) {
                        if (!tomoyo_path_matches_pattern(filename,
                                                         acl->filename))
@@ -679,7 +649,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;
 }
 
@@ -691,27 +660,28 @@ 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,
                                 const u8 operation)
 {
-       u16 perm = 0;
+       u32 perm = 0;
 
        if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
                return 0;
        if (operation == 6)
-               perm = 1 << TOMOYO_TYPE_READ_WRITE_ACL;
+               perm = 1 << TOMOYO_TYPE_READ_WRITE;
        else if (operation == 4)
-               perm = 1 << TOMOYO_TYPE_READ_ACL;
+               perm = 1 << TOMOYO_TYPE_READ;
        else if (operation == 2)
-               perm = 1 << TOMOYO_TYPE_WRITE_ACL;
+               perm = 1 << TOMOYO_TYPE_WRITE;
        else if (operation == 1)
-               perm = 1 << TOMOYO_TYPE_EXECUTE_ACL;
+               perm = 1 << TOMOYO_TYPE_EXECUTE;
        else
                BUG();
-       return tomoyo_check_single_path_acl2(domain, filename, perm,
-                                            operation != 1);
+       return tomoyo_path_acl2(domain, filename, perm, operation != 1);
 }
 
 /**
@@ -724,6 +694,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,
@@ -737,18 +709,17 @@ static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain,
        if (!filename)
                return 0;
        error = tomoyo_check_file_acl(domain, filename, perm);
-       if (error && perm == 4 &&
-           (domain->flags & TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) == 0
+       if (error && perm == 4 && !domain->ignore_global_allow_read
            && tomoyo_is_globally_readable_file(filename))
                error = 0;
        if (perm == 6)
-               msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_WRITE_ACL);
+               msg = tomoyo_path2keyword(TOMOYO_TYPE_READ_WRITE);
        else if (perm == 4)
-               msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_ACL);
+               msg = tomoyo_path2keyword(TOMOYO_TYPE_READ);
        else if (perm == 2)
-               msg = tomoyo_sp2keyword(TOMOYO_TYPE_WRITE_ACL);
+               msg = tomoyo_path2keyword(TOMOYO_TYPE_WRITE);
        else if (perm == 1)
-               msg = tomoyo_sp2keyword(TOMOYO_TYPE_EXECUTE_ACL);
+               msg = tomoyo_path2keyword(TOMOYO_TYPE_EXECUTE);
        else
                BUG();
        if (!error)
@@ -777,6 +748,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)
@@ -795,28 +768,28 @@ int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
        if (strncmp(data, "allow_", 6))
                goto out;
        data += 6;
-       for (type = 0; type < TOMOYO_MAX_SINGLE_PATH_OPERATION; type++) {
-               if (strcmp(data, tomoyo_sp_keyword[type]))
+       for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) {
+               if (strcmp(data, tomoyo_path_keyword[type]))
                        continue;
-               return tomoyo_update_single_path_acl(type, filename,
-                                                    domain, is_delete);
+               return tomoyo_update_path_acl(type, filename, domain,
+                                             is_delete);
        }
        filename2 = strchr(filename, ' ');
        if (!filename2)
                goto out;
        *filename2++ = '\0';
-       for (type = 0; type < TOMOYO_MAX_DOUBLE_PATH_OPERATION; type++) {
-               if (strcmp(data, tomoyo_dp_keyword[type]))
+       for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) {
+               if (strcmp(data, tomoyo_path2_keyword[type]))
                        continue;
-               return tomoyo_update_double_path_acl(type, filename, filename2,
-                                                    domain, is_delete);
+               return tomoyo_update_path2_acl(type, filename, filename2,
+                                              domain, is_delete);
        }
  out:
        return -EINVAL;
 }
 
 /**
- * tomoyo_update_single_path_acl - Update "struct tomoyo_single_path_acl_record" list.
+ * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list.
  *
  * @type:      Type of operation.
  * @filename:  Filename.
@@ -824,85 +797,82 @@ 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 *
-                                        const domain, const bool is_delete)
+static int tomoyo_update_path_acl(const u8 type, const char *filename,
+                                 struct tomoyo_domain_info *const domain,
+                                 const bool is_delete)
 {
-       static const u16 rw_mask =
-               (1 << TOMOYO_TYPE_READ_ACL) | (1 << TOMOYO_TYPE_WRITE_ACL);
+       static const u32 rw_mask =
+               (1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE);
        const struct tomoyo_path_info *saved_filename;
        struct tomoyo_acl_info *ptr;
-       struct tomoyo_single_path_acl_record *acl;
-       int error = -ENOMEM;
-       const u16 perm = 1 << type;
+       struct tomoyo_path_acl *entry = NULL;
+       int error = is_delete ? -ENOENT : -ENOMEM;
+       const u32 perm = 1 << type;
 
        if (!domain)
                return -EINVAL;
-       if (!tomoyo_is_correct_path(filename, 0, 0, 0, __func__))
+       if (!tomoyo_is_correct_path(filename, 0, 0, 0))
                return -EINVAL;
-       saved_filename = tomoyo_save_name(filename);
+       saved_filename = tomoyo_get_name(filename);
        if (!saved_filename)
                return -ENOMEM;
-       down_write(&tomoyo_domain_acl_info_list_lock);
-       if (is_delete)
-               goto delete;
-       list_for_each_entry(ptr, &domain->acl_info_list, list) {
-               if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
+       if (!is_delete)
+               entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+       mutex_lock(&tomoyo_policy_lock);
+       list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
+               struct tomoyo_path_acl *acl =
+                       container_of(ptr, struct tomoyo_path_acl, head);
+               if (ptr->type != TOMOYO_TYPE_PATH_ACL)
                        continue;
-               acl = container_of(ptr, struct tomoyo_single_path_acl_record,
-                                  head);
                if (acl->filename != saved_filename)
                        continue;
-               /* Special case. Clear all bits if marked as deleted. */
-               if (ptr->type & TOMOYO_ACL_DELETED)
-                       acl->perm = 0;
-               acl->perm |= perm;
-               if ((acl->perm & rw_mask) == rw_mask)
-                       acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE_ACL;
-               else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL))
-                       acl->perm |= rw_mask;
-               ptr->type &= ~TOMOYO_ACL_DELETED;
+               if (is_delete) {
+                       if (perm <= 0xFFFF)
+                               acl->perm &= ~perm;
+                       else
+                               acl->perm_high &= ~(perm >> 16);
+                       if ((acl->perm & rw_mask) != rw_mask)
+                               acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE);
+                       else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE)))
+                               acl->perm &= ~rw_mask;
+               } else {
+                       if (perm <= 0xFFFF)
+                               acl->perm |= perm;
+                       else
+                               acl->perm_high |= (perm >> 16);
+                       if ((acl->perm & rw_mask) == rw_mask)
+                               acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE;
+                       else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE))
+                               acl->perm |= rw_mask;
+               }
                error = 0;
-               goto out;
+               break;
        }
-       /* Not found. Append it to the tail. */
-       acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_SINGLE_PATH_ACL);
-       if (!acl)
-               goto out;
-       acl->perm = perm;
-       if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL))
-               acl->perm |= rw_mask;
-       acl->filename = saved_filename;
-       list_add_tail(&acl->head.list, &domain->acl_info_list);
-       error = 0;
-       goto out;
- delete:
-       error = -ENOENT;
-       list_for_each_entry(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,
-                                  head);
-               if (acl->filename != saved_filename)
-                       continue;
-               acl->perm &= ~perm;
-               if ((acl->perm & rw_mask) != rw_mask)
-                       acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE_ACL);
-               else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL)))
-                       acl->perm &= ~rw_mask;
-               if (!acl->perm)
-                       ptr->type |= TOMOYO_ACL_DELETED;
+       if (!is_delete && error && tomoyo_memory_ok(entry)) {
+               entry->head.type = TOMOYO_TYPE_PATH_ACL;
+               if (perm <= 0xFFFF)
+                       entry->perm = perm;
+               else
+                       entry->perm_high = (perm >> 16);
+               if (perm == (1 << TOMOYO_TYPE_READ_WRITE))
+                       entry->perm |= rw_mask;
+               entry->filename = saved_filename;
+               saved_filename = NULL;
+               list_add_tail_rcu(&entry->head.list, &domain->acl_info_list);
+               entry = NULL;
                error = 0;
-               break;
        }
- out:
-       up_write(&tomoyo_domain_acl_info_list_lock);
+       mutex_unlock(&tomoyo_policy_lock);
+       kfree(entry);
+       tomoyo_put_name(saved_filename);
        return error;
 }
 
 /**
- * tomoyo_update_double_path_acl - Update "struct tomoyo_double_path_acl_record" list.
+ * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list.
  *
  * @type:      Type of operation.
  * @filename1: First filename.
@@ -911,98 +881,88 @@ 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,
-                                        struct tomoyo_domain_info *
-                                        const domain, const bool is_delete)
+static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
+                                  const char *filename2,
+                                  struct tomoyo_domain_info *const domain,
+                                  const bool is_delete)
 {
        const struct tomoyo_path_info *saved_filename1;
        const struct tomoyo_path_info *saved_filename2;
        struct tomoyo_acl_info *ptr;
-       struct tomoyo_double_path_acl_record *acl;
-       int error = -ENOMEM;
+       struct tomoyo_path2_acl *entry = NULL;
+       int error = is_delete ? -ENOENT : -ENOMEM;
        const u8 perm = 1 << type;
 
        if (!domain)
                return -EINVAL;
-       if (!tomoyo_is_correct_path(filename1, 0, 0, 0, __func__) ||
-           !tomoyo_is_correct_path(filename2, 0, 0, 0, __func__))
+       if (!tomoyo_is_correct_path(filename1, 0, 0, 0) ||
+           !tomoyo_is_correct_path(filename2, 0, 0, 0))
                return -EINVAL;
-       saved_filename1 = tomoyo_save_name(filename1);
-       saved_filename2 = tomoyo_save_name(filename2);
+       saved_filename1 = tomoyo_get_name(filename1);
+       saved_filename2 = tomoyo_get_name(filename2);
        if (!saved_filename1 || !saved_filename2)
-               return -ENOMEM;
-       down_write(&tomoyo_domain_acl_info_list_lock);
-       if (is_delete)
-               goto delete;
-       list_for_each_entry(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,
-                                  head);
-               if (acl->filename1 != saved_filename1 ||
-                   acl->filename2 != saved_filename2)
-                       continue;
-               /* Special case. Clear all bits if marked as deleted. */
-               if (ptr->type & TOMOYO_ACL_DELETED)
-                       acl->perm = 0;
-               acl->perm |= perm;
-               ptr->type &= ~TOMOYO_ACL_DELETED;
-               error = 0;
                goto out;
-       }
-       /* Not found. Append it to the tail. */
-       acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_DOUBLE_PATH_ACL);
-       if (!acl)
-               goto out;
-       acl->perm = perm;
-       acl->filename1 = saved_filename1;
-       acl->filename2 = saved_filename2;
-       list_add_tail(&acl->head.list, &domain->acl_info_list);
-       error = 0;
-       goto out;
- delete:
-       error = -ENOENT;
-       list_for_each_entry(ptr, &domain->acl_info_list, list) {
-               if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
+       if (!is_delete)
+               entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+       mutex_lock(&tomoyo_policy_lock);
+       list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
+               struct tomoyo_path2_acl *acl =
+                       container_of(ptr, struct tomoyo_path2_acl, head);
+               if (ptr->type != TOMOYO_TYPE_PATH2_ACL)
                        continue;
-               acl = container_of(ptr, struct tomoyo_double_path_acl_record,
-                                  head);
                if (acl->filename1 != saved_filename1 ||
                    acl->filename2 != saved_filename2)
                        continue;
-               acl->perm &= ~perm;
-               if (!acl->perm)
-                       ptr->type |= TOMOYO_ACL_DELETED;
+               if (is_delete)
+                       acl->perm &= ~perm;
+               else
+                       acl->perm |= perm;
                error = 0;
                break;
        }
+       if (!is_delete && error && tomoyo_memory_ok(entry)) {
+               entry->head.type = TOMOYO_TYPE_PATH2_ACL;
+               entry->perm = perm;
+               entry->filename1 = saved_filename1;
+               saved_filename1 = NULL;
+               entry->filename2 = saved_filename2;
+               saved_filename2 = NULL;
+               list_add_tail_rcu(&entry->head.list, &domain->acl_info_list);
+               entry = NULL;
+               error = 0;
+       }
+       mutex_unlock(&tomoyo_policy_lock);
  out:
-       up_write(&tomoyo_domain_acl_info_list_lock);
+       tomoyo_put_name(saved_filename1);
+       tomoyo_put_name(saved_filename2);
+       kfree(entry);
        return error;
 }
 
 /**
- * tomoyo_check_single_path_acl - Check permission for single path operation.
+ * tomoyo_path_acl - Check permission for single path operation.
  *
  * @domain:   Pointer to "struct tomoyo_domain_info".
  * @type:     Type of operation.
  * @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,
-                                       const struct tomoyo_path_info *filename)
+static int tomoyo_path_acl(struct tomoyo_domain_info *domain, const u8 type,
+                          const struct tomoyo_path_info *filename)
 {
        if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
                return 0;
-       return tomoyo_check_single_path_acl2(domain, filename, 1 << type, 1);
+       return tomoyo_path_acl2(domain, filename, 1 << type, 1);
 }
 
 /**
- * tomoyo_check_double_path_acl - Check permission for double path operation.
+ * tomoyo_path2_acl - Check permission for double path operation.
  *
  * @domain:    Pointer to "struct tomoyo_domain_info".
  * @type:      Type of operation.
@@ -1010,13 +970,13 @@ 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,
-                                       const struct tomoyo_path_info *
-                                       filename1,
-                                       const struct tomoyo_path_info *
-                                       filename2)
+static int tomoyo_path2_acl(const struct tomoyo_domain_info *domain,
+                           const u8 type,
+                           const struct tomoyo_path_info *filename1,
+                           const struct tomoyo_path_info *filename2)
 {
        struct tomoyo_acl_info *ptr;
        const u8 perm = 1 << type;
@@ -1024,13 +984,11 @@ 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) {
-               struct tomoyo_double_path_acl_record *acl;
-               if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
+       list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
+               struct tomoyo_path2_acl *acl;
+               if (ptr->type != TOMOYO_TYPE_PATH2_ACL)
                        continue;
-               acl = container_of(ptr, struct tomoyo_double_path_acl_record,
-                                  head);
+               acl = container_of(ptr, struct tomoyo_path2_acl, head);
                if (!(acl->perm & perm))
                        continue;
                if (!tomoyo_path_matches_pattern(filename1, acl->filename1))
@@ -1040,12 +998,11 @@ 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;
 }
 
 /**
- * tomoyo_check_single_path_permission2 - Check permission for single path operation.
+ * tomoyo_path_permission2 - Check permission for single path operation.
  *
  * @domain:    Pointer to "struct tomoyo_domain_info".
  * @operation: Type of operation.
@@ -1053,11 +1010,13 @@ 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,
-                                               const struct tomoyo_path_info *
-                                               filename, const u8 mode)
+static int tomoyo_path_permission2(struct tomoyo_domain_info *const domain,
+                                  u8 operation,
+                                  const struct tomoyo_path_info *filename,
+                                  const u8 mode)
 {
        const char *msg;
        int error;
@@ -1066,8 +1025,8 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info *
        if (!mode)
                return 0;
  next:
-       error = tomoyo_check_single_path_acl(domain, operation, filename);
-       msg = tomoyo_sp2keyword(operation);
+       error = tomoyo_path_acl(domain, operation, filename);
+       msg = tomoyo_path2keyword(operation);
        if (!error)
                goto ok;
        if (tomoyo_verbose_mode(domain))
@@ -1076,7 +1035,7 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info *
                       tomoyo_get_last_name(domain));
        if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
                const char *name = tomoyo_get_file_pattern(filename)->name;
-               tomoyo_update_single_path_acl(operation, name, domain, false);
+               tomoyo_update_path_acl(operation, name, domain, false);
        }
        if (!is_enforce)
                error = 0;
@@ -1086,9 +1045,9 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info *
         * we need to check "allow_rewrite" permission if the filename is
         * specified by "deny_rewrite" keyword.
         */
-       if (!error && operation == TOMOYO_TYPE_TRUNCATE_ACL &&
+       if (!error && operation == TOMOYO_TYPE_TRUNCATE &&
            tomoyo_is_no_rewrite_file(filename)) {
-               operation = TOMOYO_TYPE_REWRITE_ACL;
+               operation = TOMOYO_TYPE_REWRITE;
                goto next;
        }
        return error;
@@ -1101,6 +1060,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)
@@ -1129,6 +1090,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;
@@ -1140,6 +1102,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;
@@ -1152,49 +1115,50 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
        if ((acc_mode & MAY_WRITE) &&
            ((flag & O_TRUNC) || !(flag & O_APPEND)) &&
            (tomoyo_is_no_rewrite_file(buf))) {
-               error = tomoyo_check_single_path_permission2(domain,
-                                                    TOMOYO_TYPE_REWRITE_ACL,
-                                                            buf, mode);
+               error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE,
+                                               buf, mode);
        }
        if (!error)
                error = tomoyo_check_file_perm2(domain, buf, acc_mode, "open",
                                                mode);
        if (!error && (flag & O_TRUNC))
-               error = tomoyo_check_single_path_permission2(domain,
-                                                    TOMOYO_TYPE_TRUNCATE_ACL,
-                                                            buf, mode);
+               error = tomoyo_path_permission2(domain, TOMOYO_TYPE_TRUNCATE,
+                                               buf, mode);
  out:
-       tomoyo_free(buf);
+       kfree(buf);
+       tomoyo_read_unlock(idx);
        if (!is_enforce)
                error = 0;
        return error;
 }
 
 /**
- * tomoyo_check_1path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate" and "symlink".
+ * tomoyo_path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate", "symlink", "ioctl", "chmod", "chown", "chgrp", "chroot", "mount" and "unmount".
  *
- * @domain:    Pointer to "struct tomoyo_domain_info".
  * @operation: Type of operation.
  * @path:      Pointer to "struct path".
  *
  * Returns 0 on success, negative value otherwise.
  */
-int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain,
-                           const u8 operation, struct path *path)
+int tomoyo_path_perm(const u8 operation, struct path *path)
 {
        int error = -ENOMEM;
        struct tomoyo_path_info *buf;
+       struct tomoyo_domain_info *domain = tomoyo_domain();
        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;
        switch (operation) {
-       case TOMOYO_TYPE_MKDIR_ACL:
-       case TOMOYO_TYPE_RMDIR_ACL:
+       case TOMOYO_TYPE_MKDIR:
+       case TOMOYO_TYPE_RMDIR:
+       case TOMOYO_TYPE_CHROOT:
                if (!buf->is_dir) {
                        /*
                         * tomoyo_get_path() reserves space for appending "/."
@@ -1203,10 +1167,10 @@ int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain,
                        tomoyo_fill_path_info(buf);
                }
        }
-       error = tomoyo_check_single_path_permission2(domain, operation, buf,
-                                                    mode);
+       error = tomoyo_path_permission2(domain, operation, buf, mode);
  out:
-       tomoyo_free(buf);
+       kfree(buf);
+       tomoyo_read_unlock(idx);
        if (!is_enforce)
                error = 0;
        return error;
@@ -1215,21 +1179,23 @@ int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain,
 /**
  * tomoyo_check_rewrite_permission - Check permission for "rewrite".
  *
- * @domain: Pointer to "struct tomoyo_domain_info".
  * @filp: Pointer to "struct file".
  *
  * Returns 0 on success, negative value otherwise.
  */
-int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain,
-                                   struct file *filp)
+int tomoyo_check_rewrite_permission(struct file *filp)
 {
        int error = -ENOMEM;
+       struct tomoyo_domain_info *domain = tomoyo_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;
@@ -1237,38 +1203,38 @@ int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain,
                error = 0;
                goto out;
        }
-       error = tomoyo_check_single_path_permission2(domain,
-                                                    TOMOYO_TYPE_REWRITE_ACL,
-                                                    buf, mode);
+       error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE, buf, mode);
  out:
-       tomoyo_free(buf);
+       kfree(buf);
+       tomoyo_read_unlock(idx);
        if (!is_enforce)
                error = 0;
        return error;
 }
 
 /**
- * tomoyo_check_2path_perm - Check permission for "rename" and "link".
+ * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root".
  *
- * @domain:    Pointer to "struct tomoyo_domain_info".
  * @operation: Type of operation.
  * @path1:      Pointer to "struct path".
  * @path2:      Pointer to "struct path".
  *
  * Returns 0 on success, negative value otherwise.
  */
-int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain,
-                           const u8 operation, struct path *path1,
-                           struct path *path2)
+int tomoyo_path2_perm(const u8 operation, struct path *path1,
+                     struct path *path2)
 {
        int error = -ENOMEM;
        struct tomoyo_path_info *buf1, *buf2;
+       struct tomoyo_domain_info *domain = tomoyo_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)
@@ -1289,8 +1255,8 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain,
                        }
                }
        }
-       error = tomoyo_check_double_path_acl(domain, operation, buf1, buf2);
-       msg = tomoyo_dp2keyword(operation);
+       error = tomoyo_path2_acl(domain, operation, buf1, buf2);
+       msg = tomoyo_path22keyword(operation);
        if (!error)
                goto out;
        if (tomoyo_verbose_mode(domain))
@@ -1301,12 +1267,13 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain,
        if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
                const char *name1 = tomoyo_get_file_pattern(buf1)->name;
                const char *name2 = tomoyo_get_file_pattern(buf2)->name;
-               tomoyo_update_double_path_acl(operation, name1, name2, domain,
-                                             false);
+               tomoyo_update_path2_acl(operation, name1, name2, domain,
+                                       false);
        }
  out:
-       tomoyo_free(buf1);
-       tomoyo_free(buf2);
+       kfree(buf1);
+       kfree(buf2);
+       tomoyo_read_unlock(idx);
        if (!is_enforce)
                error = 0;
        return error;