diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/tomoyo/common.c | 6 | ||||
-rw-r--r-- | security/tomoyo/common.h | 12 | ||||
-rw-r--r-- | security/tomoyo/condition.c | 8 | ||||
-rw-r--r-- | security/tomoyo/domain.c | 5 | ||||
-rw-r--r-- | security/tomoyo/file.c | 4 | ||||
-rw-r--r-- | security/tomoyo/gc.c | 498 | ||||
-rw-r--r-- | security/tomoyo/memory.c | 39 | ||||
-rw-r--r-- | security/tomoyo/securityfs_if.c | 1 |
8 files changed, 221 insertions, 352 deletions
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 0994948f3edc..2e2802060eef 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -262,13 +262,17 @@ static void tomoyo_set_string(struct tomoyo_io_buffer *head, const char *string) | |||
262 | WARN_ON(1); | 262 | WARN_ON(1); |
263 | } | 263 | } |
264 | 264 | ||
265 | static void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, | ||
266 | ...) __printf(2, 3); | ||
267 | |||
265 | /** | 268 | /** |
266 | * tomoyo_io_printf - printf() to "struct tomoyo_io_buffer" structure. | 269 | * tomoyo_io_printf - printf() to "struct tomoyo_io_buffer" structure. |
267 | * | 270 | * |
268 | * @head: Pointer to "struct tomoyo_io_buffer". | 271 | * @head: Pointer to "struct tomoyo_io_buffer". |
269 | * @fmt: The printf()'s format string, followed by parameters. | 272 | * @fmt: The printf()'s format string, followed by parameters. |
270 | */ | 273 | */ |
271 | void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) | 274 | static void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, |
275 | ...) | ||
272 | { | 276 | { |
273 | va_list args; | 277 | va_list args; |
274 | size_t len; | 278 | size_t len; |
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index a2bc33fc60b6..ed311d7a8ce0 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
@@ -52,6 +52,9 @@ | |||
52 | 52 | ||
53 | #define TOMOYO_EXEC_TMPSIZE 4096 | 53 | #define TOMOYO_EXEC_TMPSIZE 4096 |
54 | 54 | ||
55 | /* Garbage collector is trying to kfree() this element. */ | ||
56 | #define TOMOYO_GC_IN_PROGRESS -1 | ||
57 | |||
55 | /* Profile number is an integer between 0 and 255. */ | 58 | /* Profile number is an integer between 0 and 255. */ |
56 | #define TOMOYO_MAX_PROFILES 256 | 59 | #define TOMOYO_MAX_PROFILES 256 |
57 | 60 | ||
@@ -398,7 +401,7 @@ enum tomoyo_pref_index { | |||
398 | /* Common header for holding ACL entries. */ | 401 | /* Common header for holding ACL entries. */ |
399 | struct tomoyo_acl_head { | 402 | struct tomoyo_acl_head { |
400 | struct list_head list; | 403 | struct list_head list; |
401 | bool is_deleted; | 404 | s8 is_deleted; /* true or false or TOMOYO_GC_IN_PROGRESS */ |
402 | } __packed; | 405 | } __packed; |
403 | 406 | ||
404 | /* Common header for shared entries. */ | 407 | /* Common header for shared entries. */ |
@@ -665,7 +668,7 @@ struct tomoyo_condition { | |||
665 | struct tomoyo_acl_info { | 668 | struct tomoyo_acl_info { |
666 | struct list_head list; | 669 | struct list_head list; |
667 | struct tomoyo_condition *cond; /* Maybe NULL. */ | 670 | struct tomoyo_condition *cond; /* Maybe NULL. */ |
668 | bool is_deleted; | 671 | s8 is_deleted; /* true or false or TOMOYO_GC_IN_PROGRESS */ |
669 | u8 type; /* One of values in "enum tomoyo_acl_entry_type_index". */ | 672 | u8 type; /* One of values in "enum tomoyo_acl_entry_type_index". */ |
670 | } __packed; | 673 | } __packed; |
671 | 674 | ||
@@ -978,8 +981,6 @@ int tomoyo_path_number_perm(const u8 operation, struct path *path, | |||
978 | unsigned long number); | 981 | unsigned long number); |
979 | int tomoyo_path_perm(const u8 operation, struct path *path, | 982 | int tomoyo_path_perm(const u8 operation, struct path *path, |
980 | const char *target); | 983 | const char *target); |
981 | int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, | ||
982 | const struct tomoyo_path_info *filename); | ||
983 | int tomoyo_poll_control(struct file *file, poll_table *wait); | 984 | int tomoyo_poll_control(struct file *file, poll_table *wait); |
984 | int tomoyo_poll_log(struct file *file, poll_table *wait); | 985 | int tomoyo_poll_log(struct file *file, poll_table *wait); |
985 | int tomoyo_socket_bind_permission(struct socket *sock, struct sockaddr *addr, | 986 | int tomoyo_socket_bind_permission(struct socket *sock, struct sockaddr *addr, |
@@ -1041,10 +1042,7 @@ void tomoyo_del_condition(struct list_head *element); | |||
1041 | void tomoyo_fill_path_info(struct tomoyo_path_info *ptr); | 1042 | void tomoyo_fill_path_info(struct tomoyo_path_info *ptr); |
1042 | void tomoyo_get_attributes(struct tomoyo_obj_info *obj); | 1043 | void tomoyo_get_attributes(struct tomoyo_obj_info *obj); |
1043 | void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns); | 1044 | void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns); |
1044 | void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) | ||
1045 | __printf(2, 3); | ||
1046 | void tomoyo_load_policy(const char *filename); | 1045 | void tomoyo_load_policy(const char *filename); |
1047 | void tomoyo_memory_free(void *ptr); | ||
1048 | void tomoyo_normalize_line(unsigned char *buffer); | 1046 | void tomoyo_normalize_line(unsigned char *buffer); |
1049 | void tomoyo_notify_gc(struct tomoyo_io_buffer *head, const bool is_register); | 1047 | void tomoyo_notify_gc(struct tomoyo_io_buffer *head, const bool is_register); |
1050 | void tomoyo_print_ip(char *buf, const unsigned int size, | 1048 | void tomoyo_print_ip(char *buf, const unsigned int size, |
diff --git a/security/tomoyo/condition.c b/security/tomoyo/condition.c index b854959c0fd4..986330b8c73e 100644 --- a/security/tomoyo/condition.c +++ b/security/tomoyo/condition.c | |||
@@ -400,8 +400,9 @@ static struct tomoyo_condition *tomoyo_commit_condition | |||
400 | found = true; | 400 | found = true; |
401 | goto out; | 401 | goto out; |
402 | } | 402 | } |
403 | list_for_each_entry_rcu(ptr, &tomoyo_condition_list, head.list) { | 403 | list_for_each_entry(ptr, &tomoyo_condition_list, head.list) { |
404 | if (!tomoyo_same_condition(ptr, entry)) | 404 | if (!tomoyo_same_condition(ptr, entry) || |
405 | atomic_read(&ptr->head.users) == TOMOYO_GC_IN_PROGRESS) | ||
405 | continue; | 406 | continue; |
406 | /* Same entry found. Share this entry. */ | 407 | /* Same entry found. Share this entry. */ |
407 | atomic_inc(&ptr->head.users); | 408 | atomic_inc(&ptr->head.users); |
@@ -411,8 +412,7 @@ static struct tomoyo_condition *tomoyo_commit_condition | |||
411 | if (!found) { | 412 | if (!found) { |
412 | if (tomoyo_memory_ok(entry)) { | 413 | if (tomoyo_memory_ok(entry)) { |
413 | atomic_set(&entry->head.users, 1); | 414 | atomic_set(&entry->head.users, 1); |
414 | list_add_rcu(&entry->head.list, | 415 | list_add(&entry->head.list, &tomoyo_condition_list); |
415 | &tomoyo_condition_list); | ||
416 | } else { | 416 | } else { |
417 | found = true; | 417 | found = true; |
418 | ptr = NULL; | 418 | ptr = NULL; |
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 860390ee1fbe..da16dfeed728 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
@@ -39,6 +39,8 @@ int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size, | |||
39 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 39 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
40 | return -ENOMEM; | 40 | return -ENOMEM; |
41 | list_for_each_entry_rcu(entry, list, list) { | 41 | list_for_each_entry_rcu(entry, list, list) { |
42 | if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS) | ||
43 | continue; | ||
42 | if (!check_duplicate(entry, new_entry)) | 44 | if (!check_duplicate(entry, new_entry)) |
43 | continue; | 45 | continue; |
44 | entry->is_deleted = param->is_delete; | 46 | entry->is_deleted = param->is_delete; |
@@ -115,6 +117,8 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, | |||
115 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 117 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
116 | goto out; | 118 | goto out; |
117 | list_for_each_entry_rcu(entry, list, list) { | 119 | list_for_each_entry_rcu(entry, list, list) { |
120 | if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS) | ||
121 | continue; | ||
118 | if (!tomoyo_same_acl_head(entry, new_entry) || | 122 | if (!tomoyo_same_acl_head(entry, new_entry) || |
119 | !check_duplicate(entry, new_entry)) | 123 | !check_duplicate(entry, new_entry)) |
120 | continue; | 124 | continue; |
@@ -567,6 +571,7 @@ out: | |||
567 | tomoyo_write_log(&r, "use_profile %u\n", | 571 | tomoyo_write_log(&r, "use_profile %u\n", |
568 | entry->profile); | 572 | entry->profile); |
569 | tomoyo_write_log(&r, "use_group %u\n", entry->group); | 573 | tomoyo_write_log(&r, "use_group %u\n", entry->group); |
574 | tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES); | ||
570 | } | 575 | } |
571 | } | 576 | } |
572 | return entry; | 577 | return entry; |
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index b280c1bd652d..400390790745 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c | |||
@@ -555,8 +555,8 @@ static int tomoyo_update_path2_acl(const u8 perm, | |||
555 | * | 555 | * |
556 | * Caller holds tomoyo_read_lock(). | 556 | * Caller holds tomoyo_read_lock(). |
557 | */ | 557 | */ |
558 | int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, | 558 | static int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, |
559 | const struct tomoyo_path_info *filename) | 559 | const struct tomoyo_path_info *filename) |
560 | { | 560 | { |
561 | int error; | 561 | int error; |
562 | 562 | ||
diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c index 7747ceb9a221..c3214b32dbfb 100644 --- a/security/tomoyo/gc.c +++ b/security/tomoyo/gc.c | |||
@@ -8,40 +8,26 @@ | |||
8 | #include <linux/kthread.h> | 8 | #include <linux/kthread.h> |
9 | #include <linux/slab.h> | 9 | #include <linux/slab.h> |
10 | 10 | ||
11 | /** | ||
12 | * tomoyo_memory_free - Free memory for elements. | ||
13 | * | ||
14 | * @ptr: Pointer to allocated memory. | ||
15 | * | ||
16 | * Returns nothing. | ||
17 | * | ||
18 | * Caller holds tomoyo_policy_lock mutex. | ||
19 | */ | ||
20 | static inline void tomoyo_memory_free(void *ptr) | ||
21 | { | ||
22 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= ksize(ptr); | ||
23 | kfree(ptr); | ||
24 | } | ||
25 | |||
11 | /* The list for "struct tomoyo_io_buffer". */ | 26 | /* The list for "struct tomoyo_io_buffer". */ |
12 | static LIST_HEAD(tomoyo_io_buffer_list); | 27 | static LIST_HEAD(tomoyo_io_buffer_list); |
13 | /* Lock for protecting tomoyo_io_buffer_list. */ | 28 | /* Lock for protecting tomoyo_io_buffer_list. */ |
14 | static DEFINE_SPINLOCK(tomoyo_io_buffer_list_lock); | 29 | static DEFINE_SPINLOCK(tomoyo_io_buffer_list_lock); |
15 | 30 | ||
16 | /* Size of an element. */ | ||
17 | static const u8 tomoyo_element_size[TOMOYO_MAX_POLICY] = { | ||
18 | [TOMOYO_ID_GROUP] = sizeof(struct tomoyo_group), | ||
19 | [TOMOYO_ID_ADDRESS_GROUP] = sizeof(struct tomoyo_address_group), | ||
20 | [TOMOYO_ID_PATH_GROUP] = sizeof(struct tomoyo_path_group), | ||
21 | [TOMOYO_ID_NUMBER_GROUP] = sizeof(struct tomoyo_number_group), | ||
22 | [TOMOYO_ID_AGGREGATOR] = sizeof(struct tomoyo_aggregator), | ||
23 | [TOMOYO_ID_TRANSITION_CONTROL] = | ||
24 | sizeof(struct tomoyo_transition_control), | ||
25 | [TOMOYO_ID_MANAGER] = sizeof(struct tomoyo_manager), | ||
26 | /* [TOMOYO_ID_CONDITION] = "struct tomoyo_condition"->size, */ | ||
27 | /* [TOMOYO_ID_NAME] = "struct tomoyo_name"->size, */ | ||
28 | /* [TOMOYO_ID_ACL] = | ||
29 | tomoyo_acl_size["struct tomoyo_acl_info"->type], */ | ||
30 | [TOMOYO_ID_DOMAIN] = sizeof(struct tomoyo_domain_info), | ||
31 | }; | ||
32 | |||
33 | /* Size of a domain ACL element. */ | ||
34 | static const u8 tomoyo_acl_size[] = { | ||
35 | [TOMOYO_TYPE_PATH_ACL] = sizeof(struct tomoyo_path_acl), | ||
36 | [TOMOYO_TYPE_PATH2_ACL] = sizeof(struct tomoyo_path2_acl), | ||
37 | [TOMOYO_TYPE_PATH_NUMBER_ACL] = sizeof(struct tomoyo_path_number_acl), | ||
38 | [TOMOYO_TYPE_MKDEV_ACL] = sizeof(struct tomoyo_mkdev_acl), | ||
39 | [TOMOYO_TYPE_MOUNT_ACL] = sizeof(struct tomoyo_mount_acl), | ||
40 | [TOMOYO_TYPE_INET_ACL] = sizeof(struct tomoyo_inet_acl), | ||
41 | [TOMOYO_TYPE_UNIX_ACL] = sizeof(struct tomoyo_unix_acl), | ||
42 | [TOMOYO_TYPE_ENV_ACL] = sizeof(struct tomoyo_env_acl), | ||
43 | }; | ||
44 | |||
45 | /** | 31 | /** |
46 | * tomoyo_struct_used_by_io_buffer - Check whether the list element is used by /sys/kernel/security/tomoyo/ users or not. | 32 | * tomoyo_struct_used_by_io_buffer - Check whether the list element is used by /sys/kernel/security/tomoyo/ users or not. |
47 | * | 33 | * |
@@ -59,15 +45,11 @@ static bool tomoyo_struct_used_by_io_buffer(const struct list_head *element) | |||
59 | list_for_each_entry(head, &tomoyo_io_buffer_list, list) { | 45 | list_for_each_entry(head, &tomoyo_io_buffer_list, list) { |
60 | head->users++; | 46 | head->users++; |
61 | spin_unlock(&tomoyo_io_buffer_list_lock); | 47 | spin_unlock(&tomoyo_io_buffer_list_lock); |
62 | if (mutex_lock_interruptible(&head->io_sem)) { | 48 | mutex_lock(&head->io_sem); |
63 | in_use = true; | ||
64 | goto out; | ||
65 | } | ||
66 | if (head->r.domain == element || head->r.group == element || | 49 | if (head->r.domain == element || head->r.group == element || |
67 | head->r.acl == element || &head->w.domain->list == element) | 50 | head->r.acl == element || &head->w.domain->list == element) |
68 | in_use = true; | 51 | in_use = true; |
69 | mutex_unlock(&head->io_sem); | 52 | mutex_unlock(&head->io_sem); |
70 | out: | ||
71 | spin_lock(&tomoyo_io_buffer_list_lock); | 53 | spin_lock(&tomoyo_io_buffer_list_lock); |
72 | head->users--; | 54 | head->users--; |
73 | if (in_use) | 55 | if (in_use) |
@@ -81,15 +63,14 @@ out: | |||
81 | * tomoyo_name_used_by_io_buffer - Check whether the string is used by /sys/kernel/security/tomoyo/ users or not. | 63 | * tomoyo_name_used_by_io_buffer - Check whether the string is used by /sys/kernel/security/tomoyo/ users or not. |
82 | * | 64 | * |
83 | * @string: String to check. | 65 | * @string: String to check. |
84 | * @size: Memory allocated for @string . | ||
85 | * | 66 | * |
86 | * Returns true if @string is used by /sys/kernel/security/tomoyo/ users, | 67 | * Returns true if @string is used by /sys/kernel/security/tomoyo/ users, |
87 | * false otherwise. | 68 | * false otherwise. |
88 | */ | 69 | */ |
89 | static bool tomoyo_name_used_by_io_buffer(const char *string, | 70 | static bool tomoyo_name_used_by_io_buffer(const char *string) |
90 | const size_t size) | ||
91 | { | 71 | { |
92 | struct tomoyo_io_buffer *head; | 72 | struct tomoyo_io_buffer *head; |
73 | const size_t size = strlen(string) + 1; | ||
93 | bool in_use = false; | 74 | bool in_use = false; |
94 | 75 | ||
95 | spin_lock(&tomoyo_io_buffer_list_lock); | 76 | spin_lock(&tomoyo_io_buffer_list_lock); |
@@ -97,10 +78,7 @@ static bool tomoyo_name_used_by_io_buffer(const char *string, | |||
97 | int i; | 78 | int i; |
98 | head->users++; | 79 | head->users++; |
99 | spin_unlock(&tomoyo_io_buffer_list_lock); | 80 | spin_unlock(&tomoyo_io_buffer_list_lock); |
100 | if (mutex_lock_interruptible(&head->io_sem)) { | 81 | mutex_lock(&head->io_sem); |
101 | in_use = true; | ||
102 | goto out; | ||
103 | } | ||
104 | for (i = 0; i < TOMOYO_MAX_IO_READ_QUEUE; i++) { | 82 | for (i = 0; i < TOMOYO_MAX_IO_READ_QUEUE; i++) { |
105 | const char *w = head->r.w[i]; | 83 | const char *w = head->r.w[i]; |
106 | if (w < string || w > string + size) | 84 | if (w < string || w > string + size) |
@@ -109,7 +87,6 @@ static bool tomoyo_name_used_by_io_buffer(const char *string, | |||
109 | break; | 87 | break; |
110 | } | 88 | } |
111 | mutex_unlock(&head->io_sem); | 89 | mutex_unlock(&head->io_sem); |
112 | out: | ||
113 | spin_lock(&tomoyo_io_buffer_list_lock); | 90 | spin_lock(&tomoyo_io_buffer_list_lock); |
114 | head->users--; | 91 | head->users--; |
115 | if (in_use) | 92 | if (in_use) |
@@ -119,84 +96,6 @@ out: | |||
119 | return in_use; | 96 | return in_use; |
120 | } | 97 | } |
121 | 98 | ||
122 | /* Structure for garbage collection. */ | ||
123 | struct tomoyo_gc { | ||
124 | struct list_head list; | ||
125 | enum tomoyo_policy_id type; | ||
126 | size_t size; | ||
127 | struct list_head *element; | ||
128 | }; | ||
129 | /* List of entries to be deleted. */ | ||
130 | static LIST_HEAD(tomoyo_gc_list); | ||
131 | /* Length of tomoyo_gc_list. */ | ||
132 | static int tomoyo_gc_list_len; | ||
133 | |||
134 | /** | ||
135 | * tomoyo_add_to_gc - Add an entry to to be deleted list. | ||
136 | * | ||
137 | * @type: One of values in "enum tomoyo_policy_id". | ||
138 | * @element: Pointer to "struct list_head". | ||
139 | * | ||
140 | * Returns true on success, false otherwise. | ||
141 | * | ||
142 | * Caller holds tomoyo_policy_lock mutex. | ||
143 | * | ||
144 | * Adding an entry needs kmalloc(). Thus, if we try to add thousands of | ||
145 | * entries at once, it will take too long time. Thus, do not add more than 128 | ||
146 | * entries per a scan. But to be able to handle worst case where all entries | ||
147 | * are in-use, we accept one more entry per a scan. | ||
148 | * | ||
149 | * If we use singly linked list using "struct list_head"->prev (which is | ||
150 | * LIST_POISON2), we can avoid kmalloc(). | ||
151 | */ | ||
152 | static bool tomoyo_add_to_gc(const int type, struct list_head *element) | ||
153 | { | ||
154 | struct tomoyo_gc *entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | ||
155 | if (!entry) | ||
156 | return false; | ||
157 | entry->type = type; | ||
158 | if (type == TOMOYO_ID_ACL) | ||
159 | entry->size = tomoyo_acl_size[ | ||
160 | container_of(element, | ||
161 | typeof(struct tomoyo_acl_info), | ||
162 | list)->type]; | ||
163 | else if (type == TOMOYO_ID_NAME) | ||
164 | entry->size = strlen(container_of(element, | ||
165 | typeof(struct tomoyo_name), | ||
166 | head.list)->entry.name) + 1; | ||
167 | else if (type == TOMOYO_ID_CONDITION) | ||
168 | entry->size = | ||
169 | container_of(element, typeof(struct tomoyo_condition), | ||
170 | head.list)->size; | ||
171 | else | ||
172 | entry->size = tomoyo_element_size[type]; | ||
173 | entry->element = element; | ||
174 | list_add(&entry->list, &tomoyo_gc_list); | ||
175 | list_del_rcu(element); | ||
176 | return tomoyo_gc_list_len++ < 128; | ||
177 | } | ||
178 | |||
179 | /** | ||
180 | * tomoyo_element_linked_by_gc - Validate next element of an entry. | ||
181 | * | ||
182 | * @element: Pointer to an element. | ||
183 | * @size: Size of @element in byte. | ||
184 | * | ||
185 | * Returns true if @element is linked by other elements in the garbage | ||
186 | * collector's queue, false otherwise. | ||
187 | */ | ||
188 | static bool tomoyo_element_linked_by_gc(const u8 *element, const size_t size) | ||
189 | { | ||
190 | struct tomoyo_gc *p; | ||
191 | list_for_each_entry(p, &tomoyo_gc_list, list) { | ||
192 | const u8 *ptr = (const u8 *) p->element->next; | ||
193 | if (ptr < element || element + size < ptr) | ||
194 | continue; | ||
195 | return true; | ||
196 | } | ||
197 | return false; | ||
198 | } | ||
199 | |||
200 | /** | 99 | /** |
201 | * tomoyo_del_transition_control - Delete members in "struct tomoyo_transition_control". | 100 | * tomoyo_del_transition_control - Delete members in "struct tomoyo_transition_control". |
202 | * | 101 | * |
@@ -204,7 +103,7 @@ static bool tomoyo_element_linked_by_gc(const u8 *element, const size_t size) | |||
204 | * | 103 | * |
205 | * Returns nothing. | 104 | * Returns nothing. |
206 | */ | 105 | */ |
207 | static void tomoyo_del_transition_control(struct list_head *element) | 106 | static inline void tomoyo_del_transition_control(struct list_head *element) |
208 | { | 107 | { |
209 | struct tomoyo_transition_control *ptr = | 108 | struct tomoyo_transition_control *ptr = |
210 | container_of(element, typeof(*ptr), head.list); | 109 | container_of(element, typeof(*ptr), head.list); |
@@ -219,7 +118,7 @@ static void tomoyo_del_transition_control(struct list_head *element) | |||
219 | * | 118 | * |
220 | * Returns nothing. | 119 | * Returns nothing. |
221 | */ | 120 | */ |
222 | static void tomoyo_del_aggregator(struct list_head *element) | 121 | static inline void tomoyo_del_aggregator(struct list_head *element) |
223 | { | 122 | { |
224 | struct tomoyo_aggregator *ptr = | 123 | struct tomoyo_aggregator *ptr = |
225 | container_of(element, typeof(*ptr), head.list); | 124 | container_of(element, typeof(*ptr), head.list); |
@@ -234,7 +133,7 @@ static void tomoyo_del_aggregator(struct list_head *element) | |||
234 | * | 133 | * |
235 | * Returns nothing. | 134 | * Returns nothing. |
236 | */ | 135 | */ |
237 | static void tomoyo_del_manager(struct list_head *element) | 136 | static inline void tomoyo_del_manager(struct list_head *element) |
238 | { | 137 | { |
239 | struct tomoyo_manager *ptr = | 138 | struct tomoyo_manager *ptr = |
240 | container_of(element, typeof(*ptr), head.list); | 139 | container_of(element, typeof(*ptr), head.list); |
@@ -330,44 +229,26 @@ static void tomoyo_del_acl(struct list_head *element) | |||
330 | * | 229 | * |
331 | * @element: Pointer to "struct list_head". | 230 | * @element: Pointer to "struct list_head". |
332 | * | 231 | * |
333 | * Returns true if deleted, false otherwise. | 232 | * Returns nothing. |
233 | * | ||
234 | * Caller holds tomoyo_policy_lock mutex. | ||
334 | */ | 235 | */ |
335 | static bool tomoyo_del_domain(struct list_head *element) | 236 | static inline void tomoyo_del_domain(struct list_head *element) |
336 | { | 237 | { |
337 | struct tomoyo_domain_info *domain = | 238 | struct tomoyo_domain_info *domain = |
338 | container_of(element, typeof(*domain), list); | 239 | container_of(element, typeof(*domain), list); |
339 | struct tomoyo_acl_info *acl; | 240 | struct tomoyo_acl_info *acl; |
340 | struct tomoyo_acl_info *tmp; | 241 | struct tomoyo_acl_info *tmp; |
341 | /* | 242 | /* |
342 | * Since we don't protect whole execve() operation using SRCU, | 243 | * Since this domain is referenced from neither |
343 | * we need to recheck domain->users at this point. | 244 | * "struct tomoyo_io_buffer" nor "struct cred"->security, we can delete |
344 | * | 245 | * elements without checking for is_deleted flag. |
345 | * (1) Reader starts SRCU section upon execve(). | ||
346 | * (2) Reader traverses tomoyo_domain_list and finds this domain. | ||
347 | * (3) Writer marks this domain as deleted. | ||
348 | * (4) Garbage collector removes this domain from tomoyo_domain_list | ||
349 | * because this domain is marked as deleted and used by nobody. | ||
350 | * (5) Reader saves reference to this domain into | ||
351 | * "struct linux_binprm"->cred->security . | ||
352 | * (6) Reader finishes SRCU section, although execve() operation has | ||
353 | * not finished yet. | ||
354 | * (7) Garbage collector waits for SRCU synchronization. | ||
355 | * (8) Garbage collector kfree() this domain because this domain is | ||
356 | * used by nobody. | ||
357 | * (9) Reader finishes execve() operation and restores this domain from | ||
358 | * "struct linux_binprm"->cred->security. | ||
359 | * | ||
360 | * By updating domain->users at (5), we can solve this race problem | ||
361 | * by rechecking domain->users at (8). | ||
362 | */ | 246 | */ |
363 | if (atomic_read(&domain->users)) | ||
364 | return false; | ||
365 | list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) { | 247 | list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) { |
366 | tomoyo_del_acl(&acl->list); | 248 | tomoyo_del_acl(&acl->list); |
367 | tomoyo_memory_free(acl); | 249 | tomoyo_memory_free(acl); |
368 | } | 250 | } |
369 | tomoyo_put_name(domain->domainname); | 251 | tomoyo_put_name(domain->domainname); |
370 | return true; | ||
371 | } | 252 | } |
372 | 253 | ||
373 | /** | 254 | /** |
@@ -416,10 +297,9 @@ void tomoyo_del_condition(struct list_head *element) | |||
416 | * | 297 | * |
417 | * Returns nothing. | 298 | * Returns nothing. |
418 | */ | 299 | */ |
419 | static void tomoyo_del_name(struct list_head *element) | 300 | static inline void tomoyo_del_name(struct list_head *element) |
420 | { | 301 | { |
421 | const struct tomoyo_name *ptr = | 302 | /* Nothing to do. */ |
422 | container_of(element, typeof(*ptr), head.list); | ||
423 | } | 303 | } |
424 | 304 | ||
425 | /** | 305 | /** |
@@ -429,7 +309,7 @@ static void tomoyo_del_name(struct list_head *element) | |||
429 | * | 309 | * |
430 | * Returns nothing. | 310 | * Returns nothing. |
431 | */ | 311 | */ |
432 | static void tomoyo_del_path_group(struct list_head *element) | 312 | static inline void tomoyo_del_path_group(struct list_head *element) |
433 | { | 313 | { |
434 | struct tomoyo_path_group *member = | 314 | struct tomoyo_path_group *member = |
435 | container_of(element, typeof(*member), head.list); | 315 | container_of(element, typeof(*member), head.list); |
@@ -443,7 +323,7 @@ static void tomoyo_del_path_group(struct list_head *element) | |||
443 | * | 323 | * |
444 | * Returns nothing. | 324 | * Returns nothing. |
445 | */ | 325 | */ |
446 | static void tomoyo_del_group(struct list_head *element) | 326 | static inline void tomoyo_del_group(struct list_head *element) |
447 | { | 327 | { |
448 | struct tomoyo_group *group = | 328 | struct tomoyo_group *group = |
449 | container_of(element, typeof(*group), head.list); | 329 | container_of(element, typeof(*group), head.list); |
@@ -469,10 +349,110 @@ static inline void tomoyo_del_address_group(struct list_head *element) | |||
469 | * | 349 | * |
470 | * Returns nothing. | 350 | * Returns nothing. |
471 | */ | 351 | */ |
472 | static void tomoyo_del_number_group(struct list_head *element) | 352 | static inline void tomoyo_del_number_group(struct list_head *element) |
473 | { | 353 | { |
474 | struct tomoyo_number_group *member = | 354 | /* Nothing to do. */ |
475 | container_of(element, typeof(*member), head.list); | 355 | } |
356 | |||
357 | /** | ||
358 | * tomoyo_try_to_gc - Try to kfree() an entry. | ||
359 | * | ||
360 | * @type: One of values in "enum tomoyo_policy_id". | ||
361 | * @element: Pointer to "struct list_head". | ||
362 | * | ||
363 | * Returns nothing. | ||
364 | * | ||
365 | * Caller holds tomoyo_policy_lock mutex. | ||
366 | */ | ||
367 | static void tomoyo_try_to_gc(const enum tomoyo_policy_id type, | ||
368 | struct list_head *element) | ||
369 | { | ||
370 | /* | ||
371 | * __list_del_entry() guarantees that the list element became no longer | ||
372 | * reachable from the list which the element was originally on (e.g. | ||
373 | * tomoyo_domain_list). Also, synchronize_srcu() guarantees that the | ||
374 | * list element became no longer referenced by syscall users. | ||
375 | */ | ||
376 | __list_del_entry(element); | ||
377 | mutex_unlock(&tomoyo_policy_lock); | ||
378 | synchronize_srcu(&tomoyo_ss); | ||
379 | /* | ||
380 | * However, there are two users which may still be using the list | ||
381 | * element. We need to defer until both users forget this element. | ||
382 | * | ||
383 | * Don't kfree() until "struct tomoyo_io_buffer"->r.{domain,group,acl} | ||
384 | * and "struct tomoyo_io_buffer"->w.domain forget this element. | ||
385 | */ | ||
386 | if (tomoyo_struct_used_by_io_buffer(element)) | ||
387 | goto reinject; | ||
388 | switch (type) { | ||
389 | case TOMOYO_ID_TRANSITION_CONTROL: | ||
390 | tomoyo_del_transition_control(element); | ||
391 | break; | ||
392 | case TOMOYO_ID_MANAGER: | ||
393 | tomoyo_del_manager(element); | ||
394 | break; | ||
395 | case TOMOYO_ID_AGGREGATOR: | ||
396 | tomoyo_del_aggregator(element); | ||
397 | break; | ||
398 | case TOMOYO_ID_GROUP: | ||
399 | tomoyo_del_group(element); | ||
400 | break; | ||
401 | case TOMOYO_ID_PATH_GROUP: | ||
402 | tomoyo_del_path_group(element); | ||
403 | break; | ||
404 | case TOMOYO_ID_ADDRESS_GROUP: | ||
405 | tomoyo_del_address_group(element); | ||
406 | break; | ||
407 | case TOMOYO_ID_NUMBER_GROUP: | ||
408 | tomoyo_del_number_group(element); | ||
409 | break; | ||
410 | case TOMOYO_ID_CONDITION: | ||
411 | tomoyo_del_condition(element); | ||
412 | break; | ||
413 | case TOMOYO_ID_NAME: | ||
414 | /* | ||
415 | * Don't kfree() until all "struct tomoyo_io_buffer"->r.w[] | ||
416 | * forget this element. | ||
417 | */ | ||
418 | if (tomoyo_name_used_by_io_buffer | ||
419 | (container_of(element, typeof(struct tomoyo_name), | ||
420 | head.list)->entry.name)) | ||
421 | goto reinject; | ||
422 | tomoyo_del_name(element); | ||
423 | break; | ||
424 | case TOMOYO_ID_ACL: | ||
425 | tomoyo_del_acl(element); | ||
426 | break; | ||
427 | case TOMOYO_ID_DOMAIN: | ||
428 | /* | ||
429 | * Don't kfree() until all "struct cred"->security forget this | ||
430 | * element. | ||
431 | */ | ||
432 | if (atomic_read(&container_of | ||
433 | (element, typeof(struct tomoyo_domain_info), | ||
434 | list)->users)) | ||
435 | goto reinject; | ||
436 | break; | ||
437 | case TOMOYO_MAX_POLICY: | ||
438 | break; | ||
439 | } | ||
440 | mutex_lock(&tomoyo_policy_lock); | ||
441 | if (type == TOMOYO_ID_DOMAIN) | ||
442 | tomoyo_del_domain(element); | ||
443 | tomoyo_memory_free(element); | ||
444 | return; | ||
445 | reinject: | ||
446 | /* | ||
447 | * We can safely reinject this element here bacause | ||
448 | * (1) Appending list elements and removing list elements are protected | ||
449 | * by tomoyo_policy_lock mutex. | ||
450 | * (2) Only this function removes list elements and this function is | ||
451 | * exclusively executed by tomoyo_gc_mutex mutex. | ||
452 | * are true. | ||
453 | */ | ||
454 | mutex_lock(&tomoyo_policy_lock); | ||
455 | list_add_rcu(element, element->prev); | ||
476 | } | 456 | } |
477 | 457 | ||
478 | /** | 458 | /** |
@@ -481,19 +461,19 @@ static void tomoyo_del_number_group(struct list_head *element) | |||
481 | * @id: One of values in "enum tomoyo_policy_id". | 461 | * @id: One of values in "enum tomoyo_policy_id". |
482 | * @member_list: Pointer to "struct list_head". | 462 | * @member_list: Pointer to "struct list_head". |
483 | * | 463 | * |
484 | * Returns true if some elements are deleted, false otherwise. | 464 | * Returns nothing. |
485 | */ | 465 | */ |
486 | static bool tomoyo_collect_member(const enum tomoyo_policy_id id, | 466 | static void tomoyo_collect_member(const enum tomoyo_policy_id id, |
487 | struct list_head *member_list) | 467 | struct list_head *member_list) |
488 | { | 468 | { |
489 | struct tomoyo_acl_head *member; | 469 | struct tomoyo_acl_head *member; |
490 | list_for_each_entry(member, member_list, list) { | 470 | struct tomoyo_acl_head *tmp; |
471 | list_for_each_entry_safe(member, tmp, member_list, list) { | ||
491 | if (!member->is_deleted) | 472 | if (!member->is_deleted) |
492 | continue; | 473 | continue; |
493 | if (!tomoyo_add_to_gc(id, &member->list)) | 474 | member->is_deleted = TOMOYO_GC_IN_PROGRESS; |
494 | return false; | 475 | tomoyo_try_to_gc(id, &member->list); |
495 | } | 476 | } |
496 | return true; | ||
497 | } | 477 | } |
498 | 478 | ||
499 | /** | 479 | /** |
@@ -501,22 +481,22 @@ static bool tomoyo_collect_member(const enum tomoyo_policy_id id, | |||
501 | * | 481 | * |
502 | * @list: Pointer to "struct list_head". | 482 | * @list: Pointer to "struct list_head". |
503 | * | 483 | * |
504 | * Returns true if some elements are deleted, false otherwise. | 484 | * Returns nothing. |
505 | */ | 485 | */ |
506 | static bool tomoyo_collect_acl(struct list_head *list) | 486 | static void tomoyo_collect_acl(struct list_head *list) |
507 | { | 487 | { |
508 | struct tomoyo_acl_info *acl; | 488 | struct tomoyo_acl_info *acl; |
509 | list_for_each_entry(acl, list, list) { | 489 | struct tomoyo_acl_info *tmp; |
490 | list_for_each_entry_safe(acl, tmp, list, list) { | ||
510 | if (!acl->is_deleted) | 491 | if (!acl->is_deleted) |
511 | continue; | 492 | continue; |
512 | if (!tomoyo_add_to_gc(TOMOYO_ID_ACL, &acl->list)) | 493 | acl->is_deleted = TOMOYO_GC_IN_PROGRESS; |
513 | return false; | 494 | tomoyo_try_to_gc(TOMOYO_ID_ACL, &acl->list); |
514 | } | 495 | } |
515 | return true; | ||
516 | } | 496 | } |
517 | 497 | ||
518 | /** | 498 | /** |
519 | * tomoyo_collect_entry - Scan lists for deleted elements. | 499 | * tomoyo_collect_entry - Try to kfree() deleted elements. |
520 | * | 500 | * |
521 | * Returns nothing. | 501 | * Returns nothing. |
522 | */ | 502 | */ |
@@ -525,36 +505,40 @@ static void tomoyo_collect_entry(void) | |||
525 | int i; | 505 | int i; |
526 | enum tomoyo_policy_id id; | 506 | enum tomoyo_policy_id id; |
527 | struct tomoyo_policy_namespace *ns; | 507 | struct tomoyo_policy_namespace *ns; |
528 | int idx; | 508 | mutex_lock(&tomoyo_policy_lock); |
529 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | ||
530 | return; | ||
531 | idx = tomoyo_read_lock(); | ||
532 | { | 509 | { |
533 | struct tomoyo_domain_info *domain; | 510 | struct tomoyo_domain_info *domain; |
534 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | 511 | struct tomoyo_domain_info *tmp; |
535 | if (!tomoyo_collect_acl(&domain->acl_info_list)) | 512 | list_for_each_entry_safe(domain, tmp, &tomoyo_domain_list, |
536 | goto unlock; | 513 | list) { |
514 | tomoyo_collect_acl(&domain->acl_info_list); | ||
537 | if (!domain->is_deleted || atomic_read(&domain->users)) | 515 | if (!domain->is_deleted || atomic_read(&domain->users)) |
538 | continue; | 516 | continue; |
539 | /* | 517 | tomoyo_try_to_gc(TOMOYO_ID_DOMAIN, &domain->list); |
540 | * Nobody is referring this domain. But somebody may | ||
541 | * refer this domain after successful execve(). | ||
542 | * We recheck domain->users after SRCU synchronization. | ||
543 | */ | ||
544 | if (!tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, &domain->list)) | ||
545 | goto unlock; | ||
546 | } | 518 | } |
547 | } | 519 | } |
548 | list_for_each_entry_rcu(ns, &tomoyo_namespace_list, namespace_list) { | 520 | list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) { |
549 | for (id = 0; id < TOMOYO_MAX_POLICY; id++) | 521 | for (id = 0; id < TOMOYO_MAX_POLICY; id++) |
550 | if (!tomoyo_collect_member(id, &ns->policy_list[id])) | 522 | tomoyo_collect_member(id, &ns->policy_list[id]); |
551 | goto unlock; | ||
552 | for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++) | 523 | for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++) |
553 | if (!tomoyo_collect_acl(&ns->acl_group[i])) | 524 | tomoyo_collect_acl(&ns->acl_group[i]); |
554 | goto unlock; | 525 | } |
526 | { | ||
527 | struct tomoyo_shared_acl_head *ptr; | ||
528 | struct tomoyo_shared_acl_head *tmp; | ||
529 | list_for_each_entry_safe(ptr, tmp, &tomoyo_condition_list, | ||
530 | list) { | ||
531 | if (atomic_read(&ptr->users) > 0) | ||
532 | continue; | ||
533 | atomic_set(&ptr->users, TOMOYO_GC_IN_PROGRESS); | ||
534 | tomoyo_try_to_gc(TOMOYO_ID_CONDITION, &ptr->list); | ||
535 | } | ||
536 | } | ||
537 | list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) { | ||
555 | for (i = 0; i < TOMOYO_MAX_GROUP; i++) { | 538 | for (i = 0; i < TOMOYO_MAX_GROUP; i++) { |
556 | struct list_head *list = &ns->group_list[i]; | 539 | struct list_head *list = &ns->group_list[i]; |
557 | struct tomoyo_group *group; | 540 | struct tomoyo_group *group; |
541 | struct tomoyo_group *tmp; | ||
558 | switch (i) { | 542 | switch (i) { |
559 | case 0: | 543 | case 0: |
560 | id = TOMOYO_ID_PATH_GROUP; | 544 | id = TOMOYO_ID_PATH_GROUP; |
@@ -566,139 +550,37 @@ static void tomoyo_collect_entry(void) | |||
566 | id = TOMOYO_ID_ADDRESS_GROUP; | 550 | id = TOMOYO_ID_ADDRESS_GROUP; |
567 | break; | 551 | break; |
568 | } | 552 | } |
569 | list_for_each_entry(group, list, head.list) { | 553 | list_for_each_entry_safe(group, tmp, list, head.list) { |
570 | if (!tomoyo_collect_member | 554 | tomoyo_collect_member(id, &group->member_list); |
571 | (id, &group->member_list)) | ||
572 | goto unlock; | ||
573 | if (!list_empty(&group->member_list) || | 555 | if (!list_empty(&group->member_list) || |
574 | atomic_read(&group->head.users)) | 556 | atomic_read(&group->head.users) > 0) |
575 | continue; | 557 | continue; |
576 | if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP, | 558 | atomic_set(&group->head.users, |
577 | &group->head.list)) | 559 | TOMOYO_GC_IN_PROGRESS); |
578 | goto unlock; | 560 | tomoyo_try_to_gc(TOMOYO_ID_GROUP, |
561 | &group->head.list); | ||
579 | } | 562 | } |
580 | } | 563 | } |
581 | } | 564 | } |
582 | id = TOMOYO_ID_CONDITION; | 565 | for (i = 0; i < TOMOYO_MAX_HASH; i++) { |
583 | for (i = 0; i < TOMOYO_MAX_HASH + 1; i++) { | 566 | struct list_head *list = &tomoyo_name_list[i]; |
584 | struct list_head *list = !i ? | ||
585 | &tomoyo_condition_list : &tomoyo_name_list[i - 1]; | ||
586 | struct tomoyo_shared_acl_head *ptr; | 567 | struct tomoyo_shared_acl_head *ptr; |
587 | list_for_each_entry(ptr, list, list) { | 568 | struct tomoyo_shared_acl_head *tmp; |
588 | if (atomic_read(&ptr->users)) | 569 | list_for_each_entry_safe(ptr, tmp, list, list) { |
570 | if (atomic_read(&ptr->users) > 0) | ||
589 | continue; | 571 | continue; |
590 | if (!tomoyo_add_to_gc(id, &ptr->list)) | 572 | atomic_set(&ptr->users, TOMOYO_GC_IN_PROGRESS); |
591 | goto unlock; | 573 | tomoyo_try_to_gc(TOMOYO_ID_NAME, &ptr->list); |
592 | } | 574 | } |
593 | id = TOMOYO_ID_NAME; | ||
594 | } | 575 | } |
595 | unlock: | ||
596 | tomoyo_read_unlock(idx); | ||
597 | mutex_unlock(&tomoyo_policy_lock); | 576 | mutex_unlock(&tomoyo_policy_lock); |
598 | } | 577 | } |
599 | 578 | ||
600 | /** | 579 | /** |
601 | * tomoyo_kfree_entry - Delete entries in tomoyo_gc_list. | ||
602 | * | ||
603 | * Returns true if some entries were kfree()d, false otherwise. | ||
604 | */ | ||
605 | static bool tomoyo_kfree_entry(void) | ||
606 | { | ||
607 | struct tomoyo_gc *p; | ||
608 | struct tomoyo_gc *tmp; | ||
609 | bool result = false; | ||
610 | |||
611 | list_for_each_entry_safe(p, tmp, &tomoyo_gc_list, list) { | ||
612 | struct list_head *element = p->element; | ||
613 | |||
614 | /* | ||
615 | * list_del_rcu() in tomoyo_add_to_gc() guarantees that the | ||
616 | * list element became no longer reachable from the list which | ||
617 | * the element was originally on (e.g. tomoyo_domain_list). | ||
618 | * Also, synchronize_srcu() in tomoyo_gc_thread() guarantees | ||
619 | * that the list element became no longer referenced by syscall | ||
620 | * users. | ||
621 | * | ||
622 | * However, there are three users which may still be using the | ||
623 | * list element. We need to defer until all of these users | ||
624 | * forget the list element. | ||
625 | * | ||
626 | * Firstly, defer until "struct tomoyo_io_buffer"->r.{domain, | ||
627 | * group,acl} and "struct tomoyo_io_buffer"->w.domain forget | ||
628 | * the list element. | ||
629 | */ | ||
630 | if (tomoyo_struct_used_by_io_buffer(element)) | ||
631 | continue; | ||
632 | /* | ||
633 | * Secondly, defer until all other elements in the | ||
634 | * tomoyo_gc_list list forget the list element. | ||
635 | */ | ||
636 | if (tomoyo_element_linked_by_gc((const u8 *) element, p->size)) | ||
637 | continue; | ||
638 | switch (p->type) { | ||
639 | case TOMOYO_ID_TRANSITION_CONTROL: | ||
640 | tomoyo_del_transition_control(element); | ||
641 | break; | ||
642 | case TOMOYO_ID_AGGREGATOR: | ||
643 | tomoyo_del_aggregator(element); | ||
644 | break; | ||
645 | case TOMOYO_ID_MANAGER: | ||
646 | tomoyo_del_manager(element); | ||
647 | break; | ||
648 | case TOMOYO_ID_CONDITION: | ||
649 | tomoyo_del_condition(element); | ||
650 | break; | ||
651 | case TOMOYO_ID_NAME: | ||
652 | /* | ||
653 | * Thirdly, defer until all "struct tomoyo_io_buffer" | ||
654 | * ->r.w[] forget the list element. | ||
655 | */ | ||
656 | if (tomoyo_name_used_by_io_buffer( | ||
657 | container_of(element, typeof(struct tomoyo_name), | ||
658 | head.list)->entry.name, p->size)) | ||
659 | continue; | ||
660 | tomoyo_del_name(element); | ||
661 | break; | ||
662 | case TOMOYO_ID_ACL: | ||
663 | tomoyo_del_acl(element); | ||
664 | break; | ||
665 | case TOMOYO_ID_DOMAIN: | ||
666 | if (!tomoyo_del_domain(element)) | ||
667 | continue; | ||
668 | break; | ||
669 | case TOMOYO_ID_PATH_GROUP: | ||
670 | tomoyo_del_path_group(element); | ||
671 | break; | ||
672 | case TOMOYO_ID_ADDRESS_GROUP: | ||
673 | tomoyo_del_address_group(element); | ||
674 | break; | ||
675 | case TOMOYO_ID_GROUP: | ||
676 | tomoyo_del_group(element); | ||
677 | break; | ||
678 | case TOMOYO_ID_NUMBER_GROUP: | ||
679 | tomoyo_del_number_group(element); | ||
680 | break; | ||
681 | case TOMOYO_MAX_POLICY: | ||
682 | break; | ||
683 | } | ||
684 | tomoyo_memory_free(element); | ||
685 | list_del(&p->list); | ||
686 | kfree(p); | ||
687 | tomoyo_gc_list_len--; | ||
688 | result = true; | ||
689 | } | ||
690 | return result; | ||
691 | } | ||
692 | |||
693 | /** | ||
694 | * tomoyo_gc_thread - Garbage collector thread function. | 580 | * tomoyo_gc_thread - Garbage collector thread function. |
695 | * | 581 | * |
696 | * @unused: Unused. | 582 | * @unused: Unused. |
697 | * | 583 | * |
698 | * In case OOM-killer choose this thread for termination, we create this thread | ||
699 | * as a short live thread whenever /sys/kernel/security/tomoyo/ interface was | ||
700 | * close()d. | ||
701 | * | ||
702 | * Returns 0. | 584 | * Returns 0. |
703 | */ | 585 | */ |
704 | static int tomoyo_gc_thread(void *unused) | 586 | static int tomoyo_gc_thread(void *unused) |
@@ -707,13 +589,7 @@ static int tomoyo_gc_thread(void *unused) | |||
707 | static DEFINE_MUTEX(tomoyo_gc_mutex); | 589 | static DEFINE_MUTEX(tomoyo_gc_mutex); |
708 | if (!mutex_trylock(&tomoyo_gc_mutex)) | 590 | if (!mutex_trylock(&tomoyo_gc_mutex)) |
709 | goto out; | 591 | goto out; |
710 | 592 | tomoyo_collect_entry(); | |
711 | do { | ||
712 | tomoyo_collect_entry(); | ||
713 | if (list_empty(&tomoyo_gc_list)) | ||
714 | break; | ||
715 | synchronize_srcu(&tomoyo_ss); | ||
716 | } while (tomoyo_kfree_entry()); | ||
717 | { | 593 | { |
718 | struct tomoyo_io_buffer *head; | 594 | struct tomoyo_io_buffer *head; |
719 | struct tomoyo_io_buffer *tmp; | 595 | struct tomoyo_io_buffer *tmp; |
diff --git a/security/tomoyo/memory.c b/security/tomoyo/memory.c index 7a56051146c2..0e995716cc25 100644 --- a/security/tomoyo/memory.c +++ b/security/tomoyo/memory.c | |||
@@ -27,8 +27,6 @@ void tomoyo_warn_oom(const char *function) | |||
27 | panic("MAC Initialization failed.\n"); | 27 | panic("MAC Initialization failed.\n"); |
28 | } | 28 | } |
29 | 29 | ||
30 | /* Lock for protecting tomoyo_memory_used. */ | ||
31 | static DEFINE_SPINLOCK(tomoyo_policy_memory_lock); | ||
32 | /* Memoy currently used by policy/audit log/query. */ | 30 | /* Memoy currently used by policy/audit log/query. */ |
33 | unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT]; | 31 | unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT]; |
34 | /* Memory quota for "policy"/"audit log"/"query". */ | 32 | /* Memory quota for "policy"/"audit log"/"query". */ |
@@ -42,22 +40,19 @@ unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT]; | |||
42 | * Returns true on success, false otherwise. | 40 | * Returns true on success, false otherwise. |
43 | * | 41 | * |
44 | * Returns true if @ptr is not NULL and quota not exceeded, false otherwise. | 42 | * Returns true if @ptr is not NULL and quota not exceeded, false otherwise. |
43 | * | ||
44 | * Caller holds tomoyo_policy_lock mutex. | ||
45 | */ | 45 | */ |
46 | bool tomoyo_memory_ok(void *ptr) | 46 | bool tomoyo_memory_ok(void *ptr) |
47 | { | 47 | { |
48 | if (ptr) { | 48 | if (ptr) { |
49 | const size_t s = ksize(ptr); | 49 | const size_t s = ksize(ptr); |
50 | bool result; | ||
51 | spin_lock(&tomoyo_policy_memory_lock); | ||
52 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] += s; | 50 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] += s; |
53 | result = !tomoyo_memory_quota[TOMOYO_MEMORY_POLICY] || | 51 | if (!tomoyo_memory_quota[TOMOYO_MEMORY_POLICY] || |
54 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] <= | 52 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] <= |
55 | tomoyo_memory_quota[TOMOYO_MEMORY_POLICY]; | 53 | tomoyo_memory_quota[TOMOYO_MEMORY_POLICY]) |
56 | if (!result) | ||
57 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= s; | ||
58 | spin_unlock(&tomoyo_policy_memory_lock); | ||
59 | if (result) | ||
60 | return true; | 54 | return true; |
55 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= s; | ||
61 | } | 56 | } |
62 | tomoyo_warn_oom(__func__); | 57 | tomoyo_warn_oom(__func__); |
63 | return false; | 58 | return false; |
@@ -71,6 +66,8 @@ bool tomoyo_memory_ok(void *ptr) | |||
71 | * | 66 | * |
72 | * Returns pointer to allocated memory on success, NULL otherwise. | 67 | * Returns pointer to allocated memory on success, NULL otherwise. |
73 | * @data is zero-cleared on success. | 68 | * @data is zero-cleared on success. |
69 | * | ||
70 | * Caller holds tomoyo_policy_lock mutex. | ||
74 | */ | 71 | */ |
75 | void *tomoyo_commit_ok(void *data, const unsigned int size) | 72 | void *tomoyo_commit_ok(void *data, const unsigned int size) |
76 | { | 73 | { |
@@ -85,20 +82,6 @@ void *tomoyo_commit_ok(void *data, const unsigned int size) | |||
85 | } | 82 | } |
86 | 83 | ||
87 | /** | 84 | /** |
88 | * tomoyo_memory_free - Free memory for elements. | ||
89 | * | ||
90 | * @ptr: Pointer to allocated memory. | ||
91 | */ | ||
92 | void tomoyo_memory_free(void *ptr) | ||
93 | { | ||
94 | size_t s = ksize(ptr); | ||
95 | spin_lock(&tomoyo_policy_memory_lock); | ||
96 | tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= s; | ||
97 | spin_unlock(&tomoyo_policy_memory_lock); | ||
98 | kfree(ptr); | ||
99 | } | ||
100 | |||
101 | /** | ||
102 | * tomoyo_get_group - Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group". | 85 | * tomoyo_get_group - Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group". |
103 | * | 86 | * |
104 | * @param: Pointer to "struct tomoyo_acl_param". | 87 | * @param: Pointer to "struct tomoyo_acl_param". |
@@ -123,7 +106,8 @@ struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param, | |||
123 | goto out; | 106 | goto out; |
124 | list = ¶m->ns->group_list[idx]; | 107 | list = ¶m->ns->group_list[idx]; |
125 | list_for_each_entry(group, list, head.list) { | 108 | list_for_each_entry(group, list, head.list) { |
126 | if (e.group_name != group->group_name) | 109 | if (e.group_name != group->group_name || |
110 | atomic_read(&group->head.users) == TOMOYO_GC_IN_PROGRESS) | ||
127 | continue; | 111 | continue; |
128 | atomic_inc(&group->head.users); | 112 | atomic_inc(&group->head.users); |
129 | found = true; | 113 | found = true; |
@@ -175,7 +159,8 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name) | |||
175 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 159 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
176 | return NULL; | 160 | return NULL; |
177 | list_for_each_entry(ptr, head, head.list) { | 161 | list_for_each_entry(ptr, head, head.list) { |
178 | if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name)) | 162 | if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name) || |
163 | atomic_read(&ptr->head.users) == TOMOYO_GC_IN_PROGRESS) | ||
179 | continue; | 164 | continue; |
180 | atomic_inc(&ptr->head.users); | 165 | atomic_inc(&ptr->head.users); |
181 | goto out; | 166 | goto out; |
diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c index d08296a4882b..2672ac4f3beb 100644 --- a/security/tomoyo/securityfs_if.c +++ b/security/tomoyo/securityfs_if.c | |||
@@ -265,6 +265,7 @@ static int __init tomoyo_initerface_init(void) | |||
265 | TOMOYO_VERSION); | 265 | TOMOYO_VERSION); |
266 | securityfs_create_file("self_domain", 0666, tomoyo_dir, NULL, | 266 | securityfs_create_file("self_domain", 0666, tomoyo_dir, NULL, |
267 | &tomoyo_self_operations); | 267 | &tomoyo_self_operations); |
268 | tomoyo_load_builtin_policy(); | ||
268 | return 0; | 269 | return 0; |
269 | } | 270 | } |
270 | 271 | ||