diff options
| author | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | 2011-09-25 04:50:23 -0400 |
|---|---|---|
| committer | James Morris <jmorris@namei.org> | 2011-09-25 20:46:20 -0400 |
| commit | f9732ea145886786a6f8b0493bc2239e70cbacdb (patch) | |
| tree | e29b2441cc916a174d7cd0b03cd18986ae545250 /security | |
| parent | 778c4a4d60d932c1df6d270dcbc88365823c3963 (diff) | |
TOMOYO: Simplify garbage collector.
When TOMOYO started using garbage collector at commit 847b173e "TOMOYO: Add
garbage collector.", we waited for close() before kfree(). Thus, elements to be
kfree()d were queued up using tomoyo_gc_list list.
But it turned out that tomoyo_element_linked_by_gc() tends to choke garbage
collector when certain pattern of entries are queued.
Since garbage collector is no longer waiting for close() since commit 2e503bbb
"TOMOYO: Fix lockdep warning.", we can remove tomoyo_gc_list list and
tomoyo_element_linked_by_gc() by doing sequential processing.
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security')
| -rw-r--r-- | security/tomoyo/common.h | 7 | ||||
| -rw-r--r-- | security/tomoyo/condition.c | 8 | ||||
| -rw-r--r-- | security/tomoyo/domain.c | 4 | ||||
| -rw-r--r-- | security/tomoyo/gc.c | 480 | ||||
| -rw-r--r-- | security/tomoyo/memory.c | 6 |
5 files changed, 186 insertions, 319 deletions
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 1a19ad3e67ea..a0212fbf60fb 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
| @@ -52,6 +52,9 @@ | |||
| 52 | 52 | ||
| 53 | #define TOMOYO_EXEC_TMPSIZE 4096 | 53 | #define TOMOYO_EXEC_TMPSIZE 4096 |
| 54 | 54 | ||
| 55 | /* Garbage collector is trying to kfree() this element. */ | ||
| 56 | #define TOMOYO_GC_IN_PROGRESS -1 | ||
| 57 | |||
| 55 | /* Profile number is an integer between 0 and 255. */ | 58 | /* Profile number is an integer between 0 and 255. */ |
| 56 | #define TOMOYO_MAX_PROFILES 256 | 59 | #define TOMOYO_MAX_PROFILES 256 |
| 57 | 60 | ||
| @@ -398,7 +401,7 @@ enum tomoyo_pref_index { | |||
| 398 | /* Common header for holding ACL entries. */ | 401 | /* Common header for holding ACL entries. */ |
| 399 | struct tomoyo_acl_head { | 402 | struct tomoyo_acl_head { |
| 400 | struct list_head list; | 403 | struct list_head list; |
| 401 | bool is_deleted; | 404 | s8 is_deleted; /* true or false or TOMOYO_GC_IN_PROGRESS */ |
| 402 | } __packed; | 405 | } __packed; |
| 403 | 406 | ||
| 404 | /* Common header for shared entries. */ | 407 | /* Common header for shared entries. */ |
| @@ -665,7 +668,7 @@ struct tomoyo_condition { | |||
| 665 | struct tomoyo_acl_info { | 668 | struct tomoyo_acl_info { |
| 666 | struct list_head list; | 669 | struct list_head list; |
| 667 | struct tomoyo_condition *cond; /* Maybe NULL. */ | 670 | struct tomoyo_condition *cond; /* Maybe NULL. */ |
| 668 | bool is_deleted; | 671 | s8 is_deleted; /* true or false or TOMOYO_GC_IN_PROGRESS */ |
| 669 | u8 type; /* One of values in "enum tomoyo_acl_entry_type_index". */ | 672 | u8 type; /* One of values in "enum tomoyo_acl_entry_type_index". */ |
| 670 | } __packed; | 673 | } __packed; |
| 671 | 674 | ||
diff --git a/security/tomoyo/condition.c b/security/tomoyo/condition.c index b854959c0fd4..986330b8c73e 100644 --- a/security/tomoyo/condition.c +++ b/security/tomoyo/condition.c | |||
| @@ -400,8 +400,9 @@ static struct tomoyo_condition *tomoyo_commit_condition | |||
| 400 | found = true; | 400 | found = true; |
| 401 | goto out; | 401 | goto out; |
| 402 | } | 402 | } |
| 403 | list_for_each_entry_rcu(ptr, &tomoyo_condition_list, head.list) { | 403 | list_for_each_entry(ptr, &tomoyo_condition_list, head.list) { |
| 404 | if (!tomoyo_same_condition(ptr, entry)) | 404 | if (!tomoyo_same_condition(ptr, entry) || |
| 405 | atomic_read(&ptr->head.users) == TOMOYO_GC_IN_PROGRESS) | ||
| 405 | continue; | 406 | continue; |
| 406 | /* Same entry found. Share this entry. */ | 407 | /* Same entry found. Share this entry. */ |
| 407 | atomic_inc(&ptr->head.users); | 408 | atomic_inc(&ptr->head.users); |
| @@ -411,8 +412,7 @@ static struct tomoyo_condition *tomoyo_commit_condition | |||
| 411 | if (!found) { | 412 | if (!found) { |
| 412 | if (tomoyo_memory_ok(entry)) { | 413 | if (tomoyo_memory_ok(entry)) { |
| 413 | atomic_set(&entry->head.users, 1); | 414 | atomic_set(&entry->head.users, 1); |
| 414 | list_add_rcu(&entry->head.list, | 415 | list_add(&entry->head.list, &tomoyo_condition_list); |
| 415 | &tomoyo_condition_list); | ||
| 416 | } else { | 416 | } else { |
| 417 | found = true; | 417 | found = true; |
| 418 | ptr = NULL; | 418 | ptr = NULL; |
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 70acf7aebbda..da16dfeed728 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
| @@ -39,6 +39,8 @@ int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size, | |||
| 39 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 39 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
| 40 | return -ENOMEM; | 40 | return -ENOMEM; |
| 41 | list_for_each_entry_rcu(entry, list, list) { | 41 | list_for_each_entry_rcu(entry, list, list) { |
| 42 | if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS) | ||
| 43 | continue; | ||
| 42 | if (!check_duplicate(entry, new_entry)) | 44 | if (!check_duplicate(entry, new_entry)) |
| 43 | continue; | 45 | continue; |
| 44 | entry->is_deleted = param->is_delete; | 46 | entry->is_deleted = param->is_delete; |
| @@ -115,6 +117,8 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, | |||
| 115 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 117 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
| 116 | goto out; | 118 | goto out; |
| 117 | list_for_each_entry_rcu(entry, list, list) { | 119 | list_for_each_entry_rcu(entry, list, list) { |
| 120 | if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS) | ||
| 121 | continue; | ||
| 118 | if (!tomoyo_same_acl_head(entry, new_entry) || | 122 | if (!tomoyo_same_acl_head(entry, new_entry) || |
| 119 | !check_duplicate(entry, new_entry)) | 123 | !check_duplicate(entry, new_entry)) |
| 120 | continue; | 124 | continue; |
diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c index 7747ceb9a221..f2295c65f1e4 100644 --- a/security/tomoyo/gc.c +++ b/security/tomoyo/gc.c | |||
| @@ -13,35 +13,6 @@ static LIST_HEAD(tomoyo_io_buffer_list); | |||
| 13 | /* Lock for protecting tomoyo_io_buffer_list. */ | 13 | /* Lock for protecting tomoyo_io_buffer_list. */ |
| 14 | static DEFINE_SPINLOCK(tomoyo_io_buffer_list_lock); | 14 | static DEFINE_SPINLOCK(tomoyo_io_buffer_list_lock); |
| 15 | 15 | ||
| 16 | /* Size of an element. */ | ||
| 17 | static const u8 tomoyo_element_size[TOMOYO_MAX_POLICY] = { | ||
| 18 | [TOMOYO_ID_GROUP] = sizeof(struct tomoyo_group), | ||
| 19 | [TOMOYO_ID_ADDRESS_GROUP] = sizeof(struct tomoyo_address_group), | ||
| 20 | [TOMOYO_ID_PATH_GROUP] = sizeof(struct tomoyo_path_group), | ||
| 21 | [TOMOYO_ID_NUMBER_GROUP] = sizeof(struct tomoyo_number_group), | ||
| 22 | [TOMOYO_ID_AGGREGATOR] = sizeof(struct tomoyo_aggregator), | ||
| 23 | [TOMOYO_ID_TRANSITION_CONTROL] = | ||
| 24 | sizeof(struct tomoyo_transition_control), | ||
| 25 | [TOMOYO_ID_MANAGER] = sizeof(struct tomoyo_manager), | ||
| 26 | /* [TOMOYO_ID_CONDITION] = "struct tomoyo_condition"->size, */ | ||
| 27 | /* [TOMOYO_ID_NAME] = "struct tomoyo_name"->size, */ | ||
| 28 | /* [TOMOYO_ID_ACL] = | ||
| 29 | tomoyo_acl_size["struct tomoyo_acl_info"->type], */ | ||
| 30 | [TOMOYO_ID_DOMAIN] = sizeof(struct tomoyo_domain_info), | ||
| 31 | }; | ||
| 32 | |||
| 33 | /* Size of a domain ACL element. */ | ||
| 34 | static const u8 tomoyo_acl_size[] = { | ||
| 35 | [TOMOYO_TYPE_PATH_ACL] = sizeof(struct tomoyo_path_acl), | ||
| 36 | [TOMOYO_TYPE_PATH2_ACL] = sizeof(struct tomoyo_path2_acl), | ||
| 37 | [TOMOYO_TYPE_PATH_NUMBER_ACL] = sizeof(struct tomoyo_path_number_acl), | ||
| 38 | [TOMOYO_TYPE_MKDEV_ACL] = sizeof(struct tomoyo_mkdev_acl), | ||
| 39 | [TOMOYO_TYPE_MOUNT_ACL] = sizeof(struct tomoyo_mount_acl), | ||
| 40 | [TOMOYO_TYPE_INET_ACL] = sizeof(struct tomoyo_inet_acl), | ||
| 41 | [TOMOYO_TYPE_UNIX_ACL] = sizeof(struct tomoyo_unix_acl), | ||
| 42 | [TOMOYO_TYPE_ENV_ACL] = sizeof(struct tomoyo_env_acl), | ||
| 43 | }; | ||
| 44 | |||
| 45 | /** | 16 | /** |
| 46 | * tomoyo_struct_used_by_io_buffer - Check whether the list element is used by /sys/kernel/security/tomoyo/ users or not. | 17 | * tomoyo_struct_used_by_io_buffer - Check whether the list element is used by /sys/kernel/security/tomoyo/ users or not. |
| 47 | * | 18 | * |
| @@ -59,15 +30,11 @@ static bool tomoyo_struct_used_by_io_buffer(const struct list_head *element) | |||
| 59 | list_for_each_entry(head, &tomoyo_io_buffer_list, list) { | 30 | list_for_each_entry(head, &tomoyo_io_buffer_list, list) { |
| 60 | head->users++; | 31 | head->users++; |
| 61 | spin_unlock(&tomoyo_io_buffer_list_lock); | 32 | spin_unlock(&tomoyo_io_buffer_list_lock); |
| 62 | if (mutex_lock_interruptible(&head->io_sem)) { | 33 | mutex_lock(&head->io_sem); |
| 63 | in_use = true; | ||
| 64 | goto out; | ||
| 65 | } | ||
| 66 | if (head->r.domain == element || head->r.group == element || | 34 | if (head->r.domain == element || head->r.group == element || |
| 67 | head->r.acl == element || &head->w.domain->list == element) | 35 | head->r.acl == element || &head->w.domain->list == element) |
| 68 | in_use = true; | 36 | in_use = true; |
| 69 | mutex_unlock(&head->io_sem); | 37 | mutex_unlock(&head->io_sem); |
| 70 | out: | ||
| 71 | spin_lock(&tomoyo_io_buffer_list_lock); | 38 | spin_lock(&tomoyo_io_buffer_list_lock); |
| 72 | head->users--; | 39 | head->users--; |
| 73 | if (in_use) | 40 | if (in_use) |
| @@ -81,15 +48,14 @@ out: | |||
| 81 | * tomoyo_name_used_by_io_buffer - Check whether the string is used by /sys/kernel/security/tomoyo/ users or not. | 48 | * tomoyo_name_used_by_io_buffer - Check whether the string is used by /sys/kernel/security/tomoyo/ users or not. |
| 82 | * | 49 | * |
| 83 | * @string: String to check. | 50 | * @string: String to check. |
| 84 | * @size: Memory allocated for @string . | ||
| 85 | * | 51 | * |
| 86 | * Returns true if @string is used by /sys/kernel/security/tomoyo/ users, | 52 | * Returns true if @string is used by /sys/kernel/security/tomoyo/ users, |
| 87 | * false otherwise. | 53 | * false otherwise. |
| 88 | */ | 54 | */ |
| 89 | static bool tomoyo_name_used_by_io_buffer(const char *string, | 55 | static bool tomoyo_name_used_by_io_buffer(const char *string) |
| 90 | const size_t size) | ||
| 91 | { | 56 | { |
| 92 | struct tomoyo_io_buffer *head; | 57 | struct tomoyo_io_buffer *head; |
| 58 | const size_t size = strlen(string) + 1; | ||
| 93 | bool in_use = false; | 59 | bool in_use = false; |
| 94 | 60 | ||
| 95 | spin_lock(&tomoyo_io_buffer_list_lock); | 61 | spin_lock(&tomoyo_io_buffer_list_lock); |
| @@ -97,10 +63,7 @@ static bool tomoyo_name_used_by_io_buffer(const char *string, | |||
| 97 | int i; | 63 | int i; |
| 98 | head->users++; | 64 | head->users++; |
| 99 | spin_unlock(&tomoyo_io_buffer_list_lock); | 65 | spin_unlock(&tomoyo_io_buffer_list_lock); |
| 100 | if (mutex_lock_interruptible(&head->io_sem)) { | 66 | mutex_lock(&head->io_sem); |
| 101 | in_use = true; | ||
| 102 | goto out; | ||
| 103 | } | ||
| 104 | for (i = 0; i < TOMOYO_MAX_IO_READ_QUEUE; i++) { | 67 | for (i = 0; i < TOMOYO_MAX_IO_READ_QUEUE; i++) { |
| 105 | const char *w = head->r.w[i]; | 68 | const char *w = head->r.w[i]; |
| 106 | if (w < string || w > string + size) | 69 | if (w < string || w > string + size) |
| @@ -109,7 +72,6 @@ static bool tomoyo_name_used_by_io_buffer(const char *string, | |||
| 109 | break; | 72 | break; |
| 110 | } | 73 | } |
| 111 | mutex_unlock(&head->io_sem); | 74 | mutex_unlock(&head->io_sem); |
| 112 | out: | ||
| 113 | spin_lock(&tomoyo_io_buffer_list_lock); | 75 | spin_lock(&tomoyo_io_buffer_list_lock); |
| 114 | head->users--; | 76 | head->users--; |
| 115 | if (in_use) | 77 | if (in_use) |
| @@ -119,84 +81,6 @@ out: | |||
| 119 | return in_use; | 81 | return in_use; |
| 120 | } | 82 | } |
| 121 | 83 | ||
| 122 | /* Structure for garbage collection. */ | ||
| 123 | struct tomoyo_gc { | ||
| 124 | struct list_head list; | ||
| 125 | enum tomoyo_policy_id type; | ||
| 126 | size_t size; | ||
| 127 | struct list_head *element; | ||
| 128 | }; | ||
| 129 | /* List of entries to be deleted. */ | ||
| 130 | static LIST_HEAD(tomoyo_gc_list); | ||
| 131 | /* Length of tomoyo_gc_list. */ | ||
| 132 | static int tomoyo_gc_list_len; | ||
| 133 | |||
| 134 | /** | ||
| 135 | * tomoyo_add_to_gc - Add an entry to to be deleted list. | ||
| 136 | * | ||
| 137 | * @type: One of values in "enum tomoyo_policy_id". | ||
| 138 | * @element: Pointer to "struct list_head". | ||
| 139 | * | ||
| 140 | * Returns true on success, false otherwise. | ||
| 141 | * | ||
| 142 | * Caller holds tomoyo_policy_lock mutex. | ||
| 143 | * | ||
| 144 | * Adding an entry needs kmalloc(). Thus, if we try to add thousands of | ||
| 145 | * entries at once, it will take too long time. Thus, do not add more than 128 | ||
| 146 | * entries per a scan. But to be able to handle worst case where all entries | ||
| 147 | * are in-use, we accept one more entry per a scan. | ||
| 148 | * | ||
| 149 | * If we use singly linked list using "struct list_head"->prev (which is | ||
| 150 | * LIST_POISON2), we can avoid kmalloc(). | ||
| 151 | */ | ||
| 152 | static bool tomoyo_add_to_gc(const int type, struct list_head *element) | ||
| 153 | { | ||
| 154 | struct tomoyo_gc *entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | ||
| 155 | if (!entry) | ||
| 156 | return false; | ||
| 157 | entry->type = type; | ||
| 158 | if (type == TOMOYO_ID_ACL) | ||
| 159 | entry->size = tomoyo_acl_size[ | ||
| 160 | container_of(element, | ||
| 161 | typeof(struct tomoyo_acl_info), | ||
| 162 | list)->type]; | ||
| 163 | else if (type == TOMOYO_ID_NAME) | ||
| 164 | entry->size = strlen(container_of(element, | ||
| 165 | typeof(struct tomoyo_name), | ||
| 166 | head.list)->entry.name) + 1; | ||
| 167 | else if (type == TOMOYO_ID_CONDITION) | ||
| 168 | entry->size = | ||
| 169 | container_of(element, typeof(struct tomoyo_condition), | ||
| 170 | head.list)->size; | ||
| 171 | else | ||
| 172 | entry->size = tomoyo_element_size[type]; | ||
| 173 | entry->element = element; | ||
| 174 | list_add(&entry->list, &tomoyo_gc_list); | ||
| 175 | list_del_rcu(element); | ||
| 176 | return tomoyo_gc_list_len++ < 128; | ||
| 177 | } | ||
| 178 | |||
| 179 | /** | ||
| 180 | * tomoyo_element_linked_by_gc - Validate next element of an entry. | ||
| 181 | * | ||
| 182 | * @element: Pointer to an element. | ||
| 183 | * @size: Size of @element in byte. | ||
| 184 | * | ||
| 185 | * Returns true if @element is linked by other elements in the garbage | ||
| 186 | * collector's queue, false otherwise. | ||
| 187 | */ | ||
| 188 | static bool tomoyo_element_linked_by_gc(const u8 *element, const size_t size) | ||
| 189 | { | ||
| 190 | struct tomoyo_gc *p; | ||
| 191 | list_for_each_entry(p, &tomoyo_gc_list, list) { | ||
| 192 | const u8 *ptr = (const u8 *) p->element->next; | ||
| 193 | if (ptr < element || element + size < ptr) | ||
| 194 | continue; | ||
| 195 | return true; | ||
| 196 | } | ||
| 197 | return false; | ||
| 198 | } | ||
| 199 | |||
| 200 | /** | 84 | /** |
| 201 | * tomoyo_del_transition_control - Delete members in "struct tomoyo_transition_control". | 85 | * tomoyo_del_transition_control - Delete members in "struct tomoyo_transition_control". |
| 202 | * | 86 | * |
| @@ -204,7 +88,7 @@ static bool tomoyo_element_linked_by_gc(const u8 *element, const size_t size) | |||
| 204 | * | 88 | * |
| 205 | * Returns nothing. | 89 | * Returns nothing. |
| 206 | */ | 90 | */ |
| 207 | static void tomoyo_del_transition_control(struct list_head *element) | 91 | static inline void tomoyo_del_transition_control(struct list_head *element) |
| 208 | { | 92 | { |
| 209 | struct tomoyo_transition_control *ptr = | 93 | struct tomoyo_transition_control *ptr = |
| 210 | container_of(element, typeof(*ptr), head.list); | 94 | container_of(element, typeof(*ptr), head.list); |
| @@ -219,7 +103,7 @@ static void tomoyo_del_transition_control(struct list_head *element) | |||
| 219 | * | 103 | * |
| 220 | * Returns nothing. | 104 | * Returns nothing. |
| 221 | */ | 105 | */ |
| 222 | static void tomoyo_del_aggregator(struct list_head *element) | 106 | static inline void tomoyo_del_aggregator(struct list_head *element) |
| 223 | { | 107 | { |
| 224 | struct tomoyo_aggregator *ptr = | 108 | struct tomoyo_aggregator *ptr = |
| 225 | container_of(element, typeof(*ptr), head.list); | 109 | container_of(element, typeof(*ptr), head.list); |
| @@ -234,7 +118,7 @@ static void tomoyo_del_aggregator(struct list_head *element) | |||
| 234 | * | 118 | * |
| 235 | * Returns nothing. | 119 | * Returns nothing. |
| 236 | */ | 120 | */ |
| 237 | static void tomoyo_del_manager(struct list_head *element) | 121 | static inline void tomoyo_del_manager(struct list_head *element) |
| 238 | { | 122 | { |
| 239 | struct tomoyo_manager *ptr = | 123 | struct tomoyo_manager *ptr = |
| 240 | container_of(element, typeof(*ptr), head.list); | 124 | container_of(element, typeof(*ptr), head.list); |
| @@ -330,44 +214,24 @@ static void tomoyo_del_acl(struct list_head *element) | |||
| 330 | * | 214 | * |
| 331 | * @element: Pointer to "struct list_head". | 215 | * @element: Pointer to "struct list_head". |
| 332 | * | 216 | * |
| 333 | * Returns true if deleted, false otherwise. | 217 | * Returns nothing. |
| 334 | */ | 218 | */ |
| 335 | static bool tomoyo_del_domain(struct list_head *element) | 219 | static inline void tomoyo_del_domain(struct list_head *element) |
| 336 | { | 220 | { |
| 337 | struct tomoyo_domain_info *domain = | 221 | struct tomoyo_domain_info *domain = |
| 338 | container_of(element, typeof(*domain), list); | 222 | container_of(element, typeof(*domain), list); |
| 339 | struct tomoyo_acl_info *acl; | 223 | struct tomoyo_acl_info *acl; |
| 340 | struct tomoyo_acl_info *tmp; | 224 | struct tomoyo_acl_info *tmp; |
| 341 | /* | 225 | /* |
| 342 | * Since we don't protect whole execve() operation using SRCU, | 226 | * Since this domain is referenced from neither |
| 343 | * we need to recheck domain->users at this point. | 227 | * "struct tomoyo_io_buffer" nor "struct cred"->security, we can delete |
| 344 | * | 228 | * elements without checking for is_deleted flag. |
| 345 | * (1) Reader starts SRCU section upon execve(). | ||
| 346 | * (2) Reader traverses tomoyo_domain_list and finds this domain. | ||
| 347 | * (3) Writer marks this domain as deleted. | ||
| 348 | * (4) Garbage collector removes this domain from tomoyo_domain_list | ||
| 349 | * because this domain is marked as deleted and used by nobody. | ||
| 350 | * (5) Reader saves reference to this domain into | ||
| 351 | * "struct linux_binprm"->cred->security . | ||
| 352 | * (6) Reader finishes SRCU section, although execve() operation has | ||
| 353 | * not finished yet. | ||
| 354 | * (7) Garbage collector waits for SRCU synchronization. | ||
| 355 | * (8) Garbage collector kfree() this domain because this domain is | ||
| 356 | * used by nobody. | ||
| 357 | * (9) Reader finishes execve() operation and restores this domain from | ||
| 358 | * "struct linux_binprm"->cred->security. | ||
| 359 | * | ||
| 360 | * By updating domain->users at (5), we can solve this race problem | ||
| 361 | * by rechecking domain->users at (8). | ||
| 362 | */ | 229 | */ |
| 363 | if (atomic_read(&domain->users)) | ||
| 364 | return false; | ||
| 365 | list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) { | 230 | list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) { |
| 366 | tomoyo_del_acl(&acl->list); | 231 | tomoyo_del_acl(&acl->list); |
| 367 | tomoyo_memory_free(acl); | 232 | tomoyo_memory_free(acl); |
| 368 | } | 233 | } |
| 369 | tomoyo_put_name(domain->domainname); | 234 | tomoyo_put_name(domain->domainname); |
| 370 | return true; | ||
| 371 | } | 235 | } |
| 372 | 236 | ||
| 373 | /** | 237 | /** |
| @@ -416,10 +280,9 @@ void tomoyo_del_condition(struct list_head *element) | |||
| 416 | * | 280 | * |
| 417 | * Returns nothing. | 281 | * Returns nothing. |
| 418 | */ | 282 | */ |
| 419 | static void tomoyo_del_name(struct list_head *element) | 283 | static inline void tomoyo_del_name(struct list_head *element) |
| 420 | { | 284 | { |
| 421 | const struct tomoyo_name *ptr = | 285 | /* Nothing to do. */ |
| 422 | container_of(element, typeof(*ptr), head.list); | ||
| 423 | } | 286 | } |
| 424 | 287 | ||
| 425 | /** | 288 | /** |
| @@ -429,7 +292,7 @@ static void tomoyo_del_name(struct list_head *element) | |||
| 429 | * | 292 | * |
| 430 | * Returns nothing. | 293 | * Returns nothing. |
| 431 | */ | 294 | */ |
| 432 | static void tomoyo_del_path_group(struct list_head *element) | 295 | static inline void tomoyo_del_path_group(struct list_head *element) |
| 433 | { | 296 | { |
| 434 | struct tomoyo_path_group *member = | 297 | struct tomoyo_path_group *member = |
| 435 | container_of(element, typeof(*member), head.list); | 298 | container_of(element, typeof(*member), head.list); |
| @@ -443,7 +306,7 @@ static void tomoyo_del_path_group(struct list_head *element) | |||
| 443 | * | 306 | * |
| 444 | * Returns nothing. | 307 | * Returns nothing. |
| 445 | */ | 308 | */ |
| 446 | static void tomoyo_del_group(struct list_head *element) | 309 | static inline void tomoyo_del_group(struct list_head *element) |
| 447 | { | 310 | { |
| 448 | struct tomoyo_group *group = | 311 | struct tomoyo_group *group = |
| 449 | container_of(element, typeof(*group), head.list); | 312 | container_of(element, typeof(*group), head.list); |
| @@ -469,10 +332,109 @@ static inline void tomoyo_del_address_group(struct list_head *element) | |||
| 469 | * | 332 | * |
| 470 | * Returns nothing. | 333 | * Returns nothing. |
| 471 | */ | 334 | */ |
| 472 | static void tomoyo_del_number_group(struct list_head *element) | 335 | static inline void tomoyo_del_number_group(struct list_head *element) |
| 473 | { | 336 | { |
| 474 | struct tomoyo_number_group *member = | 337 | /* Nothing to do. */ |
| 475 | container_of(element, typeof(*member), head.list); | 338 | } |
| 339 | |||
| 340 | /** | ||
| 341 | * tomoyo_try_to_gc - Try to kfree() an entry. | ||
| 342 | * | ||
| 343 | * @type: One of values in "enum tomoyo_policy_id". | ||
| 344 | * @element: Pointer to "struct list_head". | ||
| 345 | * | ||
| 346 | * Returns nothing. | ||
| 347 | * | ||
| 348 | * Caller holds tomoyo_policy_lock mutex. | ||
| 349 | */ | ||
| 350 | static void tomoyo_try_to_gc(const enum tomoyo_policy_id type, | ||
| 351 | struct list_head *element) | ||
| 352 | { | ||
| 353 | /* | ||
| 354 | * __list_del_entry() guarantees that the list element became no longer | ||
| 355 | * reachable from the list which the element was originally on (e.g. | ||
| 356 | * tomoyo_domain_list). Also, synchronize_srcu() guarantees that the | ||
| 357 | * list element became no longer referenced by syscall users. | ||
| 358 | */ | ||
| 359 | __list_del_entry(element); | ||
| 360 | mutex_unlock(&tomoyo_policy_lock); | ||
| 361 | synchronize_srcu(&tomoyo_ss); | ||
| 362 | /* | ||
| 363 | * However, there are two users which may still be using the list | ||
| 364 | * element. We need to defer until both users forget this element. | ||
| 365 | * | ||
| 366 | * Don't kfree() until "struct tomoyo_io_buffer"->r.{domain,group,acl} | ||
| 367 | * and "struct tomoyo_io_buffer"->w.domain forget this element. | ||
| 368 | */ | ||
| 369 | if (tomoyo_struct_used_by_io_buffer(element)) | ||
| 370 | goto reinject; | ||
| 371 | switch (type) { | ||
| 372 | case TOMOYO_ID_TRANSITION_CONTROL: | ||
| 373 | tomoyo_del_transition_control(element); | ||
| 374 | break; | ||
| 375 | case TOMOYO_ID_MANAGER: | ||
| 376 | tomoyo_del_manager(element); | ||
| 377 | break; | ||
| 378 | case TOMOYO_ID_AGGREGATOR: | ||
| 379 | tomoyo_del_aggregator(element); | ||
| 380 | break; | ||
| 381 | case TOMOYO_ID_GROUP: | ||
| 382 | tomoyo_del_group(element); | ||
| 383 | break; | ||
| 384 | case TOMOYO_ID_PATH_GROUP: | ||
| 385 | tomoyo_del_path_group(element); | ||
| 386 | break; | ||
| 387 | case TOMOYO_ID_ADDRESS_GROUP: | ||
| 388 | tomoyo_del_address_group(element); | ||
| 389 | break; | ||
| 390 | case TOMOYO_ID_NUMBER_GROUP: | ||
| 391 | tomoyo_del_number_group(element); | ||
| 392 | break; | ||
| 393 | case TOMOYO_ID_CONDITION: | ||
| 394 | tomoyo_del_condition(element); | ||
| 395 | break; | ||
| 396 | case TOMOYO_ID_NAME: | ||
| 397 | /* | ||
| 398 | * Don't kfree() until all "struct tomoyo_io_buffer"->r.w[] | ||
| 399 | * forget this element. | ||
| 400 | */ | ||
| 401 | if (tomoyo_name_used_by_io_buffer | ||
| 402 | (container_of(element, typeof(struct tomoyo_name), | ||
| 403 | head.list)->entry.name)) | ||
| 404 | goto reinject; | ||
| 405 | tomoyo_del_name(element); | ||
| 406 | break; | ||
| 407 | case TOMOYO_ID_ACL: | ||
| 408 | tomoyo_del_acl(element); | ||
| 409 | break; | ||
| 410 | case TOMOYO_ID_DOMAIN: | ||
| 411 | /* | ||
| 412 | * Don't kfree() until all "struct cred"->security forget this | ||
| 413 | * element. | ||
| 414 | */ | ||
| 415 | if (atomic_read(&container_of | ||
| 416 | (element, typeof(struct tomoyo_domain_info), | ||
| 417 | list)->users)) | ||
| 418 | goto reinject; | ||
| 419 | tomoyo_del_domain(element); | ||
| 420 | break; | ||
| 421 | case TOMOYO_MAX_POLICY: | ||
| 422 | break; | ||
| 423 | } | ||
| 424 | mutex_lock(&tomoyo_policy_lock); | ||
| 425 | tomoyo_memory_free(element); | ||
| 426 | return; | ||
| 427 | reinject: | ||
| 428 | /* | ||
| 429 | * We can safely reinject this element here bacause | ||
| 430 | * (1) Appending list elements and removing list elements are protected | ||
| 431 | * by tomoyo_policy_lock mutex. | ||
| 432 | * (2) Only this function removes list elements and this function is | ||
| 433 | * exclusively executed by tomoyo_gc_mutex mutex. | ||
| 434 | * are true. | ||
| 435 | */ | ||
| 436 | mutex_lock(&tomoyo_policy_lock); | ||
| 437 | list_add_rcu(element, element->prev); | ||
| 476 | } | 438 | } |
| 477 | 439 | ||
| 478 | /** | 440 | /** |
| @@ -481,19 +443,19 @@ static void tomoyo_del_number_group(struct list_head *element) | |||
| 481 | * @id: One of values in "enum tomoyo_policy_id". | 443 | * @id: One of values in "enum tomoyo_policy_id". |
| 482 | * @member_list: Pointer to "struct list_head". | 444 | * @member_list: Pointer to "struct list_head". |
| 483 | * | 445 | * |
| 484 | * Returns true if some elements are deleted, false otherwise. | 446 | * Returns nothing. |
| 485 | */ | 447 | */ |
| 486 | static bool tomoyo_collect_member(const enum tomoyo_policy_id id, | 448 | static void tomoyo_collect_member(const enum tomoyo_policy_id id, |
| 487 | struct list_head *member_list) | 449 | struct list_head *member_list) |
| 488 | { | 450 | { |
| 489 | struct tomoyo_acl_head *member; | 451 | struct tomoyo_acl_head *member; |
| 490 | list_for_each_entry(member, member_list, list) { | 452 | struct tomoyo_acl_head *tmp; |
| 453 | list_for_each_entry_safe(member, tmp, member_list, list) { | ||
| 491 | if (!member->is_deleted) | 454 | if (!member->is_deleted) |
| 492 | continue; | 455 | continue; |
| 493 | if (!tomoyo_add_to_gc(id, &member->list)) | 456 | member->is_deleted = TOMOYO_GC_IN_PROGRESS; |
| 494 | return false; | 457 | tomoyo_try_to_gc(id, &member->list); |
| 495 | } | 458 | } |
| 496 | return true; | ||
| 497 | } | 459 | } |
| 498 | 460 | ||
| 499 | /** | 461 | /** |
| @@ -501,22 +463,22 @@ static bool tomoyo_collect_member(const enum tomoyo_policy_id id, | |||
| 501 | * | 463 | * |
| 502 | * @list: Pointer to "struct list_head". | 464 | * @list: Pointer to "struct list_head". |
| 503 | * | 465 | * |
| 504 | * Returns true if some elements are deleted, false otherwise. | 466 | * Returns nothing. |
| 505 | */ | 467 | */ |
| 506 | static bool tomoyo_collect_acl(struct list_head *list) | 468 | static void tomoyo_collect_acl(struct list_head *list) |
| 507 | { | 469 | { |
| 508 | struct tomoyo_acl_info *acl; | 470 | struct tomoyo_acl_info *acl; |
| 509 | list_for_each_entry(acl, list, list) { | 471 | struct tomoyo_acl_info *tmp; |
| 472 | list_for_each_entry_safe(acl, tmp, list, list) { | ||
| 510 | if (!acl->is_deleted) | 473 | if (!acl->is_deleted) |
| 511 | continue; | 474 | continue; |
| 512 | if (!tomoyo_add_to_gc(TOMOYO_ID_ACL, &acl->list)) | 475 | acl->is_deleted = TOMOYO_GC_IN_PROGRESS; |
| 513 | return false; | 476 | tomoyo_try_to_gc(TOMOYO_ID_ACL, &acl->list); |
| 514 | } | 477 | } |
| 515 | return true; | ||
| 516 | } | 478 | } |
| 517 | 479 | ||
| 518 | /** | 480 | /** |
| 519 | * tomoyo_collect_entry - Scan lists for deleted elements. | 481 | * tomoyo_collect_entry - Try to kfree() deleted elements. |
| 520 | * | 482 | * |
| 521 | * Returns nothing. | 483 | * Returns nothing. |
| 522 | */ | 484 | */ |
| @@ -525,36 +487,40 @@ static void tomoyo_collect_entry(void) | |||
| 525 | int i; | 487 | int i; |
| 526 | enum tomoyo_policy_id id; | 488 | enum tomoyo_policy_id id; |
| 527 | struct tomoyo_policy_namespace *ns; | 489 | struct tomoyo_policy_namespace *ns; |
| 528 | int idx; | 490 | mutex_lock(&tomoyo_policy_lock); |
| 529 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | ||
| 530 | return; | ||
| 531 | idx = tomoyo_read_lock(); | ||
| 532 | { | 491 | { |
| 533 | struct tomoyo_domain_info *domain; | 492 | struct tomoyo_domain_info *domain; |
| 534 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | 493 | struct tomoyo_domain_info *tmp; |
| 535 | if (!tomoyo_collect_acl(&domain->acl_info_list)) | 494 | list_for_each_entry_safe(domain, tmp, &tomoyo_domain_list, |
| 536 | goto unlock; | 495 | list) { |
| 496 | tomoyo_collect_acl(&domain->acl_info_list); | ||
| 537 | if (!domain->is_deleted || atomic_read(&domain->users)) | 497 | if (!domain->is_deleted || atomic_read(&domain->users)) |
| 538 | continue; | 498 | continue; |
| 539 | /* | 499 | tomoyo_try_to_gc(TOMOYO_ID_DOMAIN, &domain->list); |
| 540 | * Nobody is referring this domain. But somebody may | ||
| 541 | * refer this domain after successful execve(). | ||
| 542 | * We recheck domain->users after SRCU synchronization. | ||
| 543 | */ | ||
| 544 | if (!tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, &domain->list)) | ||
| 545 | goto unlock; | ||
| 546 | } | 500 | } |
| 547 | } | 501 | } |
| 548 | list_for_each_entry_rcu(ns, &tomoyo_namespace_list, namespace_list) { | 502 | list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) { |
| 549 | for (id = 0; id < TOMOYO_MAX_POLICY; id++) | 503 | for (id = 0; id < TOMOYO_MAX_POLICY; id++) |
| 550 | if (!tomoyo_collect_member(id, &ns->policy_list[id])) | 504 | tomoyo_collect_member(id, &ns->policy_list[id]); |
| 551 | goto unlock; | ||
| 552 | for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++) | 505 | for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++) |
| 553 | if (!tomoyo_collect_acl(&ns->acl_group[i])) | 506 | tomoyo_collect_acl(&ns->acl_group[i]); |
| 554 | goto unlock; | 507 | } |
| 508 | { | ||
| 509 | struct tomoyo_shared_acl_head *ptr; | ||
| 510 | struct tomoyo_shared_acl_head *tmp; | ||
| 511 | list_for_each_entry_safe(ptr, tmp, &tomoyo_condition_list, | ||
| 512 | list) { | ||
| 513 | if (atomic_read(&ptr->users) > 0) | ||
| 514 | continue; | ||
| 515 | atomic_set(&ptr->users, TOMOYO_GC_IN_PROGRESS); | ||
| 516 | tomoyo_try_to_gc(TOMOYO_ID_CONDITION, &ptr->list); | ||
| 517 | } | ||
| 518 | } | ||
| 519 | list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) { | ||
| 555 | for (i = 0; i < TOMOYO_MAX_GROUP; i++) { | 520 | for (i = 0; i < TOMOYO_MAX_GROUP; i++) { |
| 556 | struct list_head *list = &ns->group_list[i]; | 521 | struct list_head *list = &ns->group_list[i]; |
| 557 | struct tomoyo_group *group; | 522 | struct tomoyo_group *group; |
| 523 | struct tomoyo_group *tmp; | ||
| 558 | switch (i) { | 524 | switch (i) { |
| 559 | case 0: | 525 | case 0: |
| 560 | id = TOMOYO_ID_PATH_GROUP; | 526 | id = TOMOYO_ID_PATH_GROUP; |
| @@ -566,139 +532,37 @@ static void tomoyo_collect_entry(void) | |||
| 566 | id = TOMOYO_ID_ADDRESS_GROUP; | 532 | id = TOMOYO_ID_ADDRESS_GROUP; |
| 567 | break; | 533 | break; |
| 568 | } | 534 | } |
| 569 | list_for_each_entry(group, list, head.list) { | 535 | list_for_each_entry_safe(group, tmp, list, head.list) { |
| 570 | if (!tomoyo_collect_member | 536 | tomoyo_collect_member(id, &group->member_list); |
| 571 | (id, &group->member_list)) | ||
| 572 | goto unlock; | ||
| 573 | if (!list_empty(&group->member_list) || | 537 | if (!list_empty(&group->member_list) || |
| 574 | atomic_read(&group->head.users)) | 538 | atomic_read(&group->head.users) > 0) |
| 575 | continue; | 539 | continue; |
| 576 | if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP, | 540 | atomic_set(&group->head.users, |
| 577 | &group->head.list)) | 541 | TOMOYO_GC_IN_PROGRESS); |
| 578 | goto unlock; | 542 | tomoyo_try_to_gc(TOMOYO_ID_GROUP, |
| 543 | &group->head.list); | ||
| 579 | } | 544 | } |
| 580 | } | 545 | } |
| 581 | } | 546 | } |
| 582 | id = TOMOYO_ID_CONDITION; | 547 | for (i = 0; i < TOMOYO_MAX_HASH; i++) { |
| 583 | for (i = 0; i < TOMOYO_MAX_HASH + 1; i++) { | 548 | struct list_head *list = &tomoyo_name_list[i]; |
| 584 | struct list_head *list = !i ? | ||
| 585 | &tomoyo_condition_list : &tomoyo_name_list[i - 1]; | ||
| 586 | struct tomoyo_shared_acl_head *ptr; | 549 | struct tomoyo_shared_acl_head *ptr; |
| 587 | list_for_each_entry(ptr, list, list) { | 550 | struct tomoyo_shared_acl_head *tmp; |
| 588 | if (atomic_read(&ptr->users)) | 551 | list_for_each_entry_safe(ptr, tmp, list, list) { |
| 552 | if (atomic_read(&ptr->users) > 0) | ||
| 589 | continue; | 553 | continue; |
| 590 | if (!tomoyo_add_to_gc(id, &ptr->list)) | 554 | atomic_set(&ptr->users, TOMOYO_GC_IN_PROGRESS); |
| 591 | goto unlock; | 555 | tomoyo_try_to_gc(TOMOYO_ID_NAME, &ptr->list); |
| 592 | } | 556 | } |
| 593 | id = TOMOYO_ID_NAME; | ||
| 594 | } | 557 | } |
| 595 | unlock: | ||
| 596 | tomoyo_read_unlock(idx); | ||
| 597 | mutex_unlock(&tomoyo_policy_lock); | 558 | mutex_unlock(&tomoyo_policy_lock); |
| 598 | } | 559 | } |
| 599 | 560 | ||
| 600 | /** | 561 | /** |
| 601 | * tomoyo_kfree_entry - Delete entries in tomoyo_gc_list. | ||
| 602 | * | ||
| 603 | * Returns true if some entries were kfree()d, false otherwise. | ||
| 604 | */ | ||
| 605 | static bool tomoyo_kfree_entry(void) | ||
| 606 | { | ||
| 607 | struct tomoyo_gc *p; | ||
| 608 | struct tomoyo_gc *tmp; | ||
| 609 | bool result = false; | ||
| 610 | |||
| 611 | list_for_each_entry_safe(p, tmp, &tomoyo_gc_list, list) { | ||
| 612 | struct list_head *element = p->element; | ||
| 613 | |||
| 614 | /* | ||
| 615 | * list_del_rcu() in tomoyo_add_to_gc() guarantees that the | ||
| 616 | * list element became no longer reachable from the list which | ||
| 617 | * the element was originally on (e.g. tomoyo_domain_list). | ||
| 618 | * Also, synchronize_srcu() in tomoyo_gc_thread() guarantees | ||
| 619 | * that the list element became no longer referenced by syscall | ||
| 620 | * users. | ||
| 621 | * | ||
| 622 | * However, there are three users which may still be using the | ||
| 623 | * list element. We need to defer until all of these users | ||
| 624 | * forget the list element. | ||
| 625 | * | ||
| 626 | * Firstly, defer until "struct tomoyo_io_buffer"->r.{domain, | ||
| 627 | * group,acl} and "struct tomoyo_io_buffer"->w.domain forget | ||
| 628 | * the list element. | ||
| 629 | */ | ||
| 630 | if (tomoyo_struct_used_by_io_buffer(element)) | ||
| 631 | continue; | ||
| 632 | /* | ||
| 633 | * Secondly, defer until all other elements in the | ||
| 634 | * tomoyo_gc_list list forget the list element. | ||
| 635 | */ | ||
| 636 | if (tomoyo_element_linked_by_gc((const u8 *) element, p->size)) | ||
| 637 | continue; | ||
| 638 | switch (p->type) { | ||
| 639 | case TOMOYO_ID_TRANSITION_CONTROL: | ||
| 640 | tomoyo_del_transition_control(element); | ||
| 641 | break; | ||
| 642 | case TOMOYO_ID_AGGREGATOR: | ||
| 643 | tomoyo_del_aggregator(element); | ||
| 644 | break; | ||
| 645 | case TOMOYO_ID_MANAGER: | ||
| 646 | tomoyo_del_manager(element); | ||
| 647 | break; | ||
| 648 | case TOMOYO_ID_CONDITION: | ||
| 649 | tomoyo_del_condition(element); | ||
| 650 | break; | ||
| 651 | case TOMOYO_ID_NAME: | ||
| 652 | /* | ||
| 653 | * Thirdly, defer until all "struct tomoyo_io_buffer" | ||
| 654 | * ->r.w[] forget the list element. | ||
| 655 | */ | ||
| 656 | if (tomoyo_name_used_by_io_buffer( | ||
| 657 | container_of(element, typeof(struct tomoyo_name), | ||
| 658 | head.list)->entry.name, p->size)) | ||
| 659 | continue; | ||
| 660 | tomoyo_del_name(element); | ||
| 661 | break; | ||
| 662 | case TOMOYO_ID_ACL: | ||
| 663 | tomoyo_del_acl(element); | ||
| 664 | break; | ||
| 665 | case TOMOYO_ID_DOMAIN: | ||
| 666 | if (!tomoyo_del_domain(element)) | ||
| 667 | continue; | ||
| 668 | break; | ||
| 669 | case TOMOYO_ID_PATH_GROUP: | ||
| 670 | tomoyo_del_path_group(element); | ||
| 671 | break; | ||
| 672 | case TOMOYO_ID_ADDRESS_GROUP: | ||
| 673 | tomoyo_del_address_group(element); | ||
| 674 | break; | ||
| 675 | case TOMOYO_ID_GROUP: | ||
| 676 | tomoyo_del_group(element); | ||
| 677 | break; | ||
| 678 | case TOMOYO_ID_NUMBER_GROUP: | ||
| 679 | tomoyo_del_number_group(element); | ||
| 680 | break; | ||
| 681 | case TOMOYO_MAX_POLICY: | ||
| 682 | break; | ||
| 683 | } | ||
| 684 | tomoyo_memory_free(element); | ||
| 685 | list_del(&p->list); | ||
| 686 | kfree(p); | ||
| 687 | tomoyo_gc_list_len--; | ||
| 688 | result = true; | ||
| 689 | } | ||
| 690 | return result; | ||
| 691 | } | ||
| 692 | |||
| 693 | /** | ||
| 694 | * tomoyo_gc_thread - Garbage collector thread function. | 562 | * tomoyo_gc_thread - Garbage collector thread function. |
| 695 | * | 563 | * |
| 696 | * @unused: Unused. | 564 | * @unused: Unused. |
| 697 | * | 565 | * |
| 698 | * In case OOM-killer choose this thread for termination, we create this thread | ||
| 699 | * as a short live thread whenever /sys/kernel/security/tomoyo/ interface was | ||
| 700 | * close()d. | ||
| 701 | * | ||
| 702 | * Returns 0. | 566 | * Returns 0. |
| 703 | */ | 567 | */ |
| 704 | static int tomoyo_gc_thread(void *unused) | 568 | static int tomoyo_gc_thread(void *unused) |
| @@ -707,13 +571,7 @@ static int tomoyo_gc_thread(void *unused) | |||
| 707 | static DEFINE_MUTEX(tomoyo_gc_mutex); | 571 | static DEFINE_MUTEX(tomoyo_gc_mutex); |
| 708 | if (!mutex_trylock(&tomoyo_gc_mutex)) | 572 | if (!mutex_trylock(&tomoyo_gc_mutex)) |
| 709 | goto out; | 573 | goto out; |
| 710 | 574 | tomoyo_collect_entry(); | |
| 711 | do { | ||
| 712 | tomoyo_collect_entry(); | ||
| 713 | if (list_empty(&tomoyo_gc_list)) | ||
| 714 | break; | ||
| 715 | synchronize_srcu(&tomoyo_ss); | ||
| 716 | } while (tomoyo_kfree_entry()); | ||
| 717 | { | 575 | { |
| 718 | struct tomoyo_io_buffer *head; | 576 | struct tomoyo_io_buffer *head; |
| 719 | struct tomoyo_io_buffer *tmp; | 577 | struct tomoyo_io_buffer *tmp; |
diff --git a/security/tomoyo/memory.c b/security/tomoyo/memory.c index 7a56051146c2..277b9ade4408 100644 --- a/security/tomoyo/memory.c +++ b/security/tomoyo/memory.c | |||
| @@ -123,7 +123,8 @@ struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param, | |||
| 123 | goto out; | 123 | goto out; |
| 124 | list = ¶m->ns->group_list[idx]; | 124 | list = ¶m->ns->group_list[idx]; |
| 125 | list_for_each_entry(group, list, head.list) { | 125 | list_for_each_entry(group, list, head.list) { |
| 126 | if (e.group_name != group->group_name) | 126 | if (e.group_name != group->group_name || |
| 127 | atomic_read(&group->head.users) == TOMOYO_GC_IN_PROGRESS) | ||
| 127 | continue; | 128 | continue; |
| 128 | atomic_inc(&group->head.users); | 129 | atomic_inc(&group->head.users); |
| 129 | found = true; | 130 | found = true; |
| @@ -175,7 +176,8 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name) | |||
| 175 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 176 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
| 176 | return NULL; | 177 | return NULL; |
| 177 | list_for_each_entry(ptr, head, head.list) { | 178 | list_for_each_entry(ptr, head, head.list) { |
| 178 | if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name)) | 179 | if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name) || |
| 180 | atomic_read(&ptr->head.users) == TOMOYO_GC_IN_PROGRESS) | ||
| 179 | continue; | 181 | continue; |
| 180 | atomic_inc(&ptr->head.users); | 182 | atomic_inc(&ptr->head.users); |
| 181 | goto out; | 183 | goto out; |
