From: "Serge E. Hallyn" <serue@us.ibm.com>
To: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Cc: linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH] TOMOYO: Use RCU primitives for list operation
Date: Mon, 14 Dec 2009 10:39:11 -0600 [thread overview]
Message-ID: <20091214163910.GA8502@us.ibm.com> (raw)
In-Reply-To: <200912112253.BCC87030.FLtMOOFOVSQFJH@I-love.SAKURA.ne.jp>
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
next prev parent reply other threads:[~2009-12-14 16:39 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-12-11 13:53 [PATCH] TOMOYO: Use RCU primitives for list operation Tetsuo Handa
2009-12-14 16:39 ` Serge E. Hallyn [this message]
2009-12-15 1:39 ` Tetsuo Handa
-- strict thread matches above, loose matches on Subject: below --
2009-10-04 12:49 [TOMOYO #16 01/25] LSM: Add security_path_chmod() and security_path_chown() Tetsuo Handa
2009-10-08 17:10 ` John Johansen
2009-10-12 1:04 ` James Morris
2009-10-13 11:34 ` [TOMOYO #16 01/25] LSM: Add security_path_chmod() andsecurity_path_chown() Tetsuo Handa
2009-10-13 11:37 ` [PATCH] TOMOYO: Add recursive directory matching operator support Tetsuo Handa
2009-10-13 11:39 ` [PATCH] TOMOYO: Use RCU primitives for list operation Tetsuo Handa
2009-10-29 5:40 ` Serge E. Hallyn
2009-12-04 12:34 ` Tetsuo Handa
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20091214163910.GA8502@us.ibm.com \
--to=serue@us.ibm.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=penguin-kernel@I-love.SAKURA.ne.jp \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.