]> bbs.cooldavid.org Git - net-next-2.6.git/blob - security/tomoyo/gc.c
TOMOYO: Add numeric values grouping support.
[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         default:
110                 printk(KERN_WARNING "Unknown type\n");
111                 break;
112         }
113 }
114
115 static bool tomoyo_del_domain(struct tomoyo_domain_info *domain)
116 {
117         struct tomoyo_acl_info *acl;
118         struct tomoyo_acl_info *tmp;
119         /*
120          * Since we don't protect whole execve() operation using SRCU,
121          * we need to recheck domain->users at this point.
122          *
123          * (1) Reader starts SRCU section upon execve().
124          * (2) Reader traverses tomoyo_domain_list and finds this domain.
125          * (3) Writer marks this domain as deleted.
126          * (4) Garbage collector removes this domain from tomoyo_domain_list
127          *     because this domain is marked as deleted and used by nobody.
128          * (5) Reader saves reference to this domain into
129          *     "struct linux_binprm"->cred->security .
130          * (6) Reader finishes SRCU section, although execve() operation has
131          *     not finished yet.
132          * (7) Garbage collector waits for SRCU synchronization.
133          * (8) Garbage collector kfree() this domain because this domain is
134          *     used by nobody.
135          * (9) Reader finishes execve() operation and restores this domain from
136          *     "struct linux_binprm"->cred->security.
137          *
138          * By updating domain->users at (5), we can solve this race problem
139          * by rechecking domain->users at (8).
140          */
141         if (atomic_read(&domain->users))
142                 return false;
143         list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) {
144                 tomoyo_del_acl(acl);
145                 tomoyo_memory_free(acl);
146         }
147         tomoyo_put_name(domain->domainname);
148         return true;
149 }
150
151
152 static void tomoyo_del_name(const struct tomoyo_name_entry *ptr)
153 {
154 }
155
156 static void tomoyo_del_path_group_member(struct tomoyo_path_group_member
157                                          *member)
158 {
159         tomoyo_put_name(member->member_name);
160 }
161
162 static void tomoyo_del_path_group(struct tomoyo_path_group *group)
163 {
164         tomoyo_put_name(group->group_name);
165 }
166
167 static void tomoyo_del_number_group_member(struct tomoyo_number_group_member
168                                            *member)
169 {
170 }
171
172 static void tomoyo_del_number_group(struct tomoyo_number_group *group)
173 {
174         tomoyo_put_name(group->group_name);
175 }
176
177 static void tomoyo_collect_entry(void)
178 {
179         if (mutex_lock_interruptible(&tomoyo_policy_lock))
180                 return;
181         {
182                 struct tomoyo_globally_readable_file_entry *ptr;
183                 list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list,
184                                         list) {
185                         if (!ptr->is_deleted)
186                                 continue;
187                         if (tomoyo_add_to_gc(TOMOYO_ID_GLOBALLY_READABLE, ptr))
188                                 list_del_rcu(&ptr->list);
189                         else
190                                 break;
191                 }
192         }
193         {
194                 struct tomoyo_pattern_entry *ptr;
195                 list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
196                         if (!ptr->is_deleted)
197                                 continue;
198                         if (tomoyo_add_to_gc(TOMOYO_ID_PATTERN, ptr))
199                                 list_del_rcu(&ptr->list);
200                         else
201                                 break;
202                 }
203         }
204         {
205                 struct tomoyo_no_rewrite_entry *ptr;
206                 list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
207                         if (!ptr->is_deleted)
208                                 continue;
209                         if (tomoyo_add_to_gc(TOMOYO_ID_NO_REWRITE, ptr))
210                                 list_del_rcu(&ptr->list);
211                         else
212                                 break;
213                 }
214         }
215         {
216                 struct tomoyo_domain_initializer_entry *ptr;
217                 list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list,
218                                         list) {
219                         if (!ptr->is_deleted)
220                                 continue;
221                         if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_INITIALIZER, ptr))
222                                 list_del_rcu(&ptr->list);
223                         else
224                                 break;
225                 }
226         }
227         {
228                 struct tomoyo_domain_keeper_entry *ptr;
229                 list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
230                         if (!ptr->is_deleted)
231                                 continue;
232                         if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_KEEPER, ptr))
233                                 list_del_rcu(&ptr->list);
234                         else
235                                 break;
236                 }
237         }
238         {
239                 struct tomoyo_alias_entry *ptr;
240                 list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
241                         if (!ptr->is_deleted)
242                                 continue;
243                         if (tomoyo_add_to_gc(TOMOYO_ID_ALIAS, ptr))
244                                 list_del_rcu(&ptr->list);
245                         else
246                                 break;
247                 }
248         }
249         {
250                 struct tomoyo_policy_manager_entry *ptr;
251                 list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list,
252                                         list) {
253                         if (!ptr->is_deleted)
254                                 continue;
255                         if (tomoyo_add_to_gc(TOMOYO_ID_MANAGER, ptr))
256                                 list_del_rcu(&ptr->list);
257                         else
258                                 break;
259                 }
260         }
261         {
262                 struct tomoyo_domain_info *domain;
263                 list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
264                         struct tomoyo_acl_info *acl;
265                         list_for_each_entry_rcu(acl, &domain->acl_info_list,
266                                                 list) {
267                                 switch (acl->type) {
268                                 case TOMOYO_TYPE_PATH_ACL:
269                                         if (container_of(acl,
270                                          struct tomoyo_path_acl,
271                                                          head)->perm ||
272                                             container_of(acl,
273                                          struct tomoyo_path_acl,
274                                                          head)->perm_high)
275                                                 continue;
276                                         break;
277                                 case TOMOYO_TYPE_PATH2_ACL:
278                                         if (container_of(acl,
279                                          struct tomoyo_path2_acl,
280                                                          head)->perm)
281                                                 continue;
282                                         break;
283                                 default:
284                                         continue;
285                                 }
286                                 if (tomoyo_add_to_gc(TOMOYO_ID_ACL, acl))
287                                         list_del_rcu(&acl->list);
288                                 else
289                                         break;
290                         }
291                         if (!domain->is_deleted || atomic_read(&domain->users))
292                                 continue;
293                         /*
294                          * Nobody is referring this domain. But somebody may
295                          * refer this domain after successful execve().
296                          * We recheck domain->users after SRCU synchronization.
297                          */
298                         if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, domain))
299                                 list_del_rcu(&domain->list);
300                         else
301                                 break;
302                 }
303         }
304         {
305                 int i;
306                 for (i = 0; i < TOMOYO_MAX_HASH; i++) {
307                         struct tomoyo_name_entry *ptr;
308                         list_for_each_entry_rcu(ptr, &tomoyo_name_list[i],
309                                                 list) {
310                                 if (atomic_read(&ptr->users))
311                                         continue;
312                                 if (tomoyo_add_to_gc(TOMOYO_ID_NAME, ptr))
313                                         list_del_rcu(&ptr->list);
314                                 else {
315                                         i = TOMOYO_MAX_HASH;
316                                         break;
317                                 }
318                         }
319                 }
320         }
321         {
322                 struct tomoyo_path_group *group;
323                 list_for_each_entry_rcu(group, &tomoyo_path_group_list, list) {
324                         struct tomoyo_path_group_member *member;
325                         list_for_each_entry_rcu(member, &group->member_list,
326                                                 list) {
327                                 if (!member->is_deleted)
328                                         continue;
329                                 if (tomoyo_add_to_gc(TOMOYO_ID_PATH_GROUP_MEMBER,
330                                                      member))
331                                         list_del_rcu(&member->list);
332                                 else
333                                         break;
334                         }
335                         if (!list_empty(&group->member_list) ||
336                             atomic_read(&group->users))
337                                 continue;
338                         if (tomoyo_add_to_gc(TOMOYO_ID_PATH_GROUP, group))
339                                 list_del_rcu(&group->list);
340                         else
341                                 break;
342                 }
343         }
344         {
345                 struct tomoyo_number_group *group;
346                 list_for_each_entry_rcu(group, &tomoyo_number_group_list, list) {
347                         struct tomoyo_number_group_member *member;
348                         list_for_each_entry_rcu(member, &group->member_list,
349                                                 list) {
350                                 if (!member->is_deleted)
351                                         continue;
352                                 if (tomoyo_add_to_gc(TOMOYO_ID_NUMBER_GROUP_MEMBER,
353                                                      member))
354                                         list_del_rcu(&member->list);
355                                 else
356                                         break;
357                         }
358                         if (!list_empty(&group->member_list) ||
359                             atomic_read(&group->users))
360                                 continue;
361                         if (tomoyo_add_to_gc(TOMOYO_ID_NUMBER_GROUP, group))
362                                 list_del_rcu(&group->list);
363                         else
364                                 break;
365                 }
366         }
367         mutex_unlock(&tomoyo_policy_lock);
368 }
369
370 static void tomoyo_kfree_entry(void)
371 {
372         struct tomoyo_gc_entry *p;
373         struct tomoyo_gc_entry *tmp;
374
375         list_for_each_entry_safe(p, tmp, &tomoyo_gc_queue, list) {
376                 switch (p->type) {
377                 case TOMOYO_ID_DOMAIN_INITIALIZER:
378                         tomoyo_del_domain_initializer(p->element);
379                         break;
380                 case TOMOYO_ID_DOMAIN_KEEPER:
381                         tomoyo_del_domain_keeper(p->element);
382                         break;
383                 case TOMOYO_ID_ALIAS:
384                         tomoyo_del_alias(p->element);
385                         break;
386                 case TOMOYO_ID_GLOBALLY_READABLE:
387                         tomoyo_del_allow_read(p->element);
388                         break;
389                 case TOMOYO_ID_PATTERN:
390                         tomoyo_del_file_pattern(p->element);
391                         break;
392                 case TOMOYO_ID_NO_REWRITE:
393                         tomoyo_del_no_rewrite(p->element);
394                         break;
395                 case TOMOYO_ID_MANAGER:
396                         tomoyo_del_manager(p->element);
397                         break;
398                 case TOMOYO_ID_NAME:
399                         tomoyo_del_name(p->element);
400                         break;
401                 case TOMOYO_ID_ACL:
402                         tomoyo_del_acl(p->element);
403                         break;
404                 case TOMOYO_ID_DOMAIN:
405                         if (!tomoyo_del_domain(p->element))
406                                 continue;
407                         break;
408                 case TOMOYO_ID_PATH_GROUP_MEMBER:
409                         tomoyo_del_path_group_member(p->element);
410                         break;
411                 case TOMOYO_ID_PATH_GROUP:
412                         tomoyo_del_path_group(p->element);
413                         break;
414                 case TOMOYO_ID_NUMBER_GROUP_MEMBER:
415                         tomoyo_del_number_group_member(p->element);
416                         break;
417                 case TOMOYO_ID_NUMBER_GROUP:
418                         tomoyo_del_number_group(p->element);
419                         break;
420                 default:
421                         printk(KERN_WARNING "Unknown type\n");
422                         break;
423                 }
424                 tomoyo_memory_free(p->element);
425                 list_del(&p->list);
426                 kfree(p);
427         }
428 }
429
430 static int tomoyo_gc_thread(void *unused)
431 {
432         daemonize("GC for TOMOYO");
433         if (mutex_trylock(&tomoyo_gc_mutex)) {
434                 int i;
435                 for (i = 0; i < 10; i++) {
436                         tomoyo_collect_entry();
437                         if (list_empty(&tomoyo_gc_queue))
438                                 break;
439                         synchronize_srcu(&tomoyo_ss);
440                         tomoyo_kfree_entry();
441                 }
442                 mutex_unlock(&tomoyo_gc_mutex);
443         }
444         do_exit(0);
445 }
446
447 void tomoyo_run_gc(void)
448 {
449         struct task_struct *task = kthread_create(tomoyo_gc_thread, NULL,
450                                                   "GC for TOMOYO");
451         if (!IS_ERR(task))
452                 wake_up_process(task);
453 }