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