summary refs log tree commit diff
path: root/security
diff options
context:
space:
mode:
authorTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>2010-01-05 06:39:37 +0900
committerJames Morris <jmorris@namei.org>2010-01-11 09:27:40 +1100
commitcd7bec6ad80188394a8ea857ff1aa3512fc2282a (patch)
tree598e7d59c29966e0d8fa8abf24eb51bbb2f567a6 /security
parente41035a996356c257183e53a70abfb46fa84908b (diff)
downloadlinux-cd7bec6ad80188394a8ea857ff1aa3512fc2282a.tar.gz
TOMOYO: Remove memory pool for list elements.
Currently, TOMOYO allocates memory for list elements from memory pool allocated
by kmalloc(PAGE_SIZE). But that makes it difficult to kfree() when garbage
collector is added. Thus, remove memory pool and use kmalloc(sizeof()).

Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security')
-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 642e0e565dfc..e331e699cf54 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 874abf8df43e..610a6a056828 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 7d0b0bc48201..a55a1cced58e 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 5d1689d6e16c..075392c052b4 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 9105e5e29da9..54226d5be493 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 78217a37960b..47b4f59dad6f 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.