TOMOYO: Add refcounter on string data.
Tetsuo Handa [Thu, 11 Feb 2010 00:41:58 +0000 (09:41 +0900)]
Add refcounter to "struct tomoyo_name_entry" and replace tomoyo_save_name()
with tomoyo_get_name()/tomoyo_put_name() pair so that we can kfree() when
garbage collector is added.

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/common.c
security/tomoyo/domain.c
security/tomoyo/file.c
security/tomoyo/realpath.c
security/tomoyo/realpath.h

index a53ee05..0c7ea51 100644 (file)
@@ -12,8 +12,8 @@
 #include <linux/uaccess.h>
 #include <linux/security.h>
 #include <linux/hardirq.h>
-#include "realpath.h"
 #include "common.h"
+#include "realpath.h"
 #include "tomoyo.h"
 
 /* Lock for protecting policy. */
@@ -943,7 +943,9 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head)
                return -EINVAL;
        *cp = '\0';
        if (!strcmp(data, "COMMENT")) {
-               profile->comment = tomoyo_save_name(cp + 1);
+               const struct tomoyo_path_info *old_comment = profile->comment;
+               profile->comment = tomoyo_get_name(cp + 1);
+               tomoyo_put_name(old_comment);
                return 0;
        }
        for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) {
@@ -1117,7 +1119,7 @@ static int tomoyo_update_manager_entry(const char *manager,
                if (!tomoyo_is_correct_path(manager, 1, -1, -1, __func__))
                        return -EINVAL;
        }
-       saved_manager = tomoyo_save_name(manager);
+       saved_manager = tomoyo_get_name(manager);
        if (!saved_manager)
                return -ENOMEM;
        if (!is_delete)
@@ -1132,12 +1134,14 @@ static int tomoyo_update_manager_entry(const char *manager,
        }
        if (!is_delete && error && tomoyo_memory_ok(entry)) {
                entry->manager = saved_manager;
+               saved_manager = NULL;
                entry->is_domain = is_domain;
                list_add_tail_rcu(&entry->list, &tomoyo_policy_manager_list);
                entry = NULL;
                error = 0;
        }
        mutex_unlock(&tomoyo_policy_lock);
+       tomoyo_put_name(saved_manager);
        kfree(entry);
        return error;
 }
index 229de1e..0b82625 100644 (file)
@@ -203,7 +203,7 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname,
 {
        struct tomoyo_domain_initializer_entry *entry = NULL;
        struct tomoyo_domain_initializer_entry *ptr;
-       const struct tomoyo_path_info *saved_program;
+       const struct tomoyo_path_info *saved_program = NULL;
        const struct tomoyo_path_info *saved_domainname = NULL;
        int error = is_delete ? -ENOENT : -ENOMEM;
        bool is_last_name = false;
@@ -216,11 +216,11 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname,
                        is_last_name = true;
                else if (!tomoyo_is_correct_domain(domainname, __func__))
                        return -EINVAL;
-               saved_domainname = tomoyo_save_name(domainname);
+               saved_domainname = tomoyo_get_name(domainname);
                if (!saved_domainname)
                        goto out;
        }
-       saved_program = tomoyo_save_name(program);
+       saved_program = tomoyo_get_name(program);
        if (!saved_program)
                goto out;
        if (!is_delete)
@@ -237,7 +237,9 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname,
        }
        if (!is_delete && error && tomoyo_memory_ok(entry)) {
                entry->domainname = saved_domainname;
+               saved_domainname = NULL;
                entry->program = saved_program;
+               saved_program = NULL;
                entry->is_not = is_not;
                entry->is_last_name = is_last_name;
                list_add_tail_rcu(&entry->list,
@@ -247,6 +249,8 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname,
        }
        mutex_unlock(&tomoyo_policy_lock);
  out:
+       tomoyo_put_name(saved_domainname);
+       tomoyo_put_name(saved_program);
        kfree(entry);
        return error;
 }
