summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--security/tomoyo/common.c41
-rw-r--r--security/tomoyo/common.h2
-rw-r--r--security/tomoyo/domain.c58
-rw-r--r--security/tomoyo/file.c34
-rw-r--r--security/tomoyo/realpath.c65
-rw-r--r--security/tomoyo/realpath.h7
6 files changed, 73 insertions, 134 deletions
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c
index 642e0e565df..e331e699cf5 100644
--- a/security/tomoyo/common.c
+++ b/security/tomoyo/common.c
@@ -900,9 +900,11 @@ static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned
ptr = tomoyo_profile_ptr[profile];
if (ptr)
goto ok;
- ptr = tomoyo_alloc_element(sizeof(*ptr));
- if (!ptr)
+ ptr = kmalloc(sizeof(*ptr), GFP_KERNEL);
+ if (!tomoyo_memory_ok(ptr)) {
+ kfree(ptr);
goto ok;
+ }
for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++)
ptr->value[i] = tomoyo_control_array[i].current_value;
mb(); /* Avoid out-of-order execution. */
@@ -1120,6 +1122,7 @@ static int tomoyo_update_manager_entry(const char *manager,
saved_manager = tomoyo_save_name(manager);
if (!saved_manager)
return -ENOMEM;
+ new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
mutex_lock(&tomoyo_policy_lock);
list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
if (ptr->manager != saved_manager)
@@ -1132,15 +1135,16 @@ static int tomoyo_update_manager_entry(const char *manager,
error = -ENOENT;
goto out;
}
- new_entry = tomoyo_alloc_element(sizeof(*new_entry));
- if (!new_entry)
+ if (!tomoyo_memory_ok(new_entry))
goto out;
new_entry->manager = saved_manager;
new_entry->is_domain = is_domain;
list_add_tail_rcu(&new_entry->list, &tomoyo_policy_manager_list);
+ new_entry = NULL;
error = 0;
out:
mutex_unlock(&tomoyo_policy_lock);
+ kfree(new_entry);
return error;
}
@@ -2148,35 +2152,6 @@ static int tomoyo_close_control(struct file *file)
}
/**
- * tomoyo_alloc_acl_element - Allocate permanent memory for ACL entry.
- *
- * @acl_type: Type of ACL entry.
- *
- * Returns pointer to the ACL entry on success, NULL otherwise.
- */
-void *tomoyo_alloc_acl_element(const u8 acl_type)
-{
- int len;
- struct tomoyo_acl_info *ptr;
-
- switch (acl_type) {
- case TOMOYO_TYPE_SINGLE_PATH_ACL:
- len = sizeof(struct tomoyo_single_path_acl_record);
- break;
- case TOMOYO_TYPE_DOUBLE_PATH_ACL:
- len = sizeof(struct tomoyo_double_path_acl_record);
- break;
- default:
- return NULL;
- }
- ptr = tomoyo_alloc_element(len);
- if (!ptr)
- return NULL;
- ptr->type = acl_type;
- return ptr;
-}
-
-/**
* tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface.
*
* @inode: Pointer to "struct inode".
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
index 874abf8df43..610a6a05682 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -376,8 +376,6 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
/* Check mode for specified functionality. */
unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
const u8 index);
-/* Allocate memory for structures. */
-void *tomoyo_alloc_acl_element(const u8 acl_type);
/* Fill in "struct tomoyo_path_info" members. */
void tomoyo_fill_path_info(struct tomoyo_path_info *ptr);
/* Run policy loader when /sbin/init starts. */
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
index 7d0b0bc4820..a55a1cced58 100644
--- a/security/tomoyo/domain.c
+++ b/security/tomoyo/domain.c
@@ -245,6 +245,7 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname,
saved_program = tomoyo_save_name(program);
if (!saved_program)
return -ENOMEM;
+ new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
mutex_lock(&tomoyo_policy_lock);
list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
if (ptr->is_not != is_not ||
@@ -259,17 +260,18 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname,
error = -ENOENT;
goto out;
}
- new_entry = tomoyo_alloc_element(sizeof(*new_entry));
- if (!new_entry)
+ if (!tomoyo_memory_ok(new_entry))
goto out;
new_entry->domainname = saved_domainname;
new_entry->program = saved_program;
new_entry->is_not = is_not;
new_entry->is_last_name = is_last_name;
list_add_tail_rcu(&new_entry->list, &tomoyo_domain_initializer_list);
+ new_entry = NULL;
error = 0;
out:
mutex_unlock(&tomoyo_policy_lock);
+ kfree(new_entry);
return error;
}
@@ -461,6 +463,7 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname,
saved_domainname = tomoyo_save_name(domainname);
if (!saved_domainname)
return -ENOMEM;
+ new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
mutex_lock(&tomoyo_policy_lock);
list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
if (ptr->is_not != is_not ||
@@ -475,17 +478,18 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname,
error = -ENOENT;
goto out;
}
- new_entry = tomoyo_alloc_element(sizeof(*new_entry));
- if (!new_entry)
+ if (!tomoyo_memory_ok(new_entry))
goto out;
new_entry->domainname = saved_domainname;
new_entry->program = saved_program;
new_entry->is_not = is_not;
new_entry->is_last_name = is_last_name;
list_add_tail_rcu(&new_entry->list, &tomoyo_domain_keeper_list);
+ new_entry = NULL;
error = 0;
out:
mutex_unlock(&tomoyo_policy_lock);
+ kfree(new_entry);
return error;
}
@@ -650,6 +654,7 @@ static int tomoyo_update_alias_entry(const char *original_name,
saved_aliased_name = tomoyo_save_name(aliased_name);
if (!saved_original_name || !saved_aliased_name)
return -ENOMEM;
+ new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
mutex_lock(&tomoyo_policy_lock);
list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
if (ptr->original_name != saved_original_name ||
@@ -663,15 +668,16 @@ static int tomoyo_update_alias_entry(const char *original_name,
error = -ENOENT;
goto out;
}
- new_entry = tomoyo_alloc_element(sizeof(*new_entry));
- if (!new_entry)
+ if (!tomoyo_memory_ok(new_entry))
goto out;
new_entry->original_name = saved_original_name;
new_entry->aliased_name = saved_aliased_name;
list_add_tail_rcu(&new_entry->list, &tomoyo_alias_list);
+ new_entry = NULL;
error = 0;
out:
mutex_unlock(&tomoyo_policy_lock);
+ kfree(new_entry);
return error;
}
@@ -738,7 +744,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
domainname,
const u8 profile)
{
- struct tomoyo_domain_info *domain = NULL;
+ struct tomoyo_domain_info *domain;
const struct tomoyo_path_info *saved_domainname;
mutex_lock(&tomoyo_policy_lock);
@@ -750,43 +756,17 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
saved_domainname = tomoyo_save_name(domainname);
if (!saved_domainname)
goto out;
- /* Can I reuse memory of deleted domain? */
- list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
- struct task_struct *p;
- struct tomoyo_acl_info *ptr;
- bool flag;
- if (!domain->is_deleted ||
- domain->domainname != saved_domainname)
- continue;
- flag = false;
- read_lock(&tasklist_lock);
- for_each_process(p) {
- if (tomoyo_real_domain(p) != domain)
- continue;
- flag = true;
- break;
- }
- read_unlock(&tasklist_lock);
- if (flag)
- continue;
- list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
- ptr->type |= TOMOYO_ACL_DELETED;
- }
- tomoyo_set_domain_flag(domain, true, domain->flags);
- domain->profile = profile;
- domain->quota_warned = false;
- mb(); /* Avoid out-of-order execution. */
- domain->is_deleted = false;
- goto out;
- }
- /* No memory reusable. Create using new memory. */
- domain = tomoyo_alloc_element(sizeof(*domain));
- if (domain) {
+ domain = kmalloc(sizeof(*domain), GFP_KERNEL);
+ if (tomoyo_memory_ok(domain)) {
INIT_LIST_HEAD(&domain->acl_info_list);
domain->domainname = saved_domainname;
domain->profile = profile;
list_add_tail_rcu(&domain->list, &tomoyo_domain_list);
+ } else {
+ kfree(domain);
+ domain = NULL;
}
+
out:
mutex_unlock(&tomoyo_policy_lock);
return domain;
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c
index 5d1689d6e16..075392c052b 100644
--- a/security/tomoyo/file.c
+++ b/security/tomoyo/file.c
@@ -225,6 +225,7 @@ static int tomoyo_update_globally_readable_entry(const char *filename,
saved_filename = tomoyo_save_name(filename);
if (!saved_filename)
return -ENOMEM;
+ new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
mutex_lock(&tomoyo_policy_lock);
list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) {
if (ptr->filename != saved_filename)
@@ -237,14 +238,15 @@ static int tomoyo_update_globally_readable_entry(const char *filename,
error = -ENOENT;
goto out;
}
- new_entry = tomoyo_alloc_element(sizeof(*new_entry));
- if (!new_entry)
+ if (!tomoyo_memory_ok(new_entry))
goto out;
new_entry->filename = saved_filename;
list_add_tail_rcu(&new_entry->list, &tomoyo_globally_readable_list);
+ new_entry = NULL;
error = 0;
out:
mutex_unlock(&tomoyo_policy_lock);
+ kfree(new_entry);
return error;
}
@@ -372,6 +374,7 @@ static int tomoyo_update_file_pattern_entry(const char *pattern,
saved_pattern = tomoyo_save_name(pattern);
if (!saved_pattern)
return -ENOMEM;
+ new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
mutex_lock(&tomoyo_policy_lock);
list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
if (saved_pattern != ptr->pattern)
@@ -384,14 +387,15 @@ static int tomoyo_update_file_pattern_entry(const char *pattern,
error = -ENOENT;
goto out;
}
- new_entry = tomoyo_alloc_element(sizeof(*new_entry));
- if (!new_entry)
+ if (!tomoyo_memory_ok(new_entry))
goto out;
new_entry->pattern = saved_pattern;
list_add_tail_rcu(&new_entry->list, &tomoyo_pattern_list);
+ new_entry = NULL;
error = 0;
out:
mutex_unlock(&tomoyo_policy_lock);
+ kfree(new_entry);
return error;
}
@@ -523,6 +527,7 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern,
saved_pattern = tomoyo_save_name(pattern);
if (!saved_pattern)
return -ENOMEM;
+ new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
mutex_lock(&tomoyo_policy_lock);
list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
if (ptr->pattern != saved_pattern)
@@ -535,14 +540,15 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern,
error = -ENOENT;
goto out;
}
- new_entry = tomoyo_alloc_element(sizeof(*new_entry));
- if (!new_entry)
+ if (!tomoyo_memory_ok(new_entry))
goto out;
new_entry->pattern = saved_pattern;
list_add_tail_rcu(&new_entry->list, &tomoyo_no_rewrite_list);
+ new_entry = NULL;
error = 0;
out:
mutex_unlock(&tomoyo_policy_lock);
+ kfree(new_entry);
return error;
}
@@ -901,9 +907,13 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
goto out;
}
/* Not found. Append it to the tail. */
- acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_SINGLE_PATH_ACL);
- if (!acl)
+ acl = kmalloc(sizeof(*acl), GFP_KERNEL);
+ if (!tomoyo_memory_ok(acl)) {
+ kfree(acl);
+ acl = NULL;
goto out;
+ }
+ acl->head.type = TOMOYO_TYPE_SINGLE_PATH_ACL;
if (perm <= 0xFFFF)
acl->perm = perm;
else
@@ -995,9 +1005,13 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
goto out;
}
/* Not found. Append it to the tail. */
- acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_DOUBLE_PATH_ACL);
- if (!acl)
+ acl = kmalloc(sizeof(*acl), GFP_KERNEL);
+ if (!tomoyo_memory_ok(acl)) {
+ kfree(acl);
+ acl = NULL;
goto out;
+ }
+ acl->head.type = TOMOYO_TYPE_DOUBLE_PATH_ACL;
acl->perm = perm;
acl->filename1 = saved_filename1;
acl->filename2 = saved_filename2;
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c
index 9105e5e29da..54226d5be49 100644
--- a/security/tomoyo/realpath.c
+++ b/security/tomoyo/realpath.c
@@ -212,57 +212,32 @@ static unsigned int tomoyo_allocated_memory_for_elements;
static unsigned int tomoyo_quota_for_elements;
/**
- * tomoyo_alloc_element - Allocate permanent memory for structures.
+ * tomoyo_memory_ok - Check memory quota.
*
- * @size: Size in bytes.
+ * @ptr: Pointer to allocated memory.
*
- * Returns pointer to allocated memory on success, NULL otherwise.
+ * Returns true on success, false otherwise.
*
- * Memory has to be zeroed.
- * The RAM is chunked, so NEVER try to kfree() the returned pointer.
+ * Caller holds tomoyo_policy_lock.
+ * Memory pointed by @ptr will be zeroed on success.
*/
-void *tomoyo_alloc_element(const unsigned int size)
+bool tomoyo_memory_ok(void *ptr)
{
- static char *buf;
- static DEFINE_MUTEX(lock);
- static unsigned int buf_used_len = PATH_MAX;
- char *ptr = NULL;
- /*Assumes sizeof(void *) >= sizeof(long) is true. */
- const unsigned int word_aligned_size
- = roundup(size, max(sizeof(void *), sizeof(long)));
- if (word_aligned_size > PATH_MAX)
- return NULL;
- mutex_lock(&lock);
- if (buf_used_len + word_aligned_size > PATH_MAX) {
- if (!tomoyo_quota_for_elements ||
- tomoyo_allocated_memory_for_elements
- + PATH_MAX <= tomoyo_quota_for_elements)
- ptr = kzalloc(PATH_MAX, GFP_KERNEL);
- if (!ptr) {
- printk(KERN_WARNING "ERROR: Out of memory "
- "for tomoyo_alloc_element().\n");
- if (!tomoyo_policy_loaded)
- panic("MAC Initialization failed.\n");
- } else {
- buf = ptr;
- tomoyo_allocated_memory_for_elements += PATH_MAX;
- buf_used_len = word_aligned_size;
- ptr = buf;
- }
- } else if (word_aligned_size) {
- int i;
- ptr = buf + buf_used_len;
- buf_used_len += word_aligned_size;
- for (i = 0; i < word_aligned_size; i++) {
- if (!ptr[i])
- continue;
- printk(KERN_ERR "WARNING: Reserved memory was tainted! "
- "The system might go wrong.\n");
- ptr[i] = '\0';
- }
+ 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;
+ memset(ptr, 0, allocated_len);
}
- mutex_unlock(&lock);
- return ptr;
+ return result;
}
/* Memory allocated for string data in bytes. */
diff --git a/security/tomoyo/realpath.h b/security/tomoyo/realpath.h
index 78217a37960..47b4f59dad6 100644
--- a/security/tomoyo/realpath.h
+++ b/security/tomoyo/realpath.h
@@ -36,11 +36,8 @@ char *tomoyo_realpath_nofollow(const char *pathname);
/* Same with tomoyo_realpath() except that the pathname is already solved. */
char *tomoyo_realpath_from_path(struct path *path);
-/*
- * Allocate memory for ACL entry.
- * The RAM is chunked, so NEVER try to kfree() the returned pointer.
- */
-void *tomoyo_alloc_element(const unsigned int size);
+/* Check memory quota. */
+bool tomoyo_memory_ok(void *ptr);
/*
* Keep the given name on the RAM.