TOMOYO: Use RCU primitives for list operation

Replace list operation with RCU primitives and replace
down_read()/up_read() with srcu_read_lock()/srcu_read_unlock().

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>
This commit is contained in:
Tetsuo Handa 2009-12-08 09:34:43 +09:00 committed by James Morris
parent 86fc80f16e
commit fdb8ebb729
6 changed files with 207 additions and 112 deletions

View File

@ -365,10 +365,9 @@ bool tomoyo_is_domain_def(const unsigned char *buffer)
* *
* @domainname: The domainname to find. * @domainname: The domainname to find.
* *
* Caller must call down_read(&tomoyo_domain_list_lock); or
* down_write(&tomoyo_domain_list_lock); .
*
* Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise. * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname) struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
{ {
@ -377,7 +376,7 @@ struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
name.name = domainname; name.name = domainname;
tomoyo_fill_path_info(&name); tomoyo_fill_path_info(&name);
list_for_each_entry(domain, &tomoyo_domain_list, list) { list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
if (!domain->is_deleted && if (!domain->is_deleted &&
!tomoyo_pathcmp(&name, domain->domainname)) !tomoyo_pathcmp(&name, domain->domainname))
return domain; return domain;
@ -829,6 +828,8 @@ bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain)
* @domain: Pointer to "struct tomoyo_domain_info". * @domain: Pointer to "struct tomoyo_domain_info".
* *
* Returns true if the domain is not exceeded quota, false otherwise. * Returns true if the domain is not exceeded quota, false otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain) bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain)
{ {
@ -837,8 +838,7 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain)
if (!domain) if (!domain)
return true; return true;
down_read(&tomoyo_domain_acl_info_list_lock); list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
list_for_each_entry(ptr, &domain->acl_info_list, list) {
if (ptr->type & TOMOYO_ACL_DELETED) if (ptr->type & TOMOYO_ACL_DELETED)
continue; continue;
switch (tomoyo_acl_type2(ptr)) { switch (tomoyo_acl_type2(ptr)) {
@ -866,7 +866,6 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain)
break; break;
} }
} }
up_read(&tomoyo_domain_acl_info_list_lock);
if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY)) if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY))
return true; return true;
if (!domain->quota_warned) { if (!domain->quota_warned) {
@ -1096,6 +1095,8 @@ static DECLARE_RWSEM(tomoyo_policy_manager_list_lock);
* @is_delete: True if it is a delete request. * @is_delete: True if it is a delete request.
* *
* Returns 0 on success, negative value otherwise. * Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
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)
@ -1118,7 +1119,7 @@ static int tomoyo_update_manager_entry(const char *manager,
if (!saved_manager) if (!saved_manager)
return -ENOMEM; return -ENOMEM;
down_write(&tomoyo_policy_manager_list_lock); down_write(&tomoyo_policy_manager_list_lock);
list_for_each_entry(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 != saved_manager)
continue; continue;
ptr->is_deleted = is_delete; ptr->is_deleted = is_delete;
@ -1134,7 +1135,7 @@ static int tomoyo_update_manager_entry(const char *manager,
goto out; goto out;
new_entry->manager = saved_manager; new_entry->manager = saved_manager;
new_entry->is_domain = is_domain; new_entry->is_domain = is_domain;
list_add_tail(&new_entry->list, &tomoyo_policy_manager_list); list_add_tail_rcu(&new_entry->list, &tomoyo_policy_manager_list);
error = 0; error = 0;
out: out:
up_write(&tomoyo_policy_manager_list_lock); up_write(&tomoyo_policy_manager_list_lock);
@ -1147,6 +1148,8 @@ static int tomoyo_update_manager_entry(const char *manager,
* @head: Pointer to "struct tomoyo_io_buffer". * @head: Pointer to "struct tomoyo_io_buffer".
* *
* Returns 0 on success, negative value otherwise. * Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head) static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head)
{ {
@ -1166,6 +1169,8 @@ static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head)
* @head: Pointer to "struct tomoyo_io_buffer". * @head: Pointer to "struct tomoyo_io_buffer".
* *
* Returns 0. * Returns 0.
*
* Caller holds tomoyo_read_lock().
*/ */
static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head) static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head)
{ {
@ -1174,7 +1179,6 @@ static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head)
if (head->read_eof) if (head->read_eof)
return 0; return 0;
down_read(&tomoyo_policy_manager_list_lock);
list_for_each_cookie(pos, head->read_var2, list_for_each_cookie(pos, head->read_var2,
&tomoyo_policy_manager_list) { &tomoyo_policy_manager_list) {
struct tomoyo_policy_manager_entry *ptr; struct tomoyo_policy_manager_entry *ptr;
@ -1186,7 +1190,6 @@ static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head)
if (!done) if (!done)
break; break;
} }
up_read(&tomoyo_policy_manager_list_lock);
head->read_eof = done; head->read_eof = done;
return 0; return 0;
} }
@ -1196,6 +1199,8 @@ static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head)
* *
* Returns true if the current process is permitted to modify policy * Returns true if the current process is permitted to modify policy
* via /sys/kernel/security/tomoyo/ interface. * via /sys/kernel/security/tomoyo/ interface.
*
* Caller holds tomoyo_read_lock().
*/ */
static bool tomoyo_is_policy_manager(void) static bool tomoyo_is_policy_manager(void)
{ {
@ -1209,29 +1214,25 @@ static bool tomoyo_is_policy_manager(void)
return true; return true;
if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid)) if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid))
return false; return false;
down_read(&tomoyo_policy_manager_list_lock); list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
if (!ptr->is_deleted && ptr->is_domain if (!ptr->is_deleted && ptr->is_domain
&& !tomoyo_pathcmp(domainname, ptr->manager)) { && !tomoyo_pathcmp(domainname, ptr->manager)) {
found = true; found = true;
break; break;
} }
} }
up_read(&tomoyo_policy_manager_list_lock);
if (found) if (found)
return true; return true;
exe = tomoyo_get_exe(); exe = tomoyo_get_exe();
if (!exe) if (!exe)
return false; return false;
down_read(&tomoyo_policy_manager_list_lock); list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
if (!ptr->is_deleted && !ptr->is_domain if (!ptr->is_deleted && !ptr->is_domain
&& !strcmp(exe, ptr->manager->name)) { && !strcmp(exe, ptr->manager->name)) {
found = true; found = true;
break; break;
} }
} }
up_read(&tomoyo_policy_manager_list_lock);
if (!found) { /* Reduce error messages. */ if (!found) { /* Reduce error messages. */
static pid_t last_pid; static pid_t last_pid;
const pid_t pid = current->pid; const pid_t pid = current->pid;
@ -1252,6 +1253,8 @@ static bool tomoyo_is_policy_manager(void)
* @data: String to parse. * @data: String to parse.
* *
* Returns true on success, false otherwise. * Returns true on success, false otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
const char *data) const char *data)
@ -1267,11 +1270,8 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
domain = tomoyo_real_domain(p); domain = tomoyo_real_domain(p);
read_unlock(&tasklist_lock); read_unlock(&tasklist_lock);
} else if (!strncmp(data, "domain=", 7)) { } else if (!strncmp(data, "domain=", 7)) {
if (tomoyo_is_domain_def(data + 7)) { if (tomoyo_is_domain_def(data + 7))
down_read(&tomoyo_domain_list_lock);
domain = tomoyo_find_domain(data + 7); domain = tomoyo_find_domain(data + 7);
up_read(&tomoyo_domain_list_lock);
}
} else } else
return false; return false;
head->write_var1 = domain; head->write_var1 = domain;
@ -1285,13 +1285,11 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
if (domain) { if (domain) {
struct tomoyo_domain_info *d; struct tomoyo_domain_info *d;
head->read_var1 = NULL; head->read_var1 = NULL;
down_read(&tomoyo_domain_list_lock); list_for_each_entry_rcu(d, &tomoyo_domain_list, list) {
list_for_each_entry(d, &tomoyo_domain_list, list) {
if (d == domain) if (d == domain)
break; break;
head->read_var1 = &d->list; head->read_var1 = &d->list;
} }
up_read(&tomoyo_domain_list_lock);
head->read_var2 = NULL; head->read_var2 = NULL;
head->read_bit = 0; head->read_bit = 0;
head->read_step = 0; head->read_step = 0;
@ -1307,6 +1305,8 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
* @domainname: The name of domain. * @domainname: The name of domain.
* *
* Returns 0. * Returns 0.
*
* Caller holds tomoyo_read_lock().
*/ */
static int tomoyo_delete_domain(char *domainname) static int tomoyo_delete_domain(char *domainname)
{ {
@ -1317,7 +1317,7 @@ static int tomoyo_delete_domain(char *domainname)
tomoyo_fill_path_info(&name); tomoyo_fill_path_info(&name);
down_write(&tomoyo_domain_list_lock); down_write(&tomoyo_domain_list_lock);
/* Is there an active domain? */ /* Is there an active domain? */
list_for_each_entry(domain, &tomoyo_domain_list, list) { list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
/* Never delete tomoyo_kernel_domain */ /* Never delete tomoyo_kernel_domain */
if (domain == &tomoyo_kernel_domain) if (domain == &tomoyo_kernel_domain)
continue; continue;
@ -1337,6 +1337,8 @@ static int tomoyo_delete_domain(char *domainname)
* @head: Pointer to "struct tomoyo_io_buffer". * @head: Pointer to "struct tomoyo_io_buffer".
* *
* Returns 0 on success, negative value otherwise. * Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head) static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head)
{ {
@ -1359,11 +1361,9 @@ static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head)
domain = NULL; domain = NULL;
if (is_delete) if (is_delete)
tomoyo_delete_domain(data); tomoyo_delete_domain(data);
else if (is_select) { else if (is_select)
down_read(&tomoyo_domain_list_lock);
domain = tomoyo_find_domain(data); domain = tomoyo_find_domain(data);
up_read(&tomoyo_domain_list_lock); else
} else
domain = tomoyo_find_or_assign_new_domain(data, 0); domain = tomoyo_find_or_assign_new_domain(data, 0);
head->write_var1 = domain; head->write_var1 = domain;
return 0; return 0;
@ -1508,6 +1508,8 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
* @head: Pointer to "struct tomoyo_io_buffer". * @head: Pointer to "struct tomoyo_io_buffer".
* *
* Returns 0. * Returns 0.
*
* Caller holds tomoyo_read_lock().
*/ */
static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head) static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head)
{ {
@ -1519,7 +1521,6 @@ static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head)
return 0; return 0;
if (head->read_step == 0) if (head->read_step == 0)
head->read_step = 1; head->read_step = 1;
down_read(&tomoyo_domain_list_lock);
list_for_each_cookie(dpos, head->read_var1, &tomoyo_domain_list) { list_for_each_cookie(dpos, head->read_var1, &tomoyo_domain_list) {
struct tomoyo_domain_info *domain; struct tomoyo_domain_info *domain;
const char *quota_exceeded = ""; const char *quota_exceeded = "";
@ -1552,7 +1553,6 @@ acl_loop:
if (head->read_step == 3) if (head->read_step == 3)
goto tail_mark; goto tail_mark;
/* Print ACL entries in the domain. */ /* Print ACL entries in the domain. */
down_read(&tomoyo_domain_acl_info_list_lock);
list_for_each_cookie(apos, head->read_var2, list_for_each_cookie(apos, head->read_var2,
&domain->acl_info_list) { &domain->acl_info_list) {
struct tomoyo_acl_info *ptr struct tomoyo_acl_info *ptr
@ -1562,7 +1562,6 @@ acl_loop:
if (!done) if (!done)
break; break;
} }
up_read(&tomoyo_domain_acl_info_list_lock);
if (!done) if (!done)
break; break;
head->read_step = 3; head->read_step = 3;
@ -1574,7 +1573,6 @@ tail_mark:
if (head->read_single_domain) if (head->read_single_domain)
break; break;
} }
up_read(&tomoyo_domain_list_lock);
head->read_eof = done; head->read_eof = done;
return 0; return 0;
} }
@ -1590,6 +1588,8 @@ tail_mark:
* *
* ( echo "select " $domainname; echo "use_profile " $profile ) | * ( echo "select " $domainname; echo "use_profile " $profile ) |
* /usr/lib/ccs/loadpolicy -d * /usr/lib/ccs/loadpolicy -d
*
* Caller holds tomoyo_read_lock().
*/ */
static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head) static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head)
{ {
@ -1601,9 +1601,7 @@ static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head)
if (!cp) if (!cp)
return -EINVAL; return -EINVAL;
*cp = '\0'; *cp = '\0';
down_read(&tomoyo_domain_list_lock);
domain = tomoyo_find_domain(cp + 1); domain = tomoyo_find_domain(cp + 1);
up_read(&tomoyo_domain_list_lock);
if (strict_strtoul(data, 10, &profile)) if (strict_strtoul(data, 10, &profile))
return -EINVAL; return -EINVAL;
if (domain && profile < TOMOYO_MAX_PROFILES if (domain && profile < TOMOYO_MAX_PROFILES
@ -1625,6 +1623,8 @@ static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head)
* awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" ) * awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" )
* domainname = $0; } else if ( $1 == "use_profile" ) { * domainname = $0; } else if ( $1 == "use_profile" ) {
* print $2 " " domainname; domainname = ""; } } ; ' * print $2 " " domainname; domainname = ""; } } ; '
*
* Caller holds tomoyo_read_lock().
*/ */
static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head) static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
{ {
@ -1633,7 +1633,6 @@ static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
if (head->read_eof) if (head->read_eof)
return 0; return 0;
down_read(&tomoyo_domain_list_lock);
list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) { list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) {
struct tomoyo_domain_info *domain; struct tomoyo_domain_info *domain;
domain = list_entry(pos, struct tomoyo_domain_info, list); domain = list_entry(pos, struct tomoyo_domain_info, list);
@ -1644,7 +1643,6 @@ static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
if (!done) if (!done)
break; break;
} }
up_read(&tomoyo_domain_list_lock);
head->read_eof = done; head->read_eof = done;
return 0; return 0;
} }
@ -1701,6 +1699,8 @@ static int tomoyo_read_pid(struct tomoyo_io_buffer *head)
* @head: Pointer to "struct tomoyo_io_buffer". * @head: Pointer to "struct tomoyo_io_buffer".
* *
* Returns 0 on success, negative value otherwise. * Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head) static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head)
{ {
@ -1735,6 +1735,8 @@ static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head)
* @head: Pointer to "struct tomoyo_io_buffer". * @head: Pointer to "struct tomoyo_io_buffer".
* *
* Returns 0 on success, -EINVAL otherwise. * Returns 0 on success, -EINVAL otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head) static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head)
{ {
@ -1864,15 +1866,13 @@ void tomoyo_load_policy(const char *filename)
tomoyo_policy_loaded = true; tomoyo_policy_loaded = true;
{ /* Check all profiles currently assigned to domains are defined. */ { /* Check all profiles currently assigned to domains are defined. */
struct tomoyo_domain_info *domain; struct tomoyo_domain_info *domain;
down_read(&tomoyo_domain_list_lock); list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
list_for_each_entry(domain, &tomoyo_domain_list, list) {
const u8 profile = domain->profile; const u8 profile = domain->profile;
if (tomoyo_profile_ptr[profile]) if (tomoyo_profile_ptr[profile])
continue; continue;
panic("Profile %u (used by '%s') not defined.\n", panic("Profile %u (used by '%s') not defined.\n",
profile, domain->domainname->name); profile, domain->domainname->name);
} }
up_read(&tomoyo_domain_list_lock);
} }
} }
@ -1920,6 +1920,8 @@ static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head)
* @file: Pointer to "struct file". * @file: Pointer to "struct file".
* *
* Associates policy handler and returns 0 on success, -ENOMEM otherwise. * Associates policy handler and returns 0 on success, -ENOMEM otherwise.
*
* Caller acquires tomoyo_read_lock().
*/ */
static int tomoyo_open_control(const u8 type, struct file *file) static int tomoyo_open_control(const u8 type, struct file *file)
{ {
@ -2005,6 +2007,7 @@ static int tomoyo_open_control(const u8 type, struct file *file)
return -ENOMEM; return -ENOMEM;
} }
} }
head->reader_idx = tomoyo_read_lock();
file->private_data = head; file->private_data = head;
/* /*
* Call the handler now if the file is * Call the handler now if the file is
@ -2026,6 +2029,8 @@ static int tomoyo_open_control(const u8 type, struct file *file)
* @buffer_len: Size of @buffer. * @buffer_len: Size of @buffer.
* *
* Returns bytes read on success, negative value otherwise. * Returns bytes read on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
static int tomoyo_read_control(struct file *file, char __user *buffer, static int tomoyo_read_control(struct file *file, char __user *buffer,
const int buffer_len) const int buffer_len)
@ -2069,6 +2074,8 @@ static int tomoyo_read_control(struct file *file, char __user *buffer,
* @buffer_len: Size of @buffer. * @buffer_len: Size of @buffer.
* *
* Returns @buffer_len on success, negative value otherwise. * Returns @buffer_len on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
static int tomoyo_write_control(struct file *file, const char __user *buffer, static int tomoyo_write_control(struct file *file, const char __user *buffer,
const int buffer_len) const int buffer_len)
@ -2119,11 +2126,14 @@ static int tomoyo_write_control(struct file *file, const char __user *buffer,
* @file: Pointer to "struct file". * @file: Pointer to "struct file".
* *
* Releases memory and returns 0. * Releases memory and returns 0.
*
* Caller looses tomoyo_read_lock().
*/ */
static int tomoyo_close_control(struct file *file) static int tomoyo_close_control(struct file *file)
{ {
struct tomoyo_io_buffer *head = file->private_data; struct tomoyo_io_buffer *head = file->private_data;
tomoyo_read_unlock(head->reader_idx);
/* Release memory used for policy I/O. */ /* Release memory used for policy I/O. */
tomoyo_free(head->read_buf); tomoyo_free(head->read_buf);
head->read_buf = NULL; head->read_buf = NULL;

View File

@ -269,6 +269,8 @@ struct tomoyo_io_buffer {
int (*write) (struct tomoyo_io_buffer *); int (*write) (struct tomoyo_io_buffer *);
/* Exclusive lock for this structure. */ /* Exclusive lock for this structure. */
struct mutex io_sem; struct mutex io_sem;
/* Index returned by tomoyo_read_lock(). */
int reader_idx;
/* The position currently reading from. */ /* The position currently reading from. */
struct list_head *read_var1; struct list_head *read_var1;
/* Extra variables for reading. */ /* Extra variables for reading. */
@ -446,7 +448,7 @@ extern struct tomoyo_domain_info tomoyo_kernel_domain;
* @cookie: the &struct list_head to use as a cookie. * @cookie: the &struct list_head to use as a cookie.
* @head: the head for your list. * @head: the head for your list.
* *
* Same with list_for_each() except that this primitive uses @cookie * Same with list_for_each_rcu() except that this primitive uses @cookie
* so that we can continue iteration. * so that we can continue iteration.
* @cookie must be NULL when iteration starts, and @cookie will become * @cookie must be NULL when iteration starts, and @cookie will become
* NULL when iteration finishes. * NULL when iteration finishes.
@ -454,8 +456,20 @@ extern struct tomoyo_domain_info tomoyo_kernel_domain;
#define list_for_each_cookie(pos, cookie, head) \ #define list_for_each_cookie(pos, cookie, head) \
for (({ if (!cookie) \ for (({ if (!cookie) \
cookie = head; }), \ cookie = head; }), \
pos = (cookie)->next; \ pos = rcu_dereference((cookie)->next); \
prefetch(pos->next), pos != (head) || ((cookie) = NULL); \ prefetch(pos->next), pos != (head) || ((cookie) = NULL); \
(cookie) = pos, pos = pos->next) (cookie) = pos, pos = rcu_dereference(pos->next))
extern struct srcu_struct tomoyo_ss;
static inline int tomoyo_read_lock(void)
{
return srcu_read_lock(&tomoyo_ss);
}
static inline void tomoyo_read_unlock(int idx)
{
srcu_read_unlock(&tomoyo_ss, idx);
}
#endif /* !defined(_SECURITY_TOMOYO_COMMON_H) */ #endif /* !defined(_SECURITY_TOMOYO_COMMON_H) */

View File

@ -217,6 +217,8 @@ static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock);
* @is_delete: True if it is a delete request. * @is_delete: True if it is a delete request.
* *
* Returns 0 on success, negative value otherwise. * Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
static int tomoyo_update_domain_initializer_entry(const char *domainname, static int tomoyo_update_domain_initializer_entry(const char *domainname,
const char *program, const char *program,
@ -246,7 +248,7 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname,
if (!saved_program) if (!saved_program)
return -ENOMEM; return -ENOMEM;
down_write(&tomoyo_domain_initializer_list_lock); down_write(&tomoyo_domain_initializer_list_lock);
list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) { list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
if (ptr->is_not != is_not || if (ptr->is_not != is_not ||
ptr->domainname != saved_domainname || ptr->domainname != saved_domainname ||
ptr->program != saved_program) ptr->program != saved_program)
@ -266,7 +268,7 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname,
new_entry->program = saved_program; new_entry->program = saved_program;
new_entry->is_not = is_not; new_entry->is_not = is_not;
new_entry->is_last_name = is_last_name; new_entry->is_last_name = is_last_name;
list_add_tail(&new_entry->list, &tomoyo_domain_initializer_list); list_add_tail_rcu(&new_entry->list, &tomoyo_domain_initializer_list);
error = 0; error = 0;
out: out:
up_write(&tomoyo_domain_initializer_list_lock); up_write(&tomoyo_domain_initializer_list_lock);
@ -279,13 +281,14 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname,
* @head: Pointer to "struct tomoyo_io_buffer". * @head: Pointer to "struct tomoyo_io_buffer".
* *
* Returns true on success, false otherwise. * Returns true on success, false otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head) bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head)
{ {
struct list_head *pos; struct list_head *pos;
bool done = true; bool done = true;
down_read(&tomoyo_domain_initializer_list_lock);
list_for_each_cookie(pos, head->read_var2, list_for_each_cookie(pos, head->read_var2,
&tomoyo_domain_initializer_list) { &tomoyo_domain_initializer_list) {
const char *no; const char *no;
@ -308,7 +311,6 @@ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head)
if (!done) if (!done)
break; break;
} }
up_read(&tomoyo_domain_initializer_list_lock);
return done; return done;
} }
@ -320,6 +322,8 @@ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head)
* @is_delete: True if it is a delete request. * @is_delete: True if it is a delete request.
* *
* Returns 0 on success, negative value otherwise. * Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
int tomoyo_write_domain_initializer_policy(char *data, const bool is_not, int tomoyo_write_domain_initializer_policy(char *data, const bool is_not,
const bool is_delete) const bool is_delete)
@ -345,6 +349,8 @@ int tomoyo_write_domain_initializer_policy(char *data, const bool is_not,
* *
* Returns true if executing @program reinitializes domain transition, * Returns true if executing @program reinitializes domain transition,
* false otherwise. * false otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info *
domainname, domainname,
@ -355,8 +361,7 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info *
struct tomoyo_domain_initializer_entry *ptr; struct tomoyo_domain_initializer_entry *ptr;
bool flag = false; bool flag = false;
down_read(&tomoyo_domain_initializer_list_lock); list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) {
if (ptr->is_deleted) if (ptr->is_deleted)
continue; continue;
if (ptr->domainname) { if (ptr->domainname) {
@ -376,7 +381,6 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info *
} }
flag = true; flag = true;
} }
up_read(&tomoyo_domain_initializer_list_lock);
return flag; return flag;
} }
@ -430,6 +434,8 @@ static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock);
* @is_delete: True if it is a delete request. * @is_delete: True if it is a delete request.
* *
* Returns 0 on success, negative value otherwise. * Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
static int tomoyo_update_domain_keeper_entry(const char *domainname, static int tomoyo_update_domain_keeper_entry(const char *domainname,
const char *program, const char *program,
@ -459,7 +465,7 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname,
if (!saved_domainname) if (!saved_domainname)
return -ENOMEM; return -ENOMEM;
down_write(&tomoyo_domain_keeper_list_lock); down_write(&tomoyo_domain_keeper_list_lock);
list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) { list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
if (ptr->is_not != is_not || if (ptr->is_not != is_not ||
ptr->domainname != saved_domainname || ptr->domainname != saved_domainname ||
ptr->program != saved_program) ptr->program != saved_program)
@ -479,7 +485,7 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname,
new_entry->program = saved_program; new_entry->program = saved_program;
new_entry->is_not = is_not; new_entry->is_not = is_not;
new_entry->is_last_name = is_last_name; new_entry->is_last_name = is_last_name;
list_add_tail(&new_entry->list, &tomoyo_domain_keeper_list); list_add_tail_rcu(&new_entry->list, &tomoyo_domain_keeper_list);
error = 0; error = 0;
out: out:
up_write(&tomoyo_domain_keeper_list_lock); up_write(&tomoyo_domain_keeper_list_lock);
@ -493,6 +499,7 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname,
* @is_not: True if it is "no_keep_domain" entry. * @is_not: True if it is "no_keep_domain" entry.
* @is_delete: True if it is a delete request. * @is_delete: True if it is a delete request.
* *
* Caller holds tomoyo_read_lock().
*/ */
int tomoyo_write_domain_keeper_policy(char *data, const bool is_not, int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
const bool is_delete) const bool is_delete)
@ -513,13 +520,14 @@ int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
* @head: Pointer to "struct tomoyo_io_buffer". * @head: Pointer to "struct tomoyo_io_buffer".
* *
* Returns true on success, false otherwise. * Returns true on success, false otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head) bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head)
{ {
struct list_head *pos; struct list_head *pos;
bool done = true; bool done = true;
down_read(&tomoyo_domain_keeper_list_lock);
list_for_each_cookie(pos, head->read_var2, list_for_each_cookie(pos, head->read_var2,
&tomoyo_domain_keeper_list) { &tomoyo_domain_keeper_list) {
struct tomoyo_domain_keeper_entry *ptr; struct tomoyo_domain_keeper_entry *ptr;
@ -542,7 +550,6 @@ bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head)
if (!done) if (!done)
break; break;
} }
up_read(&tomoyo_domain_keeper_list_lock);
return done; return done;
} }
@ -555,6 +562,8 @@ bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head)
* *
* Returns true if executing @program supresses domain transition, * Returns true if executing @program supresses domain transition,
* false otherwise. * false otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
const struct tomoyo_path_info *program, const struct tomoyo_path_info *program,
@ -563,8 +572,7 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
struct tomoyo_domain_keeper_entry *ptr; struct tomoyo_domain_keeper_entry *ptr;
bool flag = false; bool flag = false;
down_read(&tomoyo_domain_keeper_list_lock); list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
if (ptr->is_deleted) if (ptr->is_deleted)
continue; continue;
if (!ptr->is_last_name) { if (!ptr->is_last_name) {
@ -582,7 +590,6 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
} }
flag = true; flag = true;
} }
up_read(&tomoyo_domain_keeper_list_lock);
return flag; return flag;
} }
@ -627,6 +634,8 @@ static DECLARE_RWSEM(tomoyo_alias_list_lock);
* @is_delete: True if it is a delete request. * @is_delete: True if it is a delete request.
* *
* Returns 0 on success, negative value otherwise. * Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
static int tomoyo_update_alias_entry(const char *original_name, static int tomoyo_update_alias_entry(const char *original_name,
const char *aliased_name, const char *aliased_name,
@ -646,7 +655,7 @@ static int tomoyo_update_alias_entry(const char *original_name,
if (!saved_original_name || !saved_aliased_name) if (!saved_original_name || !saved_aliased_name)
return -ENOMEM; return -ENOMEM;
down_write(&tomoyo_alias_list_lock); down_write(&tomoyo_alias_list_lock);
list_for_each_entry(ptr, &tomoyo_alias_list, list) { list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
if (ptr->original_name != saved_original_name || if (ptr->original_name != saved_original_name ||
ptr->aliased_name != saved_aliased_name) ptr->aliased_name != saved_aliased_name)
continue; continue;
@ -663,7 +672,7 @@ static int tomoyo_update_alias_entry(const char *original_name,
goto out; goto out;
new_entry->original_name = saved_original_name; new_entry->original_name = saved_original_name;
new_entry->aliased_name = saved_aliased_name; new_entry->aliased_name = saved_aliased_name;
list_add_tail(&new_entry->list, &tomoyo_alias_list); list_add_tail_rcu(&new_entry->list, &tomoyo_alias_list);
error = 0; error = 0;
out: out:
up_write(&tomoyo_alias_list_lock); up_write(&tomoyo_alias_list_lock);
@ -676,13 +685,14 @@ static int tomoyo_update_alias_entry(const char *original_name,
* @head: Pointer to "struct tomoyo_io_buffer". * @head: Pointer to "struct tomoyo_io_buffer".
* *
* Returns true on success, false otherwise. * Returns true on success, false otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
{ {
struct list_head *pos; struct list_head *pos;
bool done = true; bool done = true;
down_read(&tomoyo_alias_list_lock);
list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) { list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) {
struct tomoyo_alias_entry *ptr; struct tomoyo_alias_entry *ptr;
@ -695,7 +705,6 @@ bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
if (!done) if (!done)
break; break;
} }
up_read(&tomoyo_alias_list_lock);
return done; return done;
} }
@ -706,6 +715,8 @@ bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
* @is_delete: True if it is a delete request. * @is_delete: True if it is a delete request.
* *
* Returns 0 on success, negative value otherwise. * Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
int tomoyo_write_alias_policy(char *data, const bool is_delete) int tomoyo_write_alias_policy(char *data, const bool is_delete)
{ {
@ -724,6 +735,8 @@ int tomoyo_write_alias_policy(char *data, const bool is_delete)
* @profile: Profile number to assign if the domain was newly created. * @profile: Profile number to assign if the domain was newly created.
* *
* Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise. * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
domainname, domainname,
@ -742,7 +755,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
if (!saved_domainname) if (!saved_domainname)
goto out; goto out;
/* Can I reuse memory of deleted domain? */ /* Can I reuse memory of deleted domain? */
list_for_each_entry(domain, &tomoyo_domain_list, list) { list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
struct task_struct *p; struct task_struct *p;
struct tomoyo_acl_info *ptr; struct tomoyo_acl_info *ptr;
bool flag; bool flag;
@ -760,7 +773,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
read_unlock(&tasklist_lock); read_unlock(&tasklist_lock);
if (flag) if (flag)
continue; continue;
list_for_each_entry(ptr, &domain->acl_info_list, list) { list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
ptr->type |= TOMOYO_ACL_DELETED; ptr->type |= TOMOYO_ACL_DELETED;
} }
tomoyo_set_domain_flag(domain, true, domain->flags); tomoyo_set_domain_flag(domain, true, domain->flags);
@ -776,7 +789,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
INIT_LIST_HEAD(&domain->acl_info_list); INIT_LIST_HEAD(&domain->acl_info_list);
domain->domainname = saved_domainname; domain->domainname = saved_domainname;
domain->profile = profile; domain->profile = profile;
list_add_tail(&domain->list, &tomoyo_domain_list); list_add_tail_rcu(&domain->list, &tomoyo_domain_list);
} }
out: out:
up_write(&tomoyo_domain_list_lock); up_write(&tomoyo_domain_list_lock);
@ -789,6 +802,8 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
* @bprm: Pointer to "struct linux_binprm". * @bprm: Pointer to "struct linux_binprm".
* *
* Returns 0 on success, negative value otherwise. * Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
int tomoyo_find_next_domain(struct linux_binprm *bprm) int tomoyo_find_next_domain(struct linux_binprm *bprm)
{ {
@ -849,8 +864,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
if (tomoyo_pathcmp(&r, &s)) { if (tomoyo_pathcmp(&r, &s)) {
struct tomoyo_alias_entry *ptr; struct tomoyo_alias_entry *ptr;
/* Is this program allowed to be called via symbolic links? */ /* Is this program allowed to be called via symbolic links? */
down_read(&tomoyo_alias_list_lock); list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
list_for_each_entry(ptr, &tomoyo_alias_list, list) {
if (ptr->is_deleted || if (ptr->is_deleted ||
tomoyo_pathcmp(&r, ptr->original_name) || tomoyo_pathcmp(&r, ptr->original_name) ||
tomoyo_pathcmp(&s, ptr->aliased_name)) tomoyo_pathcmp(&s, ptr->aliased_name))
@ -861,7 +875,6 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
tomoyo_fill_path_info(&r); tomoyo_fill_path_info(&r);
break; break;
} }
up_read(&tomoyo_alias_list_lock);
} }
/* Check execute permission. */ /* Check execute permission. */
@ -892,9 +905,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
} }
if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN) if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN)
goto done; goto done;
down_read(&tomoyo_domain_list_lock);
domain = tomoyo_find_domain(new_domain_name); domain = tomoyo_find_domain(new_domain_name);
up_read(&tomoyo_domain_list_lock);
if (domain) if (domain)
goto done; goto done;
if (is_enforce) if (is_enforce)

View File

@ -213,6 +213,8 @@ static DECLARE_RWSEM(tomoyo_globally_readable_list_lock);
* @is_delete: True if it is a delete request. * @is_delete: True if it is a delete request.
* *
* Returns 0 on success, negative value otherwise. * Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
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)
@ -228,7 +230,7 @@ static int tomoyo_update_globally_readable_entry(const char *filename,
if (!saved_filename) if (!saved_filename)
return -ENOMEM; return -ENOMEM;
down_write(&tomoyo_globally_readable_list_lock); down_write(&tomoyo_globally_readable_list_lock);
list_for_each_entry(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 != saved_filename)
continue; continue;
ptr->is_deleted = is_delete; ptr->is_deleted = is_delete;
@ -243,7 +245,7 @@ static int tomoyo_update_globally_readable_entry(const char *filename,
if (!new_entry) if (!new_entry)
goto out; goto out;
new_entry->filename = saved_filename; new_entry->filename = saved_filename;
list_add_tail(&new_entry->list, &tomoyo_globally_readable_list); list_add_tail_rcu(&new_entry->list, &tomoyo_globally_readable_list);
error = 0; error = 0;
out: out:
up_write(&tomoyo_globally_readable_list_lock); up_write(&tomoyo_globally_readable_list_lock);
@ -256,21 +258,22 @@ static int tomoyo_update_globally_readable_entry(const char *filename,
* @filename: The filename to check. * @filename: The filename to check.
* *
* Returns true if any domain can open @filename for reading, false otherwise. * Returns true if any domain can open @filename for reading, false otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info *
filename) filename)
{ {
struct tomoyo_globally_readable_file_entry *ptr; struct tomoyo_globally_readable_file_entry *ptr;
bool found = false; bool found = false;
down_read(&tomoyo_globally_readable_list_lock);
list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) { list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) {
if (!ptr->is_deleted && if (!ptr->is_deleted &&
tomoyo_path_matches_pattern(filename, ptr->filename)) { tomoyo_path_matches_pattern(filename, ptr->filename)) {
found = true; found = true;
break; break;
} }
} }
up_read(&tomoyo_globally_readable_list_lock);
return found; return found;
} }
@ -281,6 +284,8 @@ static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info *
* @is_delete: True if it is a delete request. * @is_delete: True if it is a delete request.
* *
* Returns 0 on success, negative value otherwise. * Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) int tomoyo_write_globally_readable_policy(char *data, const bool is_delete)
{ {
@ -293,13 +298,14 @@ int tomoyo_write_globally_readable_policy(char *data, const bool is_delete)
* @head: Pointer to "struct tomoyo_io_buffer". * @head: Pointer to "struct tomoyo_io_buffer".
* *
* Returns true on success, false otherwise. * Returns true on success, false otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head)
{ {
struct list_head *pos; struct list_head *pos;
bool done = true; bool done = true;
down_read(&tomoyo_globally_readable_list_lock);
list_for_each_cookie(pos, head->read_var2, list_for_each_cookie(pos, head->read_var2,
&tomoyo_globally_readable_list) { &tomoyo_globally_readable_list) {
struct tomoyo_globally_readable_file_entry *ptr; struct tomoyo_globally_readable_file_entry *ptr;
@ -313,7 +319,6 @@ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head)
if (!done) if (!done)
break; break;
} }
up_read(&tomoyo_globally_readable_list_lock);
return done; return done;
} }
@ -356,6 +361,8 @@ static DECLARE_RWSEM(tomoyo_pattern_list_lock);
* @is_delete: True if it is a delete request. * @is_delete: True if it is a delete request.
* *
* Returns 0 on success, negative value otherwise. * Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
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)
@ -371,7 +378,7 @@ static int tomoyo_update_file_pattern_entry(const char *pattern,
if (!saved_pattern) if (!saved_pattern)
return -ENOMEM; return -ENOMEM;
down_write(&tomoyo_pattern_list_lock); down_write(&tomoyo_pattern_list_lock);
list_for_each_entry(ptr, &tomoyo_pattern_list, list) { list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
if (saved_pattern != ptr->pattern) if (saved_pattern != ptr->pattern)
continue; continue;
ptr->is_deleted = is_delete; ptr->is_deleted = is_delete;
@ -386,7 +393,7 @@ static int tomoyo_update_file_pattern_entry(const char *pattern,
if (!new_entry) if (!new_entry)
goto out; goto out;
new_entry->pattern = saved_pattern; new_entry->pattern = saved_pattern;
list_add_tail(&new_entry->list, &tomoyo_pattern_list); list_add_tail_rcu(&new_entry->list, &tomoyo_pattern_list);
error = 0; error = 0;
out: out:
up_write(&tomoyo_pattern_list_lock); up_write(&tomoyo_pattern_list_lock);
@ -399,6 +406,8 @@ static int tomoyo_update_file_pattern_entry(const char *pattern,
* @filename: The filename to find patterned pathname. * @filename: The filename to find patterned pathname.
* *
* Returns pointer to pathname pattern if matched, @filename otherwise. * Returns pointer to pathname pattern if matched, @filename otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
static const struct tomoyo_path_info * static const struct tomoyo_path_info *
tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
@ -406,8 +415,7 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
struct tomoyo_pattern_entry *ptr; struct tomoyo_pattern_entry *ptr;
const struct tomoyo_path_info *pattern = NULL; const struct tomoyo_path_info *pattern = NULL;
down_read(&tomoyo_pattern_list_lock); list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
if (ptr->is_deleted) if (ptr->is_deleted)
continue; continue;
if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
@ -420,7 +428,6 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
break; break;
} }
} }
up_read(&tomoyo_pattern_list_lock);
if (pattern) if (pattern)
filename = pattern; filename = pattern;
return filename; return filename;
@ -433,6 +440,8 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
* @is_delete: True if it is a delete request. * @is_delete: True if it is a delete request.
* *
* Returns 0 on success, negative value otherwise. * Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
int tomoyo_write_pattern_policy(char *data, const bool is_delete) int tomoyo_write_pattern_policy(char *data, const bool is_delete)
{ {
@ -445,13 +454,14 @@ int tomoyo_write_pattern_policy(char *data, const bool is_delete)
* @head: Pointer to "struct tomoyo_io_buffer". * @head: Pointer to "struct tomoyo_io_buffer".
* *
* Returns true on success, false otherwise. * Returns true on success, false otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head)
{ {
struct list_head *pos; struct list_head *pos;
bool done = true; bool done = true;
down_read(&tomoyo_pattern_list_lock);
list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) { list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) {
struct tomoyo_pattern_entry *ptr; struct tomoyo_pattern_entry *ptr;
ptr = list_entry(pos, struct tomoyo_pattern_entry, list); ptr = list_entry(pos, struct tomoyo_pattern_entry, list);
@ -462,7 +472,6 @@ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head)
if (!done) if (!done)
break; break;
} }
up_read(&tomoyo_pattern_list_lock);
return done; return done;
} }
@ -505,6 +514,8 @@ static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock);
* @is_delete: True if it is a delete request. * @is_delete: True if it is a delete request.
* *
* Returns 0 on success, negative value otherwise. * Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
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)
@ -519,7 +530,7 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern,
if (!saved_pattern) if (!saved_pattern)
return -ENOMEM; return -ENOMEM;
down_write(&tomoyo_no_rewrite_list_lock); down_write(&tomoyo_no_rewrite_list_lock);
list_for_each_entry(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 != saved_pattern)
continue; continue;
ptr->is_deleted = is_delete; ptr->is_deleted = is_delete;
@ -534,7 +545,7 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern,
if (!new_entry) if (!new_entry)
goto out; goto out;
new_entry->pattern = saved_pattern; new_entry->pattern = saved_pattern;
list_add_tail(&new_entry->list, &tomoyo_no_rewrite_list); list_add_tail_rcu(&new_entry->list, &tomoyo_no_rewrite_list);
error = 0; error = 0;
out: out:
up_write(&tomoyo_no_rewrite_list_lock); up_write(&tomoyo_no_rewrite_list_lock);
@ -548,14 +559,15 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern,
* *
* Returns true if @filename is specified by "deny_rewrite" directive, * Returns true if @filename is specified by "deny_rewrite" directive,
* false otherwise. * false otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename)
{ {
struct tomoyo_no_rewrite_entry *ptr; struct tomoyo_no_rewrite_entry *ptr;
bool found = false; bool found = false;
down_read(&tomoyo_no_rewrite_list_lock); list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
if (ptr->is_deleted) if (ptr->is_deleted)
continue; continue;
if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
@ -563,7 +575,6 @@ static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename)
found = true; found = true;
break; break;
} }
up_read(&tomoyo_no_rewrite_list_lock);
return found; return found;
} }
@ -574,6 +585,8 @@ static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename)
* @is_delete: True if it is a delete request. * @is_delete: True if it is a delete request.
* *
* Returns 0 on success, negative value otherwise. * Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete)
{ {
@ -586,13 +599,14 @@ int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete)
* @head: Pointer to "struct tomoyo_io_buffer". * @head: Pointer to "struct tomoyo_io_buffer".
* *
* Returns true on success, false otherwise. * Returns true on success, false otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
{ {
struct list_head *pos; struct list_head *pos;
bool done = true; bool done = true;
down_read(&tomoyo_no_rewrite_list_lock);
list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) { list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) {
struct tomoyo_no_rewrite_entry *ptr; struct tomoyo_no_rewrite_entry *ptr;
ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list); ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list);
@ -603,7 +617,6 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
if (!done) if (!done)
break; break;
} }
up_read(&tomoyo_no_rewrite_list_lock);
return done; return done;
} }
@ -621,6 +634,8 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
* Current policy syntax uses "allow_read/write" instead of "6", * Current policy syntax uses "allow_read/write" instead of "6",
* "allow_read" instead of "4", "allow_write" instead of "2", * "allow_read" instead of "4", "allow_write" instead of "2",
* "allow_execute" instead of "1". * "allow_execute" instead of "1".
*
* Caller holds tomoyo_read_lock().
*/ */
static int tomoyo_update_file_acl(const char *filename, u8 perm, static int tomoyo_update_file_acl(const char *filename, u8 perm,
struct tomoyo_domain_info * const domain, struct tomoyo_domain_info * const domain,
@ -658,6 +673,8 @@ static int tomoyo_update_file_acl(const char *filename, u8 perm,
* @may_use_pattern: True if patterned ACL is permitted. * @may_use_pattern: True if patterned ACL is permitted.
* *
* Returns 0 on success, -EPERM otherwise. * Returns 0 on success, -EPERM otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info *
domain, domain,
@ -669,8 +686,7 @@ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info *
struct tomoyo_acl_info *ptr; struct tomoyo_acl_info *ptr;
int error = -EPERM; int error = -EPERM;
down_read(&tomoyo_domain_acl_info_list_lock); list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
list_for_each_entry(ptr, &domain->acl_info_list, list) {
struct tomoyo_single_path_acl_record *acl; struct tomoyo_single_path_acl_record *acl;
if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
continue; continue;
@ -693,7 +709,6 @@ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info *
error = 0; error = 0;
break; break;
} }
up_read(&tomoyo_domain_acl_info_list_lock);
return error; return error;
} }
@ -705,6 +720,8 @@ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info *
* @operation: Mode ("read" or "write" or "read/write" or "execute"). * @operation: Mode ("read" or "write" or "read/write" or "execute").
* *
* Returns 0 on success, -EPERM otherwise. * Returns 0 on success, -EPERM otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain,
const struct tomoyo_path_info *filename, const struct tomoyo_path_info *filename,
@ -738,6 +755,8 @@ static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain,
* @mode: Access control mode. * @mode: Access control mode.
* *
* Returns 0 on success, negative value otherwise. * Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain,
const struct tomoyo_path_info *filename, const struct tomoyo_path_info *filename,
@ -791,6 +810,8 @@ static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain,
* @is_delete: True if it is a delete request. * @is_delete: True if it is a delete request.
* *
* Returns 0 on success, negative value otherwise. * Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
const bool is_delete) const bool is_delete)
@ -838,6 +859,8 @@ int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
* @is_delete: True if it is a delete request. * @is_delete: True if it is a delete request.
* *
* Returns 0 on success, negative value otherwise. * Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
static int tomoyo_update_single_path_acl(const u8 type, const char *filename, static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
struct tomoyo_domain_info * struct tomoyo_domain_info *
@ -861,7 +884,7 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
down_write(&tomoyo_domain_acl_info_list_lock); down_write(&tomoyo_domain_acl_info_list_lock);
if (is_delete) if (is_delete)
goto delete; goto delete;
list_for_each_entry(ptr, &domain->acl_info_list, list) { list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
continue; continue;
acl = container_of(ptr, struct tomoyo_single_path_acl_record, acl = container_of(ptr, struct tomoyo_single_path_acl_record,
@ -894,12 +917,12 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL)) if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL))
acl->perm |= rw_mask; acl->perm |= rw_mask;
acl->filename = saved_filename; acl->filename = saved_filename;
list_add_tail(&acl->head.list, &domain->acl_info_list); list_add_tail_rcu(&acl->head.list, &domain->acl_info_list);
error = 0; error = 0;
goto out; goto out;
delete: delete:
error = -ENOENT; error = -ENOENT;
list_for_each_entry(ptr, &domain->acl_info_list, list) { list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
continue; continue;
acl = container_of(ptr, struct tomoyo_single_path_acl_record, acl = container_of(ptr, struct tomoyo_single_path_acl_record,
@ -934,6 +957,8 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
* @is_delete: True if it is a delete request. * @is_delete: True if it is a delete request.
* *
* Returns 0 on success, negative value otherwise. * Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
const char *filename2, const char *filename2,
@ -959,7 +984,7 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
down_write(&tomoyo_domain_acl_info_list_lock); down_write(&tomoyo_domain_acl_info_list_lock);
if (is_delete) if (is_delete)
goto delete; goto delete;
list_for_each_entry(ptr, &domain->acl_info_list, list) { list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
continue; continue;
acl = container_of(ptr, struct tomoyo_double_path_acl_record, acl = container_of(ptr, struct tomoyo_double_path_acl_record,
@ -982,12 +1007,12 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
acl->perm = perm; acl->perm = perm;
acl->filename1 = saved_filename1; acl->filename1 = saved_filename1;
acl->filename2 = saved_filename2; acl->filename2 = saved_filename2;
list_add_tail(&acl->head.list, &domain->acl_info_list); list_add_tail_rcu(&acl->head.list, &domain->acl_info_list);
error = 0; error = 0;
goto out; goto out;
delete: delete:
error = -ENOENT; error = -ENOENT;
list_for_each_entry(ptr, &domain->acl_info_list, list) { list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
continue; continue;
acl = container_of(ptr, struct tomoyo_double_path_acl_record, acl = container_of(ptr, struct tomoyo_double_path_acl_record,
@ -1014,6 +1039,8 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
* @filename: Filename to check. * @filename: Filename to check.
* *
* Returns 0 on success, negative value otherwise. * Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain, static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain,
const u8 type, const u8 type,
@ -1033,6 +1060,8 @@ static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain,
* @filename2: Second filename to check. * @filename2: Second filename to check.
* *
* Returns 0 on success, -EPERM otherwise. * Returns 0 on success, -EPERM otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain,
const u8 type, const u8 type,
@ -1047,8 +1076,7 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain,
if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
return 0; return 0;
down_read(&tomoyo_domain_acl_info_list_lock); list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
list_for_each_entry(ptr, &domain->acl_info_list, list) {
struct tomoyo_double_path_acl_record *acl; struct tomoyo_double_path_acl_record *acl;
if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
continue; continue;
@ -1063,7 +1091,6 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain,
error = 0; error = 0;
break; break;
} }
up_read(&tomoyo_domain_acl_info_list_lock);
return error; return error;
} }
@ -1076,6 +1103,8 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain,
* @mode: Access control mode. * @mode: Access control mode.
* *
* Returns 0 on success, negative value otherwise. * Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info *
const domain, u8 operation, const domain, u8 operation,
@ -1124,6 +1153,8 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info *
* @filename: Check permission for "execute". * @filename: Check permission for "execute".
* *
* Returns 0 on success, negativevalue otherwise. * Returns 0 on success, negativevalue otherwise.
*
* Caller holds tomoyo_read_lock().
*/ */
int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
const struct tomoyo_path_info *filename) const struct tomoyo_path_info *filename)
@ -1152,6 +1183,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
struct tomoyo_path_info *buf; struct tomoyo_path_info *buf;
const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
const bool is_enforce = (mode == 3); const bool is_enforce = (mode == 3);
int idx;
if (!mode || !path->mnt) if (!mode || !path->mnt)
return 0; return 0;
@ -1163,6 +1195,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
* don't call me. * don't call me.
*/ */
return 0; return 0;
idx = tomoyo_read_lock();
buf = tomoyo_get_path(path); buf = tomoyo_get_path(path);
if (!buf) if (!buf)
goto out; goto out;
@ -1188,6 +1221,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
buf, mode); buf, mode);
out: out:
tomoyo_free(buf); tomoyo_free(buf);
tomoyo_read_unlock(idx);
if (!is_enforce) if (!is_enforce)
error = 0; error = 0;
return error; return error;
@ -1209,9 +1243,11 @@ int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain,
struct tomoyo_path_info *buf; struct tomoyo_path_info *buf;
const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
const bool is_enforce = (mode == 3); const bool is_enforce = (mode == 3);
int idx;
if (!mode || !path->mnt) if (!mode || !path->mnt)
return 0; return 0;
idx = tomoyo_read_lock();
buf = tomoyo_get_path(path); buf = tomoyo_get_path(path);
if (!buf) if (!buf)
goto out; goto out;
@ -1231,6 +1267,7 @@ int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain,
mode); mode);
out: out:
tomoyo_free(buf); tomoyo_free(buf);
tomoyo_read_unlock(idx);
if (!is_enforce) if (!is_enforce)
error = 0; error = 0;
return error; return error;
@ -1251,9 +1288,12 @@ int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain,
const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
const bool is_enforce = (mode == 3); const bool is_enforce = (mode == 3);
struct tomoyo_path_info *buf; struct tomoyo_path_info *buf;
int idx;
if (!mode || !filp->f_path.mnt) if (!mode || !filp->f_path.mnt)
return 0; return 0;
idx = tomoyo_read_lock();
buf = tomoyo_get_path(&filp->f_path); buf = tomoyo_get_path(&filp->f_path);
if (!buf) if (!buf)
goto out; goto out;
@ -1266,6 +1306,7 @@ int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain,
buf, mode); buf, mode);
out: out:
tomoyo_free(buf); tomoyo_free(buf);
tomoyo_read_unlock(idx);
if (!is_enforce) if (!is_enforce)
error = 0; error = 0;
return error; return error;
@ -1290,9 +1331,11 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain,
const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
const bool is_enforce = (mode == 3); const bool is_enforce = (mode == 3);
const char *msg; const char *msg;
int idx;
if (!mode || !path1->mnt || !path2->mnt) if (!mode || !path1->mnt || !path2->mnt)
return 0; return 0;
idx = tomoyo_read_lock();
buf1 = tomoyo_get_path(path1); buf1 = tomoyo_get_path(path1);
buf2 = tomoyo_get_path(path2); buf2 = tomoyo_get_path(path2);
if (!buf1 || !buf2) if (!buf1 || !buf2)
@ -1331,6 +1374,7 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain,
out: out:
tomoyo_free(buf1); tomoyo_free(buf1);
tomoyo_free(buf2); tomoyo_free(buf2);
tomoyo_read_unlock(idx);
if (!is_enforce) if (!is_enforce)
error = 0; error = 0;
return error; return error;

