gc.c revision 7c75964f432d14062d8eccfc916aa290f56b5aab
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
14struct tomoyo_gc {
15	struct list_head list;
16	int type;
17	struct list_head *element;
18};
19static LIST_HEAD(tomoyo_gc_queue);
20static DEFINE_MUTEX(tomoyo_gc_mutex);
21
22/* Caller holds tomoyo_policy_lock mutex. */
23static bool tomoyo_add_to_gc(const int type, struct list_head *element)
24{
25	struct tomoyo_gc *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
26	if (!entry)
27		return false;
28	entry->type = type;
29	entry->element = element;
30	list_add(&entry->list, &tomoyo_gc_queue);
31	list_del_rcu(element);
32	return true;
33}
34
35static void tomoyo_del_transition_control(struct list_head *element)
36{
37	struct tomoyo_transition_control *ptr =
38		container_of(element, typeof(*ptr), head.list);
39	tomoyo_put_name(ptr->domainname);
40	tomoyo_put_name(ptr->program);
41}
42
43static void tomoyo_del_aggregator(struct list_head *element)
44{
45	struct tomoyo_aggregator *ptr =
46		container_of(element, typeof(*ptr), head.list);
47	tomoyo_put_name(ptr->original_name);
48	tomoyo_put_name(ptr->aggregated_name);
49}
50
51static void tomoyo_del_manager(struct list_head *element)
52{
53	struct tomoyo_manager *ptr =
54		container_of(element, typeof(*ptr), head.list);
55	tomoyo_put_name(ptr->manager);
56}
57
58static void tomoyo_del_acl(struct list_head *element)
59{
60	struct tomoyo_acl_info *acl =
61		container_of(element, typeof(*acl), list);
62	switch (acl->type) {
63	case TOMOYO_TYPE_PATH_ACL:
64		{
65			struct tomoyo_path_acl *entry
66				= container_of(acl, typeof(*entry), head);
67			tomoyo_put_name_union(&entry->name);
68		}
69		break;
70	case TOMOYO_TYPE_PATH2_ACL:
71		{
72			struct tomoyo_path2_acl *entry
73				= container_of(acl, typeof(*entry), head);
74			tomoyo_put_name_union(&entry->name1);
75			tomoyo_put_name_union(&entry->name2);
76		}
77		break;
78	case TOMOYO_TYPE_PATH_NUMBER_ACL:
79		{
80			struct tomoyo_path_number_acl *entry
81				= container_of(acl, typeof(*entry), head);
82			tomoyo_put_name_union(&entry->name);
83			tomoyo_put_number_union(&entry->number);
84		}
85		break;
86	case TOMOYO_TYPE_MKDEV_ACL:
87		{
88			struct tomoyo_mkdev_acl *entry
89				= container_of(acl, typeof(*entry), head);
90			tomoyo_put_name_union(&entry->name);
91			tomoyo_put_number_union(&entry->mode);
92			tomoyo_put_number_union(&entry->major);
93			tomoyo_put_number_union(&entry->minor);
94		}
95		break;
96	case TOMOYO_TYPE_MOUNT_ACL:
97		{
98			struct tomoyo_mount_acl *entry
99				= container_of(acl, typeof(*entry), head);
100			tomoyo_put_name_union(&entry->dev_name);
101			tomoyo_put_name_union(&entry->dir_name);
102			tomoyo_put_name_union(&entry->fs_type);
103			tomoyo_put_number_union(&entry->flags);
104		}
105		break;
106	}
107}
108
109static bool tomoyo_del_domain(struct list_head *element)
110{
111	struct tomoyo_domain_info *domain =
112		container_of(element, typeof(*domain), list);
113	struct tomoyo_acl_info *acl;
114	struct tomoyo_acl_info *tmp;
115	/*
116	 * Since we don't protect whole execve() operation using SRCU,
117	 * we need to recheck domain->users at this point.
118	 *
119	 * (1) Reader starts SRCU section upon execve().
120	 * (2) Reader traverses tomoyo_domain_list and finds this domain.
121	 * (3) Writer marks this domain as deleted.
122	 * (4) Garbage collector removes this domain from tomoyo_domain_list
123	 *     because this domain is marked as deleted and used by nobody.
124	 * (5) Reader saves reference to this domain into
125	 *     "struct linux_binprm"->cred->security .
126	 * (6) Reader finishes SRCU section, although execve() operation has
127	 *     not finished yet.
128	 * (7) Garbage collector waits for SRCU synchronization.
129	 * (8) Garbage collector kfree() this domain because this domain is
130	 *     used by nobody.
131	 * (9) Reader finishes execve() operation and restores this domain from
132	 *     "struct linux_binprm"->cred->security.
133	 *
134	 * By updating domain->users at (5), we can solve this race problem
135	 * by rechecking domain->users at (8).
136	 */
137	if (atomic_read(&domain->users))
138		return false;
139	list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) {
140		tomoyo_del_acl(&acl->list);
141		tomoyo_memory_free(acl);
142	}
143	tomoyo_put_name(domain->domainname);
144	return true;
145}
146
147
148static void tomoyo_del_name(struct list_head *element)
149{
150	const struct tomoyo_name *ptr =
151		container_of(element, typeof(*ptr), list);
152}
153
154static void tomoyo_del_path_group(struct list_head *element)
155{
156	struct tomoyo_path_group *member =
157		container_of(element, typeof(*member), head.list);
158	tomoyo_put_name(member->member_name);
159}
160
161static void tomoyo_del_group(struct list_head *element)
162{
163	struct tomoyo_group *group =
164		container_of(element, typeof(*group), list);
165	tomoyo_put_name(group->group_name);
166}
167
168static void tomoyo_del_number_group(struct list_head *element)
169{
170	struct tomoyo_number_group *member =
171		container_of(element, typeof(*member), head.list);
172}
173
174static bool tomoyo_collect_member(struct list_head *member_list, int id)
175{
176	struct tomoyo_acl_head *member;
177	list_for_each_entry(member, member_list, list) {
178		if (!member->is_deleted)
179			continue;
180		if (!tomoyo_add_to_gc(id, &member->list))
181			return false;
182	}
183        return true;
184}
185
186static bool tomoyo_collect_acl(struct tomoyo_domain_info *domain)
187{
188	struct tomoyo_acl_info *acl;
189	list_for_each_entry(acl, &domain->acl_info_list, list) {
190		if (!acl->is_deleted)
191			continue;
192		if (!tomoyo_add_to_gc(TOMOYO_ID_ACL, &acl->list))
193			return false;
194	}
195	return true;
196}
197
198static void tomoyo_collect_entry(void)
199{
200	int i;
201	if (mutex_lock_interruptible(&tomoyo_policy_lock))
202		return;
203	for (i = 0; i < TOMOYO_MAX_POLICY; i++) {
204		if (!tomoyo_collect_member(&tomoyo_policy_list[i], i))
205			goto unlock;
206	}
207	{
208		struct tomoyo_domain_info *domain;
209		list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
210			if (!tomoyo_collect_acl(domain))
211				goto unlock;
212			if (!domain->is_deleted || atomic_read(&domain->users))
213				continue;
214			/*
215			 * Nobody is referring this domain. But somebody may
216			 * refer this domain after successful execve().
217			 * We recheck domain->users after SRCU synchronization.
218			 */
219			if (!tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, &domain->list))
220				goto unlock;
221		}
222	}
223	for (i = 0; i < TOMOYO_MAX_HASH; i++) {
224		struct tomoyo_name *ptr;
225		list_for_each_entry_rcu(ptr, &tomoyo_name_list[i], list) {
226			if (atomic_read(&ptr->users))
227				continue;
228			if (!tomoyo_add_to_gc(TOMOYO_ID_NAME, &ptr->list))
229				goto unlock;
230		}
231	}
232	for (i = 0; i < TOMOYO_MAX_GROUP; i++) {
233		struct list_head *list = &tomoyo_group_list[i];
234		int id;
235		struct tomoyo_group *group;
236		switch (i) {
237		case 0:
238			id = TOMOYO_ID_PATH_GROUP;
239			break;
240		default:
241			id = TOMOYO_ID_NUMBER_GROUP;
242			break;
243		}
244		list_for_each_entry(group, list, list) {
245			if (!tomoyo_collect_member(&group->member_list, id))
246				goto unlock;
247			if (!list_empty(&group->member_list) ||
248			    atomic_read(&group->users))
249				continue;
250			if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP, &group->list))
251				goto unlock;
252		}
253	}
254 unlock:
255	mutex_unlock(&tomoyo_policy_lock);
256}
257
258static void tomoyo_kfree_entry(void)
259{
260	struct tomoyo_gc *p;
261	struct tomoyo_gc *tmp;
262
263	list_for_each_entry_safe(p, tmp, &tomoyo_gc_queue, list) {
264		struct list_head *element = p->element;
265		switch (p->type) {
266		case TOMOYO_ID_TRANSITION_CONTROL:
267			tomoyo_del_transition_control(element);
268			break;
269		case TOMOYO_ID_AGGREGATOR:
270			tomoyo_del_aggregator(element);
271			break;
272		case TOMOYO_ID_MANAGER:
273			tomoyo_del_manager(element);
274			break;
275		case TOMOYO_ID_NAME:
276			tomoyo_del_name(element);
277			break;
278		case TOMOYO_ID_ACL:
279			tomoyo_del_acl(element);
280			break;
281		case TOMOYO_ID_DOMAIN:
282			if (!tomoyo_del_domain(element))
283				continue;
284			break;
285		case TOMOYO_ID_PATH_GROUP:
286			tomoyo_del_path_group(element);
287			break;
288		case TOMOYO_ID_GROUP:
289			tomoyo_del_group(element);
290			break;
291		case TOMOYO_ID_NUMBER_GROUP:
292			tomoyo_del_number_group(element);
293			break;
294		}
295		tomoyo_memory_free(element);
296		list_del(&p->list);
297		kfree(p);
298	}
299}
300
301static int tomoyo_gc_thread(void *unused)
302{
303	daemonize("GC for TOMOYO");
304	if (mutex_trylock(&tomoyo_gc_mutex)) {
305		int i;
306		for (i = 0; i < 10; i++) {
307			tomoyo_collect_entry();
308			if (list_empty(&tomoyo_gc_queue))
309				break;
310			synchronize_srcu(&tomoyo_ss);
311			tomoyo_kfree_entry();
312		}
313		mutex_unlock(&tomoyo_gc_mutex);
314	}
315	do_exit(0);
316}
317
318void tomoyo_run_gc(void)
319{
320	struct task_struct *task = kthread_create(tomoyo_gc_thread, NULL,
321						  "GC for TOMOYO");
322	if (!IS_ERR(task))
323		wake_up_process(task);
324}
325