[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <200906020141.n521faqb003256@www262.sakura.ne.jp>
Date: Tue, 02 Jun 2009 10:41:36 +0900
From: Tetsuo Handa <penguin-kernel@...ove.sakura.ne.jp>
To: linux-security-module@...r.kernel.org
Cc: linux-kernel@...r.kernel.org
Subject: [PATCH 1/5] Move sleeping operations to outside the semaphore.
TOMOYO is using rw_semaphore for protecting list elements.
But TOMOYO is doing operations which might sleep inside down_write().
This patch makes TOMOYO's sleeping operations go outside down_write().
Signed-off-by: Kentaro Takeda <takedakn@...data.co.jp>
Signed-off-by: Tetsuo Handa <penguin-kernel@...ove.SAKURA.ne.jp>
Signed-off-by: Toshiharu Harada <haradats@...data.co.jp>
---
security/tomoyo/common.c | 80 ++++++---------------
security/tomoyo/common.h | 2
security/tomoyo/domain.c | 107 ++++++++++++++--------------
security/tomoyo/file.c | 133 ++++++++++++++++++-----------------
security/tomoyo/realpath.c | 169 ++++++++++++++-------------------------------
security/tomoyo/realpath.h | 7 -
6 files changed, 205 insertions(+), 293 deletions(-)
--- security-testing-2.6.git.orig/security/tomoyo/common.c
+++ security-testing-2.6.git/security/tomoyo/common.c
@@ -861,26 +861,27 @@ static struct tomoyo_profile *tomoyo_fin
int profile)
{
static DEFINE_MUTEX(lock);
- struct tomoyo_profile *ptr = NULL;
- int i;
+ struct tomoyo_profile *new_ptr = NULL;
+ struct tomoyo_profile *ptr;
if (profile >= TOMOYO_MAX_PROFILES)
return NULL;
+ new_ptr = kmalloc(sizeof(*new_ptr), GFP_KERNEL);
/***** EXCLUSIVE SECTION START *****/
mutex_lock(&lock);
ptr = tomoyo_profile_ptr[profile];
- if (ptr)
- goto ok;
- ptr = tomoyo_alloc_element(sizeof(*ptr));
- if (!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. */
- tomoyo_profile_ptr[profile] = ptr;
- ok:
+ if (!ptr && tomoyo_memory_ok(new_ptr)) {
+ int i;
+ ptr = new_ptr;
+ new_ptr = NULL;
+ for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++)
+ ptr->value[i] = tomoyo_control_array[i].current_value;
+ mb(); /* Avoid out-of-order execution. */
+ tomoyo_profile_ptr[profile] = ptr;
+ }
mutex_unlock(&lock);
/***** EXCLUSIVE SECTION END *****/
+ kfree(new_ptr);
return ptr;
}
@@ -1033,10 +1034,10 @@ static DECLARE_RWSEM(tomoyo_policy_manag
static int tomoyo_update_manager_entry(const char *manager,
const bool is_delete)
{
- struct tomoyo_policy_manager_entry *new_entry;
+ struct tomoyo_policy_manager_entry *new_entry = NULL;
struct tomoyo_policy_manager_entry *ptr;
const struct tomoyo_path_info *saved_manager;
- int error = -ENOMEM;
+ int error = is_delete ? -ENOENT : -ENOMEM;
bool is_domain = false;
if (tomoyo_is_domain_def(manager)) {
@@ -1050,6 +1051,8 @@ static int tomoyo_update_manager_entry(c
saved_manager = tomoyo_save_name(manager);
if (!saved_manager)
return -ENOMEM;
+ if (!is_delete)
+ new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
/***** EXCLUSIVE SECTION START *****/
down_write(&tomoyo_policy_manager_list_lock);
list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
@@ -1057,22 +1060,18 @@ static int tomoyo_update_manager_entry(c
continue;
ptr->is_deleted = is_delete;
error = 0;
- goto out;
+ break;
}
- if (is_delete) {
- error = -ENOENT;
- goto out;
+ if (!is_delete && error && tomoyo_memory_ok(new_entry)) {
+ new_entry->manager = saved_manager;
+ new_entry->is_domain = is_domain;
+ list_add_tail(&new_entry->list, &tomoyo_policy_manager_list);
+ new_entry = NULL;
+ error = 0;
}
- new_entry = tomoyo_alloc_element(sizeof(*new_entry));
- if (!new_entry)
- goto out;
- new_entry->manager = saved_manager;
- new_entry->is_domain = is_domain;
- list_add_tail(&new_entry->list, &tomoyo_policy_manager_list);
- error = 0;
- out:
up_write(&tomoyo_policy_manager_list_lock);
/***** EXCLUSIVE SECTION END *****/
+ kfree(new_entry);
return error;
}
@@ -2050,35 +2049,6 @@ static int tomoyo_close_control(struct f
}
/**
- * 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".
--- security-testing-2.6.git.orig/security/tomoyo/common.h
+++ security-testing-2.6.git/security/tomoyo/common.h
@@ -266,8 +266,6 @@ struct tomoyo_domain_info *tomoyo_find_o
/* 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. */
--- security-testing-2.6.git.orig/security/tomoyo/domain.c
+++ security-testing-2.6.git/security/tomoyo/domain.c
@@ -113,11 +113,11 @@ static int tomoyo_update_domain_initiali
const bool is_not,
const bool is_delete)
{
- struct tomoyo_domain_initializer_entry *new_entry;
+ struct tomoyo_domain_initializer_entry *new_entry = NULL;
struct tomoyo_domain_initializer_entry *ptr;
const struct tomoyo_path_info *saved_program;
const struct tomoyo_path_info *saved_domainname = NULL;
- int error = -ENOMEM;
+ int error = is_delete ? -ENOENT : -ENOMEM;
bool is_last_name = false;
if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__))
@@ -135,6 +135,8 @@ static int tomoyo_update_domain_initiali
saved_program = tomoyo_save_name(program);
if (!saved_program)
return -ENOMEM;
+ if (!is_delete)
+ new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
/***** EXCLUSIVE SECTION START *****/
down_write(&tomoyo_domain_initializer_list_lock);
list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) {
@@ -144,24 +146,21 @@ static int tomoyo_update_domain_initiali
continue;
ptr->is_deleted = is_delete;
error = 0;
- goto out;
+ break;
}
- if (is_delete) {
- error = -ENOENT;
- goto out;
+ if (!is_delete && error && tomoyo_memory_ok(new_entry)) {
+ 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(&new_entry->list,
+ &tomoyo_domain_initializer_list);
+ new_entry = NULL;
+ error = 0;
}
- new_entry = tomoyo_alloc_element(sizeof(*new_entry));
- if (!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(&new_entry->list, &tomoyo_domain_initializer_list);
- error = 0;
- out:
up_write(&tomoyo_domain_initializer_list_lock);
/***** EXCLUSIVE SECTION END *****/
+ kfree(new_entry);
return error;
}
@@ -292,12 +291,12 @@ static int tomoyo_update_domain_keeper_e
const bool is_not,
const bool is_delete)
{
- struct tomoyo_domain_keeper_entry *new_entry;
+ struct tomoyo_domain_keeper_entry *new_entry = NULL;
struct tomoyo_domain_keeper_entry *ptr;
const struct tomoyo_path_info *saved_domainname;
const struct tomoyo_path_info *saved_program = NULL;
static DEFINE_MUTEX(lock);
- int error = -ENOMEM;
+ int error = is_delete ? -ENOENT : -ENOMEM;
bool is_last_name = false;
if (!tomoyo_is_domain_def(domainname) &&
@@ -315,6 +314,8 @@ static int tomoyo_update_domain_keeper_e
saved_domainname = tomoyo_save_name(domainname);
if (!saved_domainname)
return -ENOMEM;
+ if (!is_delete)
+ new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
/***** EXCLUSIVE SECTION START *****/
down_write(&tomoyo_domain_keeper_list_lock);
list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
@@ -324,24 +325,20 @@ static int tomoyo_update_domain_keeper_e
continue;
ptr->is_deleted = is_delete;
error = 0;
- goto out;
+ break;
}
- if (is_delete) {
- error = -ENOENT;
- goto out;
+ if (!is_delete && error && tomoyo_memory_ok(new_entry)) {
+ 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(&new_entry->list, &tomoyo_domain_keeper_list);
+ new_entry = NULL;
+ error = 0;
}
- new_entry = tomoyo_alloc_element(sizeof(*new_entry));
- if (!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(&new_entry->list, &tomoyo_domain_keeper_list);
- error = 0;
- out:
up_write(&tomoyo_domain_keeper_list_lock);
/***** EXCLUSIVE SECTION END *****/
+ kfree(new_entry);
return error;
}
@@ -463,11 +460,11 @@ static int tomoyo_update_alias_entry(con
const char *aliased_name,
const bool is_delete)
{
- struct tomoyo_alias_entry *new_entry;
+ struct tomoyo_alias_entry *new_entry = NULL;
struct tomoyo_alias_entry *ptr;
const struct tomoyo_path_info *saved_original_name;
const struct tomoyo_path_info *saved_aliased_name;
- int error = -ENOMEM;
+ int error = is_delete ? -ENOENT : -ENOMEM;
if (!tomoyo_is_correct_path(original_name, 1, -1, -1, __func__) ||
!tomoyo_is_correct_path(aliased_name, 1, -1, -1, __func__))
@@ -476,6 +473,8 @@ static int tomoyo_update_alias_entry(con
saved_aliased_name = tomoyo_save_name(aliased_name);
if (!saved_original_name || !saved_aliased_name)
return -ENOMEM;
+ if (!is_delete)
+ new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
/***** EXCLUSIVE SECTION START *****/
down_write(&tomoyo_alias_list_lock);
list_for_each_entry(ptr, &tomoyo_alias_list, list) {
@@ -484,22 +483,18 @@ static int tomoyo_update_alias_entry(con
continue;
ptr->is_deleted = is_delete;
error = 0;
- goto out;
+ break;
}
- if (is_delete) {
- error = -ENOENT;
- goto out;
+ if (!is_delete && error && tomoyo_memory_ok(new_entry)) {
+ new_entry->original_name = saved_original_name;
+ new_entry->aliased_name = saved_aliased_name;
+ list_add_tail(&new_entry->list, &tomoyo_alias_list);
+ new_entry = NULL;
+ error = 0;
}
- new_entry = tomoyo_alloc_element(sizeof(*new_entry));
- if (!new_entry)
- goto out;
- new_entry->original_name = saved_original_name;
- new_entry->aliased_name = saved_aliased_name;
- list_add_tail(&new_entry->list, &tomoyo_alias_list);
- error = 0;
- out:
up_write(&tomoyo_alias_list_lock);
/***** EXCLUSIVE SECTION END *****/
+ kfree(new_entry);
return error;
}
@@ -597,19 +592,21 @@ struct tomoyo_domain_info *tomoyo_find_o
domainname,
const u8 profile)
{
- struct tomoyo_domain_info *domain = NULL;
+ struct tomoyo_domain_info *new_domain = NULL;
+ struct tomoyo_domain_info *domain;
const struct tomoyo_path_info *saved_domainname;
+ if (!tomoyo_is_correct_domain(domainname, __func__))
+ return NULL;
+ saved_domainname = tomoyo_save_name(domainname);
+ if (!saved_domainname)
+ return NULL;
+ new_domain = kmalloc(sizeof(*new_domain), GFP_KERNEL);
/***** EXCLUSIVE SECTION START *****/
down_write(&tomoyo_domain_list_lock);
domain = tomoyo_find_domain(domainname);
if (domain)
goto out;
- if (!tomoyo_is_correct_domain(domainname, __func__))
- goto out;
- saved_domainname = tomoyo_save_name(domainname);
- if (!saved_domainname)
- goto out;
/* Can I reuse memory of deleted domain? */
list_for_each_entry(domain, &tomoyo_domain_list, list) {
struct task_struct *p;
@@ -642,8 +639,9 @@ struct tomoyo_domain_info *tomoyo_find_o
goto out;
}
/* No memory reusable. Create using new memory. */
- domain = tomoyo_alloc_element(sizeof(*domain));
- if (domain) {
+ if (tomoyo_memory_ok(new_domain)) {
+ domain = new_domain;
+ new_domain = NULL;
INIT_LIST_HEAD(&domain->acl_info_list);
domain->domainname = saved_domainname;
domain->profile = profile;
@@ -652,6 +650,7 @@ struct tomoyo_domain_info *tomoyo_find_o
out:
up_write(&tomoyo_domain_list_lock);
/***** EXCLUSIVE SECTION END *****/
+ kfree(new_domain);
return domain;
}
--- security-testing-2.6.git.orig/security/tomoyo/file.c
+++ security-testing-2.6.git/security/tomoyo/file.c
@@ -156,16 +156,18 @@ static DECLARE_RWSEM(tomoyo_globally_rea
static int tomoyo_update_globally_readable_entry(const char *filename,
const bool is_delete)
{
- struct tomoyo_globally_readable_file_entry *new_entry;
+ struct tomoyo_globally_readable_file_entry *new_entry = NULL;
struct tomoyo_globally_readable_file_entry *ptr;
const struct tomoyo_path_info *saved_filename;
- int error = -ENOMEM;
+ int error = is_delete ? -ENOENT : -ENOMEM;
if (!tomoyo_is_correct_path(filename, 1, 0, -1, __func__))
return -EINVAL;
saved_filename = tomoyo_save_name(filename);
if (!saved_filename)
return -ENOMEM;
+ if (!is_delete)
+ new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
/***** EXCLUSIVE SECTION START *****/
down_write(&tomoyo_globally_readable_list_lock);
list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
@@ -173,21 +175,17 @@ static int tomoyo_update_globally_readab
continue;
ptr->is_deleted = is_delete;
error = 0;
- goto out;
+ break;
}
- if (is_delete) {
- error = -ENOENT;
- goto out;
+ if (!is_delete && error && tomoyo_memory_ok(new_entry)) {
+ new_entry->filename = saved_filename;
+ list_add_tail(&new_entry->list, &tomoyo_globally_readable_list);
+ new_entry = NULL;
+ error = 0;
}
- new_entry = tomoyo_alloc_element(sizeof(*new_entry));
- if (!new_entry)
- goto out;
- new_entry->filename = saved_filename;
- list_add_tail(&new_entry->list, &tomoyo_globally_readable_list);
- error = 0;
- out:
up_write(&tomoyo_globally_readable_list_lock);
/***** EXCLUSIVE SECTION END *****/
+ kfree(new_entry);
return error;
}
@@ -274,16 +272,18 @@ static DECLARE_RWSEM(tomoyo_pattern_list
static int tomoyo_update_file_pattern_entry(const char *pattern,
const bool is_delete)
{
- struct tomoyo_pattern_entry *new_entry;
+ struct tomoyo_pattern_entry *new_entry = NULL;
struct tomoyo_pattern_entry *ptr;
const struct tomoyo_path_info *saved_pattern;
- int error = -ENOMEM;
+ int error = is_delete ? -ENOENT : -ENOMEM;
if (!tomoyo_is_correct_path(pattern, 0, 1, 0, __func__))
return -EINVAL;
saved_pattern = tomoyo_save_name(pattern);
if (!saved_pattern)
return -ENOMEM;
+ if (!is_delete)
+ new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
/***** EXCLUSIVE SECTION START *****/
down_write(&tomoyo_pattern_list_lock);
list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
@@ -291,21 +291,17 @@ static int tomoyo_update_file_pattern_en
continue;
ptr->is_deleted = is_delete;
error = 0;
- goto out;
+ break;
}
- if (is_delete) {
- error = -ENOENT;
- goto out;
+ if (!is_delete && error && tomoyo_memory_ok(new_entry)) {
+ new_entry->pattern = saved_pattern;
+ list_add_tail(&new_entry->list, &tomoyo_pattern_list);
+ new_entry = NULL;
+ error = 0;
}
- new_entry = tomoyo_alloc_element(sizeof(*new_entry));
- if (!new_entry)
- goto out;
- new_entry->pattern = saved_pattern;
- list_add_tail(&new_entry->list, &tomoyo_pattern_list);
- error = 0;
- out:
up_write(&tomoyo_pattern_list_lock);
/***** EXCLUSIVE SECTION END *****/
+ kfree(new_entry);
return error;
}
@@ -398,15 +394,18 @@ static DECLARE_RWSEM(tomoyo_no_rewrite_l
static int tomoyo_update_no_rewrite_entry(const char *pattern,
const bool is_delete)
{
- struct tomoyo_no_rewrite_entry *new_entry, *ptr;
+ struct tomoyo_no_rewrite_entry *new_entry = NULL;
+ struct tomoyo_no_rewrite_entry *ptr;
const struct tomoyo_path_info *saved_pattern;
- int error = -ENOMEM;
+ int error = is_delete ? -ENOENT : -ENOMEM;
if (!tomoyo_is_correct_path(pattern, 0, 0, 0, __func__))
return -EINVAL;
saved_pattern = tomoyo_save_name(pattern);
if (!saved_pattern)
return -ENOMEM;
+ if (!is_delete)
+ new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
/***** EXCLUSIVE SECTION START *****/
down_write(&tomoyo_no_rewrite_list_lock);
list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
@@ -414,21 +413,17 @@ static int tomoyo_update_no_rewrite_entr
continue;
ptr->is_deleted = is_delete;
error = 0;
- goto out;
+ break;
}
- if (is_delete) {
- error = -ENOENT;
- goto out;
+ if (!is_delete && error && tomoyo_memory_ok(new_entry)) {
+ new_entry->pattern = saved_pattern;
+ list_add_tail(&new_entry->list, &tomoyo_no_rewrite_list);
+ new_entry = NULL;
+ error = 0;
}
- new_entry = tomoyo_alloc_element(sizeof(*new_entry));
- if (!new_entry)
- goto out;
- new_entry->pattern = saved_pattern;
- list_add_tail(&new_entry->list, &tomoyo_no_rewrite_list);
- error = 0;
- out:
up_write(&tomoyo_no_rewrite_list_lock);
/***** EXCLUSIVE SECTION END *****/
+ kfree(new_entry);
return error;
}
@@ -734,8 +729,8 @@ static int tomoyo_update_single_path_acl
(1 << TOMOYO_TYPE_READ_ACL) | (1 << TOMOYO_TYPE_WRITE_ACL);
const struct tomoyo_path_info *saved_filename;
struct tomoyo_acl_info *ptr;
- struct tomoyo_single_path_acl_record *acl;
- int error = -ENOMEM;
+ struct tomoyo_single_path_acl_record *new_entry = NULL;
+ int error = is_delete ? -ENOENT : -ENOMEM;
const u16 perm = 1 << type;
if (!domain)
@@ -745,11 +740,14 @@ static int tomoyo_update_single_path_acl
saved_filename = tomoyo_save_name(filename);
if (!saved_filename)
return -ENOMEM;
+ if (!is_delete)
+ new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
/***** EXCLUSIVE SECTION START *****/
down_write(&tomoyo_domain_acl_info_list_lock);
if (is_delete)
goto delete;
list_for_each_entry(ptr, &domain->acl_info_list, list) {
+ struct tomoyo_single_path_acl_record *acl;
if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
continue;
acl = container_of(ptr, struct tomoyo_single_path_acl_record,
@@ -766,22 +764,23 @@ static int tomoyo_update_single_path_acl
acl->perm |= rw_mask;
ptr->type &= ~TOMOYO_ACL_DELETED;
error = 0;
- goto out;
+ break;
}
/* Not found. Append it to the tail. */
- acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_SINGLE_PATH_ACL);
- if (!acl)
- goto out;
- acl->perm = perm;
- if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL))
- acl->perm |= rw_mask;
- acl->filename = saved_filename;
- list_add_tail(&acl->head.list, &domain->acl_info_list);
- error = 0;
+ if (error && tomoyo_memory_ok(new_entry)) {
+ new_entry->head.type = TOMOYO_TYPE_SINGLE_PATH_ACL;
+ new_entry->perm = perm;
+ if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL))
+ new_entry->perm |= rw_mask;
+ new_entry->filename = saved_filename;
+ list_add_tail(&new_entry->head.list, &domain->acl_info_list);
+ new_entry = NULL;
+ error = 0;
+ }
goto out;
delete:
- error = -ENOENT;
list_for_each_entry(ptr, &domain->acl_info_list, list) {
+ struct tomoyo_single_path_acl_record *acl;
if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
continue;
acl = container_of(ptr, struct tomoyo_single_path_acl_record,
@@ -801,6 +800,7 @@ static int tomoyo_update_single_path_acl
out:
up_write(&tomoyo_domain_acl_info_list_lock);
/***** EXCLUSIVE SECTION END *****/
+ kfree(new_entry);
return error;
}
@@ -823,8 +823,8 @@ static int tomoyo_update_double_path_acl
const struct tomoyo_path_info *saved_filename1;
const struct tomoyo_path_info *saved_filename2;
struct tomoyo_acl_info *ptr;
- struct tomoyo_double_path_acl_record *acl;
- int error = -ENOMEM;
+ struct tomoyo_double_path_acl_record *new_entry = NULL;
+ int error = is_delete ? -ENOENT : -ENOMEM;
const u8 perm = 1 << type;
if (!domain)
@@ -836,11 +836,14 @@ static int tomoyo_update_double_path_acl
saved_filename2 = tomoyo_save_name(filename2);
if (!saved_filename1 || !saved_filename2)
return -ENOMEM;
+ if (!is_delete)
+ new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
/***** EXCLUSIVE SECTION START *****/
down_write(&tomoyo_domain_acl_info_list_lock);
if (is_delete)
goto delete;
list_for_each_entry(ptr, &domain->acl_info_list, list) {
+ struct tomoyo_double_path_acl_record *acl;
if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
continue;
acl = container_of(ptr, struct tomoyo_double_path_acl_record,
@@ -854,21 +857,22 @@ static int tomoyo_update_double_path_acl
acl->perm |= perm;
ptr->type &= ~TOMOYO_ACL_DELETED;
error = 0;
- goto out;
+ break;
}
/* Not found. Append it to the tail. */
- acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_DOUBLE_PATH_ACL);
- if (!acl)
- goto out;
- acl->perm = perm;
- acl->filename1 = saved_filename1;
- acl->filename2 = saved_filename2;
- list_add_tail(&acl->head.list, &domain->acl_info_list);
- error = 0;
+ if (error && tomoyo_memory_ok(new_entry)) {
+ new_entry->head.type = TOMOYO_TYPE_DOUBLE_PATH_ACL;
+ new_entry->perm = perm;
+ new_entry->filename1 = saved_filename1;
+ new_entry->filename2 = saved_filename2;
+ list_add_tail(&new_entry->head.list, &domain->acl_info_list);
+ new_entry = NULL;
+ error = 0;
+ }
goto out;
delete:
- error = -ENOENT;
list_for_each_entry(ptr, &domain->acl_info_list, list) {
+ struct tomoyo_double_path_acl_record *acl;
if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
continue;
acl = container_of(ptr, struct tomoyo_double_path_acl_record,
@@ -885,6 +889,7 @@ static int tomoyo_update_double_path_acl
out:
up_write(&tomoyo_domain_acl_info_list_lock);
/***** EXCLUSIVE SECTION END *****/
+ kfree(new_entry);
return error;
}
--- security-testing-2.6.git.orig/security/tomoyo/realpath.c
+++ security-testing-2.6.git/security/tomoyo/realpath.c
@@ -195,68 +195,36 @@ char *tomoyo_realpath_nofollow(const cha
}
/* Memory allocated for non-string data. */
-static unsigned int tomoyo_allocated_memory_for_elements;
+static atomic_t tomoyo_allocated_memory_for_elements;
/* Quota for holding non-string data. */
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.
- *
- * Returns pointer to allocated memory on success, NULL otherwise.
+ * @ptr: Pointer to allocated memory.
*
- * Memory has to be zeroed.
- * The RAM is chunked, so NEVER try to kfree() the returned pointer.
+ * Returns true if @ptr is not NULL and quota not exceeded, false otehrwise.
*/
-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;
- /***** EXCLUSIVE SECTION START *****/
- 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';
- }
- }
- mutex_unlock(&lock);
- /***** EXCLUSIVE SECTION END *****/
- return ptr;
+ const int len = ptr ? ksize(ptr) : 0;
+ atomic_add(len, &tomoyo_allocated_memory_for_elements);
+ if (len && (!tomoyo_quota_for_elements ||
+ atomic_read(&tomoyo_allocated_memory_for_elements)
+ <= tomoyo_quota_for_elements)) {
+ memset(ptr, 0, len);
+ return true;
+ }
+ atomic_sub(len, &tomoyo_allocated_memory_for_elements);
+ printk(KERN_WARNING "ERROR: Out of memory. (%s)\n", __func__);
+ 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;
+static atomic_t tomoyo_allocated_memory_for_savename;
/* Quota for holding string data in bytes. */
static unsigned int tomoyo_quota_for_savename;
@@ -273,13 +241,6 @@ struct tomoyo_name_entry {
struct tomoyo_path_info entry;
};
-/* Structure for available memory region. */
-struct tomoyo_free_memory_block_list {
- struct list_head list;
- char *ptr; /* Pointer to a free area. */
- int len; /* Length of the area. */
-};
-
/*
* The list for "struct tomoyo_name_entry".
*
@@ -299,75 +260,57 @@ static struct list_head tomoyo_name_list
*/
const struct tomoyo_path_info *tomoyo_save_name(const char *name)
{
- static LIST_HEAD(fmb_list);
static DEFINE_MUTEX(lock);
+ struct tomoyo_name_entry *entry;
struct tomoyo_name_entry *ptr;
unsigned int hash;
- /* fmb contains available size in bytes.
- fmb is removed from the fmb_list when fmb->len becomes 0. */
- struct tomoyo_free_memory_block_list *fmb;
- int len;
- char *cp;
+ const int len = name ? strlen(name) + 1 : 0;
+ int allocated_len;
+ int error = -ENOMEM;
- if (!name)
+ if (!len)
return NULL;
- len = strlen(name) + 1;
if (len > TOMOYO_MAX_PATHNAME_LEN) {
- printk(KERN_WARNING "ERROR: Name too long "
- "for tomoyo_save_name().\n");
+ printk(KERN_WARNING "ERROR: Name too long. (%s)\n", __func__);
return NULL;
}
hash = full_name_hash((const unsigned char *) name, len - 1);
+ entry = kmalloc(sizeof(*entry) + len, GFP_KERNEL);
+ allocated_len = entry ? ksize(entry) : 0;
/***** EXCLUSIVE SECTION START *****/
mutex_lock(&lock);
list_for_each_entry(ptr, &tomoyo_name_list[hash % TOMOYO_MAX_HASH],
list) {
- if (hash == ptr->entry.hash && !strcmp(name, ptr->entry.name))
- goto out;
- }
- list_for_each_entry(fmb, &fmb_list, list) {
- if (len <= fmb->len)
- goto ready;
- }
- if (!tomoyo_quota_for_savename ||
- tomoyo_allocated_memory_for_savename + PATH_MAX
- <= tomoyo_quota_for_savename)
- cp = kzalloc(PATH_MAX, GFP_KERNEL);
- else
- cp = NULL;
- fmb = kzalloc(sizeof(*fmb), GFP_KERNEL);
- if (!cp || !fmb) {
- kfree(cp);
- kfree(fmb);
- printk(KERN_WARNING "ERROR: Out of memory "
- "for tomoyo_save_name().\n");
- if (!tomoyo_policy_loaded)
- panic("MAC Initialization failed.\n");
- ptr = NULL;
- goto out;
- }
- tomoyo_allocated_memory_for_savename += PATH_MAX;
- list_add(&fmb->list, &fmb_list);
- fmb->ptr = cp;
- fmb->len = PATH_MAX;
- ready:
- ptr = tomoyo_alloc_element(sizeof(*ptr));
- if (!ptr)
- goto out;
- ptr->entry.name = fmb->ptr;
- memmove(fmb->ptr, name, len);
- tomoyo_fill_path_info(&ptr->entry);
- fmb->ptr += len;
- fmb->len -= len;
- list_add_tail(&ptr->list, &tomoyo_name_list[hash % TOMOYO_MAX_HASH]);
- if (fmb->len == 0) {
- list_del(&fmb->list);
- kfree(fmb);
+ if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
+ continue;
+ error = 0;
+ break;
+ }
+ if (error && entry &&
+ (!tomoyo_quota_for_savename ||
+ atomic_read(&tomoyo_allocated_memory_for_savename) + allocated_len
+ <= tomoyo_quota_for_savename)) {
+ atomic_add(allocated_len,
+ &tomoyo_allocated_memory_for_savename);
+ ptr = entry;
+ memset(ptr, 0, sizeof(*ptr));
+ ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
+ memmove((char *) ptr->entry.name, name, len);
+ tomoyo_fill_path_info(&ptr->entry);
+ list_add_tail(&ptr->list,
+ &tomoyo_name_list[hash % TOMOYO_MAX_HASH]);
+ entry = NULL;
+ error = 0;
}
- out:
mutex_unlock(&lock);
/***** EXCLUSIVE SECTION END *****/
- return ptr ? &ptr->entry : NULL;
+ kfree(entry);
+ if (!error)
+ return &ptr->entry;
+ printk(KERN_WARNING "ERROR: Out of memory. (%s)\n", __func__);
+ if (!tomoyo_policy_loaded)
+ panic("MAC Initialization failed.\n");
+ return NULL;
}
/**
@@ -433,9 +376,9 @@ int tomoyo_read_memory_counter(struct to
{
if (!head->read_eof) {
const unsigned int shared
- = tomoyo_allocated_memory_for_savename;
+ = atomic_read(&tomoyo_allocated_memory_for_savename);
const unsigned int private
- = tomoyo_allocated_memory_for_elements;
+ = atomic_read(&tomoyo_allocated_memory_for_elements);
const unsigned int dynamic
= atomic_read(&tomoyo_dynamic_memory_size);
char buffer[64];
--- security-testing-2.6.git.orig/security/tomoyo/realpath.h
+++ security-testing-2.6.git/security/tomoyo/realpath.h
@@ -36,11 +36,8 @@ char *tomoyo_realpath_nofollow(const cha
/* 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.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists