446d59f8ae2559c716976ad777d5563fcce70081
[pandora-kernel.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_policy_id {
15         TOMOYO_ID_GROUP,
16         TOMOYO_ID_PATH_GROUP,
17         TOMOYO_ID_NUMBER_GROUP,
18         TOMOYO_ID_DOMAIN_INITIALIZER,
19         TOMOYO_ID_DOMAIN_KEEPER,
20         TOMOYO_ID_AGGREGATOR,
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         TOMOYO_MAX_POLICY
30 };
31
32 struct tomoyo_gc_entry {
33         struct list_head list;
34         int type;
35         struct list_head *element;
36 };
37 static LIST_HEAD(tomoyo_gc_queue);
38 static DEFINE_MUTEX(tomoyo_gc_mutex);
39
40 /* Caller holds tomoyo_policy_lock mutex. */
41 static bool tomoyo_add_to_gc(const int type, struct list_head *element)
42 {
43         struct tomoyo_gc_entry *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
44         if (!entry)
45                 return false;
46         entry->type = type;
47         entry->element = element;
48         list_add(&entry->list, &tomoyo_gc_queue);
49         list_del_rcu(element);
50         return true;
51 }
52
53 static void tomoyo_del_allow_read(struct list_head *element)
54 {
55         struct tomoyo_globally_readable_file_entry *ptr =
56                 container_of(element, typeof(*ptr), head.list);
57         tomoyo_put_name(ptr->filename);
58 }
59
60 static void tomoyo_del_file_pattern(struct list_head *element)
61 {
62         struct tomoyo_pattern_entry *ptr =
63                 container_of(element, typeof(*ptr), head.list);
64         tomoyo_put_name(ptr->pattern);
65 }
66
67 static void tomoyo_del_no_rewrite(struct list_head *element)
68 {
69         struct tomoyo_no_rewrite_entry *ptr =
70                 container_of(element, typeof(*ptr), head.list);
71         tomoyo_put_name(ptr->pattern);
72 }
73
74 static void tomoyo_del_domain_initializer(struct list_head *element)
75 {
76         struct tomoyo_domain_initializer_entry *ptr =
77                 container_of(element, typeof(*ptr), head.list);
78         tomoyo_put_name(ptr->domainname);
79         tomoyo_put_name(ptr->program);
80 }
81
82 static void tomoyo_del_domain_keeper(struct list_head *element)
83 {
84         struct tomoyo_domain_keeper_entry *ptr =
85                 container_of(element, typeof(*ptr), head.list);
86         tomoyo_put_name(ptr->domainname);
87         tomoyo_put_name(ptr->program);
88 }
89
90 static void tomoyo_del_aggregator(struct list_head *element)
91 {
92         struct tomoyo_aggregator_entry *ptr =
93                 container_of(element, typeof(*ptr), head.list);
94         tomoyo_put_name(ptr->original_name);
95         tomoyo_put_name(ptr->aggregated_name);
96 }
97
98 static void tomoyo_del_alias(struct list_head *element)
99 {
100         struct tomoyo_alias_entry *ptr =
101                 container_of(element, typeof(*ptr), head.list);
102         tomoyo_put_name(ptr->original_name);
103         tomoyo_put_name(ptr->aliased_name);
104 }
105
106 static void tomoyo_del_manager(struct list_head *element)
107 {
108         struct tomoyo_policy_manager_entry *ptr =
109                 container_of(element, typeof(*ptr), head.list);
110         tomoyo_put_name(ptr->manager);
111 }
112
113 static void tomoyo_del_acl(struct list_head *element)
114 {
115         struct tomoyo_acl_info *acl =
116                 container_of(element, typeof(*acl), list);
117         switch (acl->type) {
118         case TOMOYO_TYPE_PATH_ACL:
119                 {
120                         struct tomoyo_path_acl *entry
121                                 = container_of(acl, typeof(*entry), head);
122                         tomoyo_put_name_union(&entry->name);
123                 }
124                 break;
125         case TOMOYO_TYPE_PATH2_ACL:
126                 {
127                         struct tomoyo_path2_acl *entry
128                                 = container_of(acl, typeof(*entry), head);
129                         tomoyo_put_name_union(&entry->name1);
130                         tomoyo_put_name_union(&entry->name2);
131                 }
132                 break;
133         case TOMOYO_TYPE_PATH_NUMBER_ACL:
134                 {
135                         struct tomoyo_path_number_acl *entry
136                                 = container_of(acl, typeof(*entry), head);
137                         tomoyo_put_name_union(&entry->name);
138                         tomoyo_put_number_union(&entry->number);
139                 }
140                 break;
141         case TOMOYO_TYPE_MKDEV_ACL:
142                 {
143                         struct tomoyo_mkdev_acl *entry
144                                 = container_of(acl, typeof(*entry), head);
145                         tomoyo_put_name_union(&entry->name);
146                         tomoyo_put_number_union(&entry->mode);
147                         tomoyo_put_number_union(&entry->major);
148                         tomoyo_put_number_union(&entry->minor);
149                 }
150                 break;
151         case TOMOYO_TYPE_MOUNT_ACL:
152                 {
153                         struct tomoyo_mount_acl *entry
154                                 = container_of(acl, typeof(*entry), head);
155                         tomoyo_put_name_union(&entry->dev_name);
156                         tomoyo_put_name_union(&entry->dir_name);
157                         tomoyo_put_name_union(&entry->fs_type);
158                         tomoyo_put_number_union(&entry->flags);
159                 }
160                 break;
161         }
162 }
163
164 static bool tomoyo_del_domain(struct list_head *element)
165 {
166         struct tomoyo_domain_info *domain =
167                 container_of(element, typeof(*domain), list);
168         struct tomoyo_acl_info *acl;
169         struct tomoyo_acl_info *tmp;
170         /*
171          * Since we don't protect whole execve() operation using SRCU,
172          * we need to recheck domain->users at this point.
173          *
174          * (1) Reader starts SRCU section upon execve().
175          * (2) Reader traverses tomoyo_domain_list and finds this domain.
176          * (3) Writer marks this domain as deleted.
177          * (4) Garbage collector removes this domain from tomoyo_domain_list
178          *     because this domain is marked as deleted and used by nobody.
179          * (5) Reader saves reference to this domain into
180          *     "struct linux_binprm"->cred->security .
181          * (6) Reader finishes SRCU section, although execve() operation has
182          *     not finished yet.
183          * (7) Garbage collector waits for SRCU synchronization.
184          * (8) Garbage collector kfree() this domain because this domain is
185          *     used by nobody.
186          * (9) Reader finishes execve() operation and restores this domain from
187          *     "struct linux_binprm"->cred->security.
188          *
189          * By updating domain->users at (5), we can solve this race problem
190          * by rechecking domain->users at (8).
191          */
192         if (atomic_read(&domain->users))
193                 return false;
194         list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) {
195                 tomoyo_del_acl(&acl->list);
196                 tomoyo_memory_free(acl);
197         }
198         tomoyo_put_name(domain->domainname);
199         return true;
200 }
201
202
203 static void tomoyo_del_name(struct list_head *element)
204 {
205         const struct tomoyo_name_entry *ptr =
206                 container_of(element, typeof(*ptr), list);
207 }
208
209 static void tomoyo_del_path_group(struct list_head *element)
210 {
211         struct tomoyo_path_group *member =
212                 container_of(element, typeof(*member), head.list);
213         tomoyo_put_name(member->member_name);
214 }
215
216 static void tomoyo_del_group(struct list_head *element)
217 {
218         struct tomoyo_group *group =
219                 container_of(element, typeof(*group), list);
220         tomoyo_put_name(group->group_name);
221 }
222
223 static void tomoyo_del_number_group(struct list_head *element)
224 {
225         struct tomoyo_number_group *member =
226                 container_of(element, typeof(*member), head.list);
227 }
228
229 static struct list_head *tomoyo_policy_list[TOMOYO_MAX_POLICY] = {
230         [TOMOYO_ID_GLOBALLY_READABLE] = &tomoyo_globally_readable_list,
231         [TOMOYO_ID_PATTERN] = &tomoyo_pattern_list,
232         [TOMOYO_ID_NO_REWRITE] = &tomoyo_no_rewrite_list,
233         [TOMOYO_ID_DOMAIN_INITIALIZER] = &tomoyo_domain_initializer_list,
234         [TOMOYO_ID_DOMAIN_KEEPER] = &tomoyo_domain_keeper_list,
235         [TOMOYO_ID_AGGREGATOR] = &tomoyo_aggregator_list,
236         [TOMOYO_ID_ALIAS] = &tomoyo_alias_list,
237         [TOMOYO_ID_MANAGER] = &tomoyo_policy_manager_list,
238 };
239
240 static bool tomoyo_collect_member(struct list_head *member_list, int id)
241 {
242         struct tomoyo_acl_head *member;
243         list_for_each_entry(member, member_list, list) {
244                 if (!member->is_deleted)
245                         continue;
246                 if (!tomoyo_add_to_gc(id, &member->list))
247                         return false;
248         }
249         return true;
250 }
251
252 static bool tomoyo_collect_acl(struct tomoyo_domain_info *domain)
253 {
254         struct tomoyo_acl_info *acl;
255         list_for_each_entry(acl, &domain->acl_info_list, list) {
256                 if (!acl->is_deleted)
257                         continue;
258                 if (!tomoyo_add_to_gc(TOMOYO_ID_ACL, &acl->list))
259                         return false;
260         }
261         return true;
262 }
263
264 static void tomoyo_collect_entry(void)
265 {
266         int i;
267         if (mutex_lock_interruptible(&tomoyo_policy_lock))
268                 return;
269         for (i = 0; i < TOMOYO_MAX_POLICY; i++) {
270                 if (tomoyo_policy_list[i])
271                         if (!tomoyo_collect_member(tomoyo_policy_list[i], i))
272                                 goto unlock;
273         }
274         {
275                 struct tomoyo_domain_info *domain;
276                 list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
277                         if (!tomoyo_collect_acl(domain))
278                                 goto unlock;
279                         if (!domain->is_deleted || atomic_read(&domain->users))
280                                 continue;
281                         /*
282                          * Nobody is referring this domain. But somebody may
283                          * refer this domain after successful execve().
284                          * We recheck domain->users after SRCU synchronization.
285                          */
286                         if (!tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, &domain->list))
287                                 goto unlock;
288                 }
289         }
290         for (i = 0; i < TOMOYO_MAX_HASH; i++) {
291                 struct tomoyo_name_entry *ptr;
292                 list_for_each_entry_rcu(ptr, &tomoyo_name_list[i], list) {
293                         if (atomic_read(&ptr->users))
294                                 continue;
295                         if (!tomoyo_add_to_gc(TOMOYO_ID_NAME, &ptr->list))
296                                 goto unlock;
297                 }
298         }
299         {
300                 struct tomoyo_group *group;
301                 list_for_each_entry_rcu(group, &tomoyo_path_group_list, list) {
302                         tomoyo_collect_member(&group->member_list,
303                                               TOMOYO_ID_PATH_GROUP);
304                         if (!list_empty(&group->member_list) ||
305                             atomic_read(&group->users))
306                                 continue;
307                         if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP,
308                                               &group->list))
309                                 goto unlock;
310                 }
311         }
312         {
313                 struct tomoyo_group *group;
314                 list_for_each_entry_rcu(group, &tomoyo_number_group_list,
315                                         list) {
316                         tomoyo_collect_member(&group->member_list,
317                                               TOMOYO_ID_NUMBER_GROUP);
318                         if (!list_empty(&group->member_list) ||
319                             atomic_read(&group->users))
320                                 continue;
321                         if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP,
322                                               &group->list))
323                                 goto unlock;
324                 }
325         }
326  unlock:
327         mutex_unlock(&tomoyo_policy_lock);
328 }
329
330 static void tomoyo_kfree_entry(void)
331 {
332         struct tomoyo_gc_entry *p;
333         struct tomoyo_gc_entry *tmp;
334
335         list_for_each_entry_safe(p, tmp, &tomoyo_gc_queue, list) {
336                 struct list_head *element = p->element;
337                 switch (p->type) {
338                 case TOMOYO_ID_DOMAIN_INITIALIZER:
339                         tomoyo_del_domain_initializer(element);
340                         break;
341                 case TOMOYO_ID_DOMAIN_KEEPER:
342                         tomoyo_del_domain_keeper(element);
343                         break;
344                 case TOMOYO_ID_AGGREGATOR:
345                         tomoyo_del_aggregator(element);
346                         break;
347                 case TOMOYO_ID_ALIAS:
348                         tomoyo_del_alias(element);
349                         break;
350                 case TOMOYO_ID_GLOBALLY_READABLE:
351                         tomoyo_del_allow_read(element);
352                         break;
353                 case TOMOYO_ID_PATTERN:
354                         tomoyo_del_file_pattern(element);
355                         break;
356                 case TOMOYO_ID_NO_REWRITE:
357                         tomoyo_del_no_rewrite(element);
358                         break;
359                 case TOMOYO_ID_MANAGER:
360                         tomoyo_del_manager(element);
361                         break;
362                 case TOMOYO_ID_NAME:
363                         tomoyo_del_name(element);
364                         break;
365                 case TOMOYO_ID_ACL:
366                         tomoyo_del_acl(element);
367                         break;
368                 case TOMOYO_ID_DOMAIN:
369                         if (!tomoyo_del_domain(element))
370                                 continue;
371                         break;
372                 case TOMOYO_ID_PATH_GROUP:
373                         tomoyo_del_path_group(element);
374                         break;
375                 case TOMOYO_ID_GROUP:
376                         tomoyo_del_group(element);
377                         break;
378                 case TOMOYO_ID_NUMBER_GROUP:
379                         tomoyo_del_number_group(element);
380                         break;
381                 }
382                 tomoyo_memory_free(element);
383                 list_del(&p->list);
384                 kfree(p);
385         }
386 }
387
388 static int tomoyo_gc_thread(void *unused)
389 {
390         daemonize("GC for TOMOYO");
391         if (mutex_trylock(&tomoyo_gc_mutex)) {
392                 int i;
393                 for (i = 0; i < 10; i++) {
394                         tomoyo_collect_entry();
395                         if (list_empty(&tomoyo_gc_queue))
396                                 break;
397                         synchronize_srcu(&tomoyo_ss);
398                         tomoyo_kfree_entry();
399                 }
400                 mutex_unlock(&tomoyo_gc_mutex);
401         }
402         do_exit(0);
403 }
404
405 void tomoyo_run_gc(void)
406 {
407         struct task_struct *task = kthread_create(tomoyo_gc_thread, NULL,
408                                                   "GC for TOMOYO");
409         if (!IS_ERR(task))
410                 wake_up_process(task);
411 }