gc.c revision 2106ccd972dcd9fda7df9b181505fac1741b3508
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	case TOMOYO_TYPE_MOUNT_ACL:
128		{
129			struct tomoyo_mount_acl *entry
130				= container_of(acl, typeof(*entry), head);
131			tomoyo_put_name_union(&entry->dev_name);
132			tomoyo_put_name_union(&entry->dir_name);
133			tomoyo_put_name_union(&entry->fs_type);
134			tomoyo_put_number_union(&entry->flags);
135		}
136		break;
137	default:
138		printk(KERN_WARNING "Unknown type\n");
139		break;
140	}
141}
142
143static bool tomoyo_del_domain(struct tomoyo_domain_info *domain)
144{
145	struct tomoyo_acl_info *acl;
146	struct tomoyo_acl_info *tmp;
147	/*
148	 * Since we don't protect whole execve() operation using SRCU,
149	 * we need to recheck domain->users at this point.
150	 *
151	 * (1) Reader starts SRCU section upon execve().
152	 * (2) Reader traverses tomoyo_domain_list and finds this domain.
153	 * (3) Writer marks this domain as deleted.
154	 * (4) Garbage collector removes this domain from tomoyo_domain_list
155	 *     because this domain is marked as deleted and used by nobody.
156	 * (5) Reader saves reference to this domain into
157	 *     "struct linux_binprm"->cred->security .
158	 * (6) Reader finishes SRCU section, although execve() operation has
159	 *     not finished yet.
160	 * (7) Garbage collector waits for SRCU synchronization.
161	 * (8) Garbage collector kfree() this domain because this domain is
162	 *     used by nobody.
163	 * (9) Reader finishes execve() operation and restores this domain from
164	 *     "struct linux_binprm"->cred->security.
165	 *
166	 * By updating domain->users at (5), we can solve this race problem
167	 * by rechecking domain->users at (8).
168	 */
169	if (atomic_read(&domain->users))
170		return false;
171	list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) {
172		tomoyo_del_acl(acl);
173		tomoyo_memory_free(acl);
174	}
175	tomoyo_put_name(domain->domainname);
176	return true;
177}
178
179
180static void tomoyo_del_name(const struct tomoyo_name_entry *ptr)
181{
182}
183
184static void tomoyo_del_path_group_member(struct tomoyo_path_group_member
185					 *member)
186{
187	tomoyo_put_name(member->member_name);
188}
189
190static void tomoyo_del_path_group(struct tomoyo_path_group *group)
191{
192	tomoyo_put_name(group->group_name);
193}
194
195static void tomoyo_del_number_group_member(struct tomoyo_number_group_member
196					   *member)
197{
198}
199
200static void tomoyo_del_number_group(struct tomoyo_number_group *group)
201{
202	tomoyo_put_name(group->group_name);
203}
204
205static void tomoyo_collect_entry(void)
206{
207	if (mutex_lock_interruptible(&tomoyo_policy_lock))
208		return;
209	{
210		struct tomoyo_globally_readable_file_entry *ptr;
211		list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list,
212					list) {
213			if (!ptr->is_deleted)
214				continue;
215			if (tomoyo_add_to_gc(TOMOYO_ID_GLOBALLY_READABLE, ptr))
216				list_del_rcu(&ptr->list);
217			else
218				break;
219		}
220	}
221	{
222		struct tomoyo_pattern_entry *ptr;
223		list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
224			if (!ptr->is_deleted)
225				continue;
226			if (tomoyo_add_to_gc(TOMOYO_ID_PATTERN, ptr))
227				list_del_rcu(&ptr->list);
228			else
229				break;
230		}
231	}
232	{
233		struct tomoyo_no_rewrite_entry *ptr;
234		list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
235			if (!ptr->is_deleted)
236				continue;
237			if (tomoyo_add_to_gc(TOMOYO_ID_NO_REWRITE, ptr))
238				list_del_rcu(&ptr->list);
239			else
240				break;
241		}
242	}
243	{
244		struct tomoyo_domain_initializer_entry *ptr;
245		list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list,
246					list) {
247			if (!ptr->is_deleted)
248				continue;
249			if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_INITIALIZER, ptr))
250				list_del_rcu(&ptr->list);
251			else
252				break;
253		}
254	}
255	{
256		struct tomoyo_domain_keeper_entry *ptr;
257		list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
258			if (!ptr->is_deleted)
259				continue;
260			if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_KEEPER, ptr))
261				list_del_rcu(&ptr->list);
262			else
263				break;
264		}
265	}
266	{
267		struct tomoyo_alias_entry *ptr;
268		list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
269			if (!ptr->is_deleted)
270				continue;
271			if (tomoyo_add_to_gc(TOMOYO_ID_ALIAS, ptr))
272				list_del_rcu(&ptr->list);
273			else
274				break;
275		}
276	}
277	{
278		struct tomoyo_policy_manager_entry *ptr;
279		list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list,
280					list) {
281			if (!ptr->is_deleted)
282				continue;
283			if (tomoyo_add_to_gc(TOMOYO_ID_MANAGER, ptr))
284				list_del_rcu(&ptr->list);
285			else
286				break;
287		}
288	}
289	{
290		struct tomoyo_domain_info *domain;
291		list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
292			struct tomoyo_acl_info *acl;
293			list_for_each_entry_rcu(acl, &domain->acl_info_list,
294						list) {
295				switch (acl->type) {
296				case TOMOYO_TYPE_PATH_ACL:
297					if (container_of(acl,
298					 struct tomoyo_path_acl,
299							 head)->perm)
300						continue;
301					break;
302				case TOMOYO_TYPE_PATH2_ACL:
303					if (container_of(acl,
304					 struct tomoyo_path2_acl,
305							 head)->perm)
306						continue;
307					break;
308				case TOMOYO_TYPE_PATH_NUMBER_ACL:
309					if (container_of(acl,
310					 struct tomoyo_path_number_acl,
311							 head)->perm)
312						continue;
313					break;
314				case TOMOYO_TYPE_PATH_NUMBER3_ACL:
315					if (container_of(acl,
316					 struct tomoyo_path_number3_acl,
317							 head)->perm)
318						continue;
319					break;
320				default:
321					continue;
322				}
323				if (tomoyo_add_to_gc(TOMOYO_ID_ACL, acl))
324					list_del_rcu(&acl->list);
325				else
326					break;
327			}
328			if (!domain->is_deleted || atomic_read(&domain->users))
329				continue;
330			/*
331			 * Nobody is referring this domain. But somebody may
332			 * refer this domain after successful execve().
333			 * We recheck domain->users after SRCU synchronization.
334			 */
335			if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, domain))
336				list_del_rcu(&domain->list);
337			else
338				break;
339		}
340	}
341	{
342		int i;
343		for (i = 0; i < TOMOYO_MAX_HASH; i++) {
344			struct tomoyo_name_entry *ptr;
345			list_for_each_entry_rcu(ptr, &tomoyo_name_list[i],
346						list) {
347				if (atomic_read(&ptr->users))
348					continue;
349				if (tomoyo_add_to_gc(TOMOYO_ID_NAME, ptr))
350					list_del_rcu(&ptr->list);
351				else {
352					i = TOMOYO_MAX_HASH;
353					break;
354				}
355			}
356		}
357	}
358	{
359		struct tomoyo_path_group *group;
360		list_for_each_entry_rcu(group, &tomoyo_path_group_list, list) {
361			struct tomoyo_path_group_member *member;
362			list_for_each_entry_rcu(member, &group->member_list,
363						list) {
364				if (!member->is_deleted)
365					continue;
366				if (tomoyo_add_to_gc(TOMOYO_ID_PATH_GROUP_MEMBER,
367						     member))
368					list_del_rcu(&member->list);
369				else
370					break;
371			}
372			if (!list_empty(&group->member_list) ||
373			    atomic_read(&group->users))
374				continue;
375			if (tomoyo_add_to_gc(TOMOYO_ID_PATH_GROUP, group))
376				list_del_rcu(&group->list);
377			else
378				break;
379		}
380	}
381	{
382		struct tomoyo_number_group *group;
383		list_for_each_entry_rcu(group, &tomoyo_number_group_list, list) {
384			struct tomoyo_number_group_member *member;
385			list_for_each_entry_rcu(member, &group->member_list,
386						list) {
387				if (!member->is_deleted)
388					continue;
389				if (tomoyo_add_to_gc(TOMOYO_ID_NUMBER_GROUP_MEMBER,
390						     member))
391					list_del_rcu(&member->list);
392				else
393					break;
394			}
395			if (!list_empty(&group->member_list) ||
396			    atomic_read(&group->users))
397				continue;
398			if (tomoyo_add_to_gc(TOMOYO_ID_NUMBER_GROUP, group))
399				list_del_rcu(&group->list);
400			else
401				break;
402		}
403	}
404	mutex_unlock(&tomoyo_policy_lock);
405}
406
407static void tomoyo_kfree_entry(void)
408{
409	struct tomoyo_gc_entry *p;
410	struct tomoyo_gc_entry *tmp;
411
412	list_for_each_entry_safe(p, tmp, &tomoyo_gc_queue, list) {
413		switch (p->type) {
414		case TOMOYO_ID_DOMAIN_INITIALIZER:
415			tomoyo_del_domain_initializer(p->element);
416			break;
417		case TOMOYO_ID_DOMAIN_KEEPER:
418			tomoyo_del_domain_keeper(p->element);
419			break;
420		case TOMOYO_ID_ALIAS:
421			tomoyo_del_alias(p->element);
422			break;
423		case TOMOYO_ID_GLOBALLY_READABLE:
424			tomoyo_del_allow_read(p->element);
425			break;
426		case TOMOYO_ID_PATTERN:
427			tomoyo_del_file_pattern(p->element);
428			break;
429		case TOMOYO_ID_NO_REWRITE:
430			tomoyo_del_no_rewrite(p->element);
431			break;
432		case TOMOYO_ID_MANAGER:
433			tomoyo_del_manager(p->element);
434			break;
435		case TOMOYO_ID_NAME:
436			tomoyo_del_name(p->element);
437			break;
438		case TOMOYO_ID_ACL:
439			tomoyo_del_acl(p->element);
440			break;
441		case TOMOYO_ID_DOMAIN:
442			if (!tomoyo_del_domain(p->element))
443				continue;
444			break;
445		case TOMOYO_ID_PATH_GROUP_MEMBER:
446			tomoyo_del_path_group_member(p->element);
447			break;
448		case TOMOYO_ID_PATH_GROUP:
449			tomoyo_del_path_group(p->element);
450			break;
451		case TOMOYO_ID_NUMBER_GROUP_MEMBER:
452			tomoyo_del_number_group_member(p->element);
453			break;
454		case TOMOYO_ID_NUMBER_GROUP:
455			tomoyo_del_number_group(p->element);
456			break;
457		default:
458			printk(KERN_WARNING "Unknown type\n");
459			break;
460		}
461		tomoyo_memory_free(p->element);
462		list_del(&p->list);
463		kfree(p);
464	}
465}
466
467static int tomoyo_gc_thread(void *unused)
468{
469	daemonize("GC for TOMOYO");
470	if (mutex_trylock(&tomoyo_gc_mutex)) {
471		int i;
472		for (i = 0; i < 10; i++) {
473			tomoyo_collect_entry();
474			if (list_empty(&tomoyo_gc_queue))
475				break;
476			synchronize_srcu(&tomoyo_ss);
477			tomoyo_kfree_entry();
478		}
479		mutex_unlock(&tomoyo_gc_mutex);
480	}
481	do_exit(0);
482}
483
484void tomoyo_run_gc(void)
485{
486	struct task_struct *task = kthread_create(tomoyo_gc_thread, NULL,
487						  "GC for TOMOYO");
488	if (!IS_ERR(task))
489		wake_up_process(task);
490}
491