TOMOYO: Add garbage collector.
Tetsuo Handa [Thu, 11 Feb 2010 00:43:54 +0000 (09:43 +0900)]
This patch adds garbage collector support to TOMOYO.
Elements are protected by "struct srcu_struct tomoyo_ss".

Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Acked-by: Serge Hallyn <serue@us.ibm.com>
Signed-off-by: James Morris <jmorris@namei.org>

security/tomoyo/Makefile
security/tomoyo/common.c
security/tomoyo/common.h
security/tomoyo/domain.c
security/tomoyo/file.c
security/tomoyo/gc.c [new file with mode: 0644]
security/tomoyo/realpath.c

index 10ccd68..60a9e20 100644 (file)
@@ -1 +1 @@
-obj-y = common.o realpath.o tomoyo.o domain.o file.o
+obj-y = common.o realpath.o tomoyo.o domain.o file.o gc.o
index 634f744..3a36b56 100644 (file)
@@ -1067,7 +1067,7 @@ static int tomoyo_read_profile(struct tomoyo_io_buffer *head)
  *
  * # cat /sys/kernel/security/tomoyo/manager
  */
-static LIST_HEAD(tomoyo_policy_manager_list);
+LIST_HEAD(tomoyo_policy_manager_list);
 
 /**
  * tomoyo_update_manager_entry - Add a manager entry.
@@ -2109,6 +2109,7 @@ static int tomoyo_write_control(struct file *file, const char __user *buffer,
 static int tomoyo_close_control(struct file *file)
 {
        struct tomoyo_io_buffer *head = file->private_data;
+       const bool is_write = !!head->write_buf;
 
        tomoyo_read_unlock(head->reader_idx);
        /* Release memory used for policy I/O. */
@@ -2119,6 +2120,8 @@ static int tomoyo_close_control(struct file *file)
        kfree(head);
        head = NULL;
        file->private_data = NULL;
+       if (is_write)
+               tomoyo_run_gc();
        return 0;
 }
 
index 521b4b5..1c8c97a 100644 (file)
@@ -638,6 +638,11 @@ int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain,
                                    struct file *filp);
 int tomoyo_find_next_domain(struct linux_binprm *bprm);
 
+/* Run garbage collector. */
+void tomoyo_run_gc(void);
+
+void tomoyo_memory_free(void *ptr);
+
 /********** External variable definitions. **********/
 
 /* Lock for GC. */
@@ -646,6 +651,16 @@ extern struct srcu_struct tomoyo_ss;
 /* The list for "struct tomoyo_domain_info". */
 extern struct list_head tomoyo_domain_list;
 
+extern struct list_head tomoyo_domain_initializer_list;
+extern struct list_head tomoyo_domain_keeper_list;
+extern struct list_head tomoyo_alias_list;
+extern struct list_head tomoyo_globally_readable_list;
+extern struct list_head tomoyo_pattern_list;
+extern struct list_head tomoyo_no_rewrite_list;
+extern struct list_head tomoyo_policy_manager_list;
+extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
+extern struct mutex tomoyo_name_list_lock;
+
 /* Lock for protecting policy. */
 extern struct mutex tomoyo_policy_lock;
 
index 6f74b30..74cd0f5 100644 (file)
@@ -110,7 +110,7 @@ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain)
  * will cause "/usr/sbin/httpd" to belong to "<kernel> /usr/sbin/httpd" domain
  * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain.
  */
-static LIST_HEAD(tomoyo_domain_initializer_list);
+LIST_HEAD(tomoyo_domain_initializer_list);
 
 /**
  * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list.
@@ -330,7 +330,7 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info *
  * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless
  * explicitly specified by "initialize_domain".
  */
-static LIST_HEAD(tomoyo_domain_keeper_list);
+LIST_HEAD(tomoyo_domain_keeper_list);
 
 /**
  * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list.
@@ -533,7 +533,7 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
  * /bin/busybox and domainname which the current process will belong to after
  * execve() succeeds is calculated using /bin/cat rather than /bin/busybox .
  */
-static LIST_HEAD(tomoyo_alias_list);
+LIST_HEAD(tomoyo_alias_list);
 
 /**
  * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list.
index c69dd39..10ee7ce 100644 (file)
@@ -148,7 +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);
+LIST_HEAD(tomoyo_globally_readable_list);
 
 /**
  * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list.
@@ -295,7 +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);
+LIST_HEAD(tomoyo_pattern_list);
 
 /**
  * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list.
@@ -448,7 +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);
+LIST_HEAD(tomoyo_no_rewrite_list);
 
 /**
  * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list.
diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c
new file mode 100644 (file)
index 0000000..ee15da3
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ * security/tomoyo/gc.c
+ *
+ * Implementation of the Domain-Based Mandatory Access Control.
+ *
+ * Copyright (C) 2005-2010  NTT DATA CORPORATION
+ *
+ */
+
+#include "common.h"
+#include <linux/kthread.h>
+
+enum tomoyo_gc_id {
+       TOMOYO_ID_DOMAIN_INITIALIZER,
+       TOMOYO_ID_DOMAIN_KEEPER,
+       TOMOYO_ID_ALIAS,
+       TOMOYO_ID_GLOBALLY_READABLE,
+       TOMOYO_ID_PATTERN,
+       TOMOYO_ID_NO_REWRITE,
+       TOMOYO_ID_MANAGER,
+       TOMOYO_ID_NAME,
+       TOMOYO_ID_ACL,
+       TOMOYO_ID_DOMAIN
+};
+
+struct tomoyo_gc_entry {
+       struct list_head list;
+       int type;
+       void *element;
+};
+static LIST_HEAD(tomoyo_gc_queue);
+static DEFINE_MUTEX(tomoyo_gc_mutex);
+
+/* Caller holds tomoyo_policy_lock mutex. */
+static bool tomoyo_add_to_gc(const int type, void *element)
+{
+       struct tomoyo_gc_entry *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+       if (!entry)
+               return false;
+       entry->type = type;
+       entry->element = element;
+       list_add(&entry->list, &tomoyo_gc_queue);
+       return true;
+}
+
+static void tomoyo_del_allow_read
+(struct tomoyo_globally_readable_file_entry *ptr)
+{
+       tomoyo_put_name(ptr->filename);
+}
+
+static void tomoyo_del_file_pattern(struct tomoyo_pattern_entry *ptr)
+{
+       tomoyo_put_name(ptr->pattern);
+}
+
+static void tomoyo_del_no_rewrite(struct tomoyo_no_rewrite_entry *ptr)
+{
+       tomoyo_put_name(ptr->pattern);
+}
+
+static void tomoyo_del_domain_initializer
+(struct tomoyo_domain_initializer_entry *ptr)
+{
+       tomoyo_put_name(ptr->domainname);
+       tomoyo_put_name(ptr->program);
+}
+
+static void tomoyo_del_domain_keeper(struct tomoyo_domain_keeper_entry *ptr)
+{
+       tomoyo_put_name(ptr->domainname);
+       tomoyo_put_name(ptr->program);
+}
+
+static void tomoyo_del_alias(struct tomoyo_alias_entry *ptr)
+{
+       tomoyo_put_name(ptr->original_name);
+       tomoyo_put_name(ptr->aliased_name);
+}
+
+static void tomoyo_del_manager(struct tomoyo_policy_manager_entry *ptr)
+{
+       tomoyo_put_name(ptr->manager);
+}
+
+static void tomoyo_del_acl(struct tomoyo_acl_info *acl)
+{
+       switch (acl->type) {
+       case TOMOYO_TYPE_SINGLE_PATH_ACL:
+               {
+                       struct tomoyo_single_path_acl_record *entry
+                               = container_of(acl, typeof(*entry), head);
+                       tomoyo_put_name(entry->filename);
+               }
+               break;
+       case TOMOYO_TYPE_DOUBLE_PATH_ACL:
+               {
+                       struct tomoyo_double_path_acl_record *entry
+                               = container_of(acl, typeof(*entry), head);
+                       tomoyo_put_name(entry->filename1);
+                       tomoyo_put_name(entry->filename2);
+               }
+               break;
+       default:
+               printk(KERN_WARNING "Unknown type\n");
+               break;
+       }
+}
+
+static bool tomoyo_del_domain(struct tomoyo_domain_info *domain)
+{
+       struct tomoyo_acl_info *acl;
+       struct tomoyo_acl_info *tmp;
+       /*
+        * Since we don't protect whole execve() operation using SRCU,
+        * we need to recheck domain->users at this point.
+        *
+        * (1) Reader starts SRCU section upon execve().
+        * (2) Reader traverses tomoyo_domain_list and finds this domain.
+        * (3) Writer marks this domain as deleted.
+        * (4) Garbage collector removes this domain from tomoyo_domain_list
+        *     because this domain is marked as deleted and used by nobody.
+        * (5) Reader saves reference to this domain into
+        *     "struct linux_binprm"->cred->security .
+        * (6) Reader finishes SRCU section, although execve() operation has
+        *     not finished yet.
+        * (7) Garbage collector waits for SRCU synchronization.
+        * (8) Garbage collector kfree() this domain because this domain is
+        *     used by nobody.
+        * (9) Reader finishes execve() operation and restores this domain from
+        *     "struct linux_binprm"->cred->security.
+        *
+        * By updating domain->users at (5), we can solve this race problem
+        * by rechecking domain->users at (8).
+        */
+       if (atomic_read(&domain->users))
+               return false;
+       list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) {
+               tomoyo_del_acl(acl);
+               tomoyo_memory_free(acl);
+       }
+       tomoyo_put_name(domain->domainname);
+       return true;
+}
+
+
+static void tomoyo_del_name(const struct tomoyo_name_entry *ptr)
+{
+}
+
+static void tomoyo_collect_entry(void)
+{
+       mutex_lock(&tomoyo_policy_lock);
+       {
+               struct tomoyo_globally_readable_file_entry *ptr;
+               list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list,
+                                       list) {
+                       if (!ptr->is_deleted)
+                               continue;
+                       if (tomoyo_add_to_gc(TOMOYO_ID_GLOBALLY_READABLE, ptr))
+                               list_del_rcu(&ptr->list);
+                       else
+                               break;
+               }
+       }
+       {
+               struct tomoyo_pattern_entry *ptr;
+               list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
+                       if (!ptr->is_deleted)
+                               continue;
+                       if (tomoyo_add_to_gc(TOMOYO_ID_PATTERN, ptr))
+                               list_del_rcu(&ptr->list);
+                       else
+                               break;
+               }
+       }
+       {
+               struct tomoyo_no_rewrite_entry *ptr;
+               list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
+                       if (!ptr->is_deleted)
+                               continue;
+                       if (tomoyo_add_to_gc(TOMOYO_ID_NO_REWRITE, ptr))
+                               list_del_rcu(&ptr->list);
+                       else
+                               break;
+               }
+       }
+       {
+               struct tomoyo_domain_initializer_entry *ptr;
+               list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list,
+                                       list) {
+                       if (!ptr->is_deleted)
+                               continue;
+                       if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_INITIALIZER, ptr))
+                               list_del_rcu(&ptr->list);
+                       else
+                               break;
+               }
+       }
+       {
+               struct tomoyo_domain_keeper_entry *ptr;
+               list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
+                       if (!ptr->is_deleted)
+                               continue;
+                       if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_KEEPER, ptr))
+                               list_del_rcu(&ptr->list);
+                       else
+                               break;
+               }
+       }
+       {
+               struct tomoyo_alias_entry *ptr;
+               list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
+                       if (!ptr->is_deleted)
+                               continue;
+                       if (tomoyo_add_to_gc(TOMOYO_ID_ALIAS, ptr))
+                               list_del_rcu(&ptr->list);
+                       else
+                               break;
+               }
+       }
+       {
+               struct tomoyo_policy_manager_entry *ptr;
+               list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list,
+                                       list) {
+                       if (!ptr->is_deleted)
+                               continue;
+                       if (tomoyo_add_to_gc(TOMOYO_ID_MANAGER, ptr))
+                               list_del_rcu(&ptr->list);
+                       else
+                               break;
+               }
+       }
+       {
+               struct tomoyo_domain_info *domain;
+               list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
+                       struct tomoyo_acl_info *acl;
+                       list_for_each_entry_rcu(acl, &domain->acl_info_list,
+                                               list) {
+                               switch (acl->type) {
+                               case TOMOYO_TYPE_SINGLE_PATH_ACL:
+                                       if (container_of(acl,
+                                        struct tomoyo_single_path_acl_record,
+                                                        head)->perm ||
+                                           container_of(acl,
+                                        struct tomoyo_single_path_acl_record,
+                                                        head)->perm_high)
+                                               continue;
+                                       break;
+                               case TOMOYO_TYPE_DOUBLE_PATH_ACL:
+                                       if (container_of(acl,
+                                        struct tomoyo_double_path_acl_record,
+                                                        head)->perm)
+                                               continue;
+                                       break;
+                               default:
+                                       continue;
+                               }
+                               if (tomoyo_add_to_gc(TOMOYO_ID_ACL, acl))
+                                       list_del_rcu(&acl->list);
+                               else
+                                       break;
+                       }
+                       if (!domain->is_deleted || atomic_read(&domain->users))
+                               continue;
+                       /*
+                        * Nobody is referring this domain. But somebody may
+                        * refer this domain after successful execve().
+                        * We recheck domain->users after SRCU synchronization.
+                        */
+                       if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, domain))
+                               list_del_rcu(&domain->list);
+                       else
+                               break;
+               }
+       }
+       mutex_unlock(&tomoyo_policy_lock);
+       mutex_lock(&tomoyo_name_list_lock);
+       {
+               int i;
+               for (i = 0; i < TOMOYO_MAX_HASH; i++) {
+                       struct tomoyo_name_entry *ptr;
+                       list_for_each_entry_rcu(ptr, &tomoyo_name_list[i],
+                                               list) {
+                               if (atomic_read(&ptr->users))
+                                       continue;
+                               if (tomoyo_add_to_gc(TOMOYO_ID_NAME, ptr))
+                                       list_del_rcu(&ptr->list);
+                               else {
+                                       i = TOMOYO_MAX_HASH;
+                                       break;
+                               }
+                       }
+               }
+       }
+       mutex_unlock(&tomoyo_name_list_lock);
+}
+
+static void tomoyo_kfree_entry(void)
+{
+       struct tomoyo_gc_entry *p;
+       struct tomoyo_gc_entry *tmp;
+
+       list_for_each_entry_safe(p, tmp, &tomoyo_gc_queue, list) {
+               switch (p->type) {
+               case TOMOYO_ID_DOMAIN_INITIALIZER:
+                       tomoyo_del_domain_initializer(p->element);
+                       break;
+               case TOMOYO_ID_DOMAIN_KEEPER:
+                       tomoyo_del_domain_keeper(p->element);
+                       break;
+               case TOMOYO_ID_ALIAS:
+                       tomoyo_del_alias(p->element);
+                       break;
+               case TOMOYO_ID_GLOBALLY_READABLE:
+                       tomoyo_del_allow_read(p->element);
+                       break;
+               case TOMOYO_ID_PATTERN:
+                       tomoyo_del_file_pattern(p->element);
+                       break;
+               case TOMOYO_ID_NO_REWRITE:
+                       tomoyo_del_no_rewrite(p->element);
+                       break;
+               case TOMOYO_ID_MANAGER:
+                       tomoyo_del_manager(p->element);
+                       break;
+               case TOMOYO_ID_NAME:
+                       tomoyo_del_name(p->element);
+                       break;
+               case TOMOYO_ID_ACL:
+                       tomoyo_del_acl(p->element);
+                       break;
+               case TOMOYO_ID_DOMAIN:
+                       if (!tomoyo_del_domain(p->element))
+                               continue;
+                       break;
+               default:
+                       printk(KERN_WARNING "Unknown type\n");
+                       break;
+               }
+               tomoyo_memory_free(p->element);
+               list_del(&p->list);
+               kfree(p);
+       }
+}
+
+static int tomoyo_gc_thread(void *unused)
+{
+       daemonize("GC for TOMOYO");
+       if (mutex_trylock(&tomoyo_gc_mutex)) {
+               int i;
+               for (i = 0; i < 10; i++) {
+                       tomoyo_collect_entry();
+                       if (list_empty(&tomoyo_gc_queue))
+                               break;
+                       synchronize_srcu(&tomoyo_ss);
+                       tomoyo_kfree_entry();
+               }
+               mutex_unlock(&tomoyo_gc_mutex);
+       }
+       do_exit(0);
+}
+
+void tomoyo_run_gc(void)
+{
+       struct task_struct *task = kthread_create(tomoyo_gc_thread, NULL,
+                                                 "GC for TOMOYO");
+       if (!IS_ERR(task))
+               wake_up_process(task);
+}
index 9557168..c00df45 100644 (file)
@@ -205,9 +205,9 @@ char *tomoyo_realpath_nofollow(const char *pathname)
 }
 
 /* Memory allocated for non-string data. */