@@ -419,7 +423,7 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname,
 {
        struct tomoyo_domain_keeper_entry *entry = NULL;
        struct tomoyo_domain_keeper_entry *ptr;
-       const struct tomoyo_path_info *saved_domainname;
+       const struct tomoyo_path_info *saved_domainname = NULL;
        const struct tomoyo_path_info *saved_program = NULL;
        int error = is_delete ? -ENOENT : -ENOMEM;
        bool is_last_name = false;
@@ -432,11 +436,11 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname,
        if (program) {
                if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__))
                        return -EINVAL;
-               saved_program = tomoyo_save_name(program);
+               saved_program = tomoyo_get_name(program);
                if (!saved_program)
                        goto out;
        }
-       saved_domainname = tomoyo_save_name(domainname);
+       saved_domainname = tomoyo_get_name(domainname);
        if (!saved_domainname)
                goto out;
        if (!is_delete)
@@ -453,7 +457,9 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname,
        }
        if (!is_delete && error && tomoyo_memory_ok(entry)) {
                entry->domainname = saved_domainname;
+               saved_domainname = NULL;
                entry->program = saved_program;
+               saved_program = NULL;
                entry->is_not = is_not;
                entry->is_last_name = is_last_name;
                list_add_tail_rcu(&entry->list, &tomoyo_domain_keeper_list);
@@ -462,6 +468,8 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname,
        }
        mutex_unlock(&tomoyo_policy_lock);
  out:
+       tomoyo_put_name(saved_domainname);
+       tomoyo_put_name(saved_program);
        kfree(entry);
        return error;
 }
@@ -623,8 +631,8 @@ static int tomoyo_update_alias_entry(const char *original_name,
        if (!tomoyo_is_correct_path(original_name, 1, -1, -1, __func__) ||
            !tomoyo_is_correct_path(aliased_name, 1, -1, -1, __func__))
                return -EINVAL; /* No patterns allowed. */
-       saved_original_name = tomoyo_save_name(original_name);
-       saved_aliased_name = tomoyo_save_name(aliased_name);
+       saved_original_name = tomoyo_get_name(original_name);
+       saved_aliased_name = tomoyo_get_name(aliased_name);
        if (!saved_original_name || !saved_aliased_name)
                goto out;
        if (!is_delete)
@@ -640,13 +648,17 @@ static int tomoyo_update_alias_entry(const char *original_name,
        }
        if (!is_delete && error && tomoyo_memory_ok(entry)) {
                entry->original_name = saved_original_name;
+               saved_original_name = NULL;
                entry->aliased_name = saved_aliased_name;
+               saved_aliased_name = NULL;
                list_add_tail_rcu(&entry->list, &tomoyo_alias_list);
                entry = NULL;
                error = 0;
        }
        mutex_unlock(&tomoyo_policy_lock);
  out:
+       tomoyo_put_name(saved_original_name);
+       tomoyo_put_name(saved_aliased_name);
        kfree(entry);
        return error;
 }
@@ -721,7 +733,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
 
        if (!tomoyo_is_correct_domain(domainname, __func__))
                return NULL;
-       saved_domainname = tomoyo_save_name(domainname);
+       saved_domainname = tomoyo_get_name(domainname);
        if (!saved_domainname)
                return NULL;
        entry = kzalloc(sizeof(*entry), GFP_KERNEL);
@@ -736,6 +748,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
        if (!found && tomoyo_memory_ok(entry)) {
                INIT_LIST_HEAD(&entry->acl_info_list);
                entry->domainname = saved_domainname;
+               saved_domainname = NULL;
                entry->profile = profile;
                list_add_tail_rcu(&entry->list, &tomoyo_domain_list);
                domain = entry;
@@ -743,6 +756,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
                found = true;
        }
        mutex_unlock(&tomoyo_policy_lock);
+       tomoyo_put_name(saved_domainname);
        kfree(entry);
        return found ? domain : NULL;
 }
index f4a2771..a49e18c 100644 (file)
@@ -222,7 +222,7 @@ static int tomoyo_update_globally_readable_entry(const char *filename,
 
        if (!tomoyo_is_correct_path(filename, 1, 0, -1, __func__))
                return -EINVAL;
-       saved_filename = tomoyo_save_name(filename);
+       saved_filename = tomoyo_get_name(filename);
        if (!saved_filename)
                return -ENOMEM;
        if (!is_delete)
@@ -237,11 +237,13 @@ static int tomoyo_update_globally_readable_entry(const char *filename,
        }
        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;
        }
        mutex_unlock(&tomoyo_policy_lock);
