Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/security/tomoyo/gc.c
10814 views
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
struct tomoyo_gc {
15
struct list_head list;
16
int type;
17
struct list_head *element;
18
};
19
static LIST_HEAD(tomoyo_gc_queue);
20
static DEFINE_MUTEX(tomoyo_gc_mutex);
21
22
/* Caller holds tomoyo_policy_lock mutex. */
23
static bool tomoyo_add_to_gc(const int type, struct list_head *element)
24
{
25
struct tomoyo_gc *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
26
if (!entry)
27
return false;
28
entry->type = type;
29
entry->element = element;
30
list_add(&entry->list, &tomoyo_gc_queue);
31
list_del_rcu(element);
32
return true;
33
}
34
35
static void tomoyo_del_allow_read(struct list_head *element)
36
{
37
struct tomoyo_readable_file *ptr =
38
container_of(element, typeof(*ptr), head.list);
39
tomoyo_put_name(ptr->filename);
40
}
41
42
static void tomoyo_del_file_pattern(struct list_head *element)
43
{
44
struct tomoyo_no_pattern *ptr =
45
container_of(element, typeof(*ptr), head.list);
46
tomoyo_put_name(ptr->pattern);
47
}
48
49
static void tomoyo_del_no_rewrite(struct list_head *element)
50
{
51
struct tomoyo_no_rewrite *ptr =
52
container_of(element, typeof(*ptr), head.list);
53
tomoyo_put_name(ptr->pattern);
54
}
55
56
static void tomoyo_del_transition_control(struct list_head *element)
57
{
58
struct tomoyo_transition_control *ptr =
59
container_of(element, typeof(*ptr), head.list);
60
tomoyo_put_name(ptr->domainname);
61
tomoyo_put_name(ptr->program);
62
}
63
64
static void tomoyo_del_aggregator(struct list_head *element)
65
{
66
struct tomoyo_aggregator *ptr =
67
container_of(element, typeof(*ptr), head.list);
68
tomoyo_put_name(ptr->original_name);
69
tomoyo_put_name(ptr->aggregated_name);
70
}
71
72
static void tomoyo_del_manager(struct list_head *element)
73
{
74
struct tomoyo_manager *ptr =
75
container_of(element, typeof(*ptr), head.list);
76
tomoyo_put_name(ptr->manager);
77
}
78
79
static void tomoyo_del_acl(struct list_head *element)
80
{
81
struct tomoyo_acl_info *acl =
82
container_of(element, typeof(*acl), list);
83
switch (acl->type) {
84
case TOMOYO_TYPE_PATH_ACL:
85
{
86
struct tomoyo_path_acl *entry
87
= container_of(acl, typeof(*entry), head);
88
tomoyo_put_name_union(&entry->name);
89
}
90
break;
91
case TOMOYO_TYPE_PATH2_ACL:
92
{
93
struct tomoyo_path2_acl *entry
94
= container_of(acl, typeof(*entry), head);
95
tomoyo_put_name_union(&entry->name1);
96
tomoyo_put_name_union(&entry->name2);
97
}
98
break;
99
case TOMOYO_TYPE_PATH_NUMBER_ACL:
100
{
101
struct tomoyo_path_number_acl *entry
102
= container_of(acl, typeof(*entry), head);
103
tomoyo_put_name_union(&entry->name);
104
tomoyo_put_number_union(&entry->number);
105
}
106
break;
107
case TOMOYO_TYPE_MKDEV_ACL:
108
{
109
struct tomoyo_mkdev_acl *entry
110
= container_of(acl, typeof(*entry), head);
111
tomoyo_put_name_union(&entry->name);
112
tomoyo_put_number_union(&entry->mode);
113
tomoyo_put_number_union(&entry->major);
114
tomoyo_put_number_union(&entry->minor);
115
}
116
break;
117
case TOMOYO_TYPE_MOUNT_ACL:
118
{
119
struct tomoyo_mount_acl *entry
120
= container_of(acl, typeof(*entry), head);
121
tomoyo_put_name_union(&entry->dev_name);
122
tomoyo_put_name_union(&entry->dir_name);
123
tomoyo_put_name_union(&entry->fs_type);
124
tomoyo_put_number_union(&entry->flags);
125
}
126
break;
127
}
128
}
129
130
static bool tomoyo_del_domain(struct list_head *element)
131
{
132
struct tomoyo_domain_info *domain =
133
container_of(element, typeof(*domain), list);
134
struct tomoyo_acl_info *acl;
135
struct tomoyo_acl_info *tmp;
136
/*
137
* Since we don't protect whole execve() operation using SRCU,
138
* we need to recheck domain->users at this point.
139
*
140
* (1) Reader starts SRCU section upon execve().
141
* (2) Reader traverses tomoyo_domain_list and finds this domain.
142
* (3) Writer marks this domain as deleted.
143
* (4) Garbage collector removes this domain from tomoyo_domain_list
144
* because this domain is marked as deleted and used by nobody.
145
* (5) Reader saves reference to this domain into
146
* "struct linux_binprm"->cred->security .
147
* (6) Reader finishes SRCU section, although execve() operation has
148
* not finished yet.
149
* (7) Garbage collector waits for SRCU synchronization.
150
* (8) Garbage collector kfree() this domain because this domain is
151
* used by nobody.
152
* (9) Reader finishes execve() operation and restores this domain from
153
* "struct linux_binprm"->cred->security.
154
*
155
* By updating domain->users at (5), we can solve this race problem
156
* by rechecking domain->users at (8).
157
*/
158
if (atomic_read(&domain->users))
159
return false;
160
list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) {
161
tomoyo_del_acl(&acl->list);
162
tomoyo_memory_free(acl);
163
}
164
tomoyo_put_name(domain->domainname);
165
return true;
166
}
167
168
169
static void tomoyo_del_name(struct list_head *element)
170
{
171
const struct tomoyo_name *ptr =
172
container_of(element, typeof(*ptr), list);
173
}
174
175
static void tomoyo_del_path_group(struct list_head *element)
176
{
177
struct tomoyo_path_group *member =
178
container_of(element, typeof(*member), head.list);
179
tomoyo_put_name(member->member_name);
180
}
181
182
static void tomoyo_del_group(struct list_head *element)
183
{
184
struct tomoyo_group *group =
185
container_of(element, typeof(*group), list);
186
tomoyo_put_name(group->group_name);
187
}
188
189
static void tomoyo_del_number_group(struct list_head *element)
190
{
191
struct tomoyo_number_group *member =
192
container_of(element, typeof(*member), head.list);
193
}
194
195
static bool tomoyo_collect_member(struct list_head *member_list, int id)
196
{
197
struct tomoyo_acl_head *member;
198
list_for_each_entry(member, member_list, list) {
199
if (!member->is_deleted)
200
continue;
201
if (!tomoyo_add_to_gc(id, &member->list))
202
return false;
203
}
204
return true;
205
}
206
207
static bool tomoyo_collect_acl(struct tomoyo_domain_info *domain)
208
{
209
struct tomoyo_acl_info *acl;
210
list_for_each_entry(acl, &domain->acl_info_list, list) {
211
if (!acl->is_deleted)
212
continue;
213
if (!tomoyo_add_to_gc(TOMOYO_ID_ACL, &acl->list))
214
return false;
215
}
216
return true;
217
}
218
219
static void tomoyo_collect_entry(void)
220
{
221
int i;
222
if (mutex_lock_interruptible(&tomoyo_policy_lock))
223
return;
224
for (i = 0; i < TOMOYO_MAX_POLICY; i++) {
225
if (!tomoyo_collect_member(&tomoyo_policy_list[i], i))
226
goto unlock;
227
}
228
{
229
struct tomoyo_domain_info *domain;
230
list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
231
if (!tomoyo_collect_acl(domain))
232
goto unlock;
233
if (!domain->is_deleted || atomic_read(&domain->users))
234
continue;
235
/*
236
* Nobody is referring this domain. But somebody may
237
* refer this domain after successful execve().
238
* We recheck domain->users after SRCU synchronization.
239
*/
240
if (!tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, &domain->list))
241
goto unlock;
242
}
243
}
244
for (i = 0; i < TOMOYO_MAX_HASH; i++) {
245
struct tomoyo_name *ptr;
246
list_for_each_entry_rcu(ptr, &tomoyo_name_list[i], list) {
247
if (atomic_read(&ptr->users))
248
continue;
249
if (!tomoyo_add_to_gc(TOMOYO_ID_NAME, &ptr->list))
250
goto unlock;
251
}
252
}
253
for (i = 0; i < TOMOYO_MAX_GROUP; i++) {
254
struct list_head *list = &tomoyo_group_list[i];
255
int id;
256
struct tomoyo_group *group;
257
switch (i) {
258
case 0:
259
id = TOMOYO_ID_PATH_GROUP;
260
break;
261
default:
262
id = TOMOYO_ID_NUMBER_GROUP;
263
break;
264
}
265
list_for_each_entry(group, list, list) {
266
if (!tomoyo_collect_member(&group->member_list, id))
267
goto unlock;
268
if (!list_empty(&group->member_list) ||
269
atomic_read(&group->users))
270
continue;
271
if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP, &group->list))
272
goto unlock;
273
}
274
}
275
unlock:
276
mutex_unlock(&tomoyo_policy_lock);
277
}
278
279
static void tomoyo_kfree_entry(void)
280
{
281
struct tomoyo_gc *p;
282
struct tomoyo_gc *tmp;
283
284
list_for_each_entry_safe(p, tmp, &tomoyo_gc_queue, list) {
285
struct list_head *element = p->element;
286
switch (p->type) {
287
case TOMOYO_ID_TRANSITION_CONTROL:
288
tomoyo_del_transition_control(element);
289
break;
290
case TOMOYO_ID_AGGREGATOR:
291
tomoyo_del_aggregator(element);
292
break;
293
case TOMOYO_ID_GLOBALLY_READABLE:
294
tomoyo_del_allow_read(element);
295
break;
296
case TOMOYO_ID_PATTERN:
297
tomoyo_del_file_pattern(element);
298
break;
299
case TOMOYO_ID_NO_REWRITE:
300
tomoyo_del_no_rewrite(element);
301
break;
302
case TOMOYO_ID_MANAGER:
303
tomoyo_del_manager(element);
304
break;
305
case TOMOYO_ID_NAME:
306
tomoyo_del_name(element);
307
break;
308
case TOMOYO_ID_ACL:
309
tomoyo_del_acl(element);
310
break;
311
case TOMOYO_ID_DOMAIN:
312
if (!tomoyo_del_domain(element))
313
continue;
314
break;
315
case TOMOYO_ID_PATH_GROUP:
316
tomoyo_del_path_group(element);
317
break;
318
case TOMOYO_ID_GROUP:
319
tomoyo_del_group(element);
320
break;
321
case TOMOYO_ID_NUMBER_GROUP:
322
tomoyo_del_number_group(element);
323
break;
324
}
325
tomoyo_memory_free(element);
326
list_del(&p->list);
327
kfree(p);
328
}
329
}
330
331
static int tomoyo_gc_thread(void *unused)
332
{
333
daemonize("GC for TOMOYO");
334
if (mutex_trylock(&tomoyo_gc_mutex)) {
335
int i;
336
for (i = 0; i < 10; i++) {
337
tomoyo_collect_entry();
338
if (list_empty(&tomoyo_gc_queue))
339
break;
340
synchronize_srcu(&tomoyo_ss);
341
tomoyo_kfree_entry();
342
}
343
mutex_unlock(&tomoyo_gc_mutex);
344
}
345
do_exit(0);
346
}
347
348
void tomoyo_run_gc(void)
349
{
350
struct task_struct *task = kthread_create(tomoyo_gc_thread, NULL,
351
"GC for TOMOYO");
352
if (!IS_ERR(task))
353
wake_up_process(task);
354
}
355
356