diff options
Diffstat (limited to 'security/tomoyo/gc.c')
-rw-r--r-- | security/tomoyo/gc.c | 127 |
1 files changed, 114 insertions, 13 deletions
diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c index ba799b49ee3a..de14030823cd 100644 --- a/security/tomoyo/gc.c +++ b/security/tomoyo/gc.c | |||
@@ -13,13 +13,30 @@ | |||
13 | 13 | ||
14 | struct tomoyo_gc { | 14 | struct tomoyo_gc { |
15 | struct list_head list; | 15 | struct list_head list; |
16 | int type; | 16 | enum tomoyo_policy_id type; |
17 | struct list_head *element; | 17 | struct list_head *element; |
18 | }; | 18 | }; |
19 | static LIST_HEAD(tomoyo_gc_queue); | 19 | static LIST_HEAD(tomoyo_gc_queue); |
20 | static DEFINE_MUTEX(tomoyo_gc_mutex); | 20 | static DEFINE_MUTEX(tomoyo_gc_mutex); |
21 | 21 | ||
22 | /* Caller holds tomoyo_policy_lock mutex. */ | 22 | /** |
23 | * tomoyo_add_to_gc - Add an entry to to be deleted list. | ||
24 | * | ||
25 | * @type: One of values in "enum tomoyo_policy_id". | ||
26 | * @element: Pointer to "struct list_head". | ||
27 | * | ||
28 | * Returns true on success, false otherwise. | ||
29 | * | ||
30 | * Caller holds tomoyo_policy_lock mutex. | ||
31 | * | ||
32 | * Adding an entry needs kmalloc(). Thus, if we try to add thousands of | ||
33 | * entries at once, it will take too long time. Thus, do not add more than 128 | ||
34 | * entries per a scan. But to be able to handle worst case where all entries | ||
35 | * are in-use, we accept one more entry per a scan. | ||
36 | * | ||
37 | * If we use singly linked list using "struct list_head"->prev (which is | ||
38 | * LIST_POISON2), we can avoid kmalloc(). | ||
39 | */ | ||
23 | static bool tomoyo_add_to_gc(const int type, struct list_head *element) | 40 | static bool tomoyo_add_to_gc(const int type, struct list_head *element) |
24 | { | 41 | { |
25 | struct tomoyo_gc *entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | 42 | struct tomoyo_gc *entry = kzalloc(sizeof(*entry), GFP_ATOMIC); |
@@ -32,6 +49,13 @@ static bool tomoyo_add_to_gc(const int type, struct list_head *element) | |||
32 | return true; | 49 | return true; |
33 | } | 50 | } |
34 | 51 | ||
52 | /** | ||
53 | * tomoyo_del_transition_control - Delete members in "struct tomoyo_transition_control". | ||
54 | * | ||
55 | * @element: Pointer to "struct list_head". | ||
56 | * | ||
57 | * Returns nothing. | ||
58 | */ | ||
35 | static void tomoyo_del_transition_control(struct list_head *element) | 59 | static void tomoyo_del_transition_control(struct list_head *element) |
36 | { | 60 | { |
37 | struct tomoyo_transition_control *ptr = | 61 | struct tomoyo_transition_control *ptr = |
@@ -40,6 +64,13 @@ static void tomoyo_del_transition_control(struct list_head *element) | |||
40 | tomoyo_put_name(ptr->program); | 64 | tomoyo_put_name(ptr->program); |
41 | } | 65 | } |
42 | 66 | ||
67 | /** | ||
68 | * tomoyo_del_aggregator - Delete members in "struct tomoyo_aggregator". | ||
69 | * | ||
70 | * @element: Pointer to "struct list_head". | ||
71 | * | ||
72 | * Returns nothing. | ||
73 | */ | ||
43 | static void tomoyo_del_aggregator(struct list_head *element) | 74 | static void tomoyo_del_aggregator(struct list_head *element) |
44 | { | 75 | { |
45 | struct tomoyo_aggregator *ptr = | 76 | struct tomoyo_aggregator *ptr = |
@@ -48,6 +79,13 @@ static void tomoyo_del_aggregator(struct list_head *element) | |||
48 | tomoyo_put_name(ptr->aggregated_name); | 79 | tomoyo_put_name(ptr->aggregated_name); |
49 | } | 80 | } |
50 | 81 | ||
82 | /** | ||
83 | * tomoyo_del_manager - Delete members in "struct tomoyo_manager". | ||
84 | * | ||
85 | * @element: Pointer to "struct list_head". | ||
86 | * | ||
87 | * Returns nothing. | ||
88 | */ | ||
51 | static void tomoyo_del_manager(struct list_head *element) | 89 | static void tomoyo_del_manager(struct list_head *element) |
52 | { | 90 | { |
53 | struct tomoyo_manager *ptr = | 91 | struct tomoyo_manager *ptr = |
@@ -55,6 +93,13 @@ static void tomoyo_del_manager(struct list_head *element) | |||
55 | tomoyo_put_name(ptr->manager); | 93 | tomoyo_put_name(ptr->manager); |
56 | } | 94 | } |
57 | 95 | ||
96 | /** | ||
97 | * tomoyo_del_acl - Delete members in "struct tomoyo_acl_info". | ||
98 | * | ||
99 | * @element: Pointer to "struct list_head". | ||
100 | * | ||
101 | * Returns nothing. | ||
102 | */ | ||
58 | static void tomoyo_del_acl(struct list_head *element) | 103 | static void tomoyo_del_acl(struct list_head *element) |
59 | { | 104 | { |
60 | struct tomoyo_acl_info *acl = | 105 | struct tomoyo_acl_info *acl = |
@@ -145,12 +190,26 @@ static bool tomoyo_del_domain(struct list_head *element) | |||
145 | } | 190 | } |
146 | 191 | ||
147 | 192 | ||
193 | /** | ||
194 | * tomoyo_del_name - Delete members in "struct tomoyo_name". | ||
195 | * | ||
196 | * @element: Pointer to "struct list_head". | ||
197 | * | ||
198 | * Returns nothing. | ||
199 | */ | ||
148 | static void tomoyo_del_name(struct list_head *element) | 200 | static void tomoyo_del_name(struct list_head *element) |
149 | { | 201 | { |
150 | const struct tomoyo_name *ptr = | 202 | const struct tomoyo_name *ptr = |
151 | container_of(element, typeof(*ptr), list); | 203 | container_of(element, typeof(*ptr), head.list); |
152 | } | 204 | } |
153 | 205 | ||
206 | /** | ||
207 | * tomoyo_del_path_group - Delete members in "struct tomoyo_path_group". | ||
208 | * | ||
209 | * @element: Pointer to "struct list_head". | ||
210 | * | ||
211 | * Returns nothing. | ||
212 | */ | ||
154 | static void tomoyo_del_path_group(struct list_head *element) | 213 | static void tomoyo_del_path_group(struct list_head *element) |
155 | { | 214 | { |
156 | struct tomoyo_path_group *member = | 215 | struct tomoyo_path_group *member = |
@@ -158,20 +217,43 @@ static void tomoyo_del_path_group(struct list_head *element) | |||
158 | tomoyo_put_name(member->member_name); | 217 | tomoyo_put_name(member->member_name); |
159 | } | 218 | } |
160 | 219 | ||
220 | /** | ||
221 | * tomoyo_del_group - Delete "struct tomoyo_group". | ||
222 | * | ||
223 | * @element: Pointer to "struct list_head". | ||
224 | * | ||
225 | * Returns nothing. | ||
226 | */ | ||
161 | static void tomoyo_del_group(struct list_head *element) | 227 | static void tomoyo_del_group(struct list_head *element) |
162 | { | 228 | { |
163 | struct tomoyo_group *group = | 229 | struct tomoyo_group *group = |
164 | container_of(element, typeof(*group), list); | 230 | container_of(element, typeof(*group), head.list); |
165 | tomoyo_put_name(group->group_name); | 231 | tomoyo_put_name(group->group_name); |
166 | } | 232 | } |
167 | 233 | ||
234 | /** | ||
235 | * tomoyo_del_number_group - Delete members in "struct tomoyo_number_group". | ||
236 | * | ||
237 | * @element: Pointer to "struct list_head". | ||
238 | * | ||
239 | * Returns nothing. | ||
240 | */ | ||
168 | static void tomoyo_del_number_group(struct list_head *element) | 241 | static void tomoyo_del_number_group(struct list_head *element) |
169 | { | 242 | { |
170 | struct tomoyo_number_group *member = | 243 | struct tomoyo_number_group *member = |
171 | container_of(element, typeof(*member), head.list); | 244 | container_of(element, typeof(*member), head.list); |
172 | } | 245 | } |
173 | 246 | ||
174 | static bool tomoyo_collect_member(struct list_head *member_list, int id) | 247 | /** |
248 | * tomoyo_collect_member - Delete elements with "struct tomoyo_acl_head". | ||
249 | * | ||
250 | * @id: One of values in "enum tomoyo_policy_id". | ||
251 | * @member_list: Pointer to "struct list_head". | ||
252 | * | ||
253 | * Returns true if some elements are deleted, false otherwise. | ||
254 | */ | ||
255 | static bool tomoyo_collect_member(const enum tomoyo_policy_id id, | ||
256 | struct list_head *member_list) | ||
175 | { | 257 | { |
176 | struct tomoyo_acl_head *member; | 258 | struct tomoyo_acl_head *member; |
177 | list_for_each_entry(member, member_list, list) { | 259 | list_for_each_entry(member, member_list, list) { |
@@ -195,13 +277,18 @@ static bool tomoyo_collect_acl(struct tomoyo_domain_info *domain) | |||
195 | return true; | 277 | return true; |
196 | } | 278 | } |
197 | 279 | ||
280 | /** | ||
281 | * tomoyo_collect_entry - Scan lists for deleted elements. | ||
282 | * | ||
283 | * Returns nothing. | ||
284 | */ | ||
198 | static void tomoyo_collect_entry(void) | 285 | static void tomoyo_collect_entry(void) |
199 | { | 286 | { |
200 | int i; | 287 | int i; |
201 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 288 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
202 | return; | 289 | return; |
203 | for (i = 0; i < TOMOYO_MAX_POLICY; i++) { | 290 | for (i = 0; i < TOMOYO_MAX_POLICY; i++) { |
204 | if (!tomoyo_collect_member(&tomoyo_policy_list[i], i)) | 291 | if (!tomoyo_collect_member(i, &tomoyo_policy_list[i])) |
205 | goto unlock; | 292 | goto unlock; |
206 | } | 293 | } |
207 | { | 294 | { |
@@ -222,10 +309,10 @@ static void tomoyo_collect_entry(void) | |||
222 | } | 309 | } |
223 | for (i = 0; i < TOMOYO_MAX_HASH; i++) { | 310 | for (i = 0; i < TOMOYO_MAX_HASH; i++) { |
224 | struct tomoyo_name *ptr; | 311 | struct tomoyo_name *ptr; |
225 | list_for_each_entry_rcu(ptr, &tomoyo_name_list[i], list) { | 312 | list_for_each_entry_rcu(ptr, &tomoyo_name_list[i], head.list) { |
226 | if (atomic_read(&ptr->users)) | 313 | if (atomic_read(&ptr->head.users)) |
227 | continue; | 314 | continue; |
228 | if (!tomoyo_add_to_gc(TOMOYO_ID_NAME, &ptr->list)) | 315 | if (!tomoyo_add_to_gc(TOMOYO_ID_NAME, &ptr->head.list)) |
229 | goto unlock; | 316 | goto unlock; |
230 | } | 317 | } |
231 | } | 318 | } |
@@ -241,13 +328,14 @@ static void tomoyo_collect_entry(void) | |||
241 | id = TOMOYO_ID_NUMBER_GROUP; | 328 | id = TOMOYO_ID_NUMBER_GROUP; |
242 | break; | 329 | break; |
243 | } | 330 | } |
244 | list_for_each_entry(group, list, list) { | 331 | list_for_each_entry(group, list, head.list) { |
245 | if (!tomoyo_collect_member(&group->member_list, id)) | 332 | if (!tomoyo_collect_member(id, &group->member_list)) |
246 | goto unlock; | 333 | goto unlock; |
247 | if (!list_empty(&group->member_list) || | 334 | if (!list_empty(&group->member_list) || |
248 | atomic_read(&group->users)) | 335 | atomic_read(&group->head.users)) |
249 | continue; | 336 | continue; |
250 | if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP, &group->list)) | 337 | if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP, |
338 | &group->head.list)) | ||
251 | goto unlock; | 339 | goto unlock; |
252 | } | 340 | } |
253 | } | 341 | } |
@@ -291,6 +379,8 @@ static void tomoyo_kfree_entry(void) | |||
291 | case TOMOYO_ID_NUMBER_GROUP: | 379 | case TOMOYO_ID_NUMBER_GROUP: |
292 | tomoyo_del_number_group(element); | 380 | tomoyo_del_number_group(element); |
293 | break; | 381 | break; |
382 | case TOMOYO_MAX_POLICY: | ||
383 | break; | ||
294 | } | 384 | } |
295 | tomoyo_memory_free(element); | 385 | tomoyo_memory_free(element); |
296 | list_del(&p->list); | 386 | list_del(&p->list); |
@@ -298,6 +388,17 @@ static void tomoyo_kfree_entry(void) | |||
298 | } | 388 | } |
299 | } | 389 | } |
300 | 390 | ||
391 | /** | ||
392 | * tomoyo_gc_thread - Garbage collector thread function. | ||
393 | * | ||
394 | * @unused: Unused. | ||
395 | * | ||
396 | * In case OOM-killer choose this thread for termination, we create this thread | ||
397 | * as a short live thread whenever /sys/kernel/security/tomoyo/ interface was | ||
398 | * close()d. | ||
399 | * | ||
400 | * Returns 0. | ||
401 | */ | ||
301 | static int tomoyo_gc_thread(void *unused) | 402 | static int tomoyo_gc_thread(void *unused) |
302 | { | 403 | { |
303 | daemonize("GC for TOMOYO"); | 404 | daemonize("GC for TOMOYO"); |