gc.c revision 32997144fd9925fc4d506a16990a0c405f766526
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	enum tomoyo_policy_id type;
17	struct list_head *element;
18};
19static LIST_HEAD(tomoyo_gc_queue);
20static DEFINE_MUTEX(tomoyo_gc_mutex);
21
22/**
23 * tomoyo_add_to_gc - Add an entry to to be deleted list.
24 *
25 * @type:    One of values in "enum tomoyo_policy_id".
26 * @element: Pointer to "struct list_head".
27 *
28 * Returns true on success, false otherwise.
29 *
30 * Caller holds tomoyo_policy_lock mutex.
31 *
32 * Adding an entry needs kmalloc(). Thus, if we try to add thousands of
33 * entries at once, it will take too long time. Thus, do not add more than 128
34 * entries per a scan. But to be able to handle worst case where all entries
35 * are in-use, we accept one more entry per a scan.
36 *
37 * If we use singly linked list using "struct list_head"->prev (which is
38 * LIST_POISON2), we can avoid kmalloc().
39 */
40static bool tomoyo_add_to_gc(const int type, struct list_head *element)
41{
42	struct tomoyo_gc *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	list_del_rcu(element);
49	return true;
50}
51
52/**
53 * tomoyo_del_transition_control - Delete members in "struct tomoyo_transition_control".
54 *
55 * @element: Pointer to "struct list_head".
56 *
57 * Returns nothing.
58 */
59static void tomoyo_del_transition_control(struct list_head *element)
60{
61	struct tomoyo_transition_control *ptr =
62		container_of(element, typeof(*ptr), head.list);
63	tomoyo_put_name(ptr->domainname);
64	tomoyo_put_name(ptr->program);
65}
66
67/**
68 * tomoyo_del_aggregator - Delete members in "struct tomoyo_aggregator".
69 *
70 * @element: Pointer to "struct list_head".
71 *
72 * Returns nothing.
73 */
74static void tomoyo_del_aggregator(struct list_head *element)
75{
76	struct tomoyo_aggregator *ptr =
77		container_of(element, typeof(*ptr), head.list);
78	tomoyo_put_name(ptr->original_name);
79	tomoyo_put_name(ptr->aggregated_name);
80}
81
82/**
83 * tomoyo_del_manager - Delete members in "struct tomoyo_manager".
84 *
85 * @element: Pointer to "struct list_head".
86 *
87 * Returns nothing.
88 */
89static void tomoyo_del_manager(struct list_head *element)
90{
91	struct tomoyo_manager *ptr =
92		container_of(element, typeof(*ptr), head.list);
93	tomoyo_put_name(ptr->manager);
94}
95
96/**
97 * tomoyo_del_acl - Delete members in "struct tomoyo_acl_info".
98 *
99 * @element: Pointer to "struct list_head".
100 *
101 * Returns nothing.
102 */
103static void tomoyo_del_acl(struct list_head *element)
104{
105	struct tomoyo_acl_info *acl =
106		container_of(element, typeof(*acl), list);
107	switch (acl->type) {
108	case TOMOYO_TYPE_PATH_ACL:
109		{
110			struct tomoyo_path_acl *entry
111				= container_of(acl, typeof(*entry), head);
112			tomoyo_put_name_union(&entry->name);
113		}
114		break;
115	case TOMOYO_TYPE_PATH2_ACL:
116		{
117			struct tomoyo_path2_acl *entry
118				= container_of(acl, typeof(*entry), head);
119			tomoyo_put_name_union(&entry->name1);
120			tomoyo_put_name_union(&entry->name2);
121		}
122		break;
123	case TOMOYO_TYPE_PATH_NUMBER_ACL:
124		{
125			struct tomoyo_path_number_acl *entry
126				= container_of(acl, typeof(*entry), head);
127			tomoyo_put_name_union(&entry->name);
128			tomoyo_put_number_union(&entry->number);
129		}
130		break;
131	case TOMOYO_TYPE_MKDEV_ACL:
132		{
133			struct tomoyo_mkdev_acl *entry
134				= container_of(acl, typeof(*entry), head);
135			tomoyo_put_name_union(&entry->name);
136			tomoyo_put_number_union(&entry->mode);
137			tomoyo_put_number_union(&entry->major);
138			tomoyo_put_number_union(&entry->minor);
139		}
140		break;
141	case TOMOYO_TYPE_MOUNT_ACL:
142		{
143			struct tomoyo_mount_acl *entry
144				= container_of(acl, typeof(*entry), head);
145			tomoyo_put_name_union(&entry->dev_name);
146			tomoyo_put_name_union(&entry->dir_name);
147			tomoyo_put_name_union(&entry->fs_type);
148			tomoyo_put_number_union(&entry->flags);
149		}
150		break;
151	}
152}
153
154static bool tomoyo_del_domain(struct list_head *element)
155{
156	struct tomoyo_domain_info *domain =
157		container_of(element, typeof(*domain), list);
158	struct tomoyo_acl_info *acl;
159	struct tomoyo_acl_info *tmp;
160	/*
161	 * Since we don't protect whole execve() operation using SRCU,
162	 * we need to recheck domain->users at this point.
163	 *
164	 * (1) Reader starts SRCU section upon execve().
165	 * (2) Reader traverses tomoyo_domain_list and finds this domain.
166	 * (3) Writer marks this domain as deleted.
167	 * (4) Garbage collector removes this domain from tomoyo_domain_list
168	 *     because this domain is marked as deleted and used by nobody.
169	 * (5) Reader saves reference to this domain into
170	 *     "struct linux_binprm"->cred->security .
171	 * (6) Reader finishes SRCU section, although execve() operation has
172	 *     not finished yet.
173	 * (7) Garbage collector waits for SRCU synchronization.
174	 * (8) Garbage collector kfree() this domain because this domain is
175	 *     used by nobody.
176	 * (9) Reader finishes execve() operation and restores this domain from
177	 *     "struct linux_binprm"->cred->security.
178	 *
179	 * By updating domain->users at (5), we can solve this race problem
180	 * by rechecking domain->users at (8).
181	 */
182	if (atomic_read(&domain->users))
183		return false;
184	list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) {
185		tomoyo_del_acl(&acl->list);
186		tomoyo_memory_free(acl);
187	}
188	tomoyo_put_name(domain->domainname);
189	return true;
190}
191
192
193/**
194 * tomoyo_del_name - Delete members in "struct tomoyo_name".
195 *
196 * @element: Pointer to "struct list_head".
197 *
198 * Returns nothing.
199 */
200static void tomoyo_del_name(struct list_head *element)
201{
202	const struct tomoyo_name *ptr =
203		container_of(element, typeof(*ptr), head.list);
204}
205
206/**
207 * tomoyo_del_path_group - Delete members in "struct tomoyo_path_group".
208 *
209 * @element: Pointer to "struct list_head".
210 *
211 * Returns nothing.
212 */
213static void tomoyo_del_path_group(struct list_head *element)
214{
215	struct tomoyo_path_group *member =
216		container_of(element, typeof(*member), head.list);
217	tomoyo_put_name(member->member_name);
218}
219
220/**
221 * tomoyo_del_group - Delete "struct tomoyo_group".
222 *
223 * @element: Pointer to "struct list_head".
224 *
225 * Returns nothing.
226 */
227static void tomoyo_del_group(struct list_head *element)
228{
229	struct tomoyo_group *group =
230		container_of(element, typeof(*group), head.list);
231	tomoyo_put_name(group->group_name);
232}
233
234/**
235 * tomoyo_del_number_group - Delete members in "struct tomoyo_number_group".
236 *
237 * @element: Pointer to "struct list_head".
238 *
239 * Returns nothing.
240 */
241static void tomoyo_del_number_group(struct list_head *element)
242{
243	struct tomoyo_number_group *member =
244		container_of(element, typeof(*member), head.list);
245}
246
247/**
248 * tomoyo_collect_member - Delete elements with "struct tomoyo_acl_head".
249 *
250 * @id:          One of values in "enum tomoyo_policy_id".
251 * @member_list: Pointer to "struct list_head".
252 *
253 * Returns true if some elements are deleted, false otherwise.
254 */
255static bool tomoyo_collect_member(const enum tomoyo_policy_id id,
256				  struct list_head *member_list)
257{
258	struct tomoyo_acl_head *member;
259	list_for_each_entry(member, member_list, list) {
260		if (!member->is_deleted)
261			continue;
262		if (!tomoyo_add_to_gc(id, &member->list))
263			return false;
264	}
265        return true;
266}
267
268/**
269 * tomoyo_collect_acl - Delete elements in "struct tomoyo_domain_info".
270 *
271 * @list: Pointer to "struct list_head".
272 *
273 * Returns true if some elements are deleted, false otherwise.
274 */
275static bool tomoyo_collect_acl(struct list_head *list)
276{
277	struct tomoyo_acl_info *acl;
278	list_for_each_entry(acl, list, list) {
279		if (!acl->is_deleted)
280			continue;
281		if (!tomoyo_add_to_gc(TOMOYO_ID_ACL, &acl->list))
282			return false;
283	}
284	return true;
285}
286
287/**
288 * tomoyo_collect_entry - Scan lists for deleted elements.
289 *
290 * Returns nothing.
291 */
292static void tomoyo_collect_entry(void)
293{
294	int i;
295	if (mutex_lock_interruptible(&tomoyo_policy_lock))
296		return;
297	for (i = 0; i < TOMOYO_MAX_POLICY; i++) {
298		if (!tomoyo_collect_member(i, &tomoyo_policy_list[i]))
299			goto unlock;
300	}
301	for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++)
302		if (!tomoyo_collect_acl(&tomoyo_acl_group[i]))
303			goto unlock;
304	{
305		struct tomoyo_domain_info *domain;
306		list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
307			if (!tomoyo_collect_acl(&domain->acl_info_list))
308				goto unlock;
309			if (!domain->is_deleted || atomic_read(&domain->users))
310				continue;
311			/*
312			 * Nobody is referring this domain. But somebody may
313			 * refer this domain after successful execve().
314			 * We recheck domain->users after SRCU synchronization.
315			 */
316			if (!tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, &domain->list))
317				goto unlock;
318		}
319	}
320	for (i = 0; i < TOMOYO_MAX_HASH; i++) {
321		struct tomoyo_name *ptr;
322		list_for_each_entry_rcu(ptr, &tomoyo_name_list[i], head.list) {
323			if (atomic_read(&ptr->head.users))
324				continue;
325			if (!tomoyo_add_to_gc(TOMOYO_ID_NAME, &ptr->head.list))
326				goto unlock;
327		}
328	}
329	for (i = 0; i < TOMOYO_MAX_GROUP; i++) {
330		struct list_head *list = &tomoyo_group_list[i];
331		int id;
332		struct tomoyo_group *group;
333		switch (i) {
334		case 0:
335			id = TOMOYO_ID_PATH_GROUP;
336			break;
337		default:
338			id = TOMOYO_ID_NUMBER_GROUP;
339			break;
340		}
341		list_for_each_entry(group, list, head.list) {
342			if (!tomoyo_collect_member(id, &group->member_list))
343				goto unlock;
344			if (!list_empty(&group->member_list) ||
345			    atomic_read(&group->head.users))
346				continue;
347			if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP,
348					      &group->head.list))
349				goto unlock;
350		}
351	}
352 unlock:
353	mutex_unlock(&tomoyo_policy_lock);
354}
355
356static void tomoyo_kfree_entry(void)
357{
358	struct tomoyo_gc *p;
359	struct tomoyo_gc *tmp;
360
361	list_for_each_entry_safe(p, tmp, &tomoyo_gc_queue, list) {
362		struct list_head *element = p->element;
363		switch (p->type) {
364		case TOMOYO_ID_TRANSITION_CONTROL:
365			tomoyo_del_transition_control(element);
366			break;
367		case TOMOYO_ID_AGGREGATOR:
368			tomoyo_del_aggregator(element);
369			break;
370		case TOMOYO_ID_MANAGER:
371			tomoyo_del_manager(element);
372			break;
373		case TOMOYO_ID_NAME:
374			tomoyo_del_name(element);
375			break;
376		case TOMOYO_ID_ACL:
377			tomoyo_del_acl(element);
378			break;
379		case TOMOYO_ID_DOMAIN:
380			if (!tomoyo_del_domain(element))
381				continue;
382			break;
383		case TOMOYO_ID_PATH_GROUP:
384			tomoyo_del_path_group(element);
385			break;
386		case TOMOYO_ID_GROUP:
387			tomoyo_del_group(element);
388			break;
389		case TOMOYO_ID_NUMBER_GROUP:
390			tomoyo_del_number_group(element);
391			break;
392		case TOMOYO_MAX_POLICY:
393			break;
394		}
395		tomoyo_memory_free(element);
396		list_del(&p->list);
397		kfree(p);
398	}
399}
400
401/**
402 * tomoyo_gc_thread - Garbage collector thread function.
403 *
404 * @unused: Unused.
405 *
406 * In case OOM-killer choose this thread for termination, we create this thread
407 * as a short live thread whenever /sys/kernel/security/tomoyo/ interface was
408 * close()d.
409 *
410 * Returns 0.
411 */
412static int tomoyo_gc_thread(void *unused)
413{
414	daemonize("GC for TOMOYO");
415	if (mutex_trylock(&tomoyo_gc_mutex)) {
416		int i;
417		for (i = 0; i < 10; i++) {
418			tomoyo_collect_entry();
419			if (list_empty(&tomoyo_gc_queue))
420				break;
421			synchronize_srcu(&tomoyo_ss);
422			tomoyo_kfree_entry();
423		}
424		mutex_unlock(&tomoyo_gc_mutex);
425	}
426	do_exit(0);
427}
428
429void tomoyo_run_gc(void)
430{
431	struct task_struct *task = kthread_create(tomoyo_gc_thread, NULL,
432						  "GC for TOMOYO");
433	if (!IS_ERR(task))
434		wake_up_process(task);
435}
436