Commit 9e4b50e9 authored by Tetsuo Handa's avatar Tetsuo Handa Committed by James Morris

TOMOYO: Use stack memory for pending entry.

Use stack memory for pending entry to reduce kmalloc() which will be kfree()d.
Signed-off-by: default avatarTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: default avatarJames Morris <jmorris@namei.org>
parent 83c36ccf
...@@ -1071,46 +1071,42 @@ LIST_HEAD(tomoyo_policy_manager_list); ...@@ -1071,46 +1071,42 @@ LIST_HEAD(tomoyo_policy_manager_list);
static int tomoyo_update_manager_entry(const char *manager, static int tomoyo_update_manager_entry(const char *manager,
const bool is_delete) const bool is_delete)
{ {
struct tomoyo_policy_manager_entry *entry = NULL;
struct tomoyo_policy_manager_entry *ptr; struct tomoyo_policy_manager_entry *ptr;
const struct tomoyo_path_info *saved_manager; struct tomoyo_policy_manager_entry e = { };
int error = is_delete ? -ENOENT : -ENOMEM; int error = is_delete ? -ENOENT : -ENOMEM;
bool is_domain = false;
if (tomoyo_is_domain_def(manager)) { if (tomoyo_is_domain_def(manager)) {
if (!tomoyo_is_correct_domain(manager)) if (!tomoyo_is_correct_domain(manager))
return -EINVAL; return -EINVAL;
is_domain = true; e.is_domain = true;
} else { } else {
if (!tomoyo_is_correct_path(manager, 1, -1, -1)) if (!tomoyo_is_correct_path(manager, 1, -1, -1))
return -EINVAL; return -EINVAL;
} }
saved_manager = tomoyo_get_name(manager); e.manager = tomoyo_get_name(manager);
if (!saved_manager) if (!e.manager)
return -ENOMEM; return -ENOMEM;
if (!is_delete)
entry = kmalloc(sizeof(*entry), GFP_NOFS);
if (mutex_lock_interruptible(&tomoyo_policy_lock)) if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out; goto out;
list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) { list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
if (ptr->manager != saved_manager) if (ptr->manager != e.manager)
continue; continue;
ptr->is_deleted = is_delete; ptr->is_deleted = is_delete;
error = 0; error = 0;
break; break;
} }
if (!is_delete && error && tomoyo_memory_ok(entry)) { if (!is_delete && error) {
entry->manager = saved_manager; struct tomoyo_policy_manager_entry *entry =
saved_manager = NULL; tomoyo_commit_ok(&e, sizeof(e));
entry->is_domain = is_domain; if (entry) {
list_add_tail_rcu(&entry->list, &tomoyo_policy_manager_list); list_add_tail_rcu(&entry->list,
entry = NULL; &tomoyo_policy_manager_list);
error = 0; error = 0;
}
} }
mutex_unlock(&tomoyo_policy_lock); mutex_unlock(&tomoyo_policy_lock);
out: out:
tomoyo_put_name(saved_manager); tomoyo_put_name(e.manager);
kfree(entry);
return error; return error;
} }
......
...@@ -616,6 +616,7 @@ char *tomoyo_realpath_from_path(struct path *path); ...@@ -616,6 +616,7 @@ char *tomoyo_realpath_from_path(struct path *path);
/* Check memory quota. */ /* Check memory quota. */
bool tomoyo_memory_ok(void *ptr); bool tomoyo_memory_ok(void *ptr);
void *tomoyo_commit_ok(void *data, const unsigned int size);
/* /*
* Keep the given name on the RAM. * Keep the given name on the RAM.
...@@ -735,6 +736,31 @@ static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct ...@@ -735,6 +736,31 @@ static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct
return task_cred_xxx(task, security); return task_cred_xxx(task, security);
} }
static inline bool tomoyo_is_same_domain_initializer_entry
(const struct tomoyo_domain_initializer_entry *p1,
const struct tomoyo_domain_initializer_entry *p2)
{
return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name
&& p1->domainname == p2->domainname
&& p1->program == p2->program;
}
static inline bool tomoyo_is_same_domain_keeper_entry
(const struct tomoyo_domain_keeper_entry *p1,
const struct tomoyo_domain_keeper_entry *p2)
{
return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name
&& p1->domainname == p2->domainname
&& p1->program == p2->program;
}
static inline bool tomoyo_is_same_alias_entry
(const struct tomoyo_alias_entry *p1, const struct tomoyo_alias_entry *p2)
{
return p1->original_name == p2->original_name &&
p1->aliased_name == p2->aliased_name;
}
/** /**
* list_for_each_cookie - iterate over a list with cookie. * list_for_each_cookie - iterate over a list with cookie.
* @pos: the &struct list_head to use as a loop cursor. * @pos: the &struct list_head to use as a loop cursor.
......
...@@ -130,58 +130,47 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, ...@@ -130,58 +130,47 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname,
const bool is_not, const bool is_not,
const bool is_delete) const bool is_delete)
{ {
struct tomoyo_domain_initializer_entry *entry = NULL;
struct tomoyo_domain_initializer_entry *ptr; struct tomoyo_domain_initializer_entry *ptr;
const struct tomoyo_path_info *saved_program = NULL; struct tomoyo_domain_initializer_entry e = { .is_not = is_not };
const struct tomoyo_path_info *saved_domainname = NULL;
int error = is_delete ? -ENOENT : -ENOMEM; int error = is_delete ? -ENOENT : -ENOMEM;
bool is_last_name = false;
if (!tomoyo_is_correct_path(program, 1, -1, -1)) if (!tomoyo_is_correct_path(program, 1, -1, -1))
return -EINVAL; /* No patterns allowed. */ return -EINVAL; /* No patterns allowed. */
if (domainname) { if (domainname) {
if (!tomoyo_is_domain_def(domainname) && if (!tomoyo_is_domain_def(domainname) &&
tomoyo_is_correct_path(domainname, 1, -1, -1)) tomoyo_is_correct_path(domainname, 1, -1, -1))
is_last_name = true; e.is_last_name = true;
else if (!tomoyo_is_correct_domain(domainname)) else if (!tomoyo_is_correct_domain(domainname))
return -EINVAL; return -EINVAL;
saved_domainname = tomoyo_get_name(domainname); e.domainname = tomoyo_get_name(domainname);
if (!saved_domainname) if (!e.domainname)
goto out; goto out;
} }
saved_program = tomoyo_get_name(program); e.program = tomoyo_get_name(program);
if (!saved_program) if (!e.program)
goto out; goto out;
if (!is_delete)
entry = kmalloc(sizeof(*entry), GFP_NOFS);
if (mutex_lock_interruptible(&tomoyo_policy_lock)) if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out; goto out;
list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) { list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
if (ptr->is_not != is_not || if (!tomoyo_is_same_domain_initializer_entry(ptr, &e))
ptr->domainname != saved_domainname ||
ptr->program != saved_program)
continue; continue;
ptr->is_deleted = is_delete; ptr->is_deleted = is_delete;
error = 0; error = 0;
break; break;
} }
if (!is_delete && error && tomoyo_memory_ok(entry)) { if (!is_delete && error) {
entry->domainname = saved_domainname; struct tomoyo_domain_initializer_entry *entry =
saved_domainname = NULL; tomoyo_commit_ok(&e, sizeof(e));
entry->program = saved_program; if (entry) {
saved_program = NULL; list_add_tail_rcu(&entry->list,
entry->is_not = is_not; &tomoyo_domain_initializer_list);
entry->is_last_name = is_last_name; error = 0;
list_add_tail_rcu(&entry->list, }
&tomoyo_domain_initializer_list);
entry = NULL;
error = 0;
} }
mutex_unlock(&tomoyo_policy_lock); mutex_unlock(&tomoyo_policy_lock);
out: out:
tomoyo_put_name(saved_domainname); tomoyo_put_name(e.domainname);
tomoyo_put_name(saved_program); tomoyo_put_name(e.program);
kfree(entry);
return error; return error;
} }
...@@ -351,57 +340,47 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, ...@@ -351,57 +340,47 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname,
const bool is_not, const bool is_not,
const bool is_delete) const bool is_delete)
{ {
struct tomoyo_domain_keeper_entry *entry = NULL;
struct tomoyo_domain_keeper_entry *ptr; struct tomoyo_domain_keeper_entry *ptr;
const struct tomoyo_path_info *saved_domainname = NULL; struct tomoyo_domain_keeper_entry e = { .is_not = is_not };
const struct tomoyo_path_info *saved_program = NULL;
int error = is_delete ? -ENOENT : -ENOMEM; int error = is_delete ? -ENOENT : -ENOMEM;
bool is_last_name = false;
if (!tomoyo_is_domain_def(domainname) && if (!tomoyo_is_domain_def(domainname) &&
tomoyo_is_correct_path(domainname, 1, -1, -1)) tomoyo_is_correct_path(domainname, 1, -1, -1))
is_last_name = true; e.is_last_name = true;
else if (!tomoyo_is_correct_domain(domainname)) else if (!tomoyo_is_correct_domain(domainname))
return -EINVAL; return -EINVAL;
if (program) { if (program) {
if (!tomoyo_is_correct_path(program, 1, -1, -1)) if (!tomoyo_is_correct_path(program, 1, -1, -1))
return -EINVAL; return -EINVAL;
saved_program = tomoyo_get_name(program); e.program = tomoyo_get_name(program);
if (!saved_program) if (!e.program)
goto out; goto out;
} }
saved_domainname = tomoyo_get_name(domainname); e.domainname = tomoyo_get_name(domainname);
if (!saved_domainname) if (!e.domainname)
goto out; goto out;
if (!is_delete)
entry = kmalloc(sizeof(*entry), GFP_NOFS);
if (mutex_lock_interruptible(&tomoyo_policy_lock)) if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out; goto out;
list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
if (ptr->is_not != is_not || if (!tomoyo_is_same_domain_keeper_entry(ptr, &e))
ptr->domainname != saved_domainname ||
ptr->program != saved_program)
continue; continue;
ptr->is_deleted = is_delete; ptr->is_deleted = is_delete;
error = 0; error = 0;
break; break;
} }
if (!is_delete && error && tomoyo_memory_ok(entry)) { if (!is_delete && error) {
entry->domainname = saved_domainname; struct tomoyo_domain_keeper_entry *entry =
saved_domainname = NULL; tomoyo_commit_ok(&e, sizeof(e));
entry->program = saved_program; if (entry) {
saved_program = NULL; list_add_tail_rcu(&entry->list,
entry->is_not = is_not; &tomoyo_domain_keeper_list);
entry->is_last_name = is_last_name; error = 0;
list_add_tail_rcu(&entry->list, &tomoyo_domain_keeper_list); }
entry = NULL;
error = 0;
} }
mutex_unlock(&tomoyo_policy_lock); mutex_unlock(&tomoyo_policy_lock);
out: out:
tomoyo_put_name(saved_domainname); tomoyo_put_name(e.domainname);
tomoyo_put_name(saved_program); tomoyo_put_name(e.program);
kfree(entry);
return error; return error;
} }
...@@ -553,45 +532,38 @@ static int tomoyo_update_alias_entry(const char *original_name, ...@@ -553,45 +532,38 @@ static int tomoyo_update_alias_entry(const char *original_name,
const char *aliased_name, const char *aliased_name,
const bool is_delete) const bool is_delete)
{ {
struct tomoyo_alias_entry *entry = NULL;
struct tomoyo_alias_entry *ptr; struct tomoyo_alias_entry *ptr;
const struct tomoyo_path_info *saved_original_name; struct tomoyo_alias_entry e = { };
const struct tomoyo_path_info *saved_aliased_name;
int error = is_delete ? -ENOENT : -ENOMEM; int error = is_delete ? -ENOENT : -ENOMEM;
if (!tomoyo_is_correct_path(original_name, 1, -1, -1) || if (!tomoyo_is_correct_path(original_name, 1, -1, -1) ||
!tomoyo_is_correct_path(aliased_name, 1, -1, -1)) !tomoyo_is_correct_path(aliased_name, 1, -1, -1))
return -EINVAL; /* No patterns allowed. */ return -EINVAL; /* No patterns allowed. */
saved_original_name = tomoyo_get_name(original_name); e.original_name = tomoyo_get_name(original_name);
saved_aliased_name = tomoyo_get_name(aliased_name); e.aliased_name = tomoyo_get_name(aliased_name);
if (!saved_original_name || !saved_aliased_name) if (!e.original_name || !e.aliased_name)
goto out; goto out;
if (!is_delete)
entry = kmalloc(sizeof(*entry), GFP_NOFS);
if (mutex_lock_interruptible(&tomoyo_policy_lock)) if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out; goto out;
list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
if (ptr->original_name != saved_original_name || if (!tomoyo_is_same_alias_entry(ptr, &e))
ptr->aliased_name != saved_aliased_name)
continue; continue;
ptr->is_deleted = is_delete; ptr->is_deleted = is_delete;
error = 0; error = 0;
break; break;
} }
if (!is_delete && error && tomoyo_memory_ok(entry)) { if (!is_delete && error) {
entry->original_name = saved_original_name; struct tomoyo_alias_entry *entry =
saved_original_name = NULL; tomoyo_commit_ok(&e, sizeof(e));
entry->aliased_name = saved_aliased_name; if (entry) {
saved_aliased_name = NULL; list_add_tail_rcu(&entry->list, &tomoyo_alias_list);
list_add_tail_rcu(&entry->list, &tomoyo_alias_list); error = 0;
entry = NULL; }
error = 0;
} }
mutex_unlock(&tomoyo_policy_lock); mutex_unlock(&tomoyo_policy_lock);
out: out:
tomoyo_put_name(saved_original_name); tomoyo_put_name(e.original_name);
tomoyo_put_name(saved_aliased_name); tomoyo_put_name(e.aliased_name);
kfree(entry);
return error; return error;
} }
......
...@@ -164,38 +164,36 @@ LIST_HEAD(tomoyo_globally_readable_list); ...@@ -164,38 +164,36 @@ LIST_HEAD(tomoyo_globally_readable_list);
static int tomoyo_update_globally_readable_entry(const char *filename, static int tomoyo_update_globally_readable_entry(const char *filename,
const bool is_delete) const bool is_delete)
{ {
struct tomoyo_globally_readable_file_entry *entry = NULL;
struct tomoyo_globally_readable_file_entry *ptr; struct tomoyo_globally_readable_file_entry *ptr;
const struct tomoyo_path_info *saved_filename; struct tomoyo_globally_readable_file_entry e = { };
int error = is_delete ? -ENOENT : -ENOMEM; int error = is_delete ? -ENOENT : -ENOMEM;
if (!tomoyo_is_correct_path(filename, 1, 0, -1)) if (!tomoyo_is_correct_path(filename, 1, 0, -1))
return -EINVAL; return -EINVAL;
saved_filename = tomoyo_get_name(filename); e.filename = tomoyo_get_name(filename);
if (!saved_filename) if (!e.filename)
return -ENOMEM; return -ENOMEM;
if (!is_delete)
entry = kmalloc(sizeof(*entry), GFP_NOFS);
if (mutex_lock_interruptible(&tomoyo_policy_lock)) if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out; goto out;
list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) {
if (ptr->filename != saved_filename) if (ptr->filename != e.filename)
continue; continue;
ptr->is_deleted = is_delete; ptr->is_deleted = is_delete;
error = 0; error = 0;
break; break;
} }
if (!is_delete && error && tomoyo_memory_ok(entry)) { if (!is_delete && error) {
entry->filename = saved_filename; struct tomoyo_globally_readable_file_entry *entry =
saved_filename = NULL; tomoyo_commit_ok(&e, sizeof(e));
list_add_tail_rcu(&entry->list, &tomoyo_globally_readable_list); if (entry) {
entry = NULL; list_add_tail_rcu(&entry->list,
error = 0; &tomoyo_globally_readable_list);
error = 0;
}
} }
mutex_unlock(&tomoyo_policy_lock); mutex_unlock(&tomoyo_policy_lock);
out: out:
tomoyo_put_name(saved_filename); tomoyo_put_name(e.filename);
kfree(entry);
return error; return error;
} }
...@@ -313,38 +311,34 @@ LIST_HEAD(tomoyo_pattern_list); ...@@ -313,38 +311,34 @@ LIST_HEAD(tomoyo_pattern_list);
static int tomoyo_update_file_pattern_entry(const char *pattern, static int tomoyo_update_file_pattern_entry(const char *pattern,
const bool is_delete) const bool is_delete)
{ {
struct tomoyo_pattern_entry *entry = NULL;
struct tomoyo_pattern_entry *ptr; struct tomoyo_pattern_entry *ptr;
const struct tomoyo_path_info *saved_pattern; struct tomoyo_pattern_entry e = { .pattern = tomoyo_get_name(pattern) };
int error = is_delete ? -ENOENT : -ENOMEM; int error = is_delete ? -ENOENT : -ENOMEM;
saved_pattern = tomoyo_get_name(pattern); if (!e.pattern)
if (!saved_pattern)
return error; return error;
if (!saved_pattern->is_patterned) if (!e.pattern->is_patterned)
goto out; goto out;
if (!is_delete)
entry = kmalloc(sizeof(*entry), GFP_NOFS);
if (mutex_lock_interruptible(&tomoyo_policy_lock)) if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out; goto out;
list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
if (saved_pattern != ptr->pattern) if (e.pattern != ptr->pattern)
continue; continue;
ptr->is_deleted = is_delete; ptr->is_deleted = is_delete;
error = 0; error = 0;
break; break;
} }
if (!is_delete && error && tomoyo_memory_ok(entry)) { if (!is_delete && error) {
entry->pattern = saved_pattern; struct tomoyo_pattern_entry *entry =
saved_pattern = NULL; tomoyo_commit_ok(&e, sizeof(e));
list_add_tail_rcu(&entry->list, &tomoyo_pattern_list); if (entry) {
entry = NULL; list_add_tail_rcu(&entry->list, &tomoyo_pattern_list);
error = 0; error = 0;
}
} }
mutex_unlock(&tomoyo_policy_lock); mutex_unlock(&tomoyo_policy_lock);
out: out:
kfree(entry); tomoyo_put_name(e.pattern);
tomoyo_put_name(saved_pattern);
return error; return error;
} }
...@@ -467,38 +461,36 @@ LIST_HEAD(tomoyo_no_rewrite_list); ...@@ -467,38 +461,36 @@ LIST_HEAD(tomoyo_no_rewrite_list);
static int tomoyo_update_no_rewrite_entry(const char *pattern, static int tomoyo_update_no_rewrite_entry(const char *pattern,
const bool is_delete) const bool is_delete)
{ {
struct tomoyo_no_rewrite_entry *entry = NULL;
struct tomoyo_no_rewrite_entry *ptr; struct tomoyo_no_rewrite_entry *ptr;
const struct tomoyo_path_info *saved_pattern; struct tomoyo_no_rewrite_entry e = { };
int error = is_delete ? -ENOENT : -ENOMEM; int error = is_delete ? -ENOENT : -ENOMEM;
if (!tomoyo_is_correct_path(pattern, 0, 0, 0)) if (!tomoyo_is_correct_path(pattern, 0, 0, 0))
return -EINVAL; return -EINVAL;
saved_pattern = tomoyo_get_name(pattern); e.pattern = tomoyo_get_name(pattern);
if (!saved_pattern) if (!e.pattern)
return error; return error;
if (!is_delete)
entry = kmalloc(sizeof(*entry), GFP_NOFS);
if (mutex_lock_interruptible(&tomoyo_policy_lock)) if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out; goto out;
list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
if (ptr->pattern != saved_pattern) if (ptr->pattern != e.pattern)
continue; continue;
ptr->is_deleted = is_delete; ptr->is_deleted = is_delete;
error = 0; error = 0;
break; break;
} }
if (!is_delete && error && tomoyo_memory_ok(entry)) { if (!is_delete && error) {
entry->pattern = saved_pattern; struct tomoyo_no_rewrite_entry *entry =
saved_pattern = NULL; tomoyo_commit_ok(&e, sizeof(e));
list_add_tail_rcu(&entry->list, &tomoyo_no_rewrite_list); if (entry) {
entry = NULL; list_add_tail_rcu(&entry->list,
error = 0; &tomoyo_no_rewrite_list);
error = 0;
}
} }
mutex_unlock(&tomoyo_policy_lock); mutex_unlock(&tomoyo_policy_lock);
out: out:
tomoyo_put_name(saved_pattern); tomoyo_put_name(e.pattern);
kfree(entry);
return error; return error;
} }
...@@ -810,23 +802,26 @@ static int tomoyo_update_path_acl(const u8 type, const char *filename, ...@@ -810,23 +802,26 @@ static int tomoyo_update_path_acl(const u8 type, const char *filename,
struct tomoyo_domain_info *const domain, struct tomoyo_domain_info *const domain,
const bool is_delete) const bool is_delete)
{ {
static const u32 rw_mask = static const u32 tomoyo_rw_mask =
(1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE); (1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE);
const struct tomoyo_path_info *saved_filename; const u32 perm = 1 << type;
struct tomoyo_acl_info *ptr; struct tomoyo_acl_info *ptr;
struct tomoyo_path_acl *entry = NULL; struct tomoyo_path_acl e = {
.head.type = TOMOYO_TYPE_PATH_ACL,
.perm_high = perm >> 16,
.perm = perm
};
int error = is_delete ? -ENOENT : -ENOMEM; int error = is_delete ? -ENOENT : -ENOMEM;
const u32 perm = 1 << type;
if (type == TOMOYO_TYPE_READ_WRITE)
e.perm |= tomoyo_rw_mask;
if (!domain) if (!domain)
return -EINVAL; return -EINVAL;
if (!tomoyo_is_correct_path(filename, 0, 0, 0)) if (!tomoyo_is_correct_path(filename, 0, 0, 0))
return -EINVAL;