View File

@ -402,11 +402,13 @@ void __init tomoyo_realpath_init(void)
INIT_LIST_HEAD(&tomoyo_name_list[i]); INIT_LIST_HEAD(&tomoyo_name_list[i]);
INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list);
tomoyo_kernel_domain.domainname = tomoyo_save_name(TOMOYO_ROOT_NAME); tomoyo_kernel_domain.domainname = tomoyo_save_name(TOMOYO_ROOT_NAME);
list_add_tail(&tomoyo_kernel_domain.list, &tomoyo_domain_list); /*
down_read(&tomoyo_domain_list_lock); * tomoyo_read_lock() is not needed because this function is
* called before the first "delete" request.
*/
list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain) if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
panic("Can't register tomoyo_kernel_domain"); panic("Can't register tomoyo_kernel_domain");
up_read(&tomoyo_domain_list_lock);
} }
/* Memory allocated for temporary purpose. */ /* Memory allocated for temporary purpose. */

View File

@ -76,8 +76,18 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
* Execute permission is checked against pathname passed to do_execve() * Execute permission is checked against pathname passed to do_execve()
* using current domain. * using current domain.
*/ */
if (!domain) if (!domain) {
return tomoyo_find_next_domain(bprm); /*
* We will need to protect whole execve() operation when GC
* starts kfree()ing "struct tomoyo_domain_info" because
* bprm->cred->security points to "struct tomoyo_domain_info"
* but "struct tomoyo_domain_info" does not have a refcounter.
*/
const int idx = tomoyo_read_lock();
const int err = tomoyo_find_next_domain(bprm);
tomoyo_read_unlock(idx);
return err;
}
/* /*
* Read permission is checked against interpreters using next domain. * Read permission is checked against interpreters using next domain.
* '1' is the result of open_to_namei_flags(O_RDONLY). * '1' is the result of open_to_namei_flags(O_RDONLY).
@ -278,6 +288,9 @@ static struct security_operations tomoyo_security_ops = {
.sb_pivotroot = tomoyo_sb_pivotroot, .sb_pivotroot = tomoyo_sb_pivotroot,
}; };
/* Lock for GC. */
struct srcu_struct tomoyo_ss;
static int __init tomoyo_init(void) static int __init tomoyo_init(void)
{ {
struct cred *cred = (struct cred *) current_cred(); struct cred *cred = (struct cred *) current_cred();
@ -285,7 +298,8 @@ static int __init tomoyo_init(void)
if (!security_module_enable(&tomoyo_security_ops)) if (!security_module_enable(&tomoyo_security_ops))
return 0; return 0;
/* register ourselves with the security framework */ /* register ourselves with the security framework */
if (register_security(&tomoyo_security_ops)) if (register_security(&tomoyo_security_ops) ||
init_srcu_struct(&tomoyo_ss))
panic("Failure registering TOMOYO Linux"); panic("Failure registering TOMOYO Linux");
printk(KERN_INFO "TOMOYO Linux initialized\n"); printk(KERN_INFO "TOMOYO Linux initialized\n");
cred->security = &tomoyo_kernel_domain; cred->security = &tomoyo_kernel_domain;