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