diff options
Diffstat (limited to 'security/tomoyo/domain.c')
-rw-r--r-- | security/tomoyo/domain.c | 391 |
1 files changed, 148 insertions, 243 deletions
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index fcf52accce2b..66caaa1b842a 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
@@ -10,8 +10,6 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include "common.h" | 12 | #include "common.h" |
13 | #include "tomoyo.h" | ||
14 | #include "realpath.h" | ||
15 | #include <linux/binfmts.h> | 13 | #include <linux/binfmts.h> |
16 | 14 | ||
17 | /* Variables definitions.*/ | 15 | /* Variables definitions.*/ |
@@ -58,99 +56,6 @@ struct tomoyo_domain_info tomoyo_kernel_domain; | |||
58 | * exceptions. | 56 | * exceptions. |
59 | */ | 57 | */ |
60 | LIST_HEAD(tomoyo_domain_list); | 58 | LIST_HEAD(tomoyo_domain_list); |
61 | DECLARE_RWSEM(tomoyo_domain_list_lock); | ||
62 | |||
63 | /* | ||
64 | * tomoyo_domain_initializer_entry is a structure which is used for holding | ||
65 | * "initialize_domain" and "no_initialize_domain" entries. | ||
66 | * It has following fields. | ||
67 | * | ||
68 | * (1) "list" which is linked to tomoyo_domain_initializer_list . | ||
69 | * (2) "domainname" which is "a domainname" or "the last component of a | ||
70 | * domainname". This field is NULL if "from" clause is not specified. | ||
71 | * (3) "program" which is a program's pathname. | ||
72 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
73 | * otherwise. | ||
74 | * (5) "is_not" is a bool which is true if "no_initialize_domain", false | ||
75 | * otherwise. | ||
76 | * (6) "is_last_name" is a bool which is true if "domainname" is "the last | ||
77 | * component of a domainname", false otherwise. | ||
78 | */ | ||
79 | struct tomoyo_domain_initializer_entry { | ||
80 | struct list_head list; | ||
81 | const struct tomoyo_path_info *domainname; /* This may be NULL */ | ||
82 | const struct tomoyo_path_info *program; | ||
83 | bool is_deleted; | ||
84 | bool is_not; /* True if this entry is "no_initialize_domain". */ | ||
85 | /* True if the domainname is tomoyo_get_last_name(). */ | ||
86 | bool is_last_name; | ||
87 | }; | ||
88 | |||
89 | /* | ||
90 | * tomoyo_domain_keeper_entry is a structure which is used for holding | ||
91 | * "keep_domain" and "no_keep_domain" entries. | ||
92 | * It has following fields. | ||
93 | * | ||
94 | * (1) "list" which is linked to tomoyo_domain_keeper_list . | ||
95 | * (2) "domainname" which is "a domainname" or "the last component of a | ||
96 | * domainname". | ||
97 | * (3) "program" which is a program's pathname. | ||
98 | * This field is NULL if "from" clause is not specified. | ||
99 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
100 | * otherwise. | ||
101 | * (5) "is_not" is a bool which is true if "no_initialize_domain", false | ||
102 | * otherwise. | ||
103 | * (6) "is_last_name" is a bool which is true if "domainname" is "the last | ||
104 | * component of a domainname", false otherwise. | ||
105 | */ | ||
106 | struct tomoyo_domain_keeper_entry { | ||
107 | struct list_head list; | ||
108 | const struct tomoyo_path_info *domainname; | ||
109 | const struct tomoyo_path_info *program; /* This may be NULL */ | ||
110 | bool is_deleted; | ||
111 | bool is_not; /* True if this entry is "no_keep_domain". */ | ||
112 | /* True if the domainname is tomoyo_get_last_name(). */ | ||
113 | bool is_last_name; | ||
114 | }; | ||
115 | |||
116 | /* | ||
117 | * tomoyo_alias_entry is a structure which is used for holding "alias" entries. | ||
118 | * It has following fields. | ||
119 | * | ||
120 | * (1) "list" which is linked to tomoyo_alias_list . | ||
121 | * (2) "original_name" which is a dereferenced pathname. | ||
122 | * (3) "aliased_name" which is a symlink's pathname. | ||
123 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
124 | * otherwise. | ||
125 | */ | ||
126 | struct tomoyo_alias_entry { | ||
127 | struct list_head list; | ||
128 | const struct tomoyo_path_info *original_name; | ||
129 | const struct tomoyo_path_info *aliased_name; | ||
130 | bool is_deleted; | ||
131 | }; | ||
132 | |||
133 | /** | ||
134 | * tomoyo_set_domain_flag - Set or clear domain's attribute flags. | ||
135 | * | ||
136 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
137 | * @is_delete: True if it is a delete request. | ||
138 | * @flags: Flags to set or clear. | ||
139 | * | ||
140 | * Returns nothing. | ||
141 | */ | ||
142 | void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain, | ||
143 | const bool is_delete, const u8 flags) | ||
144 | { | ||
145 | /* We need to serialize because this is bitfield operation. */ | ||
146 | static DEFINE_SPINLOCK(lock); | ||
147 | spin_lock(&lock); | ||
148 | if (!is_delete) | ||
149 | domain->flags |= flags; | ||
150 | else | ||
151 | domain->flags &= ~flags; | ||
152 | spin_unlock(&lock); | ||
153 | } | ||
154 | 59 | ||
155 | /** | 60 | /** |
156 | * tomoyo_get_last_name - Get last component of a domainname. | 61 | * tomoyo_get_last_name - Get last component of a domainname. |
@@ -205,8 +110,7 @@ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain) | |||
205 | * 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 |
206 | * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain. | 111 | * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain. |
207 | */ | 112 | */ |
208 | static LIST_HEAD(tomoyo_domain_initializer_list); | 113 | LIST_HEAD(tomoyo_domain_initializer_list); |
209 | static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock); | ||
210 | 114 | ||
211 | /** | 115 | /** |
212 | * 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. |
@@ -217,59 +121,65 @@ static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock); | |||
217 | * @is_delete: True if it is a delete request. | 121 | * @is_delete: True if it is a delete request. |
218 | * | 122 | * |
219 | * Returns 0 on success, negative value otherwise. | 123 | * Returns 0 on success, negative value otherwise. |
124 | * | ||
125 | * Caller holds tomoyo_read_lock(). | ||
220 | */ | 126 | */ |
221 | static int tomoyo_update_domain_initializer_entry(const char *domainname, | 127 | static int tomoyo_update_domain_initializer_entry(const char *domainname, |
222 | const char *program, | 128 | const char *program, |
223 | const bool is_not, | 129 | const bool is_not, |
224 | const bool is_delete) | 130 | const bool is_delete) |
225 | { | 131 | { |
226 | struct tomoyo_domain_initializer_entry *new_entry; | 132 | struct tomoyo_domain_initializer_entry *entry = NULL; |
227 | struct tomoyo_domain_initializer_entry *ptr; | 133 | struct tomoyo_domain_initializer_entry *ptr; |
228 | const struct tomoyo_path_info *saved_program; | 134 | const struct tomoyo_path_info *saved_program = NULL; |
229 | const struct tomoyo_path_info *saved_domainname = NULL; | 135 | const struct tomoyo_path_info *saved_domainname = NULL; |
230 | int error = -ENOMEM; | 136 | int error = is_delete ? -ENOENT : -ENOMEM; |
231 | bool is_last_name = false; | 137 | bool is_last_name = false; |
232 | 138 | ||
233 | if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__)) | 139 | if (!tomoyo_is_correct_path(program, 1, -1, -1)) |
234 | return -EINVAL; /* No patterns allowed. */ | 140 | return -EINVAL; /* No patterns allowed. */ |
235 | if (domainname) { | 141 | if (domainname) { |
236 | if (!tomoyo_is_domain_def(domainname) && | 142 | if (!tomoyo_is_domain_def(domainname) && |
237 | tomoyo_is_correct_path(domainname, 1, -1, -1, __func__)) | 143 | tomoyo_is_correct_path(domainname, 1, -1, -1)) |
238 | is_last_name = true; | 144 | is_last_name = true; |
239 | else if (!tomoyo_is_correct_domain(domainname, __func__)) | 145 | else if (!tomoyo_is_correct_domain(domainname)) |
240 | return -EINVAL; | 146 | return -EINVAL; |
241 | saved_domainname = tomoyo_save_name(domainname); | 147 | saved_domainname = tomoyo_get_name(domainname); |
242 | if (!saved_domainname) | 148 | if (!saved_domainname) |
243 | return -ENOMEM; | 149 | goto out; |
244 | } | 150 | } |
245 | saved_program = tomoyo_save_name(program); | 151 | saved_program = tomoyo_get_name(program); |
246 | if (!saved_program) | 152 | if (!saved_program) |
247 | return -ENOMEM; | 153 | goto out; |
248 | down_write(&tomoyo_domain_initializer_list_lock); | 154 | if (!is_delete) |
249 | list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) { | 155 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
156 | mutex_lock(&tomoyo_policy_lock); | ||
157 | list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) { | ||
250 | if (ptr->is_not != is_not || | 158 | if (ptr->is_not != is_not || |
251 | ptr->domainname != saved_domainname || | 159 | ptr->domainname != saved_domainname || |
252 | ptr->program != saved_program) | 160 | ptr->program != saved_program) |
253 | continue; | 161 | continue; |
254 | ptr->is_deleted = is_delete; | 162 | ptr->is_deleted = is_delete; |
255 | error = 0; | 163 | error = 0; |
256 | goto out; | 164 | break; |
257 | } | 165 | } |
258 | if (is_delete) { | 166 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
259 | error = -ENOENT; | 167 | entry->domainname = saved_domainname; |
260 | goto out; | 168 | saved_domainname = NULL; |
169 | entry->program = saved_program; | ||
170 | saved_program = NULL; | ||
171 | entry->is_not = is_not; | ||
172 | entry->is_last_name = is_last_name; | ||
173 | list_add_tail_rcu(&entry->list, | ||
174 | &tomoyo_domain_initializer_list); | ||
175 | entry = NULL; | ||
176 | error = 0; | ||
261 | } | 177 | } |
262 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 178 | mutex_unlock(&tomoyo_policy_lock); |
263 | if (!new_entry) | ||
264 | goto out; | ||
265 | new_entry->domainname = saved_domainname; | ||
266 | new_entry->program = saved_program; | ||
267 | new_entry->is_not = is_not; | ||
268 | new_entry->is_last_name = is_last_name; | ||
269 | list_add_tail(&new_entry->list, &tomoyo_domain_initializer_list); | ||
270 | error = 0; | ||
271 | out: | 179 | out: |
272 | up_write(&tomoyo_domain_initializer_list_lock); | 180 | tomoyo_put_name(saved_domainname); |
181 | tomoyo_put_name(saved_program); | ||
182 | kfree(entry); | ||
273 | return error; | 183 | return error; |
274 | } | 184 | } |
275 | 185 | ||
@@ -279,13 +189,14 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, | |||
279 | * @head: Pointer to "struct tomoyo_io_buffer". | 189 | * @head: Pointer to "struct tomoyo_io_buffer". |
280 | * | 190 | * |
281 | * Returns true on success, false otherwise. | 191 | * Returns true on success, false otherwise. |
192 | * | ||
193 | * Caller holds tomoyo_read_lock(). | ||
282 | */ | 194 | */ |
283 | bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head) | 195 | bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head) |
284 | { | 196 | { |
285 | struct list_head *pos; | 197 | struct list_head *pos; |
286 | bool done = true; | 198 | bool done = true; |
287 | 199 | ||
288 | down_read(&tomoyo_domain_initializer_list_lock); | ||
289 | list_for_each_cookie(pos, head->read_var2, | 200 | list_for_each_cookie(pos, head->read_var2, |
290 | &tomoyo_domain_initializer_list) { | 201 | &tomoyo_domain_initializer_list) { |
291 | const char *no; | 202 | const char *no; |
@@ -308,7 +219,6 @@ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head) | |||
308 | if (!done) | 219 | if (!done) |
309 | break; | 220 | break; |
310 | } | 221 | } |
311 | up_read(&tomoyo_domain_initializer_list_lock); | ||
312 | return done; | 222 | return done; |
313 | } | 223 | } |
314 | 224 | ||
@@ -320,6 +230,8 @@ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head) | |||
320 | * @is_delete: True if it is a delete request. | 230 | * @is_delete: True if it is a delete request. |
321 | * | 231 | * |
322 | * Returns 0 on success, negative value otherwise. | 232 | * Returns 0 on success, negative value otherwise. |
233 | * | ||
234 | * Caller holds tomoyo_read_lock(). | ||
323 | */ | 235 | */ |
324 | int tomoyo_write_domain_initializer_policy(char *data, const bool is_not, | 236 | int tomoyo_write_domain_initializer_policy(char *data, const bool is_not, |
325 | const bool is_delete) | 237 | const bool is_delete) |
@@ -345,6 +257,8 @@ int tomoyo_write_domain_initializer_policy(char *data, const bool is_not, | |||
345 | * | 257 | * |
346 | * Returns true if executing @program reinitializes domain transition, | 258 | * Returns true if executing @program reinitializes domain transition, |
347 | * false otherwise. | 259 | * false otherwise. |
260 | * | ||
261 | * Caller holds tomoyo_read_lock(). | ||
348 | */ | 262 | */ |
349 | static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * | 263 | static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * |
350 | domainname, | 264 | domainname, |
@@ -355,8 +269,7 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * | |||
355 | struct tomoyo_domain_initializer_entry *ptr; | 269 | struct tomoyo_domain_initializer_entry *ptr; |
356 | bool flag = false; | 270 | bool flag = false; |
357 | 271 | ||
358 | down_read(&tomoyo_domain_initializer_list_lock); | 272 | list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) { |
359 | list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) { | ||
360 | if (ptr->is_deleted) | 273 | if (ptr->is_deleted) |
361 | continue; | 274 | continue; |
362 | if (ptr->domainname) { | 275 | if (ptr->domainname) { |
@@ -376,7 +289,6 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * | |||
376 | } | 289 | } |
377 | flag = true; | 290 | flag = true; |
378 | } | 291 | } |
379 | up_read(&tomoyo_domain_initializer_list_lock); | ||
380 | return flag; | 292 | return flag; |
381 | } | 293 | } |
382 | 294 | ||
@@ -418,8 +330,7 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * | |||
418 | * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless | 330 | * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless |
419 | * explicitly specified by "initialize_domain". | 331 | * explicitly specified by "initialize_domain". |
420 | */ | 332 | */ |
421 | static LIST_HEAD(tomoyo_domain_keeper_list); | 333 | LIST_HEAD(tomoyo_domain_keeper_list); |
422 | static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock); | ||
423 | 334 | ||
424 | /** | 335 | /** |
425 | * 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. |
@@ -430,59 +341,64 @@ static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock); | |||
430 | * @is_delete: True if it is a delete request. | 341 | * @is_delete: True if it is a delete request. |
431 | * | 342 | * |
432 | * Returns 0 on success, negative value otherwise. | 343 | * Returns 0 on success, negative value otherwise. |
344 | * | ||
345 | * Caller holds tomoyo_read_lock(). | ||
433 | */ | 346 | */ |
434 | static int tomoyo_update_domain_keeper_entry(const char *domainname, | 347 | static int tomoyo_update_domain_keeper_entry(const char *domainname, |
435 | const char *program, | 348 | const char *program, |
436 | const bool is_not, | 349 | const bool is_not, |
437 | const bool is_delete) | 350 | const bool is_delete) |
438 | { | 351 | { |
439 | struct tomoyo_domain_keeper_entry *new_entry; | 352 | struct tomoyo_domain_keeper_entry *entry = NULL; |
440 | struct tomoyo_domain_keeper_entry *ptr; | 353 | struct tomoyo_domain_keeper_entry *ptr; |
441 | const struct tomoyo_path_info *saved_domainname; | 354 | const struct tomoyo_path_info *saved_domainname = NULL; |
442 | const struct tomoyo_path_info *saved_program = NULL; | 355 | const struct tomoyo_path_info *saved_program = NULL; |
443 | int error = -ENOMEM; | 356 | int error = is_delete ? -ENOENT : -ENOMEM; |
444 | bool is_last_name = false; | 357 | bool is_last_name = false; |
445 | 358 | ||
446 | if (!tomoyo_is_domain_def(domainname) && | 359 | if (!tomoyo_is_domain_def(domainname) && |
447 | tomoyo_is_correct_path(domainname, 1, -1, -1, __func__)) | 360 | tomoyo_is_correct_path(domainname, 1, -1, -1)) |
448 | is_last_name = true; | 361 | is_last_name = true; |
449 | else if (!tomoyo_is_correct_domain(domainname, __func__)) | 362 | else if (!tomoyo_is_correct_domain(domainname)) |
450 | return -EINVAL; | 363 | return -EINVAL; |
451 | if (program) { | 364 | if (program) { |
452 | if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__)) | 365 | if (!tomoyo_is_correct_path(program, 1, -1, -1)) |
453 | return -EINVAL; | 366 | return -EINVAL; |
454 | saved_program = tomoyo_save_name(program); | 367 | saved_program = tomoyo_get_name(program); |
455 | if (!saved_program) | 368 | if (!saved_program) |
456 | return -ENOMEM; | 369 | goto out; |
457 | } | 370 | } |
458 | saved_domainname = tomoyo_save_name(domainname); | 371 | saved_domainname = tomoyo_get_name(domainname); |
459 | if (!saved_domainname) | 372 | if (!saved_domainname) |
460 | return -ENOMEM; | 373 | goto out; |
461 | down_write(&tomoyo_domain_keeper_list_lock); | 374 | if (!is_delete) |
462 | list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) { | 375 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
376 | mutex_lock(&tomoyo_policy_lock); | ||
377 | list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { | ||
463 | if (ptr->is_not != is_not || | 378 | if (ptr->is_not != is_not || |
464 | ptr->domainname != saved_domainname || | 379 | ptr->domainname != saved_domainname || |
465 | ptr->program != saved_program) | 380 | ptr->program != saved_program) |
466 | continue; | 381 | continue; |
467 | ptr->is_deleted = is_delete; | 382 | ptr->is_deleted = is_delete; |
468 | error = 0; | 383 | error = 0; |
469 | goto out; | 384 | break; |
470 | } | 385 | } |
471 | if (is_delete) { | 386 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
472 | error = -ENOENT; | 387 | entry->domainname = saved_domainname; |
473 | goto out; | 388 | saved_domainname = NULL; |
389 | entry->program = saved_program; | ||
390 | saved_program = NULL; | ||
391 | entry->is_not = is_not; | ||
392 | entry->is_last_name = is_last_name; | ||
393 | list_add_tail_rcu(&entry->list, &tomoyo_domain_keeper_list); | ||
394 | entry = NULL; | ||
395 | error = 0; | ||
474 | } | 396 | } |
475 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 397 | mutex_unlock(&tomoyo_policy_lock); |
476 | if (!new_entry) | ||
477 | goto out; | ||
478 | new_entry->domainname = saved_domainname; | ||
479 | new_entry->program = saved_program; | ||
480 | new_entry->is_not = is_not; | ||
481 | new_entry->is_last_name = is_last_name; | ||
482 | list_add_tail(&new_entry->list, &tomoyo_domain_keeper_list); | ||
483 | error = 0; | ||
484 | out: | 398 | out: |
485 | up_write(&tomoyo_domain_keeper_list_lock); | 399 | tomoyo_put_name(saved_domainname); |
400 | tomoyo_put_name(saved_program); | ||
401 | kfree(entry); | ||
486 | return error; | 402 | return error; |
487 | } | 403 | } |
488 | 404 | ||
@@ -493,6 +409,7 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, | |||
493 | * @is_not: True if it is "no_keep_domain" entry. | 409 | * @is_not: True if it is "no_keep_domain" entry. |
494 | * @is_delete: True if it is a delete request. | 410 | * @is_delete: True if it is a delete request. |
495 | * | 411 | * |
412 | * Caller holds tomoyo_read_lock(). | ||
496 | */ | 413 | */ |
497 | int tomoyo_write_domain_keeper_policy(char *data, const bool is_not, | 414 | int tomoyo_write_domain_keeper_policy(char *data, const bool is_not, |
498 | const bool is_delete) | 415 | const bool is_delete) |
@@ -513,13 +430,14 @@ int tomoyo_write_domain_keeper_policy(char *data, const bool is_not, | |||
513 | * @head: Pointer to "struct tomoyo_io_buffer". | 430 | * @head: Pointer to "struct tomoyo_io_buffer". |
514 | * | 431 | * |
515 | * Returns true on success, false otherwise. | 432 | * Returns true on success, false otherwise. |
433 | * | ||
434 | * Caller holds tomoyo_read_lock(). | ||
516 | */ | 435 | */ |
517 | bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head) | 436 | bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head) |
518 | { | 437 | { |
519 | struct list_head *pos; | 438 | struct list_head *pos; |
520 | bool done = true; | 439 | bool done = true; |
521 | 440 | ||
522 | down_read(&tomoyo_domain_keeper_list_lock); | ||
523 | list_for_each_cookie(pos, head->read_var2, | 441 | list_for_each_cookie(pos, head->read_var2, |
524 | &tomoyo_domain_keeper_list) { | 442 | &tomoyo_domain_keeper_list) { |
525 | struct tomoyo_domain_keeper_entry *ptr; | 443 | struct tomoyo_domain_keeper_entry *ptr; |
@@ -542,7 +460,6 @@ bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head) | |||
542 | if (!done) | 460 | if (!done) |
543 | break; | 461 | break; |
544 | } | 462 | } |
545 | up_read(&tomoyo_domain_keeper_list_lock); | ||
546 | return done; | 463 | return done; |
547 | } | 464 | } |
548 | 465 | ||
@@ -555,6 +472,8 @@ bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head) | |||
555 | * | 472 | * |
556 | * Returns true if executing @program supresses domain transition, | 473 | * Returns true if executing @program supresses domain transition, |
557 | * false otherwise. | 474 | * false otherwise. |
475 | * | ||
476 | * Caller holds tomoyo_read_lock(). | ||
558 | */ | 477 | */ |
559 | static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, | 478 | static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, |
560 | const struct tomoyo_path_info *program, | 479 | const struct tomoyo_path_info *program, |
@@ -563,8 +482,7 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, | |||
563 | struct tomoyo_domain_keeper_entry *ptr; | 482 | struct tomoyo_domain_keeper_entry *ptr; |
564 | bool flag = false; | 483 | bool flag = false; |
565 | 484 | ||
566 | down_read(&tomoyo_domain_keeper_list_lock); | 485 | list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { |
567 | list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) { | ||
568 | if (ptr->is_deleted) | 486 | if (ptr->is_deleted) |
569 | continue; | 487 | continue; |
570 | if (!ptr->is_last_name) { | 488 | if (!ptr->is_last_name) { |
@@ -582,7 +500,6 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, | |||
582 | } | 500 | } |
583 | flag = true; | 501 | flag = true; |
584 | } | 502 | } |
585 | up_read(&tomoyo_domain_keeper_list_lock); | ||
586 | return flag; | 503 | return flag; |
587 | } | 504 | } |
588 | 505 | ||
@@ -616,8 +533,7 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, | |||
616 | * /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 |
617 | * execve() succeeds is calculated using /bin/cat rather than /bin/busybox . | 534 | * execve() succeeds is calculated using /bin/cat rather than /bin/busybox . |
618 | */ | 535 | */ |
619 | static LIST_HEAD(tomoyo_alias_list); | 536 | LIST_HEAD(tomoyo_alias_list); |
620 | static DECLARE_RWSEM(tomoyo_alias_list_lock); | ||
621 | 537 | ||
622 | /** | 538 | /** |
623 | * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list. | 539 | * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list. |
@@ -627,46 +543,51 @@ static DECLARE_RWSEM(tomoyo_alias_list_lock); | |||
627 | * @is_delete: True if it is a delete request. | 543 | * @is_delete: True if it is a delete request. |
628 | * | 544 | * |
629 | * Returns 0 on success, negative value otherwise. | 545 | * Returns 0 on success, negative value otherwise. |
546 | * | ||
547 | * Caller holds tomoyo_read_lock(). | ||
630 | */ | 548 | */ |
631 | static int tomoyo_update_alias_entry(const char *original_name, | 549 | static int tomoyo_update_alias_entry(const char *original_name, |
632 | const char *aliased_name, | 550 | const char *aliased_name, |
633 | const bool is_delete) | 551 | const bool is_delete) |
634 | { | 552 | { |
635 | struct tomoyo_alias_entry *new_entry; | 553 | struct tomoyo_alias_entry *entry = NULL; |
636 | struct tomoyo_alias_entry *ptr; | 554 | struct tomoyo_alias_entry *ptr; |
637 | const struct tomoyo_path_info *saved_original_name; | 555 | const struct tomoyo_path_info *saved_original_name; |
638 | const struct tomoyo_path_info *saved_aliased_name; | 556 | const struct tomoyo_path_info *saved_aliased_name; |
639 | int error = -ENOMEM; | 557 | int error = is_delete ? -ENOENT : -ENOMEM; |
640 | 558 | ||
641 | if (!tomoyo_is_correct_path(original_name, 1, -1, -1, __func__) || | 559 | if (!tomoyo_is_correct_path(original_name, 1, -1, -1) || |
642 | !tomoyo_is_correct_path(aliased_name, 1, -1, -1, __func__)) | 560 | !tomoyo_is_correct_path(aliased_name, 1, -1, -1)) |
643 | return -EINVAL; /* No patterns allowed. */ | 561 | return -EINVAL; /* No patterns allowed. */ |
644 | saved_original_name = tomoyo_save_name(original_name); | 562 | saved_original_name = tomoyo_get_name(original_name); |
645 | saved_aliased_name = tomoyo_save_name(aliased_name); | 563 | saved_aliased_name = tomoyo_get_name(aliased_name); |
646 | if (!saved_original_name || !saved_aliased_name) | 564 | if (!saved_original_name || !saved_aliased_name) |
647 | return -ENOMEM; | 565 | goto out; |
648 | down_write(&tomoyo_alias_list_lock); | 566 | if (!is_delete) |
649 | list_for_each_entry(ptr, &tomoyo_alias_list, list) { | 567 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
568 | mutex_lock(&tomoyo_policy_lock); | ||
569 | list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { | ||
650 | if (ptr->original_name != saved_original_name || | 570 | if (ptr->original_name != saved_original_name || |
651 | ptr->aliased_name != saved_aliased_name) | 571 | ptr->aliased_name != saved_aliased_name) |
652 | continue; | 572 | continue; |
653 | ptr->is_deleted = is_delete; | 573 | ptr->is_deleted = is_delete; |
654 | error = 0; | 574 | error = 0; |
655 | goto out; | 575 | break; |
656 | } | 576 | } |
657 | if (is_delete) { | 577 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
658 | error = -ENOENT; | 578 | entry->original_name = saved_original_name; |
659 | goto out; | 579 | saved_original_name = NULL; |
580 | entry->aliased_name = saved_aliased_name; | ||
581 | saved_aliased_name = NULL; | ||
582 | list_add_tail_rcu(&entry->list, &tomoyo_alias_list); | ||
583 | entry = NULL; | ||
584 | error = 0; | ||
660 | } | 585 | } |
661 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 586 | mutex_unlock(&tomoyo_policy_lock); |
662 | if (!new_entry) | ||
663 | goto out; | ||
664 | new_entry->original_name = saved_original_name; | ||
665 | new_entry->aliased_name = saved_aliased_name; | ||
666 | list_add_tail(&new_entry->list, &tomoyo_alias_list); | ||
667 | error = 0; | ||
668 | out: | 587 | out: |
669 | up_write(&tomoyo_alias_list_lock); | 588 | tomoyo_put_name(saved_original_name); |
589 | tomoyo_put_name(saved_aliased_name); | ||
590 | kfree(entry); | ||
670 | return error; | 591 | return error; |
671 | } | 592 | } |
672 | 593 | ||
@@ -676,13 +597,14 @@ static int tomoyo_update_alias_entry(const char *original_name, | |||
676 | * @head: Pointer to "struct tomoyo_io_buffer". | 597 | * @head: Pointer to "struct tomoyo_io_buffer". |
677 | * | 598 | * |
678 | * Returns true on success, false otherwise. | 599 | * Returns true on success, false otherwise. |
600 | * | ||
601 | * Caller holds tomoyo_read_lock(). | ||
679 | */ | 602 | */ |
680 | bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) | 603 | bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) |
681 | { | 604 | { |
682 | struct list_head *pos; | 605 | struct list_head *pos; |
683 | bool done = true; | 606 | bool done = true; |
684 | 607 | ||
685 | down_read(&tomoyo_alias_list_lock); | ||
686 | list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) { | 608 | list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) { |
687 | struct tomoyo_alias_entry *ptr; | 609 | struct tomoyo_alias_entry *ptr; |
688 | 610 | ||
@@ -695,7 +617,6 @@ bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) | |||
695 | if (!done) | 617 | if (!done) |
696 | break; | 618 | break; |
697 | } | 619 | } |
698 | up_read(&tomoyo_alias_list_lock); | ||
699 | return done; | 620 | return done; |
700 | } | 621 | } |
701 | 622 | ||
@@ -706,6 +627,8 @@ bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) | |||
706 | * @is_delete: True if it is a delete request. | 627 | * @is_delete: True if it is a delete request. |
707 | * | 628 | * |
708 | * Returns 0 on success, negative value otherwise. | 629 | * Returns 0 on success, negative value otherwise. |
630 | * | ||
631 | * Caller holds tomoyo_read_lock(). | ||
709 | */ | 632 | */ |
710 | int tomoyo_write_alias_policy(char *data, const bool is_delete) | 633 | int tomoyo_write_alias_policy(char *data, const bool is_delete) |
711 | { | 634 | { |
@@ -724,63 +647,46 @@ int tomoyo_write_alias_policy(char *data, const bool is_delete) | |||
724 | * @profile: Profile number to assign if the domain was newly created. | 647 | * @profile: Profile number to assign if the domain was newly created. |
725 | * | 648 | * |
726 | * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise. | 649 | * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise. |
650 | * | ||
651 | * Caller holds tomoyo_read_lock(). | ||
727 | */ | 652 | */ |
728 | struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | 653 | struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * |
729 | domainname, | 654 | domainname, |
730 | const u8 profile) | 655 | const u8 profile) |
731 | { | 656 | { |
732 | struct tomoyo_domain_info *domain = NULL; | 657 | struct tomoyo_domain_info *entry; |
658 | struct tomoyo_domain_info *domain; | ||
733 | const struct tomoyo_path_info *saved_domainname; | 659 | const struct tomoyo_path_info *saved_domainname; |
660 | bool found = false; | ||
734 | 661 | ||
735 | down_write(&tomoyo_domain_list_lock); | 662 | if (!tomoyo_is_correct_domain(domainname)) |
736 | domain = tomoyo_find_domain(domainname); | 663 | return NULL; |
737 | if (domain) | 664 | saved_domainname = tomoyo_get_name(domainname); |
738 | goto out; | ||
739 | if (!tomoyo_is_correct_domain(domainname, __func__)) | ||
740 | goto out; | ||
741 | saved_domainname = tomoyo_save_name(domainname); | ||
742 | if (!saved_domainname) | 665 | if (!saved_domainname) |
743 | goto out; | 666 | return NULL; |
744 | /* Can I reuse memory of deleted domain? */ | 667 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
745 | list_for_each_entry(domain, &tomoyo_domain_list, list) { | 668 | mutex_lock(&tomoyo_policy_lock); |
746 | struct task_struct *p; | 669 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { |
747 | struct tomoyo_acl_info *ptr; | 670 | if (domain->is_deleted || |
748 | bool flag; | 671 | tomoyo_pathcmp(saved_domainname, domain->domainname)) |
749 | if (!domain->is_deleted || | ||
750 | domain->domainname != saved_domainname) | ||
751 | continue; | 672 | continue; |
752 | flag = false; | 673 | found = true; |
753 | read_lock(&tasklist_lock); | 674 | break; |
754 | for_each_process(p) { | ||
755 | if (tomoyo_real_domain(p) != domain) | ||
756 | continue; | ||
757 | flag = true; | ||
758 | break; | ||
759 | } | ||
760 | read_unlock(&tasklist_lock); | ||
761 | if (flag) | ||
762 | continue; | ||
763 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | ||
764 | ptr->type |= TOMOYO_ACL_DELETED; | ||
765 | } | ||
766 | tomoyo_set_domain_flag(domain, true, domain->flags); | ||
767 | domain->profile = profile; | ||
768 | domain->quota_warned = false; | ||
769 | mb(); /* Avoid out-of-order execution. */ | ||
770 | domain->is_deleted = false; | ||
771 | goto out; | ||
772 | } | 675 | } |
773 | /* No memory reusable. Create using new memory. */ | 676 | if (!found && tomoyo_memory_ok(entry)) { |
774 | domain = tomoyo_alloc_element(sizeof(*domain)); | 677 | INIT_LIST_HEAD(&entry->acl_info_list); |
775 | if (domain) { | 678 | entry->domainname = saved_domainname; |
776 | INIT_LIST_HEAD(&domain->acl_info_list); | 679 | saved_domainname = NULL; |
777 | domain->domainname = saved_domainname; | 680 | entry->profile = profile; |
778 | domain->profile = profile; | 681 | list_add_tail_rcu(&entry->list, &tomoyo_domain_list); |
779 | list_add_tail(&domain->list, &tomoyo_domain_list); | 682 | domain = entry; |
683 | entry = NULL; | ||
684 | found = true; | ||
780 | } | 685 | } |
781 | out: | 686 | mutex_unlock(&tomoyo_policy_lock); |
782 | up_write(&tomoyo_domain_list_lock); | 687 | tomoyo_put_name(saved_domainname); |
783 | return domain; | 688 | kfree(entry); |
689 | return found ? domain : NULL; | ||
784 | } | 690 | } |
785 | 691 | ||
786 | /** | 692 | /** |
@@ -789,6 +695,8 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | |||
789 | * @bprm: Pointer to "struct linux_binprm". | 695 | * @bprm: Pointer to "struct linux_binprm". |
790 | * | 696 | * |
791 | * Returns 0 on success, negative value otherwise. | 697 | * Returns 0 on success, negative value otherwise. |
698 | * | ||
699 | * Caller holds tomoyo_read_lock(). | ||
792 | */ | 700 | */ |
793 | int tomoyo_find_next_domain(struct linux_binprm *bprm) | 701 | int tomoyo_find_next_domain(struct linux_binprm *bprm) |
794 | { | 702 | { |
@@ -796,7 +704,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
796 | * This function assumes that the size of buffer returned by | 704 | * This function assumes that the size of buffer returned by |
797 | * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN. | 705 | * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN. |
798 | */ | 706 | */ |
799 | struct tomoyo_page_buffer *tmp = tomoyo_alloc(sizeof(*tmp)); | 707 | struct tomoyo_page_buffer *tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); |
800 | struct tomoyo_domain_info *old_domain = tomoyo_domain(); | 708 | struct tomoyo_domain_info *old_domain = tomoyo_domain(); |
801 | struct tomoyo_domain_info *domain = NULL; | 709 | struct tomoyo_domain_info *domain = NULL; |
802 | const char *old_domain_name = old_domain->domainname->name; | 710 | const char *old_domain_name = old_domain->domainname->name; |
@@ -849,8 +757,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
849 | if (tomoyo_pathcmp(&r, &s)) { | 757 | if (tomoyo_pathcmp(&r, &s)) { |
850 | struct tomoyo_alias_entry *ptr; | 758 | struct tomoyo_alias_entry *ptr; |
851 | /* Is this program allowed to be called via symbolic links? */ | 759 | /* Is this program allowed to be called via symbolic links? */ |
852 | down_read(&tomoyo_alias_list_lock); | 760 | list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { |
853 | list_for_each_entry(ptr, &tomoyo_alias_list, list) { | ||
854 | if (ptr->is_deleted || | 761 | if (ptr->is_deleted || |
855 | tomoyo_pathcmp(&r, ptr->original_name) || | 762 | tomoyo_pathcmp(&r, ptr->original_name) || |
856 | tomoyo_pathcmp(&s, ptr->aliased_name)) | 763 | tomoyo_pathcmp(&s, ptr->aliased_name)) |
@@ -861,7 +768,6 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
861 | tomoyo_fill_path_info(&r); | 768 | tomoyo_fill_path_info(&r); |
862 | break; | 769 | break; |
863 | } | 770 | } |
864 | up_read(&tomoyo_alias_list_lock); | ||
865 | } | 771 | } |
866 | 772 | ||
867 | /* Check execute permission. */ | 773 | /* Check execute permission. */ |
@@ -892,9 +798,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
892 | } | 798 | } |
893 | if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN) | 799 | if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN) |
894 | goto done; | 800 | goto done; |
895 | down_read(&tomoyo_domain_list_lock); | ||
896 | domain = tomoyo_find_domain(new_domain_name); | 801 | domain = tomoyo_find_domain(new_domain_name); |
897 | up_read(&tomoyo_domain_list_lock); | ||
898 | if (domain) | 802 | if (domain) |
899 | goto done; | 803 | goto done; |
900 | if (is_enforce) | 804 | if (is_enforce) |
@@ -909,14 +813,15 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
909 | if (is_enforce) | 813 | if (is_enforce) |
910 | retval = -EPERM; | 814 | retval = -EPERM; |
911 | else | 815 | else |
912 | tomoyo_set_domain_flag(old_domain, false, | 816 | old_domain->transition_failed = true; |
913 | TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED); | ||
914 | out: | 817 | out: |
915 | if (!domain) | 818 | if (!domain) |
916 | domain = old_domain; | 819 | domain = old_domain; |
820 | /* Update reference count on "struct tomoyo_domain_info". */ | ||
821 | atomic_inc(&domain->users); | ||
917 | bprm->cred->security = domain; | 822 | bprm->cred->security = domain; |
918 | tomoyo_free(real_program_name); | 823 | kfree(real_program_name); |
919 | tomoyo_free(symlink_program_name); | 824 | kfree(symlink_program_name); |
920 | tomoyo_free(tmp); | 825 | kfree(tmp); |
921 | return retval; | 826 | return retval; |
922 | } | 827 | } |