TOMOYO: Split file access control functions by type of parameters.
[deliverable/linux.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 }
This page took 0.039796 seconds and 5 git commands to generate.