]> bbs.cooldavid.org Git - net-next-2.6.git/blob - security/tomoyo/gc.c
78100180d23d2ff4c7bbcbe4190a55a3c03c21c5
[net-next-2.6.git] / security / tomoyo / gc.c
1 /*
2  * security/tomoyo/gc.c
3  *
4  * Implementation of the Domain-Based Mandatory Access Control.
5  *
6  * Copyright (C) 2005-2010  NTT DATA CORPORATION
7  *
8  */
9
10 #include "common.h"
11 #include <linux/kthread.h>
12 #include <linux/slab.h>
13
14 enum tomoyo_gc_id {
15         TOMOYO_ID_PATH_GROUP,
16         TOMOYO_ID_PATH_GROUP_MEMBER,
17         TOMOYO_ID_NUMBER_GROUP,
18         TOMOYO_ID_NUMBER_GROUP_MEMBER,
19         TOMOYO_ID_DOMAIN_INITIALIZER,
20         TOMOYO_ID_DOMAIN_KEEPER,
21         TOMOYO_ID_ALIAS,
22         TOMOYO_ID_GLOBALLY_READABLE,
23         TOMOYO_ID_PATTERN,
24         TOMOYO_ID_NO_REWRITE,
25         TOMOYO_ID_MANAGER,
26         TOMOYO_ID_NAME,
27         TOMOYO_ID_ACL,
28         TOMOYO_ID_DOMAIN
29 };
30
31 struct tomoyo_gc_entry {
32         struct list_head list;
33         int type;
34         void *element;
35 };
36 static LIST_HEAD(tomoyo_gc_queue);
37 static DEFINE_MUTEX(tomoyo_gc_mutex);
38
39 /* Caller holds tomoyo_policy_lock mutex. */
40 static bool tomoyo_add_to_gc(const int type, void *element)
41 {
42         struct tomoyo_gc_entry *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
43         if (!entry)
44                 return false;
45         entry->type = type;
46         entry->element = element;
47         list_add(&entry->list, &tomoyo_gc_queue);
48         return true;
49 }
50
51 static void tomoyo_del_allow_read
52 (struct tomoyo_globally_readable_file_entry *ptr)
53 {
54         tomoyo_put_name(ptr->filename);
55 }
56
57 static void tomoyo_del_file_pattern(struct tomoyo_pattern_entry *ptr)
58 {
59         tomoyo_put_name(ptr->pattern);
60 }
61
62 static void tomoyo_del_no_rewrite(struct tomoyo_no_rewrite_entry *ptr)
63 {
64         tomoyo_put_name(ptr->pattern);
65 }
66
67 static void tomoyo_del_domain_initializer
68 (struct tomoyo_domain_initializer_entry *ptr)
69 {
70         tomoyo_put_name(ptr->domainname);
71         tomoyo_put_name(ptr->program);
72 }
73
74 static void tomoyo_del_domain_keeper(struct tomoyo_domain_keeper_entry *ptr)
75 {
76         tomoyo_put_name(ptr->domainname);
77         tomoyo_put_name(ptr->program);
78 }
79
80 static void tomoyo_del_alias(struct tomoyo_alias_entry *ptr)
81 {
82         tomoyo_put_name(ptr->original_name);
83         tomoyo_put_name(ptr->aliased_name);
84 }
85
86 static void tomoyo_del_manager(struct tomoyo_policy_manager_entry *ptr)
87 {
88         tomoyo_put_name(ptr->manager);
89 }
90
91 static void tomoyo_del_acl(struct tomoyo_acl_info *acl)
92 {
93         switch (acl->type) {
94         case TOMOYO_TYPE_PATH_ACL:
95                 {
96                         struct tomoyo_path_acl *entry
97                                 = container_of(acl, typeof(*entry), head);
98                         tomoyo_put_name_union(&entry->name);
99                 }
100                 break;
101         case TOMOYO_TYPE_PATH2_ACL:
102                 {
103                         struct tomoyo_path2_acl *entry
104                                 = container_of(acl, typeof(*entry), head);
105                         tomoyo_put_name_union(&entry->name1);
106                         tomoyo_put_name_union(&entry->name2);
107                 }
108                 break;
109         case TOMOYO_TYPE_PATH_NUMBER_ACL:
110                 {
111                         struct tomoyo_path_number_acl *entry
112                                 = container_of(acl, typeof(*entry), head);
113                         tomoyo_put_name_union(&entry->name);
114                         tomoyo_put_number_union(&entry->number);
115                 }
116                 break;
117         case TOMOYO_TYPE_PATH_NUMBER3_ACL:
118                 {
119                         struct tomoyo_path_number3_acl *entry
120                                 = container_of(acl, typeof(*entry), head);
121                         tomoyo_put_name_union(&entry->name);
122                         tomoyo_put_number_union(&entry->mode);
123                         tomoyo_put_number_union(&entry->major);
124                         tomoyo_put_number_union(&entry->minor);
125                 }
126                 break;
127         default:
128                 printk(KERN_WARNING "Unknown type\n");
129                 break;
130         }
131 }
132
133 static bool tomoyo_del_domain(struct tomoyo_domain_info *domain)
134 {
135         struct tomoyo_acl_info *acl;
136         struct tomoyo_acl_info *tmp;
137         /*
138          * Since we don't protect whole execve() operation using SRCU,
139          * we need to recheck domain->users at this point.
140          *
141          * (1) Reader starts SRCU section upon execve().
142          * (2) Reader traverses tomoyo_domain_list and finds this domain.
143          * (3) Writer marks this domain as deleted.
144          * (4) Garbage collector removes this domain from tomoyo_domain_list
145          *     because this domain is marked as deleted and used by nobody.
146          * (5) Reader saves reference to this domain into
147          *     "struct linux_binprm"->cred->security .
148          * (6) Reader finishes SRCU section, although execve() operation has
149          *     not finished yet.
150          * (7) Garbage collector waits for SRCU synchronization.
151          * (8) Garbage collector kfree() this domain because this domain is
152          *     used by nobody.
153          * (9) Reader finishes execve() operation and restores this domain from
154          *     "struct linux_binprm"->cred->security.
155          *
156          * By updating domain->users at (5), we can solve this race problem
157          * by rechecking domain->users at (8).
158          */
159         if (atomic_read(&domain->users))
160                 return false;
161         list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) {
162                 tomoyo_del_acl(acl);
163                 tomoyo_memory_free(acl);
164         }
165         tomoyo_put_name(domain->domainname);
166         return true;
167 }
168
169
170 static void tomoyo_del_name(const struct tomoyo_name_entry *ptr)
171 {
172 }
173
174 static void tomoyo_del_path_group_member(struct tomoyo_path_group_member
175                                          *member)
176 {
177         tomoyo_put_name(member->member_name);
178 }
179
180 static void tomoyo_del_path_group(struct tomoyo_path_group *group)
181 {
182         tomoyo_put_name(group->group_name);
183 }
184
185 static void tomoyo_del_number_group_member(struct tomoyo_number_group_member
186                                            *member)
187 {
188 }
189
190 static void tomoyo_del_number_group(struct tomoyo_number_group *group)
191 {
192         tomoyo_put_name(group->group_name);
193 }
194
195 static void tomoyo_collect_entry(void)
196 {
197         if (mutex_lock_interruptible(&tomoyo_policy_lock))
198                 return;
199         {
200                 struct tomoyo_globally_readable_file_entry *ptr;
201                 list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list,
202                                         list) {
203                         if (!ptr->is_deleted)
204                                 continue;
205                         if (tomoyo_add_to_gc(TOMOYO_ID_GLOBALLY_READABLE, ptr))
206                                 list_del_rcu(&ptr->list);
207                         else
208                                 break;
209                 }
210         }
211         {
212                 struct tomoyo_pattern_entry *ptr;
213                 list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
214                         if (!ptr->is_deleted)
215                                 continue;
216                         if (tomoyo_add_to_gc(TOMOYO_ID_PATTERN, ptr))
217                                 list_del_rcu(&ptr->list);
218                         else
219                                 break;
220                 }
221         }
222         {
223                 struct tomoyo_no_rewrite_entry *ptr;
224                 list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
225                         if (!ptr->is_deleted)
226                                 continue;
227                         if (tomoyo_add_to_gc(TOMOYO_ID_NO_REWRITE, ptr))
228                                 list_del_rcu(&ptr->list);
229                         else
230                                 break;
231                 }
232         }
233         {
234                 struct tomoyo_domain_initializer_entry *ptr;
235                 list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list,
236                                         list) {
237                         if (!ptr->is_deleted)
238                                 continue;
239                         if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_INITIALIZER, ptr))
240                                 list_del_rcu(&ptr->list);
241                         else
242                                 break;
243                 }
244         }
245         {
246                 struct tomoyo_domain_keeper_entry *ptr;
247                 list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
248                         if (!ptr->is_deleted)
249                                 continue;
250                         if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_KEEPER, ptr))
251                                 list_del_rcu(&ptr->list);
252                         else
253                                 break;
254                 }
255         }
256         {
257                 struct tomoyo_alias_entry *ptr;
258                 list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
259                         if (!ptr->is_deleted)
260                                 continue;
261                         if (tomoyo_add_to_gc(TOMOYO_ID_ALIAS, ptr))
262                                 list_del_rcu(&ptr->list);
263                         else
264                                 break;
265                 }
266         }
267         {
268                 struct tomoyo_policy_manager_entry *ptr;
269                 list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list,
270                                         list) {
271                         if (!ptr->is_deleted)
272                                 continue;
273                         if (tomoyo_add_to_gc(TOMOYO_ID_MANAGER, ptr))
274                                 list_del_rcu(&ptr->list);
275                         else
276                                 break;
277                 }
278         }
279         {
280                 struct tomoyo_domain_info *domain;
281                 list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
282                         struct tomoyo_acl_info *acl;
283                         list_for_each_entry_rcu(acl, &domain->acl_info_list,
284                                                 list) {
285                                 switch (acl->type) {
286                                 case TOMOYO_TYPE_PATH_ACL:
287                                         if (container_of(acl,
288                                          struct tomoyo_path_acl,
289                                                          head)->perm)
290                                                 continue;
291                                         break;
292                                 case TOMOYO_TYPE_PATH2_ACL:
293                                         if (container_of(acl,
294                                          struct tomoyo_path2_acl,
295                                                          head)->perm)
296                                                 continue;
297                                         break;
298                                 case TOMOYO_TYPE_PATH_NUMBER_ACL:
299                                         if (container_of(acl,
300                                          struct tomoyo_path_number_acl,
301                                                          head)->perm)
302                                                 continue;
303                                         break;
304                                 case TOMOYO_TYPE_PATH_NUMBER3_ACL:
305                                         if (container_of(acl,
306                                          struct tomoyo_path_number3_acl,
307                                                          head)->perm)
308                                                 continue;
309                                         break;
310                                 default:
311                                         continue;
312                                 }
313                                 if (tomoyo_add_to_gc(TOMOYO_ID_ACL, acl))
314                                         list_del_rcu(&acl->list);
315                                 else
316                                         break;
317                         }
318                         if (!domain->is_deleted || atomic_read(&domain->users))
319                                 continue;
320                         /*
321                          * Nobody is referring this domain. But somebody may
322                          * refer this domain after successful execve().
323                          * We recheck domain->users after SRCU synchronization.
324                          */
325                         if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, domain))
326                                 list_del_rcu(&domain->list);
327                         else
328                                 break;
329                 }
330         }
331         {
332                 int i;
333                 for (i = 0; i < TOMOYO_MAX_HASH; i++) {
334                         struct tomoyo_name_entry *ptr;
335                         list_for_each_entry_rcu(ptr, &tomoyo_name_list[i],
336                                                 list) {
337                                 if (atomic_read(&ptr->users))
338                                         continue;
339                                 if (tomoyo_add_to_gc(TOMOYO_ID_NAME, ptr))
340                                         list_del_rcu(&ptr->list);
341                                 else {
342                                         i = TOMOYO_MAX_HASH;
343                                         break;
344                                 }
345                         }
346                 }
347         }
348         {
349                 struct tomoyo_path_group *group;
350                 list_for_each_entry_rcu(group, &tomoyo_path_group_list, list) {
351                         struct tomoyo_path_group_member *member;
352                         list_for_each_entry_rcu(member, &group->member_list,
353                                                 list) {
354                                 if (!member->is_deleted)
355                                         continue;
356                                 if (tomoyo_add_to_gc(TOMOYO_ID_PATH_GROUP_MEMBER,
357                                                      member))
358                                         list_del_rcu(&member->list);
359                                 else
360                                         break;
361                         }
362                         if (!list_empty(&group->member_list) ||
363                             atomic_read(&group->users))
364                                 continue;
365                         if (tomoyo_add_to_gc(TOMOYO_ID_PATH_GROUP, group))
366                                 list_del_rcu(&group->list);
367                         else
368                                 break;
369                 }
370         }
371         {
372                 struct tomoyo_number_group *group;
373                 list_for_each_entry_rcu(group, &tomoyo_number_group_list, list) {
374                         struct tomoyo_number_group_member *member;
375                         list_for_each_entry_rcu(member, &group->member_list,
376                                                 list) {
377                                 if (!member->is_deleted)
378                                         continue;
379                                 if (tomoyo_add_to_gc(TOMOYO_ID_NUMBER_GROUP_MEMBER,
380                                                      member))
381                                         list_del_rcu(&member->list);
382                                 else
383                                         break;
384                         }
385                         if (!list_empty(&group->member_list) ||
386                             atomic_read(&group->users))
387                                 continue;
388                         if (tomoyo_add_to_gc(TOMOYO_ID_NUMBER_GROUP, group))
389                                 list_del_rcu(&group->list);
390                         else
391                                 break;
392                 }
393         }
394         mutex_unlock(&tomoyo_policy_lock);
395 }
396
397 static void tomoyo_kfree_entry(void)
398 {
399         struct tomoyo_gc_entry *p;
400         struct tomoyo_gc_entry *tmp;
401
402         list_for_each_entry_safe(p, tmp, &tomoyo_gc_queue, list) {
403                 switch (p->type) {
404                 case TOMOYO_ID_DOMAIN_INITIALIZER:
405                         tomoyo_del_domain_initializer(p->element);
406                         break;
407                 case TOMOYO_ID_DOMAIN_KEEPER:
408                         tomoyo_del_domain_keeper(p->element);
409                         break;
410                 case TOMOYO_ID_ALIAS:
411                         tomoyo_del_alias(p->element);
412                         break;
413                 case TOMOYO_ID_GLOBALLY_READABLE:
414                         tomoyo_del_allow_read(p->element);
415                         break;
416                 case TOMOYO_ID_PATTERN:
417                         tomoyo_del_file_pattern(p->element);
418                         break;
419                 case TOMOYO_ID_NO_REWRITE:
420                         tomoyo_del_no_rewrite(p->element);
421                         break;
422                 case TOMOYO_ID_MANAGER:
423                         tomoyo_del_manager(p->element);
424                         break;
425                 case TOMOYO_ID_NAME:
426                         tomoyo_del_name(p->element);
427                         break;
428                 case TOMOYO_ID_ACL:
429                         tomoyo_del_acl(p->element);
430                         break;
431                 case TOMOYO_ID_DOMAIN:
432                         if (!tomoyo_del_domain(p->element))
433                                 continue;
434                         break;
435                 case TOMOYO_ID_PATH_GROUP_MEMBER:
436                         tomoyo_del_path_group_member(p->element);
437                         break;
438                 case TOMOYO_ID_PATH_GROUP:
439                         tomoyo_del_path_group(p->element);
440                         break;
441                 case TOMOYO_ID_NUMBER_GROUP_MEMBER:
442                         tomoyo_del_number_group_member(p->element);
443                         break;
444                 case TOMOYO_ID_NUMBER_GROUP:
445                         tomoyo_del_number_group(p->element);
446                         break;
447                 default:
448                         printk(KERN_WARNING "Unknown type\n");
449                         break;
450                 }
451                 tomoyo_memory_free(p->element);
452                 list_del(&p->list);
453                 kfree(p);
454         }
455 }
456
457 static int tomoyo_gc_thread(void *unused)
458 {
459         daemonize("GC for TOMOYO");
460         if (mutex_trylock(&tomoyo_gc_mutex)) {
461                 int i;
462                 for (i = 0; i < 10; i++) {
463                         tomoyo_collect_entry();
464                         if (list_empty(&tomoyo_gc_queue))
465                                 break;
466                         synchronize_srcu(&tomoyo_ss);
467                         tomoyo_kfree_entry();
468                 }
469                 mutex_unlock(&tomoyo_gc_mutex);
470         }
471         do_exit(0);
472 }
473
474 void tomoyo_run_gc(void)
475 {
476         struct task_struct *task = kthread_create(tomoyo_gc_thread, NULL,
477                                                   "GC for TOMOYO");
478         if (!IS_ERR(task))
479                 wake_up_process(task);
480 }