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