diff options
author | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | 2010-02-11 09:41:58 +0900 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2010-02-15 09:00:16 +1100 |
commit | bf24fb016c861b7f52be0c36c4cedd3e89afa2e2 (patch) | |
tree | f485ca2e70d8305d9aaecf45b5fd929b68b971b2 | |
parent | ca0b7df3374c5566468c17f26fa2dfd3fe3c6a37 (diff) |
TOMOYO: Add refcounter on string data.
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>
-rw-r--r-- | security/tomoyo/common.c | 10 | ||||
-rw-r--r-- | security/tomoyo/domain.c | 32 | ||||
-rw-r--r-- | security/tomoyo/file.c | 24 | ||||
-rw-r--r-- | security/tomoyo/realpath.c | 30 | ||||
-rw-r--r-- | security/tomoyo/realpath.h | 21 |
5 files changed, 77 insertions, 40 deletions
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index a53ee059da48..0c7ea51e7a45 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -12,8 +12,8 @@ #include <linux/uaccess.h> #include <linux/security.h> #include <linux/hardirq.h> -#include "realpath.h" #include "common.h" +#include "realpath.h" #include "tomoyo.h" /* 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; } diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 229de1e71a38..0b8262567809 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -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; } diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index f4a27714e077..a49e18cc7bc2 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -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; } diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 92460c7ded67..2f7f54fc6812 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c @@ -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. diff --git a/security/tomoyo/realpath.h b/security/tomoyo/realpath.h index da4f06ff6f8d..b94cb512adb5 100644 --- a/security/tomoyo/realpath.h +++ b/security/tomoyo/realpath.h @@ -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) */ |