+       tomoyo_put_name(saved_filename);
        kfree(entry);
        return error;
 }
@@ -365,7 +367,7 @@ static int tomoyo_update_file_pattern_entry(const char *pattern,
        const struct tomoyo_path_info *saved_pattern;
        int error = is_delete ? -ENOENT : -ENOMEM;
 
-       saved_pattern = tomoyo_save_name(pattern);
+       saved_pattern = tomoyo_get_name(pattern);
        if (!saved_pattern)
                return error;
        if (!saved_pattern->is_patterned)
@@ -382,6 +384,7 @@ static int tomoyo_update_file_pattern_entry(const char *pattern,
        }
        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;
@@ -389,6 +392,7 @@ static int tomoyo_update_file_pattern_entry(const char *pattern,
        mutex_unlock(&tomoyo_policy_lock);
  out:
        kfree(entry);
+       tomoyo_put_name(saved_pattern);
        return error;
 }
 
@@ -518,7 +522,7 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern,
 
        if (!tomoyo_is_correct_path(pattern, 0, 0, 0, __func__))
                return -EINVAL;
-       saved_pattern = tomoyo_save_name(pattern);
+       saved_pattern = tomoyo_get_name(pattern);
        if (!saved_pattern)
                return error;
        if (!is_delete)
@@ -533,11 +537,13 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern,
        }
        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;
        }
        mutex_unlock(&tomoyo_policy_lock);
+       tomoyo_put_name(saved_pattern);
        kfree(entry);
        return error;
 }
@@ -867,7 +873,7 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
                return -EINVAL;
        if (!tomoyo_is_correct_path(filename, 0, 0, 0, __func__))
                return -EINVAL;
-       saved_filename = tomoyo_save_name(filename);
+       saved_filename = tomoyo_get_name(filename);
        if (!saved_filename)
                return -ENOMEM;
        if (!is_delete)
@@ -913,12 +919,14 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
                if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL))
                        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;
        }
        mutex_unlock(&tomoyo_policy_lock);
        kfree(entry);
+       tomoyo_put_name(saved_filename);
        return error;
 }
 
@@ -952,8 +960,8 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
        if (!tomoyo_is_correct_path(filename1, 0, 0, 0, __func__) ||
            !tomoyo_is_correct_path(filename2, 0, 0, 0, __func__))
                return -EINVAL;
-       saved_filename1 = tomoyo_save_name(filename1);
-       saved_filename2 = tomoyo_save_name(filename2);
+       saved_filename1 = tomoyo_get_name(filename1);
+       saved_filename2 = tomoyo_get_name(filename2);
        if (!saved_filename1 || !saved_filename2)
                goto out;
        if (!is_delete)
@@ -979,13 +987,17 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
                entry->head.type = TOMOYO_TYPE_DOUBLE_PATH_ACL;
                entry->perm = perm;
                entry->filename1 = saved_filename1;
+               saved_filename1 = NULL;
                entry->filename2 = saved_filename2;
+               saved_filename2 = NULL;
                list_add_tail_rcu(&entry->head.list, &domain->acl_info_list);
                entry = NULL;
                error = 0;
        }
        mutex_unlock(&tomoyo_policy_lock);
  out:
+       tomoyo_put_name(saved_filename1);
+       tomoyo_put_name(saved_filename2);
        kfree(entry);
        return error;
 }
