TOMOYO: Simplify garbage collector.
[deliverable/linux.git] / security / tomoyo / gc.c
1 /*
2 * security/tomoyo/gc.c
3 *
4 * Copyright (C) 2005-2011 NTT DATA CORPORATION
5 */
6
7 #include "common.h"
8 #include <linux/kthread.h>
9 #include <linux/slab.h>
10
11 /* The list for "struct tomoyo_io_buffer". */
12 static LIST_HEAD(tomoyo_io_buffer_list);
13 /* Lock for protecting tomoyo_io_buffer_list. */
14 static DEFINE_SPINLOCK(tomoyo_io_buffer_list_lock);
15
16 /**
17 * tomoyo_struct_used_by_io_buffer - Check whether the list element is used by /sys/kernel/security/tomoyo/ users or not.
18 *
19 * @element: Pointer to "struct list_head".
20 *
21 * Returns true if @element is used by /sys/kernel/security/tomoyo/ users,
22 * false otherwise.
23 */
24 static bool tomoyo_struct_used_by_io_buffer(const struct list_head *element)
25 {
26 struct tomoyo_io_buffer *head;
27 bool in_use = false;
28
29 spin_lock(&tomoyo_io_buffer_list_lock);
30 list_for_each_entry(head, &tomoyo_io_buffer_list, list) {
31 head->users++;
32 spin_unlock(&tomoyo_io_buffer_list_lock);
33 mutex_lock(&head->io_sem);
34 if (head->r.domain == element || head->r.group == element ||
35 head->r.acl == element || &head->w.domain->list == element)
36 in_use = true;
37 mutex_unlock(&head->io_sem);
38 spin_lock(&tomoyo_io_buffer_list_lock);
39 head->users--;
40 if (in_use)
41 break;
42 }
43 spin_unlock(&tomoyo_io_buffer_list_lock);
44 return in_use;
45 }
46
47 /**
48 * tomoyo_name_used_by_io_buffer - Check whether the string is used by /sys/kernel/security/tomoyo/ users or not.
49 *
50 * @string: String to check.
51 *
52 * Returns true if @string is used by /sys/kernel/security/tomoyo/ users,
53 * false otherwise.
54 */
55 static bool tomoyo_name_used_by_io_buffer(const char *string)
56 {
57 struct tomoyo_io_buffer *head;
58 const size_t size = strlen(string) + 1;
59 bool in_use = false;
60
61 spin_lock(&tomoyo_io_buffer_list_lock);
62 list_for_each_entry(head, &tomoyo_io_buffer_list, list) {
63 int i;
64 head->users++;
65 spin_unlock(&tomoyo_io_buffer_list_lock);
66 mutex_lock(&head->io_sem);
67 for (i = 0; i < TOMOYO_MAX_IO_READ_QUEUE; i++) {
68 const char *w = head->r.w[i];
69 if (w < string || w > string + size)
70 continue;
71 in_use = true;
72 break;
73 }
74 mutex_unlock(&head->io_sem);
75 spin_lock(&tomoyo_io_buffer_list_lock);
76 head->users--;
77 if (in_use)
78 break;
79 }
80 spin_unlock(&tomoyo_io_buffer_list_lock);
81 return in_use;
82 }
83
84 /**
85 * tomoyo_del_transition_control - Delete members in "struct tomoyo_transition_control".
86 *
87 * @element: Pointer to "struct list_head".
88 *
89 * Returns nothing.
90 */
91 static inline void tomoyo_del_transition_control(struct list_head *element)
92 {
93 struct tomoyo_transition_control *ptr =
94 container_of(element, typeof(*ptr), head.list);
95 tomoyo_put_name(ptr->domainname);
96 tomoyo_put_name(ptr->program);
97 }
98
99 /**
100 * tomoyo_del_aggregator - Delete members in "struct tomoyo_aggregator".
101 *
102 * @element: Pointer to "struct list_head".
103 *
104 * Returns nothing.
105 */
106 static inline void tomoyo_del_aggregator(struct list_head *element)
107 {
108 struct tomoyo_aggregator *ptr =
109 container_of(element, typeof(*ptr), head.list);
110 tomoyo_put_name(ptr->original_name);
111 tomoyo_put_name(ptr->aggregated_name);
112 }
113
114 /**
115 * tomoyo_del_manager - Delete members in "struct tomoyo_manager".
116 *
117 * @element: Pointer to "struct list_head".
118 *
119 * Returns nothing.
120 */
121 static inline void tomoyo_del_manager(struct list_head *element)
122 {
123 struct tomoyo_manager *ptr =
124 container_of(element, typeof(*ptr), head.list);
125 tomoyo_put_name(ptr->manager);
126 }
127
128 /**
129 * tomoyo_del_acl - Delete members in "struct tomoyo_acl_info".
130 *
131 * @element: Pointer to "struct list_head".
132 *
133 * Returns nothing.
134 */
135 static void tomoyo_del_acl(struct list_head *element)
136 {
137 struct tomoyo_acl_info *acl =
138 container_of(element, typeof(*acl), list);
139 tomoyo_put_condition(acl->cond);
140 switch (acl->type) {
141 case TOMOYO_TYPE_PATH_ACL:
142 {
143 struct tomoyo_path_acl *entry
144 = container_of(acl, typeof(*entry), head);
145 tomoyo_put_name_union(&entry->name);
146 }
147 break;
148 case TOMOYO_TYPE_PATH2_ACL:
149 {
150 struct tomoyo_path2_acl *entry
151 = container_of(acl, typeof(*entry), head);
152 tomoyo_put_name_union(&entry->name1);
153 tomoyo_put_name_union(&entry->name2);
154 }
155 break;
156 case TOMOYO_TYPE_PATH_NUMBER_ACL:
157 {
158 struct tomoyo_path_number_acl *entry
159 = container_of(acl, typeof(*entry), head);
160 tomoyo_put_name_union(&entry->name);
161 tomoyo_put_number_union(&entry->number);
162 }
163 break;
164 case TOMOYO_TYPE_MKDEV_ACL:
165 {
166 struct tomoyo_mkdev_acl *entry
167 = container_of(acl, typeof(*entry), head);
168 tomoyo_put_name_union(&entry->name);
169 tomoyo_put_number_union(&entry->mode);
170 tomoyo_put_number_union(&entry->major);
171 tomoyo_put_number_union(&entry->minor);
172 }
173 break;
174 case TOMOYO_TYPE_MOUNT_ACL:
175 {
176 struct tomoyo_mount_acl *entry
177 = container_of(acl, typeof(*entry), head);
178 tomoyo_put_name_union(&entry->dev_name);
179 tomoyo_put_name_union(&entry->dir_name);
180 tomoyo_put_name_union(&entry->fs_type);
181 tomoyo_put_number_union(&entry->flags);
182 }
183 break;
184 case TOMOYO_TYPE_ENV_ACL:
185 {
186 struct tomoyo_env_acl *entry =
187 container_of(acl, typeof(*entry), head);
188
189 tomoyo_put_name(entry->env);
190 }
191 break;
192 case TOMOYO_TYPE_INET_ACL:
193 {
194 struct tomoyo_inet_acl *entry =
195 container_of(acl, typeof(*entry), head);
196
197 tomoyo_put_group(entry->address.group);
198 tomoyo_put_number_union(&entry->port);
199 }
200 break;
201 case TOMOYO_TYPE_UNIX_ACL:
202 {
203 struct tomoyo_unix_acl *entry =
204 container_of(acl, typeof(*entry), head);
205
206 tomoyo_put_name_union(&entry->name);
207 }
208 break;
209 }
210 }
211
212 /**
213 * tomoyo_del_domain - Delete members in "struct tomoyo_domain_info".
214 *
215 * @element: Pointer to "struct list_head".
216 *
217 * Returns nothing.
218 */
219 static inline void tomoyo_del_domain(struct list_head *element)
220 {
221 struct tomoyo_domain_info *domain =
222 container_of(element, typeof(*domain), list);
223 struct tomoyo_acl_info *acl;
224 struct tomoyo_acl_info *tmp;
225 /*
226 * Since this domain is referenced from neither
227 * "struct tomoyo_io_buffer" nor "struct cred"->security, we can delete
228 * elements without checking for is_deleted flag.
229 */
230 list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) {
231 tomoyo_del_acl(&acl->list);
232 tomoyo_memory_free(acl);
233 }
234 tomoyo_put_name(domain->domainname);
235 }
236
237 /**
238 * tomoyo_del_condition - Delete members in "struct tomoyo_condition".
239 *
240 * @element: Pointer to "struct list_head".
241 *
242 * Returns nothing.
243 */
244 void tomoyo_del_condition(struct list_head *element)
245 {
246 struct tomoyo_condition *cond = container_of(element, typeof(*cond),
247 head.list);
248 const u16 condc = cond->condc;
249 const u16 numbers_count = cond->numbers_count;
250 const u16 names_count = cond->names_count;
251 const u16 argc = cond->argc;
252 const u16 envc = cond->envc;
253 unsigned int i;
254 const struct tomoyo_condition_element *condp
255 = (const struct tomoyo_condition_element *) (cond + 1);
256 struct tomoyo_number_union *numbers_p
257 = (struct tomoyo_number_union *) (condp + condc);
258 struct tomoyo_name_union *names_p
259 = (struct tomoyo_name_union *) (numbers_p + numbers_count);
260 const struct tomoyo_argv *argv
261 = (const struct tomoyo_argv *) (names_p + names_count);
262 const struct tomoyo_envp *envp
263 = (const struct tomoyo_envp *) (argv + argc);
264 for (i = 0; i < numbers_count; i++)
265 tomoyo_put_number_union(numbers_p++);
266 for (i = 0; i < names_count; i++)
267 tomoyo_put_name_union(names_p++);
268 for (i = 0; i < argc; argv++, i++)
269 tomoyo_put_name(argv->value);
270 for (i = 0; i < envc; envp++, i++) {
271 tomoyo_put_name(envp->name);
272 tomoyo_put_name(envp->value);
273 }
274 }
275
276 /**
277 * tomoyo_del_name - Delete members in "struct tomoyo_name".
278 *
279 * @element: Pointer to "struct list_head".
280 *
281 * Returns nothing.
282 */
283 static inline void tomoyo_del_name(struct list_head *element)
284 {
285 /* Nothing to do. */
286 }
287
288 /**
289 * tomoyo_del_path_group - Delete members in "struct tomoyo_path_group".
290 *
291 * @element: Pointer to "struct list_head".
292 *
293 * Returns nothing.
294 */
295 static inline void tomoyo_del_path_group(struct list_head *element)
296 {
297 struct tomoyo_path_group *member =
298 container_of(element, typeof(*member), head.list);
299 tomoyo_put_name(member->member_name);
300 }
301
302 /**
303 * tomoyo_del_group - Delete "struct tomoyo_group".
304 *
305 * @element: Pointer to "struct list_head".
306 *
307 * Returns nothing.
308 */
309 static inline void tomoyo_del_group(struct list_head *element)
310 {
311 struct tomoyo_group *group =
312 container_of(element, typeof(*group), head.list);
313 tomoyo_put_name(group->group_name);
314 }
315
316 /**
317 * tomoyo_del_address_group - Delete members in "struct tomoyo_address_group".
318 *
319 * @element: Pointer to "struct list_head".
320 *
321 * Returns nothing.
322 */
323 static inline void tomoyo_del_address_group(struct list_head *element)
324 {
325 /* Nothing to do. */
326 }
327
328 /**
329 * tomoyo_del_number_group - Delete members in "struct tomoyo_number_group".
330 *
331 * @element: Pointer to "struct list_head".
332 *
333 * Returns nothing.
334 */
335 static inline void tomoyo_del_number_group(struct list_head *element)
336 {
337 /* Nothing to do. */
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);
438 }
439
440 /**
441 * tomoyo_collect_member - Delete elements with "struct tomoyo_acl_head".
442 *
443 * @id: One of values in "enum tomoyo_policy_id".
444 * @member_list: Pointer to "struct list_head".
445 *
446 * Returns nothing.
447 */
448 static void tomoyo_collect_member(const enum tomoyo_policy_id id,
449 struct list_head *member_list)
450 {
451 struct tomoyo_acl_head *member;
452 struct tomoyo_acl_head *tmp;
453 list_for_each_entry_safe(member, tmp, member_list, list) {
454 if (!member->is_deleted)
455 continue;
456 member->is_deleted = TOMOYO_GC_IN_PROGRESS;
457 tomoyo_try_to_gc(id, &member->list);
458 }
459 }
460
461 /**
462 * tomoyo_collect_acl - Delete elements in "struct tomoyo_domain_info".
463 *
464 * @list: Pointer to "struct list_head".
465 *
466 * Returns nothing.
467 */
468 static void tomoyo_collect_acl(struct list_head *list)
469 {
470 struct tomoyo_acl_info *acl;
471 struct tomoyo_acl_info *tmp;
472 list_for_each_entry_safe(acl, tmp, list, list) {
473 if (!acl->is_deleted)
474 continue;
475 acl->is_deleted = TOMOYO_GC_IN_PROGRESS;
476 tomoyo_try_to_gc(TOMOYO_ID_ACL, &acl->list);
477 }
478 }
479
480 /**
481 * tomoyo_collect_entry - Try to kfree() deleted elements.
482 *
483 * Returns nothing.
484 */
485 static void tomoyo_collect_entry(void)
486 {
487 int i;
488 enum tomoyo_policy_id id;
489 struct tomoyo_policy_namespace *ns;
490 mutex_lock(&tomoyo_policy_lock);
491 {
492 struct tomoyo_domain_info *domain;
493 struct tomoyo_domain_info *tmp;
494 list_for_each_entry_safe(domain, tmp, &tomoyo_domain_list,
495 list) {
496 tomoyo_collect_acl(&domain->acl_info_list);
497 if (!domain->is_deleted || atomic_read(&domain->users))
498 continue;
499 tomoyo_try_to_gc(TOMOYO_ID_DOMAIN, &domain->list);
500 }
501 }
502 list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) {
503 for (id = 0; id < TOMOYO_MAX_POLICY; id++)
504 tomoyo_collect_member(id, &ns->policy_list[id]);
505 for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++)
506 tomoyo_collect_acl(&ns->acl_group[i]);
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) {
520 for (i = 0; i < TOMOYO_MAX_GROUP; i++) {
521 struct list_head *list = &ns->group_list[i];
522 struct tomoyo_group *group;
523 struct tomoyo_group *tmp;
524 switch (i) {
525 case 0:
526 id = TOMOYO_ID_PATH_GROUP;
527 break;
528 case 1:
529 id = TOMOYO_ID_NUMBER_GROUP;
530 break;
531 default:
532 id = TOMOYO_ID_ADDRESS_GROUP;
533 break;
534 }
535 list_for_each_entry_safe(group, tmp, list, head.list) {
536 tomoyo_collect_member(id, &group->member_list);
537 if (!list_empty(&group->member_list) ||
538 atomic_read(&group->head.users) > 0)
539 continue;
540 atomic_set(&group->head.users,
541 TOMOYO_GC_IN_PROGRESS);
542 tomoyo_try_to_gc(TOMOYO_ID_GROUP,
543 &group->head.list);
544 }
545 }
546 }
547 for (i = 0; i < TOMOYO_MAX_HASH; i++) {
548 struct list_head *list = &tomoyo_name_list[i];
549 struct tomoyo_shared_acl_head *ptr;
550 struct tomoyo_shared_acl_head *tmp;
551 list_for_each_entry_safe(ptr, tmp, list, list) {
552 if (atomic_read(&ptr->users) > 0)
553 continue;
554 atomic_set(&ptr->users, TOMOYO_GC_IN_PROGRESS);
555 tomoyo_try_to_gc(TOMOYO_ID_NAME, &ptr->list);
556 }
557 }
558 mutex_unlock(&tomoyo_policy_lock);
559 }
560
561 /**
562 * tomoyo_gc_thread - Garbage collector thread function.
563 *
564 * @unused: Unused.
565 *
566 * Returns 0.
567 */
568 static int tomoyo_gc_thread(void *unused)
569 {
570 /* Garbage collector thread is exclusive. */
571 static DEFINE_MUTEX(tomoyo_gc_mutex);
572 if (!mutex_trylock(&tomoyo_gc_mutex))
573 goto out;
574 tomoyo_collect_entry();
575 {
576 struct tomoyo_io_buffer *head;
577 struct tomoyo_io_buffer *tmp;
578
579 spin_lock(&tomoyo_io_buffer_list_lock);
580 list_for_each_entry_safe(head, tmp, &tomoyo_io_buffer_list,
581 list) {
582 if (head->users)
583 continue;
584 list_del(&head->list);
585 kfree(head->read_buf);
586 kfree(head->write_buf);
587 kfree(head);
588 }
589 spin_unlock(&tomoyo_io_buffer_list_lock);
590 }
591 mutex_unlock(&tomoyo_gc_mutex);
592 out:
593 /* This acts as do_exit(0). */
594 return 0;
595 }
596
597 /**
598 * tomoyo_notify_gc - Register/unregister /sys/kernel/security/tomoyo/ users.
599 *
600 * @head: Pointer to "struct tomoyo_io_buffer".
601 * @is_register: True if register, false if unregister.
602 *
603 * Returns nothing.
604 */
605 void tomoyo_notify_gc(struct tomoyo_io_buffer *head, const bool is_register)
606 {
607 bool is_write = false;
608
609 spin_lock(&tomoyo_io_buffer_list_lock);
610 if (is_register) {
611 head->users = 1;
612 list_add(&head->list, &tomoyo_io_buffer_list);
613 } else {
614 is_write = head->write_buf != NULL;
615 if (!--head->users) {
616 list_del(&head->list);
617 kfree(head->read_buf);
618 kfree(head->write_buf);
619 kfree(head);
620 }
621 }
622 spin_unlock(&tomoyo_io_buffer_list_lock);
623 if (is_write) {
624 struct task_struct *task = kthread_create(tomoyo_gc_thread,
625 NULL,
626 "GC for TOMOYO");
627 if (!IS_ERR(task))
628 wake_up_process(task);
629 }
630 }
This page took 0.053867 seconds and 5 git commands to generate.