-static unsigned int tomoyo_allocated_memory_for_elements;
-/* Quota for holding non-string data. */
-static unsigned int tomoyo_quota_for_elements;
+static atomic_t tomoyo_policy_memory_size;
+/* Quota for holding policy. */
+static unsigned int tomoyo_quota_for_policy;
 
 /**
  * tomoyo_memory_ok - Check memory quota.
@@ -222,26 +222,30 @@ static unsigned int tomoyo_quota_for_elements;
 bool tomoyo_memory_ok(void *ptr)
 {
        int allocated_len = ptr ? ksize(ptr) : 0;
-       bool result = false;
-       if (!ptr || (tomoyo_quota_for_elements &&
-                    tomoyo_allocated_memory_for_elements
-                    + allocated_len > tomoyo_quota_for_elements)) {
-               printk(KERN_WARNING "ERROR: Out of memory "
-                      "for tomoyo_alloc_element().\n");
-               if (!tomoyo_policy_loaded)
-                       panic("MAC Initialization failed.\n");
-       } else {
-               result = true;
-               tomoyo_allocated_memory_for_elements += allocated_len;
+       atomic_add(allocated_len, &tomoyo_policy_memory_size);
+       if (ptr && (!tomoyo_quota_for_policy ||
+                   atomic_read(&tomoyo_policy_memory_size)
+                   <= tomoyo_quota_for_policy)) {
                memset(ptr, 0, allocated_len);
+               return true;
        }
-       return result;
+       printk(KERN_WARNING "ERROR: Out of memory "
+              "for tomoyo_alloc_element().\n");
+       if (!tomoyo_policy_loaded)
+               panic("MAC Initialization failed.\n");
+       return false;
 }
 
-/* Memory allocated for string data in bytes. */
-static unsigned int tomoyo_allocated_memory_for_savename;
-/* Quota for holding string data in bytes. */
-static unsigned int tomoyo_quota_for_savename;
+/**
+ * tomoyo_memory_free - Free memory for elements.
+ *
+ * @ptr:  Pointer to allocated memory.
+ */
+void tomoyo_memory_free(void *ptr)
+{
+       atomic_sub(ksize(ptr), &tomoyo_policy_memory_size);
+       kfree(ptr);
+}
 
 /*
  * tomoyo_name_list is used for holding string data used by TOMOYO.
@@ -249,7 +253,9 @@ static unsigned int tomoyo_quota_for_savename;
  * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of
  * "const struct tomoyo_path_info *".
  */
