~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/akari/gc.c

Version: ~ [ linux-5.5-rc6 ] ~ [ linux-5.4.11 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.95 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.164 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.209 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.209 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.81 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * security/ccsecurity/gc.c
  3  *
  4  * Copyright (C) 2005-2012  NTT DATA CORPORATION
  5  *
  6  * Version: 1.8.5   2015/11/11
  7  */
  8 
  9 #include "internal.h"
 10 
 11 /***** SECTION1: Constants definition *****/
 12 
 13 /* For compatibility with older kernels. */
 14 #ifndef for_each_process
 15 #define for_each_process for_each_task
 16 #endif
 17 
 18 /* The list for "struct ccs_io_buffer". */
 19 static LIST_HEAD(ccs_io_buffer_list);
 20 /* Lock for protecting ccs_io_buffer_list. */
 21 static DEFINE_SPINLOCK(ccs_io_buffer_list_lock);
 22 
 23 /***** SECTION2: Structure definition *****/
 24 
 25 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
 26 
 27 /*
 28  * Lock for syscall users.
 29  *
 30  * This lock is used for protecting single SRCU section for 2.6.18 and
 31  * earlier kernels because they don't have SRCU support.
 32  */
 33 struct ccs_lock_struct {
 34         int counter_idx; /* Currently active index (0 or 1). */
 35         int counter[2];  /* Current users. Protected by ccs_counter_lock. */
 36 };
 37 
 38 #endif
 39 
 40 /***** SECTION3: Prototype definition section *****/
 41 
 42 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
 43 int ccs_lock(void);
 44 #endif
 45 void ccs_del_acl(struct list_head *element);
 46 void ccs_del_condition(struct list_head *element);
 47 void ccs_notify_gc(struct ccs_io_buffer *head, const bool is_register);
 48 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
 49 void ccs_unlock(const int idx);
 50 #endif
 51 
 52 static bool ccs_domain_used_by_task(struct ccs_domain_info *domain);
 53 static bool ccs_name_used_by_io_buffer(const char *string, const size_t size);
 54 static bool ccs_struct_used_by_io_buffer(const struct list_head *element);
 55 static int ccs_gc_thread(void *unused);
 56 static void ccs_collect_acl(struct list_head *list);
 57 static void ccs_collect_entry(void);
 58 static void ccs_collect_member(const enum ccs_policy_id id,
 59                                struct list_head *member_list);
 60 static void ccs_memory_free(const void *ptr, const enum ccs_policy_id type);
 61 static void ccs_put_name_union(struct ccs_name_union *ptr);
 62 static void ccs_put_number_union(struct ccs_number_union *ptr);
 63 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
 64 static void ccs_synchronize_counter(void);
 65 #endif
 66 static void ccs_try_to_gc(const enum ccs_policy_id type,
 67                           struct list_head *element);
 68 
 69 /***** SECTION4: Standalone functions section *****/
 70 
 71 /***** SECTION5: Variables definition section *****/
 72 
 73 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
 74 
 75 /*
 76  * Lock for syscall users.
 77  *
 78  * This lock is held for only protecting single SRCU section.
 79  */
 80 struct srcu_struct ccs_ss;
 81 
 82 #else
 83 
 84 static struct ccs_lock_struct ccs_counter;
 85 /* Lock for protecting ccs_counter. */
 86 static DEFINE_SPINLOCK(ccs_counter_lock);
 87 
 88 #endif
 89 
 90 /***** SECTION6: Dependent functions section *****/
 91 
 92 /**
 93  * ccs_memory_free - Free memory for elements.
 94  *
 95  * @ptr:  Pointer to allocated memory.
 96  * @type: One of values in "enum ccs_policy_id".
 97  *
 98  * Returns nothing.
 99  *
100  * Caller holds ccs_policy_lock mutex.
101  */
102 static void ccs_memory_free(const void *ptr, const enum ccs_policy_id type)
103 {
104         /* Size of an element. */
105         static const u8 e[CCS_MAX_POLICY] = {
106 #ifdef CONFIG_CCSECURITY_PORTRESERVE
107                 [CCS_ID_RESERVEDPORT] = sizeof(struct ccs_reserved),
108 #endif
109                 [CCS_ID_GROUP] = sizeof(struct ccs_group),
110 #ifdef CONFIG_CCSECURITY_NETWORK
111                 [CCS_ID_ADDRESS_GROUP] = sizeof(struct ccs_address_group),
112 #endif
113                 [CCS_ID_PATH_GROUP] = sizeof(struct ccs_path_group),
114                 [CCS_ID_NUMBER_GROUP] = sizeof(struct ccs_number_group),
115                 [CCS_ID_AGGREGATOR] = sizeof(struct ccs_aggregator),
116                 [CCS_ID_TRANSITION_CONTROL]
117                 = sizeof(struct ccs_transition_control),
118                 [CCS_ID_MANAGER] = sizeof(struct ccs_manager),
119                 /* [CCS_ID_CONDITION] = "struct ccs_condition"->size, */
120                 /* [CCS_ID_NAME] = "struct ccs_name"->size, */
121                 /* [CCS_ID_ACL] = a["struct ccs_acl_info"->type], */
122                 [CCS_ID_DOMAIN] = sizeof(struct ccs_domain_info),
123         };
124         /* Size of a domain ACL element. */
125         static const u8 a[] = {
126                 [CCS_TYPE_PATH_ACL] = sizeof(struct ccs_path_acl),
127                 [CCS_TYPE_PATH2_ACL] = sizeof(struct ccs_path2_acl),
128                 [CCS_TYPE_PATH_NUMBER_ACL]
129                 = sizeof(struct ccs_path_number_acl),
130                 [CCS_TYPE_MKDEV_ACL] = sizeof(struct ccs_mkdev_acl),
131                 [CCS_TYPE_MOUNT_ACL] = sizeof(struct ccs_mount_acl),
132 #ifdef CONFIG_CCSECURITY_NETWORK
133                 [CCS_TYPE_INET_ACL] = sizeof(struct ccs_inet_acl),
134                 [CCS_TYPE_UNIX_ACL] = sizeof(struct ccs_unix_acl),
135 #endif
136 #ifdef CONFIG_CCSECURITY_MISC
137                 [CCS_TYPE_ENV_ACL] = sizeof(struct ccs_env_acl),
138 #endif
139 #ifdef CONFIG_CCSECURITY_CAPABILITY
140                 [CCS_TYPE_CAPABILITY_ACL] = sizeof(struct ccs_capability_acl),
141 #endif
142 #ifdef CONFIG_CCSECURITY_IPC
143                 [CCS_TYPE_SIGNAL_ACL] = sizeof(struct ccs_signal_acl),
144 #endif
145 #ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
146                 [CCS_TYPE_AUTO_EXECUTE_HANDLER]
147                 = sizeof(struct ccs_handler_acl),
148                 [CCS_TYPE_DENIED_EXECUTE_HANDLER]
149                 = sizeof(struct ccs_handler_acl),
150 #endif
151 #ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
152                 [CCS_TYPE_AUTO_TASK_ACL] = sizeof(struct ccs_task_acl),
153                 [CCS_TYPE_MANUAL_TASK_ACL] = sizeof(struct ccs_task_acl),
154 #endif
155         };
156         size_t size;
157         if (type == CCS_ID_ACL)
158                 size = a[container_of(ptr, typeof(struct ccs_acl_info),
159                                       list)->type];
160         else if (type == CCS_ID_NAME)
161                 size = container_of(ptr, typeof(struct ccs_name),
162                                     head.list)->size;
163         else if (type == CCS_ID_CONDITION)
164                 size = container_of(ptr, typeof(struct ccs_condition),
165                                     head.list)->size;
166         else
167                 size = e[type];
168         ccs_memory_used[CCS_MEMORY_POLICY] -= ccs_round2(size);
169         kfree(ptr);
170 }
171 
172 /**
173  * ccs_put_name_union - Drop reference on "struct ccs_name_union".
174  *
175  * @ptr: Pointer to "struct ccs_name_union".
176  *
177  * Returns nothing.
178  */
179 static void ccs_put_name_union(struct ccs_name_union *ptr)
180 {
181         ccs_put_group(ptr->group);
182         ccs_put_name(ptr->filename);
183 }
184 
185 /**
186  * ccs_put_number_union - Drop reference on "struct ccs_number_union".
187  *
188  * @ptr: Pointer to "struct ccs_number_union".
189  *
190  * Returns nothing.
191  */
192 static void ccs_put_number_union(struct ccs_number_union *ptr)
193 {
194         ccs_put_group(ptr->group);
195 }
196 
197 /**
198  * ccs_struct_used_by_io_buffer - Check whether the list element is used by /proc/ccs/ users or not.
199  *
200  * @element: Pointer to "struct list_head".
201  *
202  * Returns true if @element is used by /proc/ccs/ users, false otherwise.
203  */
204 static bool ccs_struct_used_by_io_buffer(const struct list_head *element)
205 {
206         struct ccs_io_buffer *head;
207         bool in_use = false;
208         spin_lock(&ccs_io_buffer_list_lock);
209         list_for_each_entry(head, &ccs_io_buffer_list, list) {
210                 head->users++;
211                 spin_unlock(&ccs_io_buffer_list_lock);
212                 mutex_lock(&head->io_sem);
213                 if (head->r.domain == element || head->r.group == element ||
214                     head->r.acl == element || &head->w.domain->list == element)
215                         in_use = true;
216                 mutex_unlock(&head->io_sem);
217                 spin_lock(&ccs_io_buffer_list_lock);
218                 head->users--;
219                 if (in_use)
220                         break;
221         }
222         spin_unlock(&ccs_io_buffer_list_lock);
223         return in_use;
224 }
225 
226 /**
227  * ccs_name_used_by_io_buffer - Check whether the string is used by /proc/ccs/ users or not.
228  *
229  * @string: String to check.
230  * @size:   Memory allocated for @string .
231  *
232  * Returns true if @string is used by /proc/ccs/ users, false otherwise.
233  */
234 static bool ccs_name_used_by_io_buffer(const char *string, const size_t size)
235 {
236         struct ccs_io_buffer *head;
237         bool in_use = false;
238         spin_lock(&ccs_io_buffer_list_lock);
239         list_for_each_entry(head, &ccs_io_buffer_list, list) {
240                 int i;
241                 head->users++;
242                 spin_unlock(&ccs_io_buffer_list_lock);
243                 mutex_lock(&head->io_sem);
244                 for (i = 0; i < CCS_MAX_IO_READ_QUEUE; i++) {
245                         const char *w = head->r.w[i];
246                         if (w < string || w > string + size)
247                                 continue;
248                         in_use = true;
249                         break;
250                 }
251                 mutex_unlock(&head->io_sem);
252                 spin_lock(&ccs_io_buffer_list_lock);
253                 head->users--;
254                 if (in_use)
255                         break;
256         }
257         spin_unlock(&ccs_io_buffer_list_lock);
258         return in_use;
259 }
260 
261 /**
262  * ccs_del_transition_control - Delete members in "struct ccs_transition_control".
263  *
264  * @element: Pointer to "struct list_head".
265  *
266  * Returns nothing.
267  */
268 static inline void ccs_del_transition_control(struct list_head *element)
269 {
270         struct ccs_transition_control *ptr =
271                 container_of(element, typeof(*ptr), head.list);
272         ccs_put_name(ptr->domainname);
273         ccs_put_name(ptr->program);
274 }
275 
276 /**
277  * ccs_del_aggregator - Delete members in "struct ccs_aggregator".
278  *
279  * @element: Pointer to "struct list_head".
280  *
281  * Returns nothing.
282  */
283 static inline void ccs_del_aggregator(struct list_head *element)
284 {
285         struct ccs_aggregator *ptr =
286                 container_of(element, typeof(*ptr), head.list);
287         ccs_put_name(ptr->original_name);
288         ccs_put_name(ptr->aggregated_name);
289 }
290 
291 /**
292  * ccs_del_manager - Delete members in "struct ccs_manager".
293  *
294  * @element: Pointer to "struct list_head".
295  *
296  * Returns nothing.
297  */
298 static inline void ccs_del_manager(struct list_head *element)
299 {
300         struct ccs_manager *ptr =
301                 container_of(element, typeof(*ptr), head.list);
302         ccs_put_name(ptr->manager);
303 }
304 
305 /**
306  * ccs_domain_used_by_task - Check whether the given pointer is referenced by a task.
307  *
308  * @domain: Pointer to "struct ccs_domain_info".
309  *
310  * Returns true if @domain is in use, false otherwise.
311  */
312 static bool ccs_domain_used_by_task(struct ccs_domain_info *domain)
313 {
314         bool in_use = false;
315         /*
316          * Don't delete this domain if somebody is doing execve().
317          *
318          * Since ccs_finish_execve() first reverts ccs_domain_info and then
319          * updates ccs_flags, we need smp_rmb() to make sure that GC first
320          * checks ccs_flags and then checks ccs_domain_info.
321          */
322 #ifdef CONFIG_CCSECURITY_USE_EXTERNAL_TASK_SECURITY
323         int idx;
324         rcu_read_lock();
325         for (idx = 0; idx < CCS_MAX_TASK_SECURITY_HASH; idx++) {
326                 struct ccs_security *ptr;
327                 struct list_head *list = &ccs_task_security_list[idx];
328                 list_for_each_entry_rcu(ptr, list, list) {
329                         if (!(ptr->ccs_flags & CCS_TASK_IS_IN_EXECVE)) {
330                                 smp_rmb(); /* Avoid out of order execution. */
331                                 if (ptr->ccs_domain_info != domain)
332                                         continue;
333                         }
334                         in_use = true;
335                         goto out;
336                 }
337         }
338         in_use = ccs_used_by_cred(domain);
339 out:
340         rcu_read_unlock();
341 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
342         struct task_struct *g;
343         struct task_struct *t;
344         ccs_tasklist_lock();
345         do_each_thread(g, t) {
346                 if (!(t->ccs_flags & CCS_TASK_IS_IN_EXECVE)) {
347                         smp_rmb(); /* Avoid out of order execution. */
348                         if (t->ccs_domain_info != domain)
349                                 continue;
350                 }
351                 in_use = true;
352                 goto out;
353         } while_each_thread(g, t);
354 out:
355         ccs_tasklist_unlock();
356 #else
357         struct task_struct *p;
358         ccs_tasklist_lock();
359         for_each_process(p) {
360                 if (!(p->ccs_flags & CCS_TASK_IS_IN_EXECVE)) {
361                         smp_rmb(); /* Avoid out of order execution. */
362                         if (p->ccs_domain_info != domain)
363                                 continue;
364                 }
365                 in_use = true;
366                 break;
367         }
368         ccs_tasklist_unlock();
369 #endif
370         return in_use;
371 }
372 
373 /**
374  * ccs_del_acl - Delete members in "struct ccs_acl_info".
375  *
376  * @element: Pointer to "struct list_head".
377  *
378  * Returns nothing.
379  */
380 void ccs_del_acl(struct list_head *element)
381 {
382         struct ccs_acl_info *acl = container_of(element, typeof(*acl), list);
383         ccs_put_condition(acl->cond);
384         switch (acl->type) {
385         case CCS_TYPE_PATH_ACL:
386                 {
387                         struct ccs_path_acl *entry =
388                                 container_of(acl, typeof(*entry), head);
389                         ccs_put_name_union(&entry->name);
390                 }
391                 break;
392         case CCS_TYPE_PATH2_ACL:
393                 {
394                         struct ccs_path2_acl *entry =
395                                 container_of(acl, typeof(*entry), head);
396                         ccs_put_name_union(&entry->name1);
397                         ccs_put_name_union(&entry->name2);
398                 }
399                 break;
400         case CCS_TYPE_PATH_NUMBER_ACL:
401                 {
402                         struct ccs_path_number_acl *entry =
403                                 container_of(acl, typeof(*entry), head);
404                         ccs_put_name_union(&entry->name);
405                         ccs_put_number_union(&entry->number);
406                 }
407                 break;
408         case CCS_TYPE_MKDEV_ACL:
409                 {
410                         struct ccs_mkdev_acl *entry =
411                                 container_of(acl, typeof(*entry), head);
412                         ccs_put_name_union(&entry->name);
413                         ccs_put_number_union(&entry->mode);
414                         ccs_put_number_union(&entry->major);
415                         ccs_put_number_union(&entry->minor);
416                 }
417                 break;
418         case CCS_TYPE_MOUNT_ACL:
419                 {
420                         struct ccs_mount_acl *entry =
421                                 container_of(acl, typeof(*entry), head);
422                         ccs_put_name_union(&entry->dev_name);
423                         ccs_put_name_union(&entry->dir_name);
424                         ccs_put_name_union(&entry->fs_type);
425                         ccs_put_number_union(&entry->flags);
426                 }
427                 break;
428 #ifdef CONFIG_CCSECURITY_NETWORK
429         case CCS_TYPE_INET_ACL:
430                 {
431                         struct ccs_inet_acl *entry =
432                                 container_of(acl, typeof(*entry), head);
433                         ccs_put_group(entry->address.group);
434                         ccs_put_number_union(&entry->port);
435                 }
436                 break;
437         case CCS_TYPE_UNIX_ACL:
438                 {
439                         struct ccs_unix_acl *entry =
440                                 container_of(acl, typeof(*entry), head);
441                         ccs_put_name_union(&entry->name);
442                 }
443                 break;
444 #endif
445 #ifdef CONFIG_CCSECURITY_MISC
446         case CCS_TYPE_ENV_ACL:
447                 {
448                         struct ccs_env_acl *entry =
449                                 container_of(acl, typeof(*entry), head);
450                         ccs_put_name(entry->env);
451                 }
452                 break;
453 #endif
454 #ifdef CONFIG_CCSECURITY_CAPABILITY
455         case CCS_TYPE_CAPABILITY_ACL:
456                 {
457                         /* Nothing to do. */
458                 }
459                 break;
460 #endif
461 #ifdef CONFIG_CCSECURITY_IPC
462         case CCS_TYPE_SIGNAL_ACL:
463                 {
464                         struct ccs_signal_acl *entry =
465                                 container_of(acl, typeof(*entry), head);
466                         ccs_put_number_union(&entry->sig);
467                         ccs_put_name(entry->domainname);
468                 }
469                 break;
470 #endif
471 #ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
472         case CCS_TYPE_AUTO_EXECUTE_HANDLER:
473         case CCS_TYPE_DENIED_EXECUTE_HANDLER:
474                 {
475                         struct ccs_handler_acl *entry =
476                                 container_of(acl, typeof(*entry), head);
477                         ccs_put_name(entry->handler);
478                 }
479                 break;
480 #endif
481 #ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
482         case CCS_TYPE_AUTO_TASK_ACL:
483         case CCS_TYPE_MANUAL_TASK_ACL:
484                 {
485                         struct ccs_task_acl *entry =
486                                 container_of(acl, typeof(*entry), head);
487                         ccs_put_name(entry->domainname);
488                 }
489                 break;
490 #endif
491         }
492 }
493 
494 /**
495  * ccs_del_domain - Delete members in "struct ccs_domain_info".
496  *
497  * @element: Pointer to "struct list_head".
498  *
499  * Returns nothing.
500  *
501  * Caller holds ccs_policy_lock mutex.
502  */
503 static inline void ccs_del_domain(struct list_head *element)
504 {
505         struct ccs_domain_info *domain =
506                 container_of(element, typeof(*domain), list);
507         struct ccs_acl_info *acl;
508         struct ccs_acl_info *tmp;
509         /*
510          * Since this domain is referenced from neither "struct ccs_io_buffer"
511          * nor "struct task_struct", we can delete elements without checking
512          * for is_deleted flag.
513          */
514         list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) {
515                 ccs_del_acl(&acl->list);
516                 ccs_memory_free(acl, CCS_ID_ACL);
517         }
518         ccs_put_name(domain->domainname);
519 }
520 
521 /**
522  * ccs_del_path_group - Delete members in "struct ccs_path_group".
523  *
524  * @element: Pointer to "struct list_head".
525  *
526  * Returns nothing.
527  */
528 static inline void ccs_del_path_group(struct list_head *element)
529 {
530         struct ccs_path_group *member =
531                 container_of(element, typeof(*member), head.list);
532         ccs_put_name(member->member_name);
533 }
534 
535 /**
536  * ccs_del_group - Delete "struct ccs_group".
537  *
538  * @element: Pointer to "struct list_head".
539  *
540  * Returns nothing.
541  */
542 static inline void ccs_del_group(struct list_head *element)
543 {
544         struct ccs_group *group =
545                 container_of(element, typeof(*group), head.list);
546         ccs_put_name(group->group_name);
547 }
548 
549 /**
550  * ccs_del_address_group - Delete members in "struct ccs_address_group".
551  *
552  * @element: Pointer to "struct list_head".
553  *
554  * Returns nothing.
555  */
556 static inline void ccs_del_address_group(struct list_head *element)
557 {
558         /* Nothing to do. */
559 }
560 
561 /**
562  * ccs_del_number_group - Delete members in "struct ccs_number_group".
563  *
564  * @element: Pointer to "struct list_head".
565  *
566  * Returns nothing.
567  */
568 static inline void ccs_del_number_group(struct list_head *element)
569 {
570         /* Nothing to do. */
571 }
572 
573 /**
574  * ccs_del_reservedport - Delete members in "struct ccs_reserved".
575  *
576  * @element: Pointer to "struct list_head".
577  *
578  * Returns nothing.
579  */
580 static inline void ccs_del_reservedport(struct list_head *element)
581 {
582         /* Nothing to do. */
583 }
584 
585 /**
586  * ccs_del_condition - Delete members in "struct ccs_condition".
587  *
588  * @element: Pointer to "struct list_head".
589  *
590  * Returns nothing.
591  */
592 void ccs_del_condition(struct list_head *element)
593 {
594         struct ccs_condition *cond = container_of(element, typeof(*cond),
595                                                   head.list);
596         const u16 condc = cond->condc;
597         const u16 numbers_count = cond->numbers_count;
598         const u16 names_count = cond->names_count;
599         const u16 argc = cond->argc;
600         const u16 envc = cond->envc;
601         unsigned int i;
602         const struct ccs_condition_element *condp
603                 = (const struct ccs_condition_element *) (cond + 1);
604         struct ccs_number_union *numbers_p
605                 = (struct ccs_number_union *) (condp + condc);
606         struct ccs_name_union *names_p
607                 = (struct ccs_name_union *) (numbers_p + numbers_count);
608         const struct ccs_argv *argv
609                 = (const struct ccs_argv *) (names_p + names_count);
610         const struct ccs_envp *envp
611                 = (const struct ccs_envp *) (argv + argc);
612         for (i = 0; i < numbers_count; i++)
613                 ccs_put_number_union(numbers_p++);
614         for (i = 0; i < names_count; i++)
615                 ccs_put_name_union(names_p++);
616         for (i = 0; i < argc; argv++, i++)
617                 ccs_put_name(argv->value);
618         for (i = 0; i < envc; envp++, i++) {
619                 ccs_put_name(envp->name);
620                 ccs_put_name(envp->value);
621         }
622         ccs_put_name(cond->transit);
623 }
624 
625 /**
626  * ccs_del_name - Delete members in "struct ccs_name".
627  *
628  * @element: Pointer to "struct list_head".
629  *
630  * Returns nothing.
631  */
632 static inline void ccs_del_name(struct list_head *element)
633 {
634         /* Nothing to do. */
635 }
636 
637 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
638 
639 /**
640  * ccs_lock - Alternative for srcu_read_lock().
641  *
642  * Returns index number which has to be passed to ccs_unlock().
643  */
644 int ccs_lock(void)
645 {
646         int idx;
647         spin_lock(&ccs_counter_lock);
648         idx = ccs_counter.counter_idx;
649         ccs_counter.counter[idx]++;
650         spin_unlock(&ccs_counter_lock);
651         return idx;
652 }
653 
654 /**
655  * ccs_unlock - Alternative for srcu_read_unlock().
656  *
657  * @idx: Index number returned by ccs_lock().
658  *
659  * Returns nothing.
660  */
661 void ccs_unlock(const int idx)
662 {
663         spin_lock(&ccs_counter_lock);
664         ccs_counter.counter[idx]--;
665         spin_unlock(&ccs_counter_lock);
666 }
667 
668 /**
669  * ccs_synchronize_counter - Alternative for synchronize_srcu().
670  *
671  * Returns nothing.
672  */
673 static void ccs_synchronize_counter(void)
674 {
675         int idx;
676         int v;
677         /*
678          * Change currently active counter's index. Make it visible to other
679          * threads by doing it with ccs_counter_lock held.
680          * This function is called by garbage collector thread, and the garbage
681          * collector thread is exclusive. Therefore, it is guaranteed that
682          * SRCU grace period has expired when returning from this function.
683          */
684         spin_lock(&ccs_counter_lock);
685         idx = ccs_counter.counter_idx;
686         ccs_counter.counter_idx ^= 1;
687         v = ccs_counter.counter[idx];
688         spin_unlock(&ccs_counter_lock);
689         /* Wait for previously active counter to become 0. */
690         while (v) {
691                 ssleep(1);
692                 spin_lock(&ccs_counter_lock);
693                 v = ccs_counter.counter[idx];
694                 spin_unlock(&ccs_counter_lock);
695         }
696 }
697 
698 #endif
699 
700 /**
701  * ccs_try_to_gc - Try to kfree() an entry.
702  *
703  * @type:    One of values in "enum ccs_policy_id".
704  * @element: Pointer to "struct list_head".
705  *
706  * Returns nothing.
707  *
708  * Caller holds ccs_policy_lock mutex.
709  */
710 static void ccs_try_to_gc(const enum ccs_policy_id type,
711                           struct list_head *element)
712 {
713         /*
714          * __list_del_entry() guarantees that the list element became no longer
715          * reachable from the list which the element was originally on (e.g.
716          * ccs_domain_list). Also, synchronize_srcu() guarantees that the list
717          * element became no longer referenced by syscall users.
718          */
719         __list_del_entry(element);
720         mutex_unlock(&ccs_policy_lock);
721 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
722         synchronize_srcu(&ccs_ss);
723 #else
724         ccs_synchronize_counter();
725 #endif
726         /*
727          * However, there are two users which may still be using the list
728          * element. We need to defer until both users forget this element.
729          *
730          * Don't kfree() until "struct ccs_io_buffer"->r.{domain,group,acl} and
731          * "struct ccs_io_buffer"->w.domain forget this element.
732          */
733         if (ccs_struct_used_by_io_buffer(element))
734                 goto reinject;
735         switch (type) {
736         case CCS_ID_TRANSITION_CONTROL:
737                 ccs_del_transition_control(element);
738                 break;
739         case CCS_ID_MANAGER:
740                 ccs_del_manager(element);
741                 break;
742         case CCS_ID_AGGREGATOR:
743                 ccs_del_aggregator(element);
744                 break;
745         case CCS_ID_GROUP:
746                 ccs_del_group(element);
747                 break;
748         case CCS_ID_PATH_GROUP:
749                 ccs_del_path_group(element);
750                 break;
751 #ifdef CONFIG_CCSECURITY_NETWORK
752         case CCS_ID_ADDRESS_GROUP:
753                 ccs_del_address_group(element);
754                 break;
755 #endif
756         case CCS_ID_NUMBER_GROUP:
757                 ccs_del_number_group(element);
758                 break;
759 #ifdef CONFIG_CCSECURITY_PORTRESERVE
760         case CCS_ID_RESERVEDPORT:
761                 ccs_del_reservedport(element);
762                 break;
763 #endif
764         case CCS_ID_CONDITION:
765                 ccs_del_condition(element);
766                 break;
767         case CCS_ID_NAME:
768                 /*
769                  * Don't kfree() until all "struct ccs_io_buffer"->r.w[] forget
770                  * this element.
771                  */
772                 if (ccs_name_used_by_io_buffer
773                     (container_of(element, typeof(struct ccs_name),
774                                   head.list)->entry.name,
775                      container_of(element, typeof(struct ccs_name),
776                                   head.list)->size))
777                         goto reinject;
778                 ccs_del_name(element);
779                 break;
780         case CCS_ID_ACL:
781                 ccs_del_acl(element);
782                 break;
783         case CCS_ID_DOMAIN:
784                 /*
785                  * Don't kfree() until all "struct task_struct" forget this
786                  * element.
787                  */
788                 if (ccs_domain_used_by_task
789                     (container_of(element, typeof(struct ccs_domain_info),
790                                   list)))
791                         goto reinject;
792                 break;
793         case CCS_MAX_POLICY:
794                 break;
795         }
796         mutex_lock(&ccs_policy_lock);
797         if (type == CCS_ID_DOMAIN)
798                 ccs_del_domain(element);
799         ccs_memory_free(element, type);
800         return;
801 reinject:
802         /*
803          * We can safely reinject this element here bacause
804          * (1) Appending list elements and removing list elements are protected
805          *     by ccs_policy_lock mutex.
806          * (2) Only this function removes list elements and this function is
807          *     exclusively executed by ccs_gc_mutex mutex.
808          * are true.
809          */
810         mutex_lock(&ccs_policy_lock);
811         list_add_rcu(element, element->prev);
812 }
813 
814 /**
815  * ccs_collect_member - Delete elements with "struct ccs_acl_head".
816  *
817  * @id:          One of values in "enum ccs_policy_id".
818  * @member_list: Pointer to "struct list_head".
819  *
820  * Returns nothing.
821  *
822  * Caller holds ccs_policy_lock mutex.
823  */
824 static void ccs_collect_member(const enum ccs_policy_id id,
825                                struct list_head *member_list)
826 {
827         struct ccs_acl_head *member;
828         struct ccs_acl_head *tmp;
829         list_for_each_entry_safe(member, tmp, member_list, list) {
830                 if (!member->is_deleted)
831                         continue;
832                 member->is_deleted = CCS_GC_IN_PROGRESS;
833                 ccs_try_to_gc(id, &member->list);
834         }
835 }
836 
837 /**
838  * ccs_collect_acl - Delete elements in "struct ccs_domain_info".
839  *
840  * @list: Pointer to "struct list_head".
841  *
842  * Returns nothing.
843  *
844  * Caller holds ccs_policy_lock mutex.
845  */
846 static void ccs_collect_acl(struct list_head *list)
847 {
848         struct ccs_acl_info *acl;
849         struct ccs_acl_info *tmp;
850         list_for_each_entry_safe(acl, tmp, list, list) {
851                 if (!acl->is_deleted)
852                         continue;
853                 acl->is_deleted = CCS_GC_IN_PROGRESS;
854                 ccs_try_to_gc(CCS_ID_ACL, &acl->list);
855         }
856 }
857 
858 /**
859  * ccs_collect_entry - Try to kfree() deleted elements.
860  *
861  * Returns nothing.
862  */
863 static void ccs_collect_entry(void)
864 {
865         int i;
866         enum ccs_policy_id id;
867         struct ccs_policy_namespace *ns;
868         mutex_lock(&ccs_policy_lock);
869         {
870                 struct ccs_domain_info *domain;
871                 struct ccs_domain_info *tmp;
872                 list_for_each_entry_safe(domain, tmp, &ccs_domain_list, list) {
873                         ccs_collect_acl(&domain->acl_info_list);
874                         if (!domain->is_deleted ||
875                             ccs_domain_used_by_task(domain))
876                                 continue;
877                         ccs_try_to_gc(CCS_ID_DOMAIN, &domain->list);
878                 }
879         }
880         list_for_each_entry(ns, &ccs_namespace_list, namespace_list) {
881                 for (id = 0; id < CCS_MAX_POLICY; id++)
882                         ccs_collect_member(id, &ns->policy_list[id]);
883                 for (i = 0; i < CCS_MAX_ACL_GROUPS; i++)
884                         ccs_collect_acl(&ns->acl_group[i]);
885         }
886         {
887                 struct ccs_shared_acl_head *ptr;
888                 struct ccs_shared_acl_head *tmp;
889                 list_for_each_entry_safe(ptr, tmp, &ccs_condition_list, list) {
890                         if (atomic_read(&ptr->users) > 0)
891                                 continue;
892                         atomic_set(&ptr->users, CCS_GC_IN_PROGRESS);
893                         ccs_try_to_gc(CCS_ID_CONDITION, &ptr->list);
894                 }
895         }
896         list_for_each_entry(ns, &ccs_namespace_list, namespace_list) {
897                 for (i = 0; i < CCS_MAX_GROUP; i++) {
898                         struct list_head *list = &ns->group_list[i];
899                         struct ccs_group *group;
900                         struct ccs_group *tmp;
901                         switch (i) {
902                         case 0:
903                                 id = CCS_ID_PATH_GROUP;
904                                 break;
905                         case 1:
906                                 id = CCS_ID_NUMBER_GROUP;
907                                 break;
908                         default:
909 #ifdef CONFIG_CCSECURITY_NETWORK
910                                 id = CCS_ID_ADDRESS_GROUP;
911 #else
912                                 continue;
913 #endif
914                                 break;
915                         }
916                         list_for_each_entry_safe(group, tmp, list, head.list) {
917                                 ccs_collect_member(id, &group->member_list);
918                                 if (!list_empty(&group->member_list) ||
919                                     atomic_read(&group->head.users) > 0)
920                                         continue;
921                                 atomic_set(&group->head.users,
922                                            CCS_GC_IN_PROGRESS);
923                                 ccs_try_to_gc(CCS_ID_GROUP, &group->head.list);
924                         }
925                 }
926         }
927         for (i = 0; i < CCS_MAX_HASH; i++) {
928                 struct list_head *list = &ccs_name_list[i];
929                 struct ccs_shared_acl_head *ptr;
930                 struct ccs_shared_acl_head *tmp;
931                 list_for_each_entry_safe(ptr, tmp, list, list) {
932                         if (atomic_read(&ptr->users) > 0)
933                                 continue;
934                         atomic_set(&ptr->users, CCS_GC_IN_PROGRESS);
935                         ccs_try_to_gc(CCS_ID_NAME, &ptr->list);
936                 }
937         }
938         mutex_unlock(&ccs_policy_lock);
939 }
940 
941 /**
942  * ccs_gc_thread - Garbage collector thread function.
943  *
944  * @unused: Unused.
945  *
946  * Returns 0.
947  */
948 static int ccs_gc_thread(void *unused)
949 {
950         /* Garbage collector thread is exclusive. */
951         static DEFINE_MUTEX(ccs_gc_mutex);
952         if (!mutex_trylock(&ccs_gc_mutex))
953                 goto out;
954 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 6)
955         /* daemonize() not needed. */
956 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
957         daemonize("GC for CCS");
958 #else
959         daemonize();
960         reparent_to_init();
961 #if defined(TASK_DEAD)
962         {
963                 struct task_struct *task = current;
964                 spin_lock_irq(&task->sighand->siglock);
965                 siginitsetinv(&task->blocked, 0);
966                 recalc_sigpending();
967                 spin_unlock_irq(&task->sighand->siglock);
968         }
969 #else
970         {
971                 struct task_struct *task = current;
972                 spin_lock_irq(&task->sigmask_lock);
973                 siginitsetinv(&task->blocked, 0);
974                 recalc_sigpending(task);
975                 spin_unlock_irq(&task->sigmask_lock);
976         }
977 #endif
978         snprintf(current->comm, sizeof(current->comm) - 1, "GC for CCS");
979 #endif
980         ccs_collect_entry();
981         {
982                 struct ccs_io_buffer *head;
983                 struct ccs_io_buffer *tmp;
984                 spin_lock(&ccs_io_buffer_list_lock);
985                 list_for_each_entry_safe(head, tmp, &ccs_io_buffer_list,
986                                          list) {
987                         if (head->users)
988                                 continue;
989                         list_del(&head->list);
990                         kfree(head->read_buf);
991                         kfree(head->write_buf);
992                         kfree(head);
993                 }
994                 spin_unlock(&ccs_io_buffer_list_lock);
995         }
996         mutex_unlock(&ccs_gc_mutex);
997 out:
998         /* This acts as do_exit(0). */
999         return 0;
1000 }
1001 
1002 /**
1003  * ccs_notify_gc - Register/unregister /proc/ccs/ users.
1004  *
1005  * @head:        Pointer to "struct ccs_io_buffer".
1006  * @is_register: True if register, false if unregister.
1007  *
1008  * Returns nothing.
1009  */
1010 void ccs_notify_gc(struct ccs_io_buffer *head, const bool is_register)
1011 {
1012         bool is_write = false;
1013         spin_lock(&ccs_io_buffer_list_lock);
1014         if (is_register) {
1015                 head->users = 1;
1016                 list_add(&head->list, &ccs_io_buffer_list);
1017         } else {
1018                 is_write = head->write_buf != NULL;
1019                 if (!--head->users) {
1020                         list_del(&head->list);
1021                         kfree(head->read_buf);
1022                         kfree(head->write_buf);
1023                         kfree(head);
1024                 }
1025         }
1026         spin_unlock(&ccs_io_buffer_list_lock);
1027         if (is_write) {
1028 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 6)
1029                 struct task_struct *task = kthread_create(ccs_gc_thread, NULL,
1030                                                           "GC for CCS");
1031                 if (!IS_ERR(task))
1032                         wake_up_process(task);
1033 #else
1034                 kernel_thread(ccs_gc_thread, NULL, 0);
1035 #endif
1036         }
1037 }
1038 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp