Messages in this thread | | | Date | Mon, 14 Dec 2009 10:39:11 -0600 | From | "Serge E. Hallyn" <> | Subject | Re: [PATCH] TOMOYO: Use RCU primitives for list operation |
| |
Quoting Tetsuo Handa (penguin-kernel@I-love.SAKURA.ne.jp): > Can somebody please review?
Thanks, Tetsuo!
Just out of curiosity (and bc I'm personally much more familiar with plain old rcu), I assume you have a list of places where sleeping under rcu is necessary or greatly simplifies/cleans up the code?
Acked-by: Serge Hallyn <serue@us.ibm.com>
-serge
> ---------- > [PATCH] TOMOYO: Use RCU primitives for list operation > > Currently, TOMOYO is using down_read() only for protecting ->prev member from > writers. If we convert list operation using RCU primitives so that readers don't > look at ->prev member, we can replace down_read() by srcu_read_lock(). > > tomoyo_read_lock()/tomoyo_read_unlock() (these are wrappers for > srcu_read_lock()/srcu_read_unlock()) protects the data against the garbage > collector (which will be added in the future). I call tomoyo_read_lock() when > /sys/kernel/security/tomoyo/ interface is open()ed and call > tomoyo_read_unlock() when /sys/kernel/security/tomoyo/ interface is close()d > rather than calling tomoyo_read_lock()/tomoyo_read_unlock() upon individual > read()/write() requests. In this way, the pointers saved in > "struct tomoyo_io_buffer" are guaranteed to be valid. Please ignore > > warning: context imbalance in 'tomoyo_open_control' - wrong count at exit > warning: context imbalance in 'tomoyo_close_control' - unexpected unlock > > messages when built with "C=1" option. > > Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> > --- > common.c | 90 +++++++++++++++++++++++++++---------------------- > common.h | 28 +++++++++++---- > domain.c | 63 ++++++++++++++++++++-------------- > file.c | 110 ++++++++++++++++++++++++++++++++++++++++++------------------- > realpath.c | 8 ++-- > tomoyo.c | 20 +++++++++-- > 6 files changed, 207 insertions(+), 112 deletions(-) > > diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c > index 6c60616..f01b936 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 bd10f9f..c6f1392 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 fcf52ac..2fd1901 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 482f0e7..3c47286 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_each_entry(ptr, &tomoyo_no_rewrite_list, list) { > + list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { > if (ptr->pattern != saved_pattern) > continue; > ptr->is_deleted = is_delete; > @@ -534,7 +545,7 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern, > if (!new_entry) > goto out; > 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; > out: > 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, > * false otherwise. > + * > + * Caller holds tomoyo_read_lock(). > */ > static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) > { > struct tomoyo_no_rewrite_entry *ptr; > bool found = false; > > - down_read(&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->is_deleted) > continue; > 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; > break; > } > - up_read(&tomoyo_no_rewrite_list_lock); > 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. > * > * Returns 0 on success, negative value otherwise. > + * > + * Caller holds tomoyo_read_lock(). > */ > 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". > * > * Returns true on success, false otherwise. > + * > + * Caller holds tomoyo_read_lock(). > */ > bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) > { > struct list_head *pos; > bool done = true; > > - down_read(&tomoyo_no_rewrite_list_lock); > list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) { > struct tomoyo_no_rewrite_entry *ptr; > 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) > break; > } > - up_read(&tomoyo_no_rewrite_list_lock); > 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", > * "allow_read" instead of "4", "allow_write" instead of "2", > * "allow_execute" instead of "1". > + * > + * Caller holds tomoyo_read_lock(). > */ > static int tomoyo_update_file_acl(const char *filename, u8 perm, > 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. > * > * Returns 0 on success, -EPERM otherwise. > + * > + * Caller holds tomoyo_read_lock(). > */ > static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * > domain, > @@ -669,8 +686,7 @@ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * > struct tomoyo_acl_info *ptr; > int error = -EPERM; > > - 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) { > struct tomoyo_single_path_acl_record *acl; > if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) > continue; > @@ -693,7 +709,6 @@ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * > error = 0; > break; > } > - up_read(&tomoyo_domain_acl_info_list_lock); > 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"). > * > * Returns 0 on success, -EPERM otherwise. > + * > + * Caller holds tomoyo_read_lock(). > */ > static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, > 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. > * > * Returns 0 on success, negative value otherwise. > + * > + * Caller holds tomoyo_read_lock(). > */ > static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, > 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. > * > * Returns 0 on success, negative value otherwise. > + * > + * Caller holds tomoyo_read_lock(). > */ > int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, > 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. > * > * 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, > 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); > if (is_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) > continue; > 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)) > acl->perm |= rw_mask; > 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; > goto out; > delete: > 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) > continue; > 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. > * > * 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, > 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); > if (is_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) > continue; > 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->filename1 = saved_filename1; > 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; > goto out; > delete: > 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) > continue; > 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. > * > * Returns 0 on success, negative value otherwise. > + * > + * Caller holds tomoyo_read_lock(). > */ > static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain, > const u8 type, > @@ -1033,6 +1060,8 @@ static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain, > * @filename2: Second filename to check. > * > * Returns 0 on success, -EPERM otherwise. > + * > + * Caller holds tomoyo_read_lock(). > */ > static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, > 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)) > return 0; > - 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) { > struct tomoyo_double_path_acl_record *acl; > if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) > continue; > @@ -1063,7 +1091,6 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, > error = 0; > break; > } > - up_read(&tomoyo_domain_acl_info_list_lock); > return error; > } > > @@ -1076,6 +1103,8 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, > * @mode: Access control mode. > * > * Returns 0 on success, negative value otherwise. > + * > + * Caller holds tomoyo_read_lock(). > */ > static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * > const domain, u8 operation, > @@ -1124,6 +1153,8 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * > * @filename: Check permission for "execute". > * > * Returns 0 on success, negativevalue otherwise. > + * > + * Caller holds tomoyo_read_lock(). > */ > int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, > 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; > const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); > const bool is_enforce = (mode == 3); > + int idx; > > if (!mode || !path->mnt) > return 0; > @@ -1163,6 +1195,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, > * don't call me. > */ > return 0; > + idx = tomoyo_read_lock(); > buf = tomoyo_get_path(path); > if (!buf) > goto out; > @@ -1188,6 +1221,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, > buf, mode); > out: > tomoyo_free(buf); > + tomoyo_read_unlock(idx); > if (!is_enforce) > error = 0; > return error; > @@ -1209,9 +1243,11 @@ int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, > struct tomoyo_path_info *buf; > const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); > const bool is_enforce = (mode == 3); > + int idx; > > if (!mode || !path->mnt) > return 0; > + idx = tomoyo_read_lock(); > buf = tomoyo_get_path(path); > if (!buf) > goto out; > @@ -1231,6 +1267,7 @@ int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, > mode); > out: > tomoyo_free(buf); > + tomoyo_read_unlock(idx); > if (!is_enforce) > error = 0; > 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 bool is_enforce = (mode == 3); > struct tomoyo_path_info *buf; > + int idx; > > if (!mode || !filp->f_path.mnt) > return 0; > + > + idx = tomoyo_read_lock(); > buf = tomoyo_get_path(&filp->f_path); > if (!buf) > goto out; > @@ -1266,6 +1306,7 @@ int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, > buf, mode); > out: > tomoyo_free(buf); > + tomoyo_read_unlock(idx); > if (!is_enforce) > error = 0; > 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 bool is_enforce = (mode == 3); > const char *msg; > + int idx; > > if (!mode || !path1->mnt || !path2->mnt) > return 0; > + idx = tomoyo_read_lock(); > buf1 = tomoyo_get_path(path1); > buf2 = tomoyo_get_path(path2); > if (!buf1 || !buf2) > @@ -1331,6 +1374,7 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain, > out: > tomoyo_free(buf1); > tomoyo_free(buf2); > + tomoyo_read_unlock(idx); > if (!is_enforce) > error = 0; > return error; > diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c > index e3c7aa0..62363b3 100644 > --- a/security/tomoyo/realpath.c > +++ b/security/tomoyo/realpath.c > @@ -402,11 +402,13 @@ void __init tomoyo_realpath_init(void) > INIT_LIST_HEAD(&tomoyo_name_list[i]); > INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); > 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) > panic("Can't register tomoyo_kernel_domain"); > - up_read(&tomoyo_domain_list_lock); > } > > /* Memory allocated for temporary purpose. */ > diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c > index ad9555f..714daa3 100644 > --- a/security/tomoyo/tomoyo.c > +++ b/security/tomoyo/tomoyo.c > @@ -76,8 +76,18 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm) > * Execute permission is checked against pathname passed to do_execve() > * using current domain. > */ > - if (!domain) > - return tomoyo_find_next_domain(bprm); > + if (!domain) { > + /* > + * 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. > * '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, > }; > > +/* Lock for GC. */ > +struct srcu_struct tomoyo_ss; > + > static int __init tomoyo_init(void) > { > struct cred *cred = (struct cred *) current_cred(); > @@ -285,7 +298,8 @@ static int __init tomoyo_init(void) > if (!security_module_enable(&tomoyo_security_ops)) > return 0; > /* 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"); > printk(KERN_INFO "TOMOYO Linux initialized\n"); > cred->security = &tomoyo_kernel_domain; > -- > To unsubscribe from this list: send the line "unsubscribe linux-security-module" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html
| |