-static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
+struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
+/* Lock for protecting tomoyo_name_list . */
+DEFINE_MUTEX(tomoyo_name_list_lock);
 
 /**
  * tomoyo_get_name - Allocate permanent memory for string data.
@@ -260,7 +266,6 @@ static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
  */
 const struct tomoyo_path_info *tomoyo_get_name(const char *name)
 {
-       static DEFINE_MUTEX(lock);
        struct tomoyo_name_entry *ptr;
        unsigned int hash;
        int len;
@@ -272,7 +277,7 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name)
        len = strlen(name) + 1;
        hash = full_name_hash((const unsigned char *) name, len - 1);
        head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)];
-       mutex_lock(&lock);
+       mutex_lock(&tomoyo_name_list_lock);
        list_for_each_entry(ptr, head, list) {
                if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
                        continue;
@@ -281,9 +286,9 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name)
        }
        ptr = kzalloc(sizeof(*ptr) + len, GFP_KERNEL);
        allocated_len = ptr ? ksize(ptr) : 0;
-       if (!ptr || (tomoyo_quota_for_savename &&
-                    tomoyo_allocated_memory_for_savename + allocated_len
-                    > tomoyo_quota_for_savename)) {
+       if (!ptr || (tomoyo_quota_for_policy &&
+                    atomic_read(&tomoyo_policy_memory_size) + allocated_len
+                    > tomoyo_quota_for_policy)) {
                kfree(ptr);
                printk(KERN_WARNING "ERROR: Out of memory "
                       "for tomoyo_get_name().\n");
@@ -292,14 +297,14 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name)
                ptr = NULL;
                goto out;
        }
