selinux: remove all rcu head initializations
[deliverable/linux.git] / security / tomoyo / gc.c
CommitLineData
847b173e
TH
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>
5a0e3ad6 12#include <linux/slab.h>
847b173e
TH
13
14enum tomoyo_gc_id {
7762fbff
TH
15 TOMOYO_ID_PATH_GROUP,
16 TOMOYO_ID_PATH_GROUP_MEMBER,
847b173e
TH
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
29struct tomoyo_gc_entry {
30 struct list_head list;
31 int type;
32 void *element;
33};
34static LIST_HEAD(tomoyo_gc_queue);
35static DEFINE_MUTEX(tomoyo_gc_mutex);
36
37/* Caller holds tomoyo_policy_lock mutex. */
38static 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
49static void tomoyo_del_allow_read
50(struct tomoyo_globally_readable_file_entry *ptr)
51{
52 tomoyo_put_name(ptr->filename);
53}
54
55static void tomoyo_del_file_pattern(struct tomoyo_pattern_entry *ptr)
56{
57 tomoyo_put_name(ptr->pattern);
58}
59
60static void tomoyo_del_no_rewrite(struct tomoyo_no_rewrite_entry *ptr)
61{
62 tomoyo_put_name(ptr->pattern);
63}
64
65static 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
72static 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
78static 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
84static void tomoyo_del_manager(struct tomoyo_policy_manager_entry *ptr)
85{
86 tomoyo_put_name(ptr->manager);
87}
88
89static void tomoyo_del_acl(struct tomoyo_acl_info *acl)
90{
91 switch (acl->type) {
7ef61233 92 case TOMOYO_TYPE_PATH_ACL:
847b173e 93 {
7ef61233 94 struct tomoyo_path_acl *entry
847b173e 95 = container_of(acl, typeof(*entry), head);
7762fbff 96 tomoyo_put_name_union(&entry->name);
847b173e
TH
97 }
98 break;
7ef61233 99 case TOMOYO_TYPE_PATH2_ACL:
847b173e 100 {
7ef61233 101 struct tomoyo_path2_acl *entry
847b173e 102 = container_of(acl, typeof(*entry), head);
7762fbff
TH
103 tomoyo_put_name_union(&entry->name1);
104 tomoyo_put_name_union(&entry->name2);
847b173e
TH
105 }
106 break;
107 default:
108 printk(KERN_WARNING "Unknown type\n");
109 break;
110 }
111}
112
113static 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
150static void tomoyo_del_name(const struct tomoyo_name_entry *ptr)
151{
152}
153
7762fbff
TH
154static void tomoyo_del_path_group_member(struct tomoyo_path_group_member
155 *member)
156{
157 tomoyo_put_name(member->member_name);
158}
159
160static void tomoyo_del_path_group(struct tomoyo_path_group *group)
161{
162 tomoyo_put_name(group->group_name);
163}
164
847b173e
TH
165static void tomoyo_collect_entry(void)
166{
29282381
TH
167 if (mutex_lock_interruptible(&tomoyo_policy_lock))
168 return;
847b173e
TH
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) {
7ef61233 256 case TOMOYO_TYPE_PATH_ACL:
847b173e 257 if (container_of(acl,
7ef61233 258 struct tomoyo_path_acl,
847b173e
TH
259 head)->perm ||
260 container_of(acl,
7ef61233 261 struct tomoyo_path_acl,
847b173e
TH
262 head)->perm_high)
263 continue;
264 break;
7ef61233 265 case TOMOYO_TYPE_PATH2_ACL:
847b173e 266 if (container_of(acl,
7ef61233 267 struct tomoyo_path2_acl,
847b173e
TH
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 }
847b173e
TH
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 }
7762fbff
TH
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 }
29282381 332 mutex_unlock(&tomoyo_policy_lock);
847b173e
TH
333}
334
335static 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;
7762fbff
TH
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;
847b173e
TH
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
389static 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
406void 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}
This page took 0.063189 seconds and 5 git commands to generate.