aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>2011-09-25 04:50:23 -0400
committerJames Morris <jmorris@namei.org>2011-09-25 20:46:20 -0400
commitf9732ea145886786a6f8b0493bc2239e70cbacdb (patch)
treee29b2441cc916a174d7cd0b03cd18986ae545250 /security
parent778c4a4d60d932c1df6d270dcbc88365823c3963 (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.h7
-rw-r--r--security/tomoyo/condition.c8
-rw-r--r--security/tomoyo/domain.c4
-rw-r--r--security/tomoyo/gc.c480
-rw-r--r--security/tomoyo/memory.c6
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. */
399struct tomoyo_acl_head { 402struct 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 {
665struct tomoyo_acl_info { 668struct 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. */
14static DEFINE_SPINLOCK(tomoyo_io_buffer_list_lock); 14static DEFINE_SPINLOCK(tomoyo_io_buffer_list_lock);
15 15
16/* Size of an element. */
17static 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. */
34static 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);
70out:
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 */
89static bool tomoyo_name_used_by_io_buffer(const char *string, 55static 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);
112out:
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. */
123struct 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. */
130static LIST_HEAD(tomoyo_gc_list);
131/* Length of tomoyo_gc_list. */
132static 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 */
152static 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 */
188static 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 */
207static void tomoyo_del_transition_control(struct list_head *element) 91static 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 */
222static void tomoyo_del_aggregator(struct list_head *element) 106static 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 */
237static void tomoyo_del_manager(struct list_head *element) 121static 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 */
335static bool tomoyo_del_domain(struct list_head *element) 219static 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 */
419static void tomoyo_del_name(struct list_head *element) 283static 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 */
432static void tomoyo_del_path_group(struct list_head *element) 295static 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 */
446static void tomoyo_del_group(struct list_head *element) 309static 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 */
472static void tomoyo_del_number_group(struct list_head *element) 335static 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 */
350static 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;
427reinject:
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 */
486static bool tomoyo_collect_member(const enum tomoyo_policy_id id, 448static 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 */
506static bool tomoyo_collect_acl(struct list_head *list) 468static 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 }
595unlock:
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 */
605static 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 */
704static int tomoyo_gc_thread(void *unused) 568static 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 = &param->ns->group_list[idx]; 124 list = &param->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;