diff options
author | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | 2010-02-10 19:43:54 -0500 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2010-02-14 17:00:24 -0500 |
commit | 847b173ea3d6f50936823d07f2245059bf44713b (patch) | |
tree | b53c6d0536af73a078bcff0375f9f4d837f79bba | |
parent | ec8e6a4e062e2edebef91e930c20572c9f4c0dda (diff) |
TOMOYO: Add garbage collector.
This patch adds garbage collector support to TOMOYO.
Elements are protected by "struct srcu_struct tomoyo_ss".
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Acked-by: Serge Hallyn <serue@us.ibm.com>
Signed-off-by: James Morris <jmorris@namei.org>
-rw-r--r-- | security/tomoyo/Makefile | 2 | ||||
-rw-r--r-- | security/tomoyo/common.c | 5 | ||||
-rw-r--r-- | security/tomoyo/common.h | 15 | ||||
-rw-r--r-- | security/tomoyo/domain.c | 6 | ||||
-rw-r--r-- | security/tomoyo/file.c | 6 | ||||
-rw-r--r-- | security/tomoyo/gc.c | 370 | ||||
-rw-r--r-- | security/tomoyo/realpath.c | 86 |
7 files changed, 436 insertions, 54 deletions
diff --git a/security/tomoyo/Makefile b/security/tomoyo/Makefile index 10ccd686b290..60a9e2002da1 100644 --- a/security/tomoyo/Makefile +++ b/security/tomoyo/Makefile | |||
@@ -1 +1 @@ | |||
obj-y = common.o realpath.o tomoyo.o domain.o file.o | obj-y = common.o realpath.o tomoyo.o domain.o file.o gc.o | ||
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 634f7449e8ba..3a36b56a2f5c 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -1067,7 +1067,7 @@ static int tomoyo_read_profile(struct tomoyo_io_buffer *head) | |||
1067 | * | 1067 | * |
1068 | * # cat /sys/kernel/security/tomoyo/manager | 1068 | * # cat /sys/kernel/security/tomoyo/manager |
1069 | */ | 1069 | */ |
1070 | static LIST_HEAD(tomoyo_policy_manager_list); | 1070 | LIST_HEAD(tomoyo_policy_manager_list); |
1071 | 1071 | ||
1072 | /** | 1072 | /** |
1073 | * tomoyo_update_manager_entry - Add a manager entry. | 1073 | * tomoyo_update_manager_entry - Add a manager entry. |
@@ -2109,6 +2109,7 @@ static int tomoyo_write_control(struct file *file, const char __user *buffer, | |||
2109 | static int tomoyo_close_control(struct file *file) | 2109 | static int tomoyo_close_control(struct file *file) |
2110 | { | 2110 | { |
2111 | struct tomoyo_io_buffer *head = file->private_data; | 2111 | struct tomoyo_io_buffer *head = file->private_data; |
2112 | const bool is_write = !!head->write_buf; | ||
2112 | 2113 | ||
2113 | tomoyo_read_unlock(head->reader_idx); | 2114 | tomoyo_read_unlock(head->reader_idx); |
2114 | /* Release memory used for policy I/O. */ | 2115 | /* Release memory used for policy I/O. */ |
@@ -2119,6 +2120,8 @@ static int tomoyo_close_control(struct file *file) | |||
2119 | kfree(head); | 2120 | kfree(head); |
2120 | head = NULL; | 2121 | head = NULL; |
2121 | file->private_data = NULL; | 2122 | file->private_data = NULL; |
2123 | if (is_write) | ||
2124 | tomoyo_run_gc(); | ||
2122 | return 0; | 2125 | return 0; |
2123 | } | 2126 | } |
2124 | 2127 | ||
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 521b4b5addaf..1c8c97a4c069 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
@@ -638,6 +638,11 @@ int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, | |||
638 | struct file *filp); | 638 | struct file *filp); |
639 | int tomoyo_find_next_domain(struct linux_binprm *bprm); | 639 | int tomoyo_find_next_domain(struct linux_binprm *bprm); |
640 | 640 | ||
641 | /* Run garbage collector. */ | ||
642 | void tomoyo_run_gc(void); | ||
643 | |||
644 | void tomoyo_memory_free(void *ptr); | ||
645 | |||
641 | /********** External variable definitions. **********/ | 646 | /********** External variable definitions. **********/ |
642 | 647 | ||
643 | /* Lock for GC. */ | 648 | /* Lock for GC. */ |
@@ -646,6 +651,16 @@ extern struct srcu_struct tomoyo_ss; | |||
646 | /* The list for "struct tomoyo_domain_info". */ | 651 | /* The list for "struct tomoyo_domain_info". */ |
647 | extern struct list_head tomoyo_domain_list; | 652 | extern struct list_head tomoyo_domain_list; |
648 | 653 | ||
654 | extern struct list_head tomoyo_domain_initializer_list; | ||
655 | extern struct list_head tomoyo_domain_keeper_list; | ||
656 | extern struct list_head tomoyo_alias_list; | ||
657 | extern struct list_head tomoyo_globally_readable_list; | ||
658 | extern struct list_head tomoyo_pattern_list; | ||
659 | extern struct list_head tomoyo_no_rewrite_list; | ||
660 | extern struct list_head tomoyo_policy_manager_list; | ||
661 | extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; | ||
662 | extern struct mutex tomoyo_name_list_lock; | ||
663 | |||
649 | /* Lock for protecting policy. */ | 664 | /* Lock for protecting policy. */ |
650 | extern struct mutex tomoyo_policy_lock; | 665 | extern struct mutex tomoyo_policy_lock; |
651 | 666 | ||
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 6f74b30d6bb1..74cd0f52e3a8 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
@@ -110,7 +110,7 @@ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain) | |||
110 | * will cause "/usr/sbin/httpd" to belong to "<kernel> /usr/sbin/httpd" domain | 110 | * will cause "/usr/sbin/httpd" to belong to "<kernel> /usr/sbin/httpd" domain |
111 | * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain. | 111 | * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain. |
112 | */ | 112 | */ |
113 | static LIST_HEAD(tomoyo_domain_initializer_list); | 113 | LIST_HEAD(tomoyo_domain_initializer_list); |
114 | 114 | ||
115 | /** | 115 | /** |
116 | * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list. | 116 | * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list. |
@@ -330,7 +330,7 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * | |||
330 | * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless | 330 | * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless |
331 | * explicitly specified by "initialize_domain". | 331 | * explicitly specified by "initialize_domain". |
332 | */ | 332 | */ |
333 | static LIST_HEAD(tomoyo_domain_keeper_list); | 333 | LIST_HEAD(tomoyo_domain_keeper_list); |
334 | 334 | ||
335 | /** | 335 | /** |
336 | * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list. | 336 | * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list. |
@@ -533,7 +533,7 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, | |||
533 | * /bin/busybox and domainname which the current process will belong to after | 533 | * /bin/busybox and domainname which the current process will belong to after |
534 | * execve() succeeds is calculated using /bin/cat rather than /bin/busybox . | 534 | * execve() succeeds is calculated using /bin/cat rather than /bin/busybox . |
535 | */ | 535 | */ |
536 | static LIST_HEAD(tomoyo_alias_list); | 536 | LIST_HEAD(tomoyo_alias_list); |
537 | 537 | ||
538 | /** | 538 | /** |
539 | * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list. | 539 | * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list. |
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index c69dd39e6042..10ee7cece080 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c | |||
@@ -148,7 +148,7 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, | |||
148 | * given "allow_read /lib/libc-2.5.so" to the domain which current process | 148 | * given "allow_read /lib/libc-2.5.so" to the domain which current process |
149 | * belongs to. | 149 | * belongs to. |
150 | */ | 150 | */ |
151 | static LIST_HEAD(tomoyo_globally_readable_list); | 151 | LIST_HEAD(tomoyo_globally_readable_list); |
152 | 152 | ||
153 | /** | 153 | /** |
154 | * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. | 154 | * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. |
@@ -295,7 +295,7 @@ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) | |||
295 | * which pretends as if /proc/self/ is not a symlink; so that we can forbid | 295 | * which pretends as if /proc/self/ is not a symlink; so that we can forbid |
296 | * current process from accessing other process's information. | 296 | * current process from accessing other process's information. |
297 | */ | 297 | */ |
298 | static LIST_HEAD(tomoyo_pattern_list); | 298 | LIST_HEAD(tomoyo_pattern_list); |
299 | 299 | ||
300 | /** | 300 | /** |
301 | * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. | 301 | * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. |
@@ -448,7 +448,7 @@ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) | |||
448 | * " (deleted)" suffix if the file is already unlink()ed; so that we don't | 448 | * " (deleted)" suffix if the file is already unlink()ed; so that we don't |
449 | * need to worry whether the file is already unlink()ed or not. | 449 | * need to worry whether the file is already unlink()ed or not. |
450 | */ | 450 | */ |
451 | static LIST_HEAD(tomoyo_no_rewrite_list); | 451 | LIST_HEAD(tomoyo_no_rewrite_list); |
452 | 452 | ||
453 | /** | 453 | /** |
454 | * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. | 454 | * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. |
diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c new file mode 100644 index 000000000000..ee15da39387d --- /dev/null +++ b/security/tomoyo/gc.c | |||
@@ -0,0 +1,370 @@ | |||
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 | |||
13 | enum tomoyo_gc_id { | ||
14 | TOMOYO_ID_DOMAIN_INITIALIZER, | ||
15 | TOMOYO_ID_DOMAIN_KEEPER, | ||
16 | TOMOYO_ID_ALIAS, | ||
17 | TOMOYO_ID_GLOBALLY_READABLE, | ||
18 | TOMOYO_ID_PATTERN, | ||
19 | TOMOYO_ID_NO_REWRITE, | ||
20 | TOMOYO_ID_MANAGER, | ||
21 | TOMOYO_ID_NAME, | ||
22 | TOMOYO_ID_ACL, | ||
23 | TOMOYO_ID_DOMAIN | ||
24 | }; | ||
25 | |||
26 | struct tomoyo_gc_entry { | ||
27 | struct list_head list; | ||
28 | int type; | ||
29 | void *element; | ||
30 | }; | ||
31 | static LIST_HEAD(tomoyo_gc_queue); | ||
32 | static DEFINE_MUTEX(tomoyo_gc_mutex); | ||
33 | |||
34 | /* Caller holds tomoyo_policy_lock mutex. */ | ||
35 | static bool tomoyo_add_to_gc(const int type, void *element) | ||
36 | { | ||
37 | struct tomoyo_gc_entry *entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | ||
38 | if (!entry) | ||
39 | return false; | ||
40 | entry->type = type; | ||
41 | entry->element = element; | ||
42 | list_add(&entry->list, &tomoyo_gc_queue); | ||
43 | return true; | ||
44 | } | ||
45 | |||
46 | static void tomoyo_del_allow_read | ||
47 | (struct tomoyo_globally_readable_file_entry *ptr) | ||
48 | { | ||
49 | tomoyo_put_name(ptr->filename); | ||
50 | } | ||
51 | |||
52 | static void tomoyo_del_file_pattern(struct tomoyo_pattern_entry *ptr) | ||
53 | { | ||
54 | tomoyo_put_name(ptr->pattern); | ||
55 | } | ||
56 | |||
57 | static void tomoyo_del_no_rewrite(struct tomoyo_no_rewrite_entry *ptr) | ||
58 | { | ||
59 | tomoyo_put_name(ptr->pattern); | ||
60 | } | ||
61 | |||
62 | static void tomoyo_del_domain_initializer | ||
63 | (struct tomoyo_domain_initializer_entry *ptr) | ||
64 | { | ||
65 | tomoyo_put_name(ptr->domainname); | ||
66 | tomoyo_put_name(ptr->program); | ||
67 | } | ||
68 | |||
69 | static void tomoyo_del_domain_keeper(struct tomoyo_domain_keeper_entry *ptr) | ||
70 | { | ||
71 | tomoyo_put_name(ptr->domainname); | ||
72 | tomoyo_put_name(ptr->program); | ||
73 | } | ||
74 | |||
75 | static void tomoyo_del_alias(struct tomoyo_alias_entry *ptr) | ||
76 | { | ||
77 | tomoyo_put_name(ptr->original_name); | ||
78 | tomoyo_put_name(ptr->aliased_name); | ||
79 | } | ||
80 | |||
81 | static void tomoyo_del_manager(struct tomoyo_policy_manager_entry *ptr) | ||
82 | { | ||
83 | tomoyo_put_name(ptr->manager); | ||
84 | } | ||
85 | |||
86 | static void tomoyo_del_acl(struct tomoyo_acl_info *acl) | ||
87 | { | ||
88 | switch (acl->type) { | ||
89 | case TOMOYO_TYPE_SINGLE_PATH_ACL: | ||
90 | { | ||
91 | struct tomoyo_single_path_acl_record *entry | ||
92 | = container_of(acl, typeof(*entry), head); | ||
93 | tomoyo_put_name(entry->filename); | ||
94 | } | ||
95 | break; | ||
96 | case TOMOYO_TYPE_DOUBLE_PATH_ACL: | ||
97 | { | ||
98 | struct tomoyo_double_path_acl_record *entry | ||
99 | = container_of(acl, typeof(*entry), head); | ||
100 | tomoyo_put_name(entry->filename1); | ||
101 | tomoyo_put_name(entry->filename2); | ||
102 | } | ||
103 | break; | ||
104 | default: | ||
105 | printk(KERN_WARNING "Unknown type\n"); | ||
106 | break; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | static bool tomoyo_del_domain(struct tomoyo_domain_info *domain) | ||
111 | { | ||
112 | struct tomoyo_acl_info *acl; | ||
113 | struct tomoyo_acl_info *tmp; | ||
114 | /* | ||
115 | * Since we don't protect whole execve() operation using SRCU, | ||
116 | * we need to recheck domain->users at this point. | ||
117 | * | ||
118 | * (1) Reader starts SRCU section upon execve(). | ||
119 | * (2) Reader traverses tomoyo_domain_list and finds this domain. | ||
120 | * (3) Writer marks this domain as deleted. | ||
121 | * (4) Garbage collector removes this domain from tomoyo_domain_list | ||
122 | * because this domain is marked as deleted and used by nobody. | ||
123 | * (5) Reader saves reference to this domain into | ||
124 | * "struct linux_binprm"->cred->security . | ||
125 | * (6) Reader finishes SRCU section, although execve() operation has | ||
126 | * not finished yet. | ||
127 | * (7) Garbage collector waits for SRCU synchronization. | ||
128 | * (8) Garbage collector kfree() this domain because this domain is | ||
129 | * used by nobody. | ||
130 | * (9) Reader finishes execve() operation and restores this domain from | ||
131 | * "struct linux_binprm"->cred->security. | ||
132 | * | ||
133 | * By updating domain->users at (5), we can solve this race problem | ||
134 | * by rechecking domain->users at (8). | ||
135 | */ | ||
136 | if (atomic_read(&domain->users)) | ||
137 | return false; | ||
138 | list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) { | ||
139 | tomoyo_del_acl(acl); | ||
140 | tomoyo_memory_free(acl); | ||
141 | } | ||
142 | tomoyo_put_name(domain->domainname); | ||
143 | return true; | ||
144 | } | ||
145 | |||
146 | |||
147 | static void tomoyo_del_name(const struct tomoyo_name_entry *ptr) | ||
148 | { | ||
149 | } | ||
150 | |||
151 | static void tomoyo_collect_entry(void) | ||
152 | { | ||
153 | mutex_lock(&tomoyo_policy_lock); | ||
154 | { | ||
155 | struct tomoyo_globally_readable_file_entry *ptr; | ||
156 | list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, | ||
157 | list) { | ||
158 | if (!ptr->is_deleted) | ||
159 | continue; | ||
160 | if (tomoyo_add_to_gc(TOMOYO_ID_GLOBALLY_READABLE, ptr)) | ||
161 | list_del_rcu(&ptr->list); | ||
162 | else | ||
163 | break; | ||
164 | } | ||
165 | } | ||
166 | { | ||
167 | struct tomoyo_pattern_entry *ptr; | ||
168 | list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { | ||
169 | if (!ptr->is_deleted) | ||
170 | continue; | ||
171 | if (tomoyo_add_to_gc(TOMOYO_ID_PATTERN, ptr)) | ||
172 | list_del_rcu(&ptr->list); | ||
173 | else | ||
174 | break; | ||
175 | } | ||
176 | } | ||
177 | { | ||
178 | struct tomoyo_no_rewrite_entry *ptr; | ||
179 | list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { | ||
180 | if (!ptr->is_deleted) | ||
181 | continue; | ||
182 | if (tomoyo_add_to_gc(TOMOYO_ID_NO_REWRITE, ptr)) | ||
183 | list_del_rcu(&ptr->list); | ||
184 | else | ||
185 | break; | ||
186 | } | ||
187 | } | ||
188 | { | ||
189 | struct tomoyo_domain_initializer_entry *ptr; | ||
190 | list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, | ||
191 | list) { | ||
192 | if (!ptr->is_deleted) | ||
193 | continue; | ||
194 | if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_INITIALIZER, ptr)) | ||
195 | list_del_rcu(&ptr->list); | ||
196 | else | ||
197 | break; | ||
198 | } | ||
199 | } | ||
200 | { | ||
201 | struct tomoyo_domain_keeper_entry *ptr; | ||
202 | list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { | ||
203 | if (!ptr->is_deleted) | ||
204 | continue; | ||
205 | if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_KEEPER, ptr)) | ||
206 | list_del_rcu(&ptr->list); | ||
207 | else | ||
208 | break; | ||
209 | } | ||
210 | } | ||
211 | { | ||
212 | struct tomoyo_alias_entry *ptr; | ||
213 | list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { | ||
214 | if (!ptr->is_deleted) | ||
215 | continue; | ||
216 | if (tomoyo_add_to_gc(TOMOYO_ID_ALIAS, ptr)) | ||
217 | list_del_rcu(&ptr->list); | ||
218 | else | ||
219 | break; | ||
220 | } | ||
221 | } | ||
222 | { | ||
223 | struct tomoyo_policy_manager_entry *ptr; | ||
224 | list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, | ||
225 | list) { | ||
226 | if (!ptr->is_deleted) | ||
227 | continue; | ||
228 | if (tomoyo_add_to_gc(TOMOYO_ID_MANAGER, ptr)) | ||
229 | list_del_rcu(&ptr->list); | ||
230 | else | ||
231 | break; | ||
232 | } | ||
233 | } | ||
234 | { | ||
235 | struct tomoyo_domain_info *domain; | ||
236 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | ||
237 | struct tomoyo_acl_info *acl; | ||
238 | list_for_each_entry_rcu(acl, &domain->acl_info_list, | ||
239 | list) { | ||
240 | switch (acl->type) { | ||
241 | case TOMOYO_TYPE_SINGLE_PATH_ACL: | ||
242 | if (container_of(acl, | ||
243 | struct tomoyo_single_path_acl_record, | ||
244 | head)->perm || | ||
245 | container_of(acl, | ||
246 | struct tomoyo_single_path_acl_record, | ||
247 | head)->perm_high) | ||
248 | continue; | ||
249 | break; | ||
250 | case TOMOYO_TYPE_DOUBLE_PATH_ACL: | ||
251 | if (container_of(acl, | ||
252 | struct tomoyo_double_path_acl_record, | ||
253 | head)->perm) | ||
254 | continue; | ||
255 | break; | ||
256 | default: | ||
257 | continue; | ||
258 | } | ||
259 | if (tomoyo_add_to_gc(TOMOYO_ID_ACL, acl)) | ||
260 | list_del_rcu(&acl->list); | ||
261 | else | ||
262 | break; | ||
263 | } | ||
264 | if (!domain->is_deleted || atomic_read(&domain->users)) | ||
265 | continue; | ||
266 | /* | ||
267 | * Nobody is referring this domain. But somebody may | ||
268 | * refer this domain after successful execve(). | ||
269 | * We recheck domain->users after SRCU synchronization. | ||
270 | */ | ||
271 | if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, domain)) | ||
272 | list_del_rcu(&domain->list); | ||
273 | else | ||
274 | break; | ||
275 | } | ||
276 | } | ||
277 | mutex_unlock(&tomoyo_policy_lock); | ||
278 | mutex_lock(&tomoyo_name_list_lock); | ||
279 | { | ||
280 | int i; | ||
281 | for (i = 0; i < TOMOYO_MAX_HASH; i++) { | ||
282 | struct tomoyo_name_entry *ptr; | ||
283 | list_for_each_entry_rcu(ptr, &tomoyo_name_list[i], | ||
284 | list) { | ||
285 | if (atomic_read(&ptr->users)) | ||
286 | continue; | ||
287 | if (tomoyo_add_to_gc(TOMOYO_ID_NAME, ptr)) | ||
288 | list_del_rcu(&ptr->list); | ||
289 | else { | ||
290 | i = TOMOYO_MAX_HASH; | ||
291 | break; | ||
292 | } | ||
293 | } | ||
294 | } | ||
295 | } | ||
296 | mutex_unlock(&tomoyo_name_list_lock); | ||
297 | } | ||
298 | |||
299 | static void tomoyo_kfree_entry(void) | ||
300 | { | ||
301 | struct tomoyo_gc_entry *p; | ||
302 | struct tomoyo_gc_entry *tmp; | ||
303 | |||
304 | list_for_each_entry_safe(p, tmp, &tomoyo_gc_queue, list) { | ||
305 | switch (p->type) { | ||
306 | case TOMOYO_ID_DOMAIN_INITIALIZER: | ||
307 | tomoyo_del_domain_initializer(p->element); | ||
308 | break; | ||
309 | case TOMOYO_ID_DOMAIN_KEEPER: | ||
310 | tomoyo_del_domain_keeper(p->element); | ||
311 | break; | ||
312 | case TOMOYO_ID_ALIAS: | ||
313 | tomoyo_del_alias(p->element); | ||
314 | break; | ||
315 | case TOMOYO_ID_GLOBALLY_READABLE: | ||
316 | tomoyo_del_allow_read(p->element); | ||
317 | break; | ||
318 | case TOMOYO_ID_PATTERN: | ||
319 | tomoyo_del_file_pattern(p->element); | ||
320 | break; | ||
321 | case TOMOYO_ID_NO_REWRITE: | ||
322 | tomoyo_del_no_rewrite(p->element); | ||
323 | break; | ||
324 | case TOMOYO_ID_MANAGER: | ||
325 | tomoyo_del_manager(p->element); | ||
326 | break; | ||
327 | case TOMOYO_ID_NAME: | ||
328 | tomoyo_del_name(p->element); | ||
329 | break; | ||
330 | case TOMOYO_ID_ACL: | ||
331 | tomoyo_del_acl(p->element); | ||
332 | break; | ||
333 | case TOMOYO_ID_DOMAIN: | ||
334 | if (!tomoyo_del_domain(p->element)) | ||
335 | continue; | ||
336 | break; | ||
337 | default: | ||
338 | printk(KERN_WARNING "Unknown type\n"); | ||
339 | break; | ||
340 | } | ||
341 | tomoyo_memory_free(p->element); | ||
342 | list_del(&p->list); | ||
343 | kfree(p); | ||
344 | } | ||
345 | } | ||
346 | |||
347 | static int tomoyo_gc_thread(void *unused) | ||
348 | { | ||
349 | daemonize("GC for TOMOYO"); | ||
350 | if (mutex_trylock(&tomoyo_gc_mutex)) { | ||
351 | int i; | ||
352 | for (i = 0; i < 10; i++) { | ||
353 | tomoyo_collect_entry(); | ||
354 | if (list_empty(&tomoyo_gc_queue)) | ||
355 | break; | ||
356 | synchronize_srcu(&tomoyo_ss); | ||
357 | tomoyo_kfree_entry(); | ||
358 | } | ||
359 | mutex_unlock(&tomoyo_gc_mutex); | ||
360 | } | ||
361 | do_exit(0); | ||
362 | } | ||
363 | |||
364 | void tomoyo_run_gc(void) | ||
365 | { | ||
366 | struct task_struct *task = kthread_create(tomoyo_gc_thread, NULL, | ||
367 | "GC for TOMOYO"); | ||
368 | if (!IS_ERR(task)) | ||
369 | wake_up_process(task); | ||
370 | } | ||
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 9557168b3767..c00df45c7ede 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c | |||
@@ -205,9 +205,9 @@ char *tomoyo_realpath_nofollow(const char *pathname) | |||
205 | } | 205 | } |
206 | 206 | ||
207 | /* Memory allocated for non-string data. */ | 207 | /* Memory allocated for non-string data. */ |
208 | static unsigned int tomoyo_allocated_memory_for_elements; | 208 | static atomic_t tomoyo_policy_memory_size; |
209 | /* Quota for holding non-string data. */ | 209 | /* Quota for holding policy. */ |
210 | static unsigned int tomoyo_quota_for_elements; | 210 | static unsigned int tomoyo_quota_for_policy; |
211 | 211 | ||
212 | /** | 212 | /** |
213 | * tomoyo_memory_ok - Check memory quota. | 213 | * tomoyo_memory_ok - Check memory quota. |
@@ -222,26 +222,30 @@ static unsigned int tomoyo_quota_for_elements; | |||
222 | bool tomoyo_memory_ok(void *ptr) | 222 | bool tomoyo_memory_ok(void *ptr) |
223 | { | 223 | { |
224 | int allocated_len = ptr ? ksize(ptr) : 0; | 224 | int allocated_len = ptr ? ksize(ptr) : 0; |
225 | bool result = false; | 225 | atomic_add(allocated_len, &tomoyo_policy_memory_size); |
226 | if (!ptr || (tomoyo_quota_for_elements && | 226 | if (ptr && (!tomoyo_quota_for_policy || |
227 | tomoyo_allocated_memory_for_elements | 227 | atomic_read(&tomoyo_policy_memory_size) |
228 | + allocated_len > tomoyo_quota_for_elements)) { | 228 | <= tomoyo_quota_for_policy)) { |
229 | printk(KERN_WARNING "ERROR: Out of memory " | ||
230 | "for tomoyo_alloc_element().\n"); | ||
231 | if (!tomoyo_policy_loaded) | ||
232 | panic("MAC Initialization failed.\n"); | ||
233 | } else { | ||
234 | result = true; | ||
235 | tomoyo_allocated_memory_for_elements += allocated_len; | ||
236 | memset(ptr, 0, allocated_len); | 229 | memset(ptr, 0, allocated_len); |
230 | return true; | ||
237 | } | 231 | } |
238 | return result; | 232 | printk(KERN_WARNING "ERROR: Out of memory " |
233 | "for tomoyo_alloc_element().\n"); | ||
234 | if (!tomoyo_policy_loaded) | ||
235 | panic("MAC Initialization failed.\n"); | ||
236 | return false; | ||
239 | } | 237 | } |
240 | 238 | ||
241 | /* Memory allocated for string data in bytes. */ | 239 | /** |
242 | static unsigned int tomoyo_allocated_memory_for_savename; | 240 | * tomoyo_memory_free - Free memory for elements. |
243 | /* Quota for holding string data in bytes. */ | 241 | * |
244 | static unsigned int tomoyo_quota_for_savename; | 242 | * @ptr: Pointer to allocated memory. |
243 | */ | ||
244 | void tomoyo_memory_free(void *ptr) | ||
245 | { | ||
246 | atomic_sub(ksize(ptr), &tomoyo_policy_memory_size); | ||
247 | kfree(ptr); | ||
248 | } | ||
245 | 249 | ||
246 | /* | 250 | /* |
247 | * tomoyo_name_list is used for holding string data used by TOMOYO. | 251 | * tomoyo_name_list is used for holding string data used by TOMOYO. |
@@ -249,7 +253,9 @@ static unsigned int tomoyo_quota_for_savename; | |||
249 | * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of | 253 | * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of |
250 | * "const struct tomoyo_path_info *". | 254 | * "const struct tomoyo_path_info *". |
251 | */ | 255 | */ |
252 | static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; | 256 | struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; |
257 | /* Lock for protecting tomoyo_name_list . */ | ||
258 | DEFINE_MUTEX(tomoyo_name_list_lock); | ||
253 | 259 | ||
254 | /** | 260 | /** |
255 | * tomoyo_get_name - Allocate permanent memory for string data. | 261 | * tomoyo_get_name - Allocate permanent memory for string data. |
@@ -260,7 +266,6 @@ static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; | |||
260 | */ | 266 | */ |
261 | const struct tomoyo_path_info *tomoyo_get_name(const char *name) | 267 | const struct tomoyo_path_info *tomoyo_get_name(const char *name) |
262 | { | 268 | { |
263 | static DEFINE_MUTEX(lock); | ||
264 | struct tomoyo_name_entry *ptr; | 269 | struct tomoyo_name_entry *ptr; |
265 | unsigned int hash; | 270 | unsigned int hash; |
266 | int len; | 271 | int len; |
@@ -272,7 +277,7 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name) | |||
272 | len = strlen(name) + 1; | 277 | len = strlen(name) + 1; |
273 | hash = full_name_hash((const unsigned char *) name, len - 1); | 278 | hash = full_name_hash((const unsigned char *) name, len - 1); |
274 | head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; | 279 | head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; |
275 | mutex_lock(&lock); | 280 | mutex_lock(&tomoyo_name_list_lock); |
276 | list_for_each_entry(ptr, head, list) { | 281 | list_for_each_entry(ptr, head, list) { |
277 | if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name)) | 282 | if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name)) |
278 | continue; | 283 | continue; |
@@ -281,9 +286,9 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name) | |||
281 | } | 286 | } |
282 | ptr = kzalloc(sizeof(*ptr) + len, GFP_KERNEL); | 287 | ptr = kzalloc(sizeof(*ptr) + len, GFP_KERNEL); |
283 | allocated_len = ptr ? ksize(ptr) : 0; | 288 | allocated_len = ptr ? ksize(ptr) : 0; |
284 | if (!ptr || (tomoyo_quota_for_savename && | 289 | if (!ptr || (tomoyo_quota_for_policy && |
285 | tomoyo_allocated_memory_for_savename + allocated_len | 290 | atomic_read(&tomoyo_policy_memory_size) + allocated_len |
286 | > tomoyo_quota_for_savename)) { | 291 | > tomoyo_quota_for_policy)) { |
287 | kfree(ptr); | 292 | kfree(ptr); |
288 | printk(KERN_WARNING "ERROR: Out of memory " | 293 | printk(KERN_WARNING "ERROR: Out of memory " |
289 | "for tomoyo_get_name().\n"); | 294 | "for tomoyo_get_name().\n"); |
@@ -292,14 +297,14 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name) | |||
292 | ptr = NULL; | 297 | ptr = NULL; |
293 | goto out; | 298 | goto out; |
294 | } | 299 | } |
295 | tomoyo_allocated_memory_for_savename += allocated_len; | 300 | atomic_add(allocated_len, &tomoyo_policy_memory_size); |
296 | ptr->entry.name = ((char *) ptr) + sizeof(*ptr); | 301 | ptr->entry.name = ((char *) ptr) + sizeof(*ptr); |
297 | memmove((char *) ptr->entry.name, name, len); | 302 | memmove((char *) ptr->entry.name, name, len); |
298 | atomic_set(&ptr->users, 1); | 303 | atomic_set(&ptr->users, 1); |
299 | tomoyo_fill_path_info(&ptr->entry); | 304 | tomoyo_fill_path_info(&ptr->entry); |
300 | list_add_tail(&ptr->list, head); | 305 | list_add_tail(&ptr->list, head); |
301 | out: | 306 | out: |
302 | mutex_unlock(&lock); | 307 | mutex_unlock(&tomoyo_name_list_lock); |
303 | return ptr ? &ptr->entry : NULL; | 308 | return ptr ? &ptr->entry : NULL; |
304 | } | 309 | } |
305 | 310 | ||
@@ -334,28 +339,19 @@ void __init tomoyo_realpath_init(void) | |||
334 | int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head) | 339 | int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head) |
335 | { | 340 | { |
336 | if (!head->read_eof) { | 341 | if (!head->read_eof) { |
337 | const unsigned int shared | 342 | const unsigned int policy |
338 | = tomoyo_allocated_memory_for_savename; | 343 | = atomic_read(&tomoyo_policy_memory_size); |
339 | const unsigned int private | ||
340 | = tomoyo_allocated_memory_for_elements; | ||
341 | char buffer[64]; | 344 | char buffer[64]; |
342 | 345 | ||
343 | memset(buffer, 0, sizeof(buffer)); | 346 | memset(buffer, 0, sizeof(buffer)); |
344 | if (tomoyo_quota_for_savename) | 347 | if (tomoyo_quota_for_policy) |
345 | snprintf(buffer, sizeof(buffer) - 1, | ||
346 | " (Quota: %10u)", | ||
347 | tomoyo_quota_for_savename); | ||
348 | else | ||
349 | buffer[0] = '\0'; | ||
350 | tomoyo_io_printf(head, "Shared: %10u%s\n", shared, buffer); | ||
351 | if (tomoyo_quota_for_elements) | ||
352 | snprintf(buffer, sizeof(buffer) - 1, | 348 | snprintf(buffer, sizeof(buffer) - 1, |
353 | " (Quota: %10u)", | 349 | " (Quota: %10u)", |
354 | tomoyo_quota_for_elements); | 350 | tomoyo_quota_for_policy); |
355 | else | 351 | else |
356 | buffer[0] = '\0'; | 352 | buffer[0] = '\0'; |
357 | tomoyo_io_printf(head, "Private: %10u%s\n", private, buffer); | 353 | tomoyo_io_printf(head, "Policy: %10u%s\n", policy, buffer); |
358 | tomoyo_io_printf(head, "Total: %10u\n", shared + private); | 354 | tomoyo_io_printf(head, "Total: %10u\n", policy); |
359 | head->read_eof = true; | 355 | head->read_eof = true; |
360 | } | 356 | } |
361 | return 0; | 357 | return 0; |
@@ -373,9 +369,7 @@ int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head) | |||
373 | char *data = head->write_buf; | 369 | char *data = head->write_buf; |
374 | unsigned int size; | 370 | unsigned int size; |
375 | 371 | ||
376 | if (sscanf(data, "Shared: %u", &size) == 1) | 372 | if (sscanf(data, "Policy: %u", &size) == 1) |
377 | tomoyo_quota_for_savename = size; | 373 | tomoyo_quota_for_policy = size; |
378 | else if (sscanf(data, "Private: %u", &size) == 1) | ||
379 | tomoyo_quota_for_elements = size; | ||
380 | return 0; | 374 | return 0; |
381 | } | 375 | } |