blob: 78100180d23d2ff4c7bbcbe4190a55a3c03c21c5 [file] [log] [blame]
Tetsuo Handa847b1732010-02-11 09:43:54 +09001/*
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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090012#include <linux/slab.h>
Tetsuo Handa847b1732010-02-11 09:43:54 +090013
14enum tomoyo_gc_id {
Tetsuo Handa7762fbf2010-05-10 17:30:26 +090015 TOMOYO_ID_PATH_GROUP,
16 TOMOYO_ID_PATH_GROUP_MEMBER,
Tetsuo Handa4c3e9e22010-05-17 10:06:58 +090017 TOMOYO_ID_NUMBER_GROUP,
18 TOMOYO_ID_NUMBER_GROUP_MEMBER,
Tetsuo Handa847b1732010-02-11 09:43:54 +090019 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) {
Tetsuo Handa7ef61232010-02-16 08:03:30 +090094 case TOMOYO_TYPE_PATH_ACL:
Tetsuo Handa847b1732010-02-11 09:43:54 +090095 {
Tetsuo Handa7ef61232010-02-16 08:03:30 +090096 struct tomoyo_path_acl *entry
Tetsuo Handa847b1732010-02-11 09:43:54 +090097 = container_of(acl, typeof(*entry), head);
Tetsuo Handa7762fbf2010-05-10 17:30:26 +090098 tomoyo_put_name_union(&entry->name);
Tetsuo Handa847b1732010-02-11 09:43:54 +090099 }
100 break;
Tetsuo Handa7ef61232010-02-16 08:03:30 +0900101 case TOMOYO_TYPE_PATH2_ACL:
Tetsuo Handa847b1732010-02-11 09:43:54 +0900102 {
Tetsuo Handa7ef61232010-02-16 08:03:30 +0900103 struct tomoyo_path2_acl *entry
Tetsuo Handa847b1732010-02-11 09:43:54 +0900104 = container_of(acl, typeof(*entry), head);
Tetsuo Handa7762fbf2010-05-10 17:30:26 +0900105 tomoyo_put_name_union(&entry->name1);
106 tomoyo_put_name_union(&entry->name2);
Tetsuo Handa847b1732010-02-11 09:43:54 +0900107 }
108 break;
Tetsuo Handaa1f9bb62010-05-17 10:09:15 +0900109 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;
Tetsuo Handa847b1732010-02-11 09:43:54 +0900127 default:
128 printk(KERN_WARNING "Unknown type\n");
129 break;
130 }
131}
132
133static 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
170static void tomoyo_del_name(const struct tomoyo_name_entry *ptr)
171{
172}
173
Tetsuo Handa7762fbf2010-05-10 17:30:26 +0900174static void tomoyo_del_path_group_member(struct tomoyo_path_group_member
175 *member)
176{
177 tomoyo_put_name(member->member_name);
178}
179
180static void tomoyo_del_path_group(struct tomoyo_path_group *group)
181{
182 tomoyo_put_name(group->group_name);
183}
184
Tetsuo Handa4c3e9e22010-05-17 10:06:58 +0900185static void tomoyo_del_number_group_member(struct tomoyo_number_group_member
186 *member)
187{
188}
189
190static void tomoyo_del_number_group(struct tomoyo_number_group *group)
191{
192 tomoyo_put_name(group->group_name);
193}
194
Tetsuo Handa847b1732010-02-11 09:43:54 +0900195static void tomoyo_collect_entry(void)
196{
Tetsuo Handa29282382010-05-06 00:18:15 +0900197 if (mutex_lock_interruptible(&tomoyo_policy_lock))
198 return;
Tetsuo Handa847b1732010-02-11 09:43:54 +0900199 {
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) {
Tetsuo Handa7ef61232010-02-16 08:03:30 +0900286 case TOMOYO_TYPE_PATH_ACL:
Tetsuo Handa847b1732010-02-11 09:43:54 +0900287 if (container_of(acl,
Tetsuo Handa7ef61232010-02-16 08:03:30 +0900288 struct tomoyo_path_acl,
Tetsuo Handaa1f9bb62010-05-17 10:09:15 +0900289 head)->perm)
Tetsuo Handa847b1732010-02-11 09:43:54 +0900290 continue;
291 break;
Tetsuo Handa7ef61232010-02-16 08:03:30 +0900292 case TOMOYO_TYPE_PATH2_ACL:
Tetsuo Handa847b1732010-02-11 09:43:54 +0900293 if (container_of(acl,
Tetsuo Handa7ef61232010-02-16 08:03:30 +0900294 struct tomoyo_path2_acl,
Tetsuo Handa847b1732010-02-11 09:43:54 +0900295 head)->perm)
296 continue;
297 break;
Tetsuo Handaa1f9bb62010-05-17 10:09:15 +0900298 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;
Tetsuo Handa847b1732010-02-11 09:43:54 +0900310 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 }
Tetsuo Handa847b1732010-02-11 09:43:54 +0900331 {
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 }
Tetsuo Handa7762fbf2010-05-10 17:30:26 +0900348 {
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 }
Tetsuo Handa4c3e9e22010-05-17 10:06:58 +0900371 {
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 }
Tetsuo Handa29282382010-05-06 00:18:15 +0900394 mutex_unlock(&tomoyo_policy_lock);
Tetsuo Handa847b1732010-02-11 09:43:54 +0900395}
396
397static 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;
Tetsuo Handa7762fbf2010-05-10 17:30:26 +0900435 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;
Tetsuo Handa4c3e9e22010-05-17 10:06:58 +0900441 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;
Tetsuo Handa847b1732010-02-11 09:43:54 +0900447 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
457static 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
474void 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}