-       tomoyo_allocated_memory_for_savename += allocated_len;
+       atomic_add(allocated_len, &tomoyo_policy_memory_size);
        ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
        memmove((char *) ptr->entry.name, name, len);
        atomic_set(&ptr->users, 1);
        tomoyo_fill_path_info(&ptr->entry);
        list_add_tail(&ptr->list, head);
  out:
-       mutex_unlock(&lock);
+       mutex_unlock(&tomoyo_name_list_lock);
        return ptr ? &ptr->entry : NULL;
 }
 
@@ -334,28 +339,19 @@ void __init tomoyo_realpath_init(void)
 int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head)
 {
        if (!head->read_eof) {
-               const unsigned int shared
-                       = tomoyo_allocated_memory_for_savename;
-               const unsigned int private
-                       = tomoyo_allocated_memory_for_elements;
+               const unsigned int policy
+                       = atomic_read(&tomoyo_policy_memory_size);
                char buffer[64];
 
                memset(buffer, 0, sizeof(buffer));
-               if (tomoyo_quota_for_savename)
-                       snprintf(buffer, sizeof(buffer) - 1,
-                                "   (Quota: %10u)",
-                                tomoyo_quota_for_savename);
-               else
-                       buffer[0] = '\0';
-               tomoyo_io_printf(head, "Shared:  %10u%s\n", shared, buffer);
-               if (tomoyo_quota_for_elements)
+               if (tomoyo_quota_for_policy)
                        snprintf(buffer, sizeof(buffer) - 1,
                                 "   (Quota: %10u)",
-                                tomoyo_quota_for_elements);
+                                tomoyo_quota_for_policy);
                else
                        buffer[0] = '\0';
-               tomoyo_io_printf(head, "Private: %10u%s\n", private, buffer);
-               tomoyo_io_printf(head, "Total:   %10u\n", shared + private);
+               tomoyo_io_printf(head, "Policy:  %10u%s\n", policy, buffer);
+               tomoyo_io_printf(head, "Total:   %10u\n", policy);
                head->read_eof = true;
        }
        return 0;
@@ -373,9 +369,7 @@ int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head)
        char *data = head->write_buf;
        unsigned int size;
 
-       if (sscanf(data, "Shared: %u", &size) == 1)
-               tomoyo_quota_for_savename = size;
-       else if (sscanf(data, "Private: %u", &size) == 1)
-               tomoyo_quota_for_elements = size;
+       if (sscanf(data, "Policy: %u", &size) == 1)
+               tomoyo_quota_for_policy = size;
        return 0;
 }