index 92460c7..2f7f54f 100644 (file)
@@ -254,21 +254,6 @@ static unsigned int tomoyo_quota_for_savename;
 #define TOMOYO_MAX_HASH (1u<<TOMOYO_HASH_BITS)
 
 /*
- * tomoyo_name_entry is a structure which is used for linking
- * "struct tomoyo_path_info" into tomoyo_name_list .
- *
- * Since tomoyo_name_list manages a list of strings which are shared by
- * multiple processes (whereas "struct tomoyo_path_info" inside
- * "struct tomoyo_path_info_with_data" is not shared), a reference counter will
- * be added to "struct tomoyo_name_entry" rather than "struct tomoyo_path_info"
- * when TOMOYO starts supporting garbage collector.
- */
-struct tomoyo_name_entry {
-       struct list_head list;
-       struct tomoyo_path_info entry;
-};
-
-/*
  * tomoyo_name_list is used for holding string data used by TOMOYO.
  * Since same string data is likely used for multiple times (e.g.
  * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of
@@ -277,13 +262,13 @@ struct tomoyo_name_entry {
 static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
 
 /**
- * tomoyo_save_name - Allocate permanent memory for string data.
+ * tomoyo_get_name - Allocate permanent memory for string data.
  *
  * @name: The string to store into the permernent memory.
  *
  * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
  */
-const struct tomoyo_path_info *tomoyo_save_name(const char *name)
+const struct tomoyo_path_info *tomoyo_get_name(const char *name)
 {
        static DEFINE_MUTEX(lock);
        struct tomoyo_name_entry *ptr;
@@ -299,8 +284,10 @@ const struct tomoyo_path_info *tomoyo_save_name(const char *name)
        head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)];
        mutex_lock(&lock);
        list_for_each_entry(ptr, head, list) {
-               if (hash == ptr->entry.hash && !strcmp(name, ptr->entry.name))
-                       goto out;
+               if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
+                       continue;
+               atomic_inc(&ptr->users);
+               goto out;
        }
        ptr = kzalloc(sizeof(*ptr) + len, GFP_KERNEL);
        allocated_len = ptr ? ksize(ptr) : 0;
@@ -309,7 +296,7 @@ const struct tomoyo_path_info *tomoyo_save_name(const char *name)
                     > tomoyo_quota_for_savename)) {
                kfree(ptr);
                printk(KERN_WARNING "ERROR: Out of memory "
-                      "for tomoyo_save_name().\n");
+                      "for tomoyo_get_name().\n");
                if (!tomoyo_policy_loaded)
                        panic("MAC Initialization failed.\n");
                ptr = NULL;
@@ -318,6 +305,7 @@ const struct tomoyo_path_info *tomoyo_save_name(const char *name)
        tomoyo_allocated_memory_for_savename += allocated_len;
        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:
@@ -336,7 +324,7 @@ void __init tomoyo_realpath_init(void)
        for (i = 0; i < TOMOYO_MAX_HASH; i++)
                INIT_LIST_HEAD(&tomoyo_name_list[i]);
        INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list);
-       tomoyo_kernel_domain.domainname = tomoyo_save_name(TOMOYO_ROOT_NAME);
+       tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME);
        /*
         * tomoyo_read_lock() is not needed because this function is
         * called before the first "delete" request.
index da4f06f..b94cb51 100644 (file)
@@ -43,7 +43,7 @@ bool tomoyo_memory_ok(void *ptr);
  * Keep the given name on the RAM.
  * The RAM is shared, so NEVER try to modify or kfree() the returned name.
  */
-const struct tomoyo_path_info *tomoyo_save_name(const char *name);
+const struct tomoyo_path_info *tomoyo_get_name(const char *name);
 
 /* Check for memory usage. */
 int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head);
@@ -54,4 +54,23 @@ int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head);
 /* Initialize realpath related code. */
 void __init tomoyo_realpath_init(void);
 
+/*
+ * tomoyo_name_entry is a structure which is used for linking
+ * "struct tomoyo_path_info" into tomoyo_name_list .
+ */
+struct tomoyo_name_entry {
+       struct list_head list;
+       atomic_t users;
+       struct tomoyo_path_info entry;
+};
+
+static inline void tomoyo_put_name(const struct tomoyo_path_info *name)
+{
+       if (name) {
+               struct tomoyo_name_entry *ptr =
+                       container_of(name, struct tomoyo_name_entry, entry);
+               atomic_dec(&ptr->users);
+       }
+}
+
 #endif /* !defined(_SECURITY_TOMOYO_REALPATH_H) */