Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/security/tomoyo/gc.c
26378 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* security/tomoyo/gc.c
4
*
5
* Copyright (C) 2005-2011 NTT DATA CORPORATION
6
*/
7
8
#include "common.h"
9
#include <linux/kthread.h>
10
#include <linux/slab.h>
11
12
/**
13
* tomoyo_memory_free - Free memory for elements.
14
*
15
* @ptr: Pointer to allocated memory.
16
*
17
* Returns nothing.
18
*
19
* Caller holds tomoyo_policy_lock mutex.
20
*/
21
static inline void tomoyo_memory_free(void *ptr)
22
{
23
tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= ksize(ptr);
24
kfree(ptr);
25
}
26
27
/* The list for "struct tomoyo_io_buffer". */
28
static LIST_HEAD(tomoyo_io_buffer_list);
29
/* Lock for protecting tomoyo_io_buffer_list. */
30
static DEFINE_SPINLOCK(tomoyo_io_buffer_list_lock);
31
32
/**
33
* tomoyo_struct_used_by_io_buffer - Check whether the list element is used by /sys/kernel/security/tomoyo/ users or not.
34
*
35
* @element: Pointer to "struct list_head".
36
*
37
* Returns true if @element is used by /sys/kernel/security/tomoyo/ users,
38
* false otherwise.
39
*/
40
static bool tomoyo_struct_used_by_io_buffer(const struct list_head *element)
41
{
42
struct tomoyo_io_buffer *head;
43
bool in_use = false;
44
45
spin_lock(&tomoyo_io_buffer_list_lock);
46
list_for_each_entry(head, &tomoyo_io_buffer_list, list) {
47
head->users++;
48
spin_unlock(&tomoyo_io_buffer_list_lock);
49
mutex_lock(&head->io_sem);
50
if (head->r.domain == element || head->r.group == element ||
51
head->r.acl == element || &head->w.domain->list == element)
52
in_use = true;
53
mutex_unlock(&head->io_sem);
54
spin_lock(&tomoyo_io_buffer_list_lock);
55
head->users--;
56
if (in_use)
57
break;
58
}
59
spin_unlock(&tomoyo_io_buffer_list_lock);
60
return in_use;
61
}
62
63
/**
64
* tomoyo_name_used_by_io_buffer - Check whether the string is used by /sys/kernel/security/tomoyo/ users or not.
65
*
66
* @string: String to check.
67
*
68
* Returns true if @string is used by /sys/kernel/security/tomoyo/ users,
69
* false otherwise.
70
*/
71
static bool tomoyo_name_used_by_io_buffer(const char *string)
72
{
73
struct tomoyo_io_buffer *head;
74
const size_t size = strlen(string) + 1;
75
bool in_use = false;
76
77
spin_lock(&tomoyo_io_buffer_list_lock);
78
list_for_each_entry(head, &tomoyo_io_buffer_list, list) {
79
int i;
80
81
head->users++;
82
spin_unlock(&tomoyo_io_buffer_list_lock);
83
mutex_lock(&head->io_sem);
84
for (i = 0; i < TOMOYO_MAX_IO_READ_QUEUE; i++) {
85
const char *w = head->r.w[i];
86
87
if (w < string || w > string + size)
88
continue;
89
in_use = true;
90
break;
91
}
92
mutex_unlock(&head->io_sem);
93
spin_lock(&tomoyo_io_buffer_list_lock);
94
head->users--;
95
if (in_use)
96
break;
97
}
98
spin_unlock(&tomoyo_io_buffer_list_lock);
99
return in_use;
100
}
101
102
/**
103
* tomoyo_del_transition_control - Delete members in "struct tomoyo_transition_control".
104
*
105
* @element: Pointer to "struct list_head".
106
*
107
* Returns nothing.
108
*/
109
static inline void tomoyo_del_transition_control(struct list_head *element)
110
{
111
struct tomoyo_transition_control *ptr =
112
container_of(element, typeof(*ptr), head.list);
113
114
tomoyo_put_name(ptr->domainname);
115
tomoyo_put_name(ptr->program);
116
}
117
118
/**
119
* tomoyo_del_aggregator - Delete members in "struct tomoyo_aggregator".
120
*
121
* @element: Pointer to "struct list_head".
122
*
123
* Returns nothing.
124
*/
125
static inline void tomoyo_del_aggregator(struct list_head *element)
126
{
127
struct tomoyo_aggregator *ptr =
128
container_of(element, typeof(*ptr), head.list);
129
130
tomoyo_put_name(ptr->original_name);
131
tomoyo_put_name(ptr->aggregated_name);
132
}
133
134
/**
135
* tomoyo_del_manager - Delete members in "struct tomoyo_manager".
136
*
137
* @element: Pointer to "struct list_head".
138
*
139
* Returns nothing.
140
*/
141
static inline void tomoyo_del_manager(struct list_head *element)
142
{
143
struct tomoyo_manager *ptr =
144
container_of(element, typeof(*ptr), head.list);
145
146
tomoyo_put_name(ptr->manager);
147
}
148
149
/**
150
* tomoyo_del_acl - Delete members in "struct tomoyo_acl_info".
151
*
152
* @element: Pointer to "struct list_head".
153
*
154
* Returns nothing.
155
*/
156
static void tomoyo_del_acl(struct list_head *element)
157
{
158
struct tomoyo_acl_info *acl =
159
container_of(element, typeof(*acl), list);
160
161
tomoyo_put_condition(acl->cond);
162
switch (acl->type) {
163
case TOMOYO_TYPE_PATH_ACL:
164
{
165
struct tomoyo_path_acl *entry
166
= container_of(acl, typeof(*entry), head);
167
tomoyo_put_name_union(&entry->name);
168
}
169
break;
170
case TOMOYO_TYPE_PATH2_ACL:
171
{
172
struct tomoyo_path2_acl *entry
173
= container_of(acl, typeof(*entry), head);
174
tomoyo_put_name_union(&entry->name1);
175
tomoyo_put_name_union(&entry->name2);
176
}
177
break;
178
case TOMOYO_TYPE_PATH_NUMBER_ACL:
179
{
180
struct tomoyo_path_number_acl *entry
181
= container_of(acl, typeof(*entry), head);
182
tomoyo_put_name_union(&entry->name);
183
tomoyo_put_number_union(&entry->number);
184
}
185
break;
186
case TOMOYO_TYPE_MKDEV_ACL:
187
{
188
struct tomoyo_mkdev_acl *entry
189
= container_of(acl, typeof(*entry), head);
190
tomoyo_put_name_union(&entry->name);
191
tomoyo_put_number_union(&entry->mode);
192
tomoyo_put_number_union(&entry->major);
193
tomoyo_put_number_union(&entry->minor);
194
}
195
break;
196
case TOMOYO_TYPE_MOUNT_ACL:
197
{
198
struct tomoyo_mount_acl *entry
199
= container_of(acl, typeof(*entry), head);
200
tomoyo_put_name_union(&entry->dev_name);
201
tomoyo_put_name_union(&entry->dir_name);
202
tomoyo_put_name_union(&entry->fs_type);
203
tomoyo_put_number_union(&entry->flags);
204
}
205
break;
206
case TOMOYO_TYPE_ENV_ACL:
207
{
208
struct tomoyo_env_acl *entry =
209
container_of(acl, typeof(*entry), head);
210
211
tomoyo_put_name(entry->env);
212
}
213
break;
214
case TOMOYO_TYPE_INET_ACL:
215
{
216
struct tomoyo_inet_acl *entry =
217
container_of(acl, typeof(*entry), head);
218
219
tomoyo_put_group(entry->address.group);
220
tomoyo_put_number_union(&entry->port);
221
}
222
break;
223
case TOMOYO_TYPE_UNIX_ACL:
224
{
225
struct tomoyo_unix_acl *entry =
226
container_of(acl, typeof(*entry), head);
227
228
tomoyo_put_name_union(&entry->name);
229
}
230
break;
231
case TOMOYO_TYPE_MANUAL_TASK_ACL:
232
{
233
struct tomoyo_task_acl *entry =
234
container_of(acl, typeof(*entry), head);
235
236
tomoyo_put_name(entry->domainname);
237
}
238
break;
239
}
240
}
241
242
/**
243
* tomoyo_del_domain - Delete members in "struct tomoyo_domain_info".
244
*
245
* @element: Pointer to "struct list_head".
246
*
247
* Returns nothing.
248
*
249
* Caller holds tomoyo_policy_lock mutex.
250
*/
251
static inline void tomoyo_del_domain(struct list_head *element)
252
{
253
struct tomoyo_domain_info *domain =
254
container_of(element, typeof(*domain), list);
255
struct tomoyo_acl_info *acl;
256
struct tomoyo_acl_info *tmp;
257
258
/*
259
* Since this domain is referenced from neither
260
* "struct tomoyo_io_buffer" nor "struct cred"->security, we can delete
261
* elements without checking for is_deleted flag.
262
*/
263
list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) {
264
tomoyo_del_acl(&acl->list);
265
tomoyo_memory_free(acl);
266
}
267
tomoyo_put_name(domain->domainname);
268
}
269
270
/**
271
* tomoyo_del_condition - Delete members in "struct tomoyo_condition".
272
*
273
* @element: Pointer to "struct list_head".
274
*
275
* Returns nothing.
276
*/
277
void tomoyo_del_condition(struct list_head *element)
278
{
279
struct tomoyo_condition *cond = container_of(element, typeof(*cond),
280
head.list);
281
const u16 condc = cond->condc;
282
const u16 numbers_count = cond->numbers_count;
283
const u16 names_count = cond->names_count;
284
const u16 argc = cond->argc;
285
const u16 envc = cond->envc;
286
unsigned int i;
287
const struct tomoyo_condition_element *condp
288
= (const struct tomoyo_condition_element *) (cond + 1);
289
struct tomoyo_number_union *numbers_p
290
= (struct tomoyo_number_union *) (condp + condc);
291
struct tomoyo_name_union *names_p
292
= (struct tomoyo_name_union *) (numbers_p + numbers_count);
293
const struct tomoyo_argv *argv
294
= (const struct tomoyo_argv *) (names_p + names_count);
295
const struct tomoyo_envp *envp
296
= (const struct tomoyo_envp *) (argv + argc);
297
298
for (i = 0; i < numbers_count; i++)
299
tomoyo_put_number_union(numbers_p++);
300
for (i = 0; i < names_count; i++)
301
tomoyo_put_name_union(names_p++);
302
for (i = 0; i < argc; argv++, i++)
303
tomoyo_put_name(argv->value);
304
for (i = 0; i < envc; envp++, i++) {
305
tomoyo_put_name(envp->name);
306
tomoyo_put_name(envp->value);
307
}
308
}
309
310
/**
311
* tomoyo_del_name - Delete members in "struct tomoyo_name".
312
*
313
* @element: Pointer to "struct list_head".
314
*
315
* Returns nothing.
316
*/
317
static inline void tomoyo_del_name(struct list_head *element)
318
{
319
/* Nothing to do. */
320
}
321
322
/**
323
* tomoyo_del_path_group - Delete members in "struct tomoyo_path_group".
324
*
325
* @element: Pointer to "struct list_head".
326
*
327
* Returns nothing.
328
*/
329
static inline void tomoyo_del_path_group(struct list_head *element)
330
{
331
struct tomoyo_path_group *member =
332
container_of(element, typeof(*member), head.list);
333
334
tomoyo_put_name(member->member_name);
335
}
336
337
/**
338
* tomoyo_del_group - Delete "struct tomoyo_group".
339
*
340
* @element: Pointer to "struct list_head".
341
*
342
* Returns nothing.
343
*/
344
static inline void tomoyo_del_group(struct list_head *element)
345
{
346
struct tomoyo_group *group =
347
container_of(element, typeof(*group), head.list);
348
349
tomoyo_put_name(group->group_name);
350
}
351
352
/**
353
* tomoyo_del_address_group - Delete members in "struct tomoyo_address_group".
354
*
355
* @element: Pointer to "struct list_head".
356
*
357
* Returns nothing.
358
*/
359
static inline void tomoyo_del_address_group(struct list_head *element)
360
{
361
/* Nothing to do. */
362
}
363
364
/**
365
* tomoyo_del_number_group - Delete members in "struct tomoyo_number_group".
366
*
367
* @element: Pointer to "struct list_head".
368
*
369
* Returns nothing.
370
*/
371
static inline void tomoyo_del_number_group(struct list_head *element)
372
{
373
/* Nothing to do. */
374
}
375
376
/**
377
* tomoyo_try_to_gc - Try to kfree() an entry.
378
*
379
* @type: One of values in "enum tomoyo_policy_id".
380
* @element: Pointer to "struct list_head".
381
*
382
* Returns nothing.
383
*
384
* Caller holds tomoyo_policy_lock mutex.
385
*/
386
static void tomoyo_try_to_gc(const enum tomoyo_policy_id type,
387
struct list_head *element)
388
{
389
/*
390
* __list_del_entry() guarantees that the list element became no longer
391
* reachable from the list which the element was originally on (e.g.
392
* tomoyo_domain_list). Also, synchronize_srcu() guarantees that the
393
* list element became no longer referenced by syscall users.
394
*/
395
__list_del_entry(element);
396
mutex_unlock(&tomoyo_policy_lock);
397
synchronize_srcu(&tomoyo_ss);
398
/*
399
* However, there are two users which may still be using the list
400
* element. We need to defer until both users forget this element.
401
*
402
* Don't kfree() until "struct tomoyo_io_buffer"->r.{domain,group,acl}
403
* and "struct tomoyo_io_buffer"->w.domain forget this element.
404
*/
405
if (tomoyo_struct_used_by_io_buffer(element))
406
goto reinject;
407
switch (type) {
408
case TOMOYO_ID_TRANSITION_CONTROL:
409
tomoyo_del_transition_control(element);
410
break;
411
case TOMOYO_ID_MANAGER:
412
tomoyo_del_manager(element);
413
break;
414
case TOMOYO_ID_AGGREGATOR:
415
tomoyo_del_aggregator(element);
416
break;
417
case TOMOYO_ID_GROUP:
418
tomoyo_del_group(element);
419
break;
420
case TOMOYO_ID_PATH_GROUP:
421
tomoyo_del_path_group(element);
422
break;
423
case TOMOYO_ID_ADDRESS_GROUP:
424
tomoyo_del_address_group(element);
425
break;
426
case TOMOYO_ID_NUMBER_GROUP:
427
tomoyo_del_number_group(element);
428
break;
429
case TOMOYO_ID_CONDITION:
430
tomoyo_del_condition(element);
431
break;
432
case TOMOYO_ID_NAME:
433
/*
434
* Don't kfree() until all "struct tomoyo_io_buffer"->r.w[]
435
* forget this element.
436
*/
437
if (tomoyo_name_used_by_io_buffer
438
(container_of(element, typeof(struct tomoyo_name),
439
head.list)->entry.name))
440
goto reinject;
441
tomoyo_del_name(element);
442
break;
443
case TOMOYO_ID_ACL:
444
tomoyo_del_acl(element);
445
break;
446
case TOMOYO_ID_DOMAIN:
447
/*
448
* Don't kfree() until all "struct cred"->security forget this
449
* element.
450
*/
451
if (atomic_read(&container_of
452
(element, typeof(struct tomoyo_domain_info),
453
list)->users))
454
goto reinject;
455
break;
456
case TOMOYO_MAX_POLICY:
457
break;
458
}
459
mutex_lock(&tomoyo_policy_lock);
460
if (type == TOMOYO_ID_DOMAIN)
461
tomoyo_del_domain(element);
462
tomoyo_memory_free(element);
463
return;
464
reinject:
465
/*
466
* We can safely reinject this element here because
467
* (1) Appending list elements and removing list elements are protected
468
* by tomoyo_policy_lock mutex.
469
* (2) Only this function removes list elements and this function is
470
* exclusively executed by tomoyo_gc_mutex mutex.
471
* are true.
472
*/
473
mutex_lock(&tomoyo_policy_lock);
474
list_add_rcu(element, element->prev);
475
}
476
477
/**
478
* tomoyo_collect_member - Delete elements with "struct tomoyo_acl_head".
479
*
480
* @id: One of values in "enum tomoyo_policy_id".
481
* @member_list: Pointer to "struct list_head".
482
*
483
* Returns nothing.
484
*/
485
static void tomoyo_collect_member(const enum tomoyo_policy_id id,
486
struct list_head *member_list)
487
{
488
struct tomoyo_acl_head *member;
489
struct tomoyo_acl_head *tmp;
490
491
list_for_each_entry_safe(member, tmp, member_list, list) {
492
if (!member->is_deleted)
493
continue;
494
member->is_deleted = TOMOYO_GC_IN_PROGRESS;
495
tomoyo_try_to_gc(id, &member->list);
496
}
497
}
498
499
/**
500
* tomoyo_collect_acl - Delete elements in "struct tomoyo_domain_info".
501
*
502
* @list: Pointer to "struct list_head".
503
*
504
* Returns nothing.
505
*/
506
static void tomoyo_collect_acl(struct list_head *list)
507
{
508
struct tomoyo_acl_info *acl;
509
struct tomoyo_acl_info *tmp;
510
511
list_for_each_entry_safe(acl, tmp, list, list) {
512
if (!acl->is_deleted)
513
continue;
514
acl->is_deleted = TOMOYO_GC_IN_PROGRESS;
515
tomoyo_try_to_gc(TOMOYO_ID_ACL, &acl->list);
516
}
517
}
518
519
/**
520
* tomoyo_collect_entry - Try to kfree() deleted elements.
521
*
522
* Returns nothing.
523
*/
524
static void tomoyo_collect_entry(void)
525
{
526
int i;
527
enum tomoyo_policy_id id;
528
struct tomoyo_policy_namespace *ns;
529
530
mutex_lock(&tomoyo_policy_lock);
531
{
532
struct tomoyo_domain_info *domain;
533
struct tomoyo_domain_info *tmp;
534
535
list_for_each_entry_safe(domain, tmp, &tomoyo_domain_list,
536
list) {
537
tomoyo_collect_acl(&domain->acl_info_list);
538
if (!domain->is_deleted || atomic_read(&domain->users))
539
continue;
540
tomoyo_try_to_gc(TOMOYO_ID_DOMAIN, &domain->list);
541
}
542
}
543
list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) {
544
for (id = 0; id < TOMOYO_MAX_POLICY; id++)
545
tomoyo_collect_member(id, &ns->policy_list[id]);
546
for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++)
547
tomoyo_collect_acl(&ns->acl_group[i]);
548
}
549
{
550
struct tomoyo_shared_acl_head *ptr;
551
struct tomoyo_shared_acl_head *tmp;
552
553
list_for_each_entry_safe(ptr, tmp, &tomoyo_condition_list,
554
list) {
555
if (atomic_read(&ptr->users) > 0)
556
continue;
557
atomic_set(&ptr->users, TOMOYO_GC_IN_PROGRESS);
558
tomoyo_try_to_gc(TOMOYO_ID_CONDITION, &ptr->list);
559
}
560
}
561
list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) {
562
for (i = 0; i < TOMOYO_MAX_GROUP; i++) {
563
struct list_head *list = &ns->group_list[i];
564
struct tomoyo_group *group;
565
struct tomoyo_group *tmp;
566
567
switch (i) {
568
case 0:
569
id = TOMOYO_ID_PATH_GROUP;
570
break;
571
case 1:
572
id = TOMOYO_ID_NUMBER_GROUP;
573
break;
574
default:
575
id = TOMOYO_ID_ADDRESS_GROUP;
576
break;
577
}
578
list_for_each_entry_safe(group, tmp, list, head.list) {
579
tomoyo_collect_member(id, &group->member_list);
580
if (!list_empty(&group->member_list) ||
581
atomic_read(&group->head.users) > 0)
582
continue;
583
atomic_set(&group->head.users,
584
TOMOYO_GC_IN_PROGRESS);
585
tomoyo_try_to_gc(TOMOYO_ID_GROUP,
586
&group->head.list);
587
}
588
}
589
}
590
for (i = 0; i < TOMOYO_MAX_HASH; i++) {
591
struct list_head *list = &tomoyo_name_list[i];
592
struct tomoyo_shared_acl_head *ptr;
593
struct tomoyo_shared_acl_head *tmp;
594
595
list_for_each_entry_safe(ptr, tmp, list, list) {
596
if (atomic_read(&ptr->users) > 0)
597
continue;
598
atomic_set(&ptr->users, TOMOYO_GC_IN_PROGRESS);
599
tomoyo_try_to_gc(TOMOYO_ID_NAME, &ptr->list);
600
}
601
}
602
mutex_unlock(&tomoyo_policy_lock);
603
}
604
605
/**
606
* tomoyo_gc_thread - Garbage collector thread function.
607
*
608
* @unused: Unused.
609
*
610
* Returns 0.
611
*/
612
static int tomoyo_gc_thread(void *unused)
613
{
614
/* Garbage collector thread is exclusive. */
615
static DEFINE_MUTEX(tomoyo_gc_mutex);
616
617
if (!mutex_trylock(&tomoyo_gc_mutex))
618
goto out;
619
tomoyo_collect_entry();
620
{
621
struct tomoyo_io_buffer *head;
622
struct tomoyo_io_buffer *tmp;
623
624
spin_lock(&tomoyo_io_buffer_list_lock);
625
list_for_each_entry_safe(head, tmp, &tomoyo_io_buffer_list,
626
list) {
627
if (head->users)
628
continue;
629
list_del(&head->list);
630
kfree(head->read_buf);
631
kfree(head->write_buf);
632
kfree(head);
633
}
634
spin_unlock(&tomoyo_io_buffer_list_lock);
635
}
636
mutex_unlock(&tomoyo_gc_mutex);
637
out:
638
/* This acts as do_exit(0). */
639
return 0;
640
}
641
642
/**
643
* tomoyo_notify_gc - Register/unregister /sys/kernel/security/tomoyo/ users.
644
*
645
* @head: Pointer to "struct tomoyo_io_buffer".
646
* @is_register: True if register, false if unregister.
647
*
648
* Returns nothing.
649
*/
650
void tomoyo_notify_gc(struct tomoyo_io_buffer *head, const bool is_register)
651
{
652
bool is_write = false;
653
654
spin_lock(&tomoyo_io_buffer_list_lock);
655
if (is_register) {
656
head->users = 1;
657
list_add(&head->list, &tomoyo_io_buffer_list);
658
} else {
659
is_write = head->write_buf != NULL;
660
if (!--head->users) {
661
list_del(&head->list);
662
kfree(head->read_buf);
663
kfree(head->write_buf);
664
kfree(head);
665
}
666
}
667
spin_unlock(&tomoyo_io_buffer_list_lock);
668
if (is_write)
669
kthread_run(tomoyo_gc_thread, NULL, "GC for TOMOYO");
670
}
671
672