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