blob: 6a48197f6ce5864cb66d696e28a08249b8efe04e [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;
109 default:
110 printk(KERN_WARNING "Unknown type\n");
111 break;
112 }
113}
114
115static 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
152static void tomoyo_del_name(const struct tomoyo_name_entry *ptr)
153{
154}
155
Tetsuo Handa7762fbf2010-05-10 17:30:26 +0900156static void tomoyo_del_path_group_member(struct tomoyo_path_group_member
157 *member)
158{
159 tomoyo_put_name(member->member_name);
160}
161
162static void tomoyo_del_path_group(struct tomoyo_path_group *group)
163{
164 tomoyo_put_name(group->group_name);
165}
166
Tetsuo Handa4c3e9e22010-05-17 10:06:58 +0900167static void tomoyo_del_number_group_member(struct tomoyo_number_group_member
168 *member)
169{
170}
171
172static void tomoyo_del_number_group(struct tomoyo_number_group *group)
173{
174 tomoyo_put_name(group->group_name);
175}
176
Tetsuo Handa847b1732010-02-11 09:43:54 +0900177static void tomoyo_collect_entry(void)
178{
Tetsuo Handa29282382010-05-06 00:18:15 +0900179 if (mutex_lock_interruptible(&tomoyo_policy_lock))
180 return;
Tetsuo Handa847b1732010-02-11 09:43:54 +0900181 {
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) {
Tetsuo Handa7ef61232010-02-16 08:03:30 +0900268 case TOMOYO_TYPE_PATH_ACL:
Tetsuo Handa847b1732010-02-11 09:43:54 +0900269 if (container_of(acl,
Tetsuo Handa7ef61232010-02-16 08:03:30 +0900270 struct tomoyo_path_acl,
Tetsuo Handa847b1732010-02-11 09:43:54 +0900271 head)->perm ||
272 container_of(acl,
Tetsuo Handa7ef61232010-02-16 08:03:30 +0900273 struct tomoyo_path_acl,
Tetsuo Handa847b1732010-02-11 09:43:54 +0900274 head)->perm_high)
275 continue;
276 break;
Tetsuo Handa7ef61232010-02-16 08:03:30 +0900277 case TOMOYO_TYPE_PATH2_ACL:
Tetsuo Handa847b1732010-02-11 09:43:54 +0900278 if (container_of(acl,
Tetsuo Handa7ef61232010-02-16 08:03:30 +0900279 struct tomoyo_path2_acl,
Tetsuo Handa847b1732010-02-11 09:43:54 +0900280 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 }
Tetsuo Handa847b1732010-02-11 09:43:54 +0900304 {
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 }
Tetsuo Handa7762fbf2010-05-10 17:30:26 +0900321 {
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 }
Tetsuo Handa4c3e9e22010-05-17 10:06:58 +0900344 {
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 }
Tetsuo Handa29282382010-05-06 00:18:15 +0900367 mutex_unlock(&tomoyo_policy_lock);
Tetsuo Handa847b1732010-02-11 09:43:54 +0900368}
369
370static 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;
Tetsuo Handa7762fbf2010-05-10 17:30:26 +0900408 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;
Tetsuo Handa4c3e9e22010-05-17 10:06:58 +0900414 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;
Tetsuo Handa847b1732010-02-11 09:43:54 +0900420 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
430static 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
447void 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}