オープンソース・ソフトウェアの開発とダウンロード

Subversion リポジトリの参照

Contents of /branches/ccs-patch/security/ccsecurity/gc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2897 - (show annotations) (download) (as text)
Wed Aug 12 06:16:57 2009 UTC (14 years, 9 months ago) by kumaneko
File MIME type: text/x-csrc
File size: 15876 byte(s)


1 /*
2 * security/ccsecurity/gc.c
3 *
4 * Copyright (C) 2005-2009 NTT DATA CORPORATION
5 *
6 * Version: 1.7.0-pre 2009/08/08
7 *
8 * This file is applicable to both 2.4.30 and 2.6.11 and later.
9 * See README.ccs for ChangeLog.
10 *
11 */
12
13 #include <linux/version.h>
14 #include "internal.h"
15 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
16 #include <linux/kthread.h>
17 #endif
18
19 enum ccs_gc_id {
20 CCS_ID_RESERVEDPORT,
21 CCS_ID_ADDRESS_GROUP,
22 CCS_ID_ADDRESS_GROUP_MEMBER,
23 CCS_ID_PATH_GROUP,
24 CCS_ID_PATH_GROUP_MEMBER,
25 CCS_ID_NUMBER_GROUP,
26 CCS_ID_NUMBER_GROUP_MEMBER,
27 CCS_ID_GLOBAL_ENV,
28 CCS_ID_AGGREGATOR,
29 CCS_ID_DOMAIN_INITIALIZER,
30 CCS_ID_DOMAIN_KEEPER,
31 CCS_ID_GLOBALLY_READABLE,
32 CCS_ID_PATTERN,
33 CCS_ID_NO_REWRITE,
34 CCS_ID_MANAGER,
35 CCS_ID_ACL,
36 CCS_ID_DOMAIN
37 };
38
39 struct ccs_gc_entry {
40 struct list_head list;
41 int type;
42 void *element;
43 };
44
45 /* Caller holds ccs_policy_lock mutex. */
46 static bool ccs_add_to_gc(const int type, void *element, struct list_head *head)
47 {
48 struct ccs_gc_entry *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
49 if (!entry)
50 return false;
51 entry->type = type;
52 entry->element = element;
53 list_add(&entry->list, head);
54 return true;
55 }
56
57 static size_t ccs_del_allow_read(struct ccs_globally_readable_file_entry *ptr)
58 {
59 ccs_put_name(ptr->filename);
60 return sizeof(*ptr);
61 }
62
63 static size_t ccs_del_allow_env(struct ccs_globally_usable_env_entry *ptr)
64 {
65 ccs_put_name(ptr->env);
66 return sizeof(*ptr);
67 }
68
69 static size_t ccs_del_file_pattern(struct ccs_pattern_entry *ptr)
70 {
71 ccs_put_name(ptr->pattern);
72 return sizeof(*ptr);
73 }
74
75 static size_t ccs_del_no_rewrite(struct ccs_no_rewrite_entry *ptr)
76 {
77 ccs_put_name(ptr->pattern);
78 return sizeof(*ptr);
79 }
80
81 static size_t ccs_del_domain_initializer(struct ccs_domain_initializer_entry *
82 ptr)
83 {
84 ccs_put_name(ptr->domainname);
85 ccs_put_name(ptr->program);
86 return sizeof(*ptr);
87 }
88
89 static size_t ccs_del_domain_keeper(struct ccs_domain_keeper_entry *ptr)
90 {
91 ccs_put_name(ptr->domainname);
92 ccs_put_name(ptr->program);
93 return sizeof(*ptr);
94 }
95
96 static size_t ccs_del_aggregator(struct ccs_aggregator_entry *ptr)
97 {
98 ccs_put_name(ptr->original_name);
99 ccs_put_name(ptr->aggregated_name);
100 return sizeof(*ptr);
101 }
102
103 static size_t ccs_del_manager(struct ccs_policy_manager_entry *ptr)
104 {
105 ccs_put_name(ptr->manager);
106 return sizeof(*ptr);
107 }
108
109 /* For compatibility with older kernels. */
110 #ifndef for_each_process
111 #define for_each_process for_each_task
112 #endif
113
114 /**
115 * ccs_used_by_task - Check whether the given pointer is referenced by a task.
116 *
117 * @domain: Pointer to "struct ccs_domain_info".
118 *
119 * Returns true if @ptr is in use, false otherwise.
120 */
121 static bool ccs_used_by_task(struct ccs_domain_info *domain)
122 {
123 bool in_use = false;
124 struct task_struct *p;
125 /***** CRITICAL SECTION START *****/
126 read_lock(&tasklist_lock);
127 for_each_process(p) {
128 if (p->ccs_domain_info != domain)
129 continue;
130 in_use = true;
131 break;
132 }
133 read_unlock(&tasklist_lock);
134 /***** CRITICAL SECTION END *****/
135 return in_use;
136 }
137
138 static size_t ccs_del_acl(struct ccs_acl_info *acl)
139 {
140 size_t size;
141 ccs_put_condition(acl->cond);
142 switch (ccs_acl_type1(acl)) {
143 case CCS_TYPE_SINGLE_PATH_ACL:
144 {
145 struct ccs_single_path_acl_record *entry;
146 size = sizeof(*entry);
147 entry = container_of(acl, typeof(*entry), head);
148 ccs_put_name_union(&entry->name);
149 }
150 break;
151 case CCS_TYPE_MKDEV_ACL:
152 {
153 struct ccs_mkdev_acl_record *entry;
154 size = sizeof(*entry);
155 entry = container_of(acl, typeof(*entry), head);
156 ccs_put_name_union(&entry->name);
157 ccs_put_number_union(&entry->major);
158 ccs_put_number_union(&entry->minor);
159 }
160 break;
161 case CCS_TYPE_DOUBLE_PATH_ACL:
162 {
163 struct ccs_double_path_acl_record *entry;
164 size = sizeof(*entry);
165 entry = container_of(acl, typeof(*entry), head);
166 ccs_put_name_union(&entry->name1);
167 ccs_put_name_union(&entry->name2);
168 }
169 break;
170 case CCS_TYPE_IP_NETWORK_ACL:
171 {
172 struct ccs_ip_network_acl_record *entry;
173 size = sizeof(*entry);
174 entry = container_of(acl, typeof(*entry), head);
175 switch (entry->record_type) {
176 case CCS_IP_RECORD_TYPE_ADDRESS_GROUP:
177 ccs_put_address_group(entry->address.group);
178 break;
179 case CCS_IP_RECORD_TYPE_IPv6:
180 ccs_put_ipv6_address(entry->address.ipv6.min);
181 ccs_put_ipv6_address(entry->address.ipv6.max);
182 break;
183 }
184 ccs_put_number_union(&entry->port);
185 }
186 break;
187 case CCS_TYPE_PATH_NUMBER_ACL:
188 {
189 struct ccs_path_number_acl_record *entry;
190 size = sizeof(*entry);
191 entry = container_of(acl, typeof(*entry), head);
192 ccs_put_name_union(&entry->name);
193 ccs_put_number_union(&entry->number);
194 }
195 break;
196 case CCS_TYPE_ENV_ACL:
197 {
198 struct ccs_env_acl_record *entry;
199 size = sizeof(*entry);
200 entry = container_of(acl, typeof(*entry), head);
201 ccs_put_name(entry->env);
202 }
203 break;
204 case CCS_TYPE_CAPABILITY_ACL:
205 {
206 struct ccs_capability_acl_record *entry;
207 size = sizeof(*entry);
208 entry = container_of(acl, typeof(*entry), head);
209 }
210 break;
211 case CCS_TYPE_SIGNAL_ACL:
212 {
213 struct ccs_signal_acl_record *entry;
214 size = sizeof(*entry);
215 entry = container_of(acl, typeof(*entry), head);
216 ccs_put_name(entry->domainname);
217 }
218 break;
219 case CCS_TYPE_EXECUTE_HANDLER:
220 case CCS_TYPE_DENIED_EXECUTE_HANDLER:
221 {
222 struct ccs_execute_handler_record *entry;
223 size = sizeof(*entry);
224 entry = container_of(acl, typeof(*entry), head);
225 ccs_put_name(entry->handler);
226 }
227 break;
228 case CCS_TYPE_MOUNT_ACL:
229 {
230 struct ccs_mount_acl_record *entry;
231 size = sizeof(*entry);
232 entry = container_of(acl, typeof(*entry), head);
233 ccs_put_name_union(&entry->dev_name);
234 ccs_put_name_union(&entry->dir_name);
235 ccs_put_name_union(&entry->fs_type);
236 ccs_put_number_union(&entry->flags);
237 }
238 break;
239 case CCS_TYPE_UMOUNT_ACL:
240 {
241 struct ccs_umount_acl_record *entry;
242 size = sizeof(*entry);
243 entry = container_of(acl, typeof(*entry), head);
244 ccs_put_name_union(&entry->dir);
245 }
246 break;
247 case CCS_TYPE_CHROOT_ACL:
248 {
249 struct ccs_chroot_acl_record *entry;
250 size = sizeof(*entry);
251 entry = container_of(acl, typeof(*entry), head);
252 ccs_put_name_union(&entry->dir);
253 }
254 break;
255 case CCS_TYPE_PIVOT_ROOT_ACL:
256 {
257 struct ccs_pivot_root_acl_record *entry;
258 size = sizeof(*entry);
259 entry = container_of(acl, typeof(*entry), head);
260 ccs_put_name_union(&entry->old_root);
261 ccs_put_name_union(&entry->new_root);
262 }
263 break;
264 default:
265 size = 0;
266 printk(KERN_WARNING "Unknown type\n");
267 break;
268 }
269 return size;
270 }
271
272 static size_t ccs_del_domain(struct ccs_domain_info *domain)
273 {
274 struct ccs_acl_info *acl;
275 struct ccs_acl_info *tmp;
276 if (ccs_used_by_task(domain))
277 return 0;
278 list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) {
279 size_t size = ccs_del_acl(acl);
280 ccs_memory_free(acl, size);
281 }
282 ccs_put_name(domain->domainname);
283 return sizeof(*domain);
284 }
285
286 static size_t ccs_del_path_group_member(struct ccs_path_group_member *member)
287 {
288 ccs_put_name(member->member_name);
289 return sizeof(*member);
290 }
291
292 static size_t ccs_del_path_group(struct ccs_path_group *group)
293 {
294 ccs_put_name(group->group_name);
295 return sizeof(*group);
296 }
297
298 static size_t ccs_del_address_group_member
299 (struct ccs_address_group_member *member)
300 {
301 if (member->is_ipv6) {
302 ccs_put_ipv6_address(member->min.ipv6);
303 ccs_put_ipv6_address(member->max.ipv6);
304 }
305 return sizeof(*member);
306 }
307
308 static size_t ccs_del_address_group(struct ccs_address_group_entry *group)
309 {
310 ccs_put_name(group->group_name);
311 return sizeof(*group);
312 }
313
314 static size_t ccs_del_number_group_member
315 (struct ccs_number_group_member *member)
316 {
317 return sizeof(*member);
318 }
319
320 static size_t ccs_del_number_group(struct ccs_number_group *group)
321 {
322 ccs_put_name(group->group_name);
323 return sizeof(*group);
324 }
325
326 static size_t ccs_del_reservedport(struct ccs_reserved_entry *ptr)
327 {
328 return sizeof(*ptr);
329 }
330
331 static int ccs_gc_thread(void *unused)
332 {
333 static DEFINE_MUTEX(ccs_gc_mutex);
334 static LIST_HEAD(ccs_gc_queue);
335 if (!mutex_trylock(&ccs_gc_mutex))
336 goto out;
337 mutex_lock(&ccs_policy_lock);
338 {
339 struct ccs_globally_readable_file_entry *ptr;
340 list_for_each_entry_rcu(ptr, &ccs_globally_readable_list,
341 list) {
342 if (!ptr->is_deleted)
343 continue;
344 if (ccs_add_to_gc(CCS_ID_GLOBALLY_READABLE, ptr,
345 &ccs_gc_queue))
346 list_del_rcu(&ptr->list);
347 else
348 break;
349 }
350 }
351 {
352 struct ccs_globally_usable_env_entry *ptr;
353 list_for_each_entry_rcu(ptr, &ccs_globally_usable_env_list,
354 list) {
355 if (!ptr->is_deleted)
356 continue;
357 if (ccs_add_to_gc(CCS_ID_GLOBAL_ENV, ptr,
358 &ccs_gc_queue))
359 list_del_rcu(&ptr->list);
360 else
361 break;
362 }
363 }
364 {
365 struct ccs_pattern_entry *ptr;
366 list_for_each_entry_rcu(ptr, &ccs_pattern_list, list) {
367 if (!ptr->is_deleted)
368 continue;
369 if (ccs_add_to_gc(CCS_ID_PATTERN, ptr,
370 &ccs_gc_queue))
371 list_del_rcu(&ptr->list);
372 else
373 break;
374 }
375 }
376 {
377 struct ccs_no_rewrite_entry *ptr;
378 list_for_each_entry_rcu(ptr, &ccs_no_rewrite_list, list) {
379 if (!ptr->is_deleted)
380 continue;
381 if (ccs_add_to_gc(CCS_ID_NO_REWRITE, ptr,
382 &ccs_gc_queue))
383 list_del_rcu(&ptr->list);
384 else
385 break;
386 }
387 }
388 {
389 struct ccs_domain_initializer_entry *ptr;
390 list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list,
391 list) {
392 if (!ptr->is_deleted)
393 continue;
394 if (ccs_add_to_gc(CCS_ID_DOMAIN_INITIALIZER,
395 ptr, &ccs_gc_queue))
396 list_del_rcu(&ptr->list);
397 else
398 break;
399 }
400 }
401 {
402 struct ccs_domain_keeper_entry *ptr;
403 list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {
404 if (!ptr->is_deleted)
405 continue;
406 if (ccs_add_to_gc(CCS_ID_DOMAIN_KEEPER, ptr,
407 &ccs_gc_queue))
408 list_del_rcu(&ptr->list);
409 else
410 break;
411 }
412 }
413 {
414 struct ccs_policy_manager_entry *ptr;
415 list_for_each_entry_rcu(ptr, &ccs_policy_manager_list, list) {
416 if (!ptr->is_deleted)
417 continue;
418 if (ccs_add_to_gc(CCS_ID_MANAGER, ptr, &ccs_gc_queue))
419 list_del_rcu(&ptr->list);
420 else
421 break;
422 }
423 }
424 {
425 struct ccs_aggregator_entry *ptr;
426 list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {
427 if (!ptr->is_deleted)
428 continue;
429 if (ccs_add_to_gc(CCS_ID_AGGREGATOR, ptr,
430 &ccs_gc_queue))
431 list_del_rcu(&ptr->list);
432 else
433 break;
434 }
435 }
436 {
437 struct ccs_domain_info *domain;
438 list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
439 struct ccs_acl_info *acl;
440 list_for_each_entry_rcu(acl, &domain->acl_info_list,
441 list) {
442 if (!(acl->type & CCS_ACL_DELETED))
443 continue;
444 if (ccs_add_to_gc(CCS_ID_ACL, acl,
445 &ccs_gc_queue))
446 list_del_rcu(&acl->list);
447 else
448 break;
449 }
450 if (!domain->is_deleted ||
451 ccs_used_by_task(domain))
452 continue;
453 if (ccs_add_to_gc(CCS_ID_DOMAIN, domain, &ccs_gc_queue))
454 list_del_rcu(&domain->list);
455 else
456 break;
457 }
458 }
459 {
460 struct ccs_path_group *group;
461 list_for_each_entry_rcu(group, &ccs_path_group_list, list) {
462 struct ccs_path_group_member *member;
463 list_for_each_entry_rcu(member,
464 &group->path_group_member_list,
465 list) {
466 if (!member->is_deleted)
467 continue;
468 if (ccs_add_to_gc(CCS_ID_PATH_GROUP_MEMBER,
469 member, &ccs_gc_queue))
470 list_del_rcu(&member->list);
471 else
472 break;
473 }
474 if (!list_empty(&group->path_group_member_list) ||
475 atomic_read(&group->users))
476 continue;
477 if (ccs_add_to_gc(CCS_ID_PATH_GROUP, group,
478 &ccs_gc_queue))
479 list_del_rcu(&group->list);
480 else
481 break;
482 }
483 }
484 {
485 struct ccs_address_group_entry *group;
486 list_for_each_entry_rcu(group, &ccs_address_group_list, list) {
487 struct ccs_address_group_member *member;
488 list_for_each_entry_rcu(member,
489 &group->address_group_member_list,
490 list) {
491 if (!member->is_deleted)
492 break;
493 if (ccs_add_to_gc(CCS_ID_ADDRESS_GROUP_MEMBER,
494 member, &ccs_gc_queue))
495 list_del_rcu(&member->list);
496 else
497 break;
498 }
499 if (!list_empty(&group->address_group_member_list) ||
500 atomic_read(&group->users))
501 continue;
502 if (ccs_add_to_gc(CCS_ID_ADDRESS_GROUP, group,
503 &ccs_gc_queue))
504 list_del_rcu(&group->list);
505 else
506 break;
507 }
508 }
509 {
510 struct ccs_number_group *group;
511 list_for_each_entry_rcu(group, &ccs_number_group_list, list) {
512 struct ccs_number_group_member *member;
513 list_for_each_entry_rcu(member,
514 &group->
515 number_group_member_list,
516 list) {
517 if (!member->is_deleted)
518 continue;
519 if (ccs_add_to_gc(CCS_ID_NUMBER_GROUP_MEMBER,
520 member, &ccs_gc_queue))
521 list_del_rcu(&member->list);
522 else
523 break;
524 }
525 if (!list_empty(&group->number_group_member_list) ||
526 atomic_read(&group->users))
527 continue;
528 if (ccs_add_to_gc(CCS_ID_NUMBER_GROUP, group,
529 &ccs_gc_queue))
530 list_del_rcu(&group->list);
531 else
532 break;
533 }
534 }
535 {
536 struct ccs_reserved_entry *ptr;
537 list_for_each_entry_rcu(ptr, &ccs_reservedport_list, list) {
538 if (!ptr->is_deleted)
539 continue;
540 if (ccs_add_to_gc(CCS_ID_RESERVEDPORT, ptr,
541 &ccs_gc_queue))
542 list_del_rcu(&ptr->list);
543 else
544 break;
545 }
546 }
547 mutex_unlock(&ccs_policy_lock);
548 if (list_empty(&ccs_gc_queue))
549 goto done;
550 synchronize_srcu(&ccs_ss);
551 {
552 struct ccs_gc_entry *p;
553 struct ccs_gc_entry *tmp;
554 size_t size = 0;
555 list_for_each_entry_safe(p, tmp, &ccs_gc_queue, list) {
556 switch (p->type) {
557 case CCS_ID_DOMAIN_INITIALIZER:
558 size = ccs_del_domain_initializer(p->element);
559 break;
560 case CCS_ID_DOMAIN_KEEPER:
561 size = ccs_del_domain_keeper(p->element);
562 break;
563 case CCS_ID_GLOBALLY_READABLE:
564 size = ccs_del_allow_read(p->element);
565 break;
566 case CCS_ID_PATTERN:
567 size = ccs_del_file_pattern(p->element);
568 break;
569 case CCS_ID_NO_REWRITE:
570 size = ccs_del_no_rewrite(p->element);
571 break;
572 case CCS_ID_MANAGER:
573 size = ccs_del_manager(p->element);
574 break;
575 case CCS_ID_GLOBAL_ENV:
576 size = ccs_del_allow_env(p->element);
577 break;
578 case CCS_ID_AGGREGATOR:
579 size = ccs_del_aggregator(p->element);
580 break;
581 case CCS_ID_PATH_GROUP_MEMBER:
582 size = ccs_del_path_group_member(p->element);
583 break;
584 case CCS_ID_PATH_GROUP:
585 size = ccs_del_path_group(p->element);
586 break;
587 case CCS_ID_ADDRESS_GROUP_MEMBER:
588 size = ccs_del_address_group_member(p->element);
589 break;
590 case CCS_ID_ADDRESS_GROUP:
591 size = ccs_del_address_group(p->element);
592 break;
593 case CCS_ID_NUMBER_GROUP_MEMBER:
594 size = ccs_del_number_group_member(p->element);
595 break;
596 case CCS_ID_NUMBER_GROUP:
597 size = ccs_del_number_group(p->element);
598 break;
599 case CCS_ID_RESERVEDPORT:
600 size = ccs_del_reservedport(p->element);
601 break;
602 case CCS_ID_ACL:
603 size = ccs_del_acl(p->element);
604 break;
605 case CCS_ID_DOMAIN:
606 size = ccs_del_domain(p->element);
607 if (!size)
608 continue;
609 break;
610 default:
611 size = 0;
612 printk(KERN_WARNING "Unknown type\n");
613 break;
614 }
615 ccs_memory_free(p->element, size);
616 list_del(&p->list);
617 kfree(p);
618 }
619 }
620 done:
621 mutex_unlock(&ccs_gc_mutex);
622 out:
623 do_exit(0);
624 }
625
626 void ccs_run_gc(void)
627 {
628 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
629 struct task_struct *task = kthread_create(ccs_gc_thread, NULL,
630 "GC for CCS");
631 if (!IS_ERR(task))
632 wake_up_process(task);
633 #else
634 kernel_thread(ccs_gc_thread, NULL, 0);
635 #endif
636 }
637
638 #ifndef _LINUX_SRCU_H
639
640 static DEFINE_SPINLOCK(ccs_counter_lock);
641
642 int srcu_read_lock(struct srcu_struct *sp)
643 {
644 int idx;
645 spin_lock(&ccs_counter_lock);
646 idx = sp->counter_idx;
647 sp->counter[idx]++;
648 spin_unlock(&ccs_counter_lock);
649 return idx;
650 }
651
652 void srcu_read_unlock(struct srcu_struct *sp, const int idx)
653 {
654 spin_lock(&ccs_counter_lock);
655 sp->counter[idx]--;
656 spin_unlock(&ccs_counter_lock);
657 }
658
659 void synchronize_srcu(struct srcu_struct *sp)
660 {
661 int idx;
662 int v;
663 spin_lock(&ccs_counter_lock);
664 idx = sp->counter_idx;
665 sp->counter_idx ^= 1;
666 v = sp->counter[idx];
667 spin_unlock(&ccs_counter_lock);
668 while (v) {
669 ssleep(1);
670 spin_lock(&ccs_counter_lock);
671 v = sp->counter[idx];
672 spin_unlock(&ccs_counter_lock);
673 }
674 }
675
676 #endif

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26