diff options
author | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | 2009-12-08 09:34:43 +0900 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2009-12-15 15:46:31 +1100 |
commit | fdb8ebb729bbb640e64028a4f579a02ebc405727 (patch) | |
tree | 9dfca7422cb858cd05208734affab31d980030fe /security/tomoyo | |
parent | 86fc80f16e8a2449d5827bf1a9838b7fd9f70097 (diff) |
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>
Diffstat (limited to 'security/tomoyo')
-rw-r--r-- | security/tomoyo/common.c | 90 | ||||
-rw-r--r-- | security/tomoyo/common.h | 28 | ||||
-rw-r--r-- | security/tomoyo/domain.c | 63 | ||||
-rw-r--r-- | security/tomoyo/file.c | 110 | ||||
-rw-r--r-- | security/tomoyo/realpath.c | 8 | ||||
-rw-r--r-- | security/tomoyo/tomoyo.c | 20 |
6 files changed, 207 insertions, 112 deletions
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 6c606168243..f01b9364db2 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -365,10 +365,9 @@ bool tomoyo_is_domain_def(const unsigned char *buffer) * * @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. + * + * Caller holds tomoyo_read_lock(). */ 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; 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 && !tomoyo_pathcmp(&name, domain->domainname)) return domain; @@ -829,6 +828,8 @@ bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain) * @domain: Pointer to "struct tomoyo_domain_info". * * 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) { @@ -837,8 +838,7 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain) if (!domain) return true; - down_read(&tomoyo_domain_acl_info_list_lock); - list_for_each_entry(ptr, &domain->acl_info_list, list) { + list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { if (ptr->type & TOMOYO_ACL_DELETED) continue; switch (tomoyo_acl_type2(ptr)) { @@ -866,7 +866,6 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain) break; } } - up_read(&tomoyo_domain_acl_info_list_lock); if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY)) return true; 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. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_update_manager_entry(const char *manager, const bool is_delete) @@ -1118,7 +1119,7 @@ static int tomoyo_update_manager_entry(const char *manager, if (!saved_manager) return -ENOMEM; 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) continue; ptr->is_deleted = is_delete; @@ -1134,7 +1135,7 @@ static int tomoyo_update_manager_entry(const char *manager, goto out; new_entry->manager = saved_manager; 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; out: 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". * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ 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". * * Returns 0. + * + * Caller holds tomoyo_read_lock(). */ 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) return 0; - down_read(&tomoyo_policy_manager_list_lock); list_for_each_cookie(pos, head->read_var2, &tomoyo_policy_manager_list) { struct tomoyo_policy_manager_entry *ptr; @@ -1186,7 +1190,6 @@ static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head) if (!done) break; } - up_read(&tomoyo_policy_manager_list_lock); head->read_eof = done; 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 * via /sys/kernel/security/tomoyo/ interface. + * + * Caller holds tomoyo_read_lock(). */ static bool tomoyo_is_policy_manager(void) { @@ -1209,29 +1214,25 @@ static bool tomoyo_is_policy_manager(void) return true; if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid)) return false; - down_read(&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->is_deleted && ptr->is_domain && !tomoyo_pathcmp(domainname, ptr->manager)) { found = true; break; } } - up_read(&tomoyo_policy_manager_list_lock); if (found) return true; exe = tomoyo_get_exe(); if (!exe) return false; - down_read(&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->is_deleted && !ptr->is_domain && !strcmp(exe, ptr->manager->name)) { found = true; break; } } - up_read(&tomoyo_policy_manager_list_lock); if (!found) { /* Reduce error messages. */ static pid_t last_pid; const pid_t pid = current->pid; @@ -1252,6 +1253,8 @@ static bool tomoyo_is_policy_manager(void) * @data: String to parse. * * Returns true on success, false otherwise. + * + * Caller holds tomoyo_read_lock(). */ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, const char *data) @@ -1267,11 +1270,8 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, domain = tomoyo_real_domain(p); read_unlock(&tasklist_lock); } else if (!strncmp(data, "domain=", 7)) { - if (tomoyo_is_domain_def(data + 7)) { - down_read(&tomoyo_domain_list_lock); + if (tomoyo_is_domain_def(data + 7)) domain = tomoyo_find_domain(data + 7); - up_read(&tomoyo_domain_list_lock); - } } else return false; head->write_var1 = domain; @@ -1285,13 +1285,11 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, if (domain) { struct tomoyo_domain_info *d; head->read_var1 = NULL; - down_read(&tomoyo_domain_list_lock); - list_for_each_entry(d, &tomoyo_domain_list, list) { + list_for_each_entry_rcu(d, &tomoyo_domain_list, list) { if (d == domain) break; head->read_var1 = &d->list; } - up_read(&tomoyo_domain_list_lock); head->read_var2 = NULL; head->read_bit = 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. * * Returns 0. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_delete_domain(char *domainname) { @@ -1317,7 +1317,7 @@ static int tomoyo_delete_domain(char *domainname) tomoyo_fill_path_info(&name); down_write(&tomoyo_domain_list_lock); /* 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 */ if (domain == &tomoyo_kernel_domain) continue; @@ -1337,6 +1337,8 @@ static int tomoyo_delete_domain(char *domainname) * @head: Pointer to "struct tomoyo_io_buffer". * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ 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; if (is_delete) tomoyo_delete_domain(data); - else if (is_select) { - down_read(&tomoyo_domain_list_lock); + else if (is_select) domain = tomoyo_find_domain(data); - up_read(&tomoyo_domain_list_lock); - } else + else domain = tomoyo_find_or_assign_new_domain(data, 0); head->write_var1 = domain; return 0; @@ -1508,6 +1508,8 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, * @head: Pointer to "struct tomoyo_io_buffer". * * Returns 0. + * + * Caller holds tomoyo_read_lock(). */ 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; if (head->read_step == 0) head->read_step = 1; - down_read(&tomoyo_domain_list_lock); list_for_each_cookie(dpos, head->read_var1, &tomoyo_domain_list) { struct tomoyo_domain_info *domain; const char *quota_exceeded = ""; @@ -1552,7 +1553,6 @@ acl_loop: if (head->read_step == 3) goto tail_mark; /* Print ACL entries in the domain. */ - down_read(&tomoyo_domain_acl_info_list_lock); list_for_each_cookie(apos, head->read_var2, &domain->acl_info_list) { struct tomoyo_acl_info *ptr @@ -1562,7 +1562,6 @@ acl_loop: if (!done) break; } - up_read(&tomoyo_domain_acl_info_list_lock); if (!done) break; head->read_step = 3; @@ -1574,7 +1573,6 @@ tail_mark: if (head->read_single_domain) break; } - up_read(&tomoyo_domain_list_lock); head->read_eof = done; return 0; } @@ -1590,6 +1588,8 @@ tail_mark: * * ( echo "select " $domainname; echo "use_profile " $profile ) | * /usr/lib/ccs/loadpolicy -d + * + * Caller holds tomoyo_read_lock(). */ 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) return -EINVAL; *cp = '\0'; - down_read(&tomoyo_domain_list_lock); domain = tomoyo_find_domain(cp + 1); - up_read(&tomoyo_domain_list_lock); if (strict_strtoul(data, 10, &profile)) return -EINVAL; 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>" ) * domainname = $0; } else if ( $1 == "use_profile" ) { * print $2 " " domainname; domainname = ""; } } ; ' + * + * Caller holds tomoyo_read_lock(). */ 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) return 0; - down_read(&tomoyo_domain_list_lock); list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) { struct tomoyo_domain_info *domain; 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) break; } - up_read(&tomoyo_domain_list_lock); head->read_eof = done; return 0; } @@ -1701,6 +1699,8 @@ static int tomoyo_read_pid(struct tomoyo_io_buffer *head) * @head: Pointer to "struct tomoyo_io_buffer". * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ 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". * * Returns 0 on success, -EINVAL otherwise. + * + * Caller holds tomoyo_read_lock(). */ 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; { /* Check all profiles currently assigned to domains are defined. */ struct tomoyo_domain_info *domain; - down_read(&tomoyo_domain_list_lock); - list_for_each_entry(domain, &tomoyo_domain_list, list) { + list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { const u8 profile = domain->profile; if (tomoyo_profile_ptr[profile]) continue; panic("Profile %u (used by '%s') not defined.\n", 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". * * 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) { @@ -2005,6 +2007,7 @@ static int tomoyo_open_control(const u8 type, struct file *file) return -ENOMEM; } } + head->reader_idx = tomoyo_read_lock(); file->private_data = head; /* * 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. * * Returns bytes read on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_read_control(struct file *file, char __user *buffer, const int buffer_len) @@ -2069,6 +2074,8 @@ static int tomoyo_read_control(struct file *file, char __user *buffer, * @buffer_len: Size of @buffer. * * 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, 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". * * Releases memory and returns 0. + * + * Caller looses tomoyo_read_lock(). */ static int tomoyo_close_control(struct file *file) { struct tomoyo_io_buffer *head = file->private_data; + tomoyo_read_unlock(head->reader_idx); /* Release memory used for policy I/O. */ tomoyo_free(head->read_buf); head->read_buf = NULL; diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index bd10f9fa351..c6f13925472 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -269,6 +269,8 @@ struct tomoyo_io_buffer { int (*write) (struct tomoyo_io_buffer *); /* Exclusive lock for this structure. */ struct mutex io_sem; + /* Index returned by tomoyo_read_lock(). */ + int reader_idx; /* The position currently reading from. */ struct list_head *read_var1; /* Extra variables for reading. */ @@ -446,16 +448,28 @@ extern struct tomoyo_domain_info tomoyo_kernel_domain; * @cookie: the &struct list_head to use as a cookie. * @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. * @cookie must be NULL when iteration starts, and @cookie will become * NULL when iteration finishes. */ -#define list_for_each_cookie(pos, cookie, head) \ - for (({ if (!cookie) \ - cookie = head; }), \ - pos = (cookie)->next; \ - prefetch(pos->next), pos != (head) || ((cookie) = NULL); \ - (cookie) = pos, pos = pos->next) +#define list_for_each_cookie(pos, cookie, head) \ + for (({ if (!cookie) \ + cookie = head; }), \ + pos = rcu_dereference((cookie)->next); \ + prefetch(pos->next), pos != (head) || ((cookie) = NULL); \ + (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) */ diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index fcf52accce2..2fd190168b7 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -217,6 +217,8 @@ static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock); * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_update_domain_initializer_entry(const char *domainname, const char *program, @@ -246,7 +248,7 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, if (!saved_program) return -ENOMEM; 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 || ptr->domainname != saved_domainname || 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->is_not = is_not; 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; out: 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". * * Returns true on success, false otherwise. + * + * Caller holds tomoyo_read_lock(). */ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head) { struct list_head *pos; bool done = true; - down_read(&tomoyo_domain_initializer_list_lock); list_for_each_cookie(pos, head->read_var2, &tomoyo_domain_initializer_list) { const char *no; @@ -308,7 +311,6 @@ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head) if (!done) break; } - up_read(&tomoyo_domain_initializer_list_lock); 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. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ int tomoyo_write_domain_initializer_policy(char *data, const bool is_not, 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, * false otherwise. + * + * Caller holds tomoyo_read_lock(). */ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * domainname, @@ -355,8 +361,7 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * struct tomoyo_domain_initializer_entry *ptr; bool flag = false; - down_read(&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_deleted) continue; if (ptr->domainname) { @@ -376,7 +381,6 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * } flag = true; } - up_read(&tomoyo_domain_initializer_list_lock); return flag; } @@ -430,6 +434,8 @@ static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock); * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_update_domain_keeper_entry(const char *domainname, const char *program, @@ -459,7 +465,7 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, if (!saved_domainname) return -ENOMEM; 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 || ptr->domainname != saved_domainname || 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->is_not = is_not; 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; out: 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_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, 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". * * Returns true on success, false otherwise. + * + * Caller holds tomoyo_read_lock(). */ bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head) { struct list_head *pos; bool done = true; - down_read(&tomoyo_domain_keeper_list_lock); list_for_each_cookie(pos, head->read_var2, &tomoyo_domain_keeper_list) { struct tomoyo_domain_keeper_entry *ptr; @@ -542,7 +550,6 @@ bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head) if (!done) break; } - up_read(&tomoyo_domain_keeper_list_lock); 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, * false otherwise. + * + * Caller holds tomoyo_read_lock(). */ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, 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; bool flag = false; - down_read(&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_deleted) continue; if (!ptr->is_last_name) { @@ -582,7 +590,6 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, } flag = true; } - up_read(&tomoyo_domain_keeper_list_lock); return flag; } @@ -627,6 +634,8 @@ static DECLARE_RWSEM(tomoyo_alias_list_lock); * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_update_alias_entry(const char *original_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) return -ENOMEM; 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 || ptr->aliased_name != saved_aliased_name) continue; @@ -663,7 +672,7 @@ static int tomoyo_update_alias_entry(const char *original_name, 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); + list_add_tail_rcu(&new_entry->list, &tomoyo_alias_list); error = 0; out: 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". * * Returns true on success, false otherwise. + * + * Caller holds tomoyo_read_lock(). */ bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) { struct list_head *pos; bool done = true; - down_read(&tomoyo_alias_list_lock); list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) { struct tomoyo_alias_entry *ptr; @@ -695,7 +705,6 @@ bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) if (!done) break; } - up_read(&tomoyo_alias_list_lock); 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. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ 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. * * 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 * domainname, @@ -742,7 +755,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * if (!saved_domainname) goto out; /* 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 tomoyo_acl_info *ptr; bool flag; @@ -760,7 +773,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * read_unlock(&tasklist_lock); if (flag) 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; } 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); domain->domainname = saved_domainname; domain->profile = profile; - list_add_tail(&domain->list, &tomoyo_domain_list); + list_add_tail_rcu(&domain->list, &tomoyo_domain_list); } out: 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". * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ 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)) { struct tomoyo_alias_entry *ptr; /* Is this program allowed to be called via symbolic links? */ - down_read(&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->is_deleted || tomoyo_pathcmp(&r, ptr->original_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); break; } - up_read(&tomoyo_alias_list_lock); } /* 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) goto done; - down_read(&tomoyo_domain_list_lock); domain = tomoyo_find_domain(new_domain_name); - up_read(&tomoyo_domain_list_lock); if (domain) goto done; if (is_enforce) diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 482f0e7ed99..3c472867634 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -213,6 +213,8 @@ static DECLARE_RWSEM(tomoyo_globally_readable_list_lock); * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_update_globally_readable_entry(const char *filename, const bool is_delete) @@ -228,7 +230,7 @@ static int tomoyo_update_globally_readable_entry(const char *filename, if (!saved_filename) return -ENOMEM; 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) continue; ptr->is_deleted = is_delete; @@ -243,7 +245,7 @@ static int tomoyo_update_globally_readable_entry(const char *filename, if (!new_entry) goto out; 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; out: 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. * * 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 * filename) { struct tomoyo_globally_readable_file_entry *ptr; 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 && tomoyo_path_matches_pattern(filename, ptr->filename)) { found = true; break; } } - up_read(&tomoyo_globally_readable_list_lock); 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. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ 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". * * Returns true on success, false otherwise. + * + * Caller holds tomoyo_read_lock(). */ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) { struct list_head *pos; bool done = true; - down_read(&tomoyo_globally_readable_list_lock); list_for_each_cookie(pos, head->read_var2, &tomoyo_globally_readable_list) { struct tomoyo_globally_readable_file_entry *ptr; @@ -313,7 +319,6 @@ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) if (!done) break; } - up_read(&tomoyo_globally_readable_list_lock); return done; } @@ -356,6 +361,8 @@ static DECLARE_RWSEM(tomoyo_pattern_list_lock); * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_update_file_pattern_entry(const char *pattern, const bool is_delete) @@ -371,7 +378,7 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, if (!saved_pattern) return -ENOMEM; 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) continue; ptr->is_deleted = is_delete; @@ -386,7 +393,7 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, if (!new_entry) goto out; 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; out: 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. * * Returns pointer to pathname pattern if matched, @filename otherwise. + * + * Caller holds tomoyo_read_lock(). */ static const struct tomoyo_path_info * 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; const struct tomoyo_path_info *pattern = NULL; - down_read(&tomoyo_pattern_list_lock); - list_for_each_entry(ptr, &tomoyo_pattern_list, list) { + list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { if (ptr->is_deleted) continue; if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) @@ -420,7 +428,6 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) break; } } - up_read(&tomoyo_pattern_list_lock); if (pattern) filename = pattern; 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. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ 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". * * Returns true on success, false otherwise. + * + * Caller holds tomoyo_read_lock(). */ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) { struct list_head *pos; bool done = true; - down_read(&tomoyo_pattern_list_lock); list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) { struct tomoyo_pattern_entry *ptr; 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) break; } - up_read(&tomoyo_pattern_list_lock); return done; } @@ -505,6 +514,8 @@ static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock); * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_update_no_rewrite_entry(const char *pattern, const bool is_delete) @@ -519,7 +530,7 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern, if (!saved_pattern) return -ENOMEM; down_write(&tomoyo_no_rewrite_list_lock); - list_for_ |