gc.c revision a1f9bb6a375a8dbf7797ffbd6739c46b338a77f7
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
14enum tomoyo_gc_id {
15	TOMOYO_ID_PATH_GROUP,
16	TOMOYO_ID_PATH_GROUP_MEMBER,
17	TOMOYO_ID_NUMBER_GROUP,
18	TOMOYO_ID_NUMBER_GROUP_MEMBER,
19	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) {
94	case TOMOYO_TYPE_PATH_ACL:
95		{
96			struct tomoyo_path_acl *entry
97				= container_of(acl, typeof(*entry), head);
98			tomoyo_put_name_union(&entry->name);
99		}
100		break;
101	case TOMOYO_TYPE_PATH2_ACL:
102		{
103			struct tomoyo_path2_acl *entry
104				= container_of(acl, typeof(*entry), head);
105			tomoyo_put_name_union(&entry->name1);
106			tomoyo_put_name_union(&entry->name2);
107		}
108		break;
109	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;
127	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
174static 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
185static 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
195static void tomoyo_collect_entry(void)
196{
197	if (mutex_lock_interruptible(&tomoyo_policy_lock))
198		return;
199	{
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) {
286				case TOMOYO_TYPE_PATH_ACL:
287					if (container_of(acl,
288					 struct tomoyo_path_acl,
289							 head)->perm)
290						continue;
291					break;
292				case TOMOYO_TYPE_PATH2_ACL:
293					if (container_of(acl,
294					 struct tomoyo_path2_acl,
295							 head)->perm)
296						continue;
297					break;
298				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;
310				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	}
331	{
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	}
348	{
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	}
371	{
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	}
394	mutex_unlock(&tomoyo_policy_lock);
395}
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;
435		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;
441		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;
447		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}
481