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