diff options
Diffstat (limited to 'security/tomoyo')
-rw-r--r-- | security/tomoyo/audit.c | 8 | ||||
-rw-r--r-- | security/tomoyo/common.c | 383 | ||||
-rw-r--r-- | security/tomoyo/common.h | 63 | ||||
-rw-r--r-- | security/tomoyo/domain.c | 360 | ||||
-rw-r--r-- | security/tomoyo/file.c | 2 | ||||
-rw-r--r-- | security/tomoyo/gc.c | 73 | ||||
-rw-r--r-- | security/tomoyo/memory.c | 21 | ||||
-rw-r--r-- | security/tomoyo/util.c | 58 |
8 files changed, 669 insertions, 299 deletions
diff --git a/security/tomoyo/audit.c b/security/tomoyo/audit.c index e882f17065f2..ef2172f29583 100644 --- a/security/tomoyo/audit.c +++ b/security/tomoyo/audit.c | |||
@@ -151,13 +151,15 @@ static unsigned int tomoyo_log_count; | |||
151 | /** | 151 | /** |
152 | * tomoyo_get_audit - Get audit mode. | 152 | * tomoyo_get_audit - Get audit mode. |
153 | * | 153 | * |
154 | * @ns: Pointer to "struct tomoyo_policy_namespace". | ||
154 | * @profile: Profile number. | 155 | * @profile: Profile number. |
155 | * @index: Index number of functionality. | 156 | * @index: Index number of functionality. |
156 | * @is_granted: True if granted log, false otherwise. | 157 | * @is_granted: True if granted log, false otherwise. |
157 | * | 158 | * |
158 | * Returns true if this request should be audited, false otherwise. | 159 | * Returns true if this request should be audited, false otherwise. |
159 | */ | 160 | */ |
160 | static bool tomoyo_get_audit(const u8 profile, const u8 index, | 161 | static bool tomoyo_get_audit(const struct tomoyo_policy_namespace *ns, |
162 | const u8 profile, const u8 index, | ||
161 | const bool is_granted) | 163 | const bool is_granted) |
162 | { | 164 | { |
163 | u8 mode; | 165 | u8 mode; |
@@ -165,7 +167,7 @@ static bool tomoyo_get_audit(const u8 profile, const u8 index, | |||
165 | struct tomoyo_profile *p; | 167 | struct tomoyo_profile *p; |
166 | if (!tomoyo_policy_loaded) | 168 | if (!tomoyo_policy_loaded) |
167 | return false; | 169 | return false; |
168 | p = tomoyo_profile(profile); | 170 | p = tomoyo_profile(ns, profile); |
169 | if (tomoyo_log_count >= p->pref[TOMOYO_PREF_MAX_AUDIT_LOG]) | 171 | if (tomoyo_log_count >= p->pref[TOMOYO_PREF_MAX_AUDIT_LOG]) |
170 | return false; | 172 | return false; |
171 | mode = p->config[index]; | 173 | mode = p->config[index]; |
@@ -194,7 +196,7 @@ void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt, | |||
194 | char *buf; | 196 | char *buf; |
195 | struct tomoyo_log *entry; | 197 | struct tomoyo_log *entry; |
196 | bool quota_exceeded = false; | 198 | bool quota_exceeded = false; |
197 | if (!tomoyo_get_audit(r->profile, r->type, r->granted)) | 199 | if (!tomoyo_get_audit(r->domain->ns, r->profile, r->type, r->granted)) |
198 | goto out; | 200 | goto out; |
199 | buf = tomoyo_init_log(r, len, fmt, args); | 201 | buf = tomoyo_init_log(r, len, fmt, args); |
200 | if (!buf) | 202 | if (!buf) |
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 507ebf01e43b..50481d2cf970 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -11,12 +11,6 @@ | |||
11 | #include <linux/security.h> | 11 | #include <linux/security.h> |
12 | #include "common.h" | 12 | #include "common.h" |
13 | 13 | ||
14 | /* Profile version. Currently only 20090903 is defined. */ | ||
15 | static unsigned int tomoyo_profile_version; | ||
16 | |||
17 | /* Profile table. Memory is allocated as needed. */ | ||
18 | static struct tomoyo_profile *tomoyo_profile_ptr[TOMOYO_MAX_PROFILES]; | ||
19 | |||
20 | /* String table for operation mode. */ | 14 | /* String table for operation mode. */ |
21 | const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE] = { | 15 | const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE] = { |
22 | [TOMOYO_CONFIG_DISABLED] = "disabled", | 16 | [TOMOYO_CONFIG_DISABLED] = "disabled", |
@@ -216,6 +210,50 @@ static void tomoyo_set_slash(struct tomoyo_io_buffer *head) | |||
216 | tomoyo_set_string(head, "/"); | 210 | tomoyo_set_string(head, "/"); |
217 | } | 211 | } |
218 | 212 | ||
213 | /* List of namespaces. */ | ||
214 | LIST_HEAD(tomoyo_namespace_list); | ||
215 | /* True if namespace other than tomoyo_kernel_namespace is defined. */ | ||
216 | static bool tomoyo_namespace_enabled; | ||
217 | |||
218 | /** | ||
219 | * tomoyo_init_policy_namespace - Initialize namespace. | ||
220 | * | ||
221 | * @ns: Pointer to "struct tomoyo_policy_namespace". | ||
222 | * | ||
223 | * Returns nothing. | ||
224 | */ | ||
225 | void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns) | ||
226 | { | ||
227 | unsigned int idx; | ||
228 | for (idx = 0; idx < TOMOYO_MAX_ACL_GROUPS; idx++) | ||
229 | INIT_LIST_HEAD(&ns->acl_group[idx]); | ||
230 | for (idx = 0; idx < TOMOYO_MAX_GROUP; idx++) | ||
231 | INIT_LIST_HEAD(&ns->group_list[idx]); | ||
232 | for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++) | ||
233 | INIT_LIST_HEAD(&ns->policy_list[idx]); | ||
234 | ns->profile_version = 20100903; | ||
235 | tomoyo_namespace_enabled = !list_empty(&tomoyo_namespace_list); | ||
236 | list_add_tail_rcu(&ns->namespace_list, &tomoyo_namespace_list); | ||
237 | } | ||
238 | |||
239 | /** | ||
240 | * tomoyo_print_namespace - Print namespace header. | ||
241 | * | ||
242 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
243 | * | ||
244 | * Returns nothing. | ||
245 | */ | ||
246 | static void tomoyo_print_namespace(struct tomoyo_io_buffer *head) | ||
247 | { | ||
248 | if (!tomoyo_namespace_enabled) | ||
249 | return; | ||
250 | tomoyo_set_string(head, | ||
251 | container_of(head->r.ns, | ||
252 | struct tomoyo_policy_namespace, | ||
253 | namespace_list)->name); | ||
254 | tomoyo_set_space(head); | ||
255 | } | ||
256 | |||
219 | /** | 257 | /** |
220 | * tomoyo_print_name_union - Print a tomoyo_name_union. | 258 | * tomoyo_print_name_union - Print a tomoyo_name_union. |
221 | * | 259 | * |
@@ -283,23 +321,25 @@ static void tomoyo_print_number_union(struct tomoyo_io_buffer *head, | |||
283 | /** | 321 | /** |
284 | * tomoyo_assign_profile - Create a new profile. | 322 | * tomoyo_assign_profile - Create a new profile. |
285 | * | 323 | * |
324 | * @ns: Pointer to "struct tomoyo_policy_namespace". | ||
286 | * @profile: Profile number to create. | 325 | * @profile: Profile number to create. |
287 | * | 326 | * |
288 | * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise. | 327 | * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise. |
289 | */ | 328 | */ |
290 | static struct tomoyo_profile *tomoyo_assign_profile(const unsigned int profile) | 329 | static struct tomoyo_profile *tomoyo_assign_profile |
330 | (struct tomoyo_policy_namespace *ns, const unsigned int profile) | ||
291 | { | 331 | { |
292 | struct tomoyo_profile *ptr; | 332 | struct tomoyo_profile *ptr; |
293 | struct tomoyo_profile *entry; | 333 | struct tomoyo_profile *entry; |
294 | if (profile >= TOMOYO_MAX_PROFILES) | 334 | if (profile >= TOMOYO_MAX_PROFILES) |
295 | return NULL; | 335 | return NULL; |
296 | ptr = tomoyo_profile_ptr[profile]; | 336 | ptr = ns->profile_ptr[profile]; |
297 | if (ptr) | 337 | if (ptr) |
298 | return ptr; | 338 | return ptr; |
299 | entry = kzalloc(sizeof(*entry), GFP_NOFS); | 339 | entry = kzalloc(sizeof(*entry), GFP_NOFS); |
300 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 340 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
301 | goto out; | 341 | goto out; |
302 | ptr = tomoyo_profile_ptr[profile]; | 342 | ptr = ns->profile_ptr[profile]; |
303 | if (!ptr && tomoyo_memory_ok(entry)) { | 343 | if (!ptr && tomoyo_memory_ok(entry)) { |
304 | ptr = entry; | 344 | ptr = entry; |
305 | ptr->default_config = TOMOYO_CONFIG_DISABLED | | 345 | ptr->default_config = TOMOYO_CONFIG_DISABLED | |
@@ -310,7 +350,7 @@ static struct tomoyo_profile *tomoyo_assign_profile(const unsigned int profile) | |||
310 | ptr->pref[TOMOYO_PREF_MAX_AUDIT_LOG] = 1024; | 350 | ptr->pref[TOMOYO_PREF_MAX_AUDIT_LOG] = 1024; |
311 | ptr->pref[TOMOYO_PREF_MAX_LEARNING_ENTRY] = 2048; | 351 | ptr->pref[TOMOYO_PREF_MAX_LEARNING_ENTRY] = 2048; |
312 | mb(); /* Avoid out-of-order execution. */ | 352 | mb(); /* Avoid out-of-order execution. */ |
313 | tomoyo_profile_ptr[profile] = ptr; | 353 | ns->profile_ptr[profile] = ptr; |
314 | entry = NULL; | 354 | entry = NULL; |
315 | } | 355 | } |
316 | mutex_unlock(&tomoyo_policy_lock); | 356 | mutex_unlock(&tomoyo_policy_lock); |
@@ -322,14 +362,16 @@ static struct tomoyo_profile *tomoyo_assign_profile(const unsigned int profile) | |||
322 | /** | 362 | /** |
323 | * tomoyo_profile - Find a profile. | 363 | * tomoyo_profile - Find a profile. |
324 | * | 364 | * |
365 | * @ns: Pointer to "struct tomoyo_policy_namespace". | ||
325 | * @profile: Profile number to find. | 366 | * @profile: Profile number to find. |
326 | * | 367 | * |
327 | * Returns pointer to "struct tomoyo_profile". | 368 | * Returns pointer to "struct tomoyo_profile". |
328 | */ | 369 | */ |
329 | struct tomoyo_profile *tomoyo_profile(const u8 profile) | 370 | struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns, |
371 | const u8 profile) | ||
330 | { | 372 | { |
331 | static struct tomoyo_profile tomoyo_null_profile; | 373 | static struct tomoyo_profile tomoyo_null_profile; |
332 | struct tomoyo_profile *ptr = tomoyo_profile_ptr[profile]; | 374 | struct tomoyo_profile *ptr = ns->profile_ptr[profile]; |
333 | if (!ptr) | 375 | if (!ptr) |
334 | ptr = &tomoyo_null_profile; | 376 | ptr = &tomoyo_null_profile; |
335 | return ptr; | 377 | return ptr; |
@@ -454,13 +496,14 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head) | |||
454 | unsigned int i; | 496 | unsigned int i; |
455 | char *cp; | 497 | char *cp; |
456 | struct tomoyo_profile *profile; | 498 | struct tomoyo_profile *profile; |
457 | if (sscanf(data, "PROFILE_VERSION=%u", &tomoyo_profile_version) == 1) | 499 | if (sscanf(data, "PROFILE_VERSION=%u", &head->w.ns->profile_version) |
500 | == 1) | ||
458 | return 0; | 501 | return 0; |
459 | i = simple_strtoul(data, &cp, 10); | 502 | i = simple_strtoul(data, &cp, 10); |
460 | if (*cp != '-') | 503 | if (*cp != '-') |
461 | return -EINVAL; | 504 | return -EINVAL; |
462 | data = cp + 1; | 505 | data = cp + 1; |
463 | profile = tomoyo_assign_profile(i); | 506 | profile = tomoyo_assign_profile(head->w.ns, i); |
464 | if (!profile) | 507 | if (!profile) |
465 | return -EINVAL; | 508 | return -EINVAL; |
466 | cp = strchr(data, '='); | 509 | cp = strchr(data, '='); |
@@ -518,19 +561,25 @@ static void tomoyo_print_config(struct tomoyo_io_buffer *head, const u8 config) | |||
518 | static void tomoyo_read_profile(struct tomoyo_io_buffer *head) | 561 | static void tomoyo_read_profile(struct tomoyo_io_buffer *head) |
519 | { | 562 | { |
520 | u8 index; | 563 | u8 index; |
564 | struct tomoyo_policy_namespace *ns = | ||
565 | container_of(head->r.ns, typeof(*ns), namespace_list); | ||
521 | const struct tomoyo_profile *profile; | 566 | const struct tomoyo_profile *profile; |
567 | if (head->r.eof) | ||
568 | return; | ||
522 | next: | 569 | next: |
523 | index = head->r.index; | 570 | index = head->r.index; |
524 | profile = tomoyo_profile_ptr[index]; | 571 | profile = ns->profile_ptr[index]; |
525 | switch (head->r.step) { | 572 | switch (head->r.step) { |
526 | case 0: | 573 | case 0: |
527 | tomoyo_io_printf(head, "PROFILE_VERSION=%u\n", 20090903); | 574 | tomoyo_print_namespace(head); |
575 | tomoyo_io_printf(head, "PROFILE_VERSION=%u\n", | ||
576 | ns->profile_version); | ||
528 | head->r.step++; | 577 | head->r.step++; |
529 | break; | 578 | break; |
530 | case 1: | 579 | case 1: |
531 | for ( ; head->r.index < TOMOYO_MAX_PROFILES; | 580 | for ( ; head->r.index < TOMOYO_MAX_PROFILES; |
532 | head->r.index++) | 581 | head->r.index++) |
533 | if (tomoyo_profile_ptr[head->r.index]) | 582 | if (ns->profile_ptr[head->r.index]) |
534 | break; | 583 | break; |
535 | if (head->r.index == TOMOYO_MAX_PROFILES) | 584 | if (head->r.index == TOMOYO_MAX_PROFILES) |
536 | return; | 585 | return; |
@@ -541,6 +590,7 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head) | |||
541 | u8 i; | 590 | u8 i; |
542 | const struct tomoyo_path_info *comment = | 591 | const struct tomoyo_path_info *comment = |
543 | profile->comment; | 592 | profile->comment; |
593 | tomoyo_print_namespace(head); | ||
544 | tomoyo_io_printf(head, "%u-COMMENT=", index); | 594 | tomoyo_io_printf(head, "%u-COMMENT=", index); |
545 | tomoyo_set_string(head, comment ? comment->name : ""); | 595 | tomoyo_set_string(head, comment ? comment->name : ""); |
546 | tomoyo_set_lf(head); | 596 | tomoyo_set_lf(head); |
@@ -555,6 +605,7 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head) | |||
555 | break; | 605 | break; |
556 | case 3: | 606 | case 3: |
557 | { | 607 | { |
608 | tomoyo_print_namespace(head); | ||
558 | tomoyo_io_printf(head, "%u-%s", index, "CONFIG"); | 609 | tomoyo_io_printf(head, "%u-%s", index, "CONFIG"); |
559 | tomoyo_print_config(head, profile->default_config); | 610 | tomoyo_print_config(head, profile->default_config); |
560 | head->r.bit = 0; | 611 | head->r.bit = 0; |
@@ -568,6 +619,7 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head) | |||
568 | const u8 config = profile->config[i]; | 619 | const u8 config = profile->config[i]; |
569 | if (config == TOMOYO_CONFIG_USE_DEFAULT) | 620 | if (config == TOMOYO_CONFIG_USE_DEFAULT) |
570 | continue; | 621 | continue; |
622 | tomoyo_print_namespace(head); | ||
571 | tomoyo_io_printf(head, "%u-%s%s", index, "CONFIG::", | 623 | tomoyo_io_printf(head, "%u-%s%s", index, "CONFIG::", |
572 | tomoyo_mac_keywords[i]); | 624 | tomoyo_mac_keywords[i]); |
573 | tomoyo_print_config(head, config); | 625 | tomoyo_print_config(head, config); |
@@ -607,8 +659,10 @@ static int tomoyo_update_manager_entry(const char *manager, | |||
607 | { | 659 | { |
608 | struct tomoyo_manager e = { }; | 660 | struct tomoyo_manager e = { }; |
609 | struct tomoyo_acl_param param = { | 661 | struct tomoyo_acl_param param = { |
662 | /* .ns = &tomoyo_kernel_namespace, */ | ||
610 | .is_delete = is_delete, | 663 | .is_delete = is_delete, |
611 | .list = &tomoyo_policy_list[TOMOYO_ID_MANAGER], | 664 | .list = &tomoyo_kernel_namespace. |
665 | policy_list[TOMOYO_ID_MANAGER], | ||
612 | }; | 666 | }; |
613 | int error = is_delete ? -ENOENT : -ENOMEM; | 667 | int error = is_delete ? -ENOENT : -ENOMEM; |
614 | if (tomoyo_domain_def(manager)) { | 668 | if (tomoyo_domain_def(manager)) { |
@@ -640,13 +694,12 @@ static int tomoyo_update_manager_entry(const char *manager, | |||
640 | static int tomoyo_write_manager(struct tomoyo_io_buffer *head) | 694 | static int tomoyo_write_manager(struct tomoyo_io_buffer *head) |
641 | { | 695 | { |
642 | char *data = head->write_buf; | 696 | char *data = head->write_buf; |
643 | bool is_delete = tomoyo_str_starts(&data, "delete "); | ||
644 | 697 | ||
645 | if (!strcmp(data, "manage_by_non_root")) { | 698 | if (!strcmp(data, "manage_by_non_root")) { |
646 | tomoyo_manage_by_non_root = !is_delete; | 699 | tomoyo_manage_by_non_root = !head->w.is_delete; |
647 | return 0; | 700 | return 0; |
648 | } | 701 | } |
649 | return tomoyo_update_manager_entry(data, is_delete); | 702 | return tomoyo_update_manager_entry(data, head->w.is_delete); |
650 | } | 703 | } |
651 | 704 | ||
652 | /** | 705 | /** |
@@ -660,8 +713,8 @@ static void tomoyo_read_manager(struct tomoyo_io_buffer *head) | |||
660 | { | 713 | { |
661 | if (head->r.eof) | 714 | if (head->r.eof) |
662 | return; | 715 | return; |
663 | list_for_each_cookie(head->r.acl, | 716 | list_for_each_cookie(head->r.acl, &tomoyo_kernel_namespace. |
664 | &tomoyo_policy_list[TOMOYO_ID_MANAGER]) { | 717 | policy_list[TOMOYO_ID_MANAGER]) { |
665 | struct tomoyo_manager *ptr = | 718 | struct tomoyo_manager *ptr = |
666 | list_entry(head->r.acl, typeof(*ptr), head.list); | 719 | list_entry(head->r.acl, typeof(*ptr), head.list); |
667 | if (ptr->head.is_deleted) | 720 | if (ptr->head.is_deleted) |
@@ -694,8 +747,8 @@ static bool tomoyo_manager(void) | |||
694 | return true; | 747 | return true; |
695 | if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid)) | 748 | if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid)) |
696 | return false; | 749 | return false; |
697 | list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_MANAGER], | 750 | list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace. |
698 | head.list) { | 751 | policy_list[TOMOYO_ID_MANAGER], head.list) { |
699 | if (!ptr->head.is_deleted && ptr->is_domain | 752 | if (!ptr->head.is_deleted && ptr->is_domain |
700 | && !tomoyo_pathcmp(domainname, ptr->manager)) { | 753 | && !tomoyo_pathcmp(domainname, ptr->manager)) { |
701 | found = true; | 754 | found = true; |
@@ -707,8 +760,8 @@ static bool tomoyo_manager(void) | |||
707 | exe = tomoyo_get_exe(); | 760 | exe = tomoyo_get_exe(); |
708 | if (!exe) | 761 | if (!exe) |
709 | return false; | 762 | return false; |
710 | list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_MANAGER], | 763 | list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace. |
711 | head.list) { | 764 | policy_list[TOMOYO_ID_MANAGER], head.list) { |
712 | if (!ptr->head.is_deleted && !ptr->is_domain | 765 | if (!ptr->head.is_deleted && !ptr->is_domain |
713 | && !strcmp(exe, ptr->manager->name)) { | 766 | && !strcmp(exe, ptr->manager->name)) { |
714 | found = true; | 767 | found = true; |
@@ -729,7 +782,7 @@ static bool tomoyo_manager(void) | |||
729 | } | 782 | } |
730 | 783 | ||
731 | /** | 784 | /** |
732 | * tomoyo_select_one - Parse select command. | 785 | * tomoyo_select_domain - Parse select command. |
733 | * | 786 | * |
734 | * @head: Pointer to "struct tomoyo_io_buffer". | 787 | * @head: Pointer to "struct tomoyo_io_buffer". |
735 | * @data: String to parse. | 788 | * @data: String to parse. |
@@ -738,16 +791,15 @@ static bool tomoyo_manager(void) | |||
738 | * | 791 | * |
739 | * Caller holds tomoyo_read_lock(). | 792 | * Caller holds tomoyo_read_lock(). |
740 | */ | 793 | */ |
741 | static bool tomoyo_select_one(struct tomoyo_io_buffer *head, const char *data) | 794 | static bool tomoyo_select_domain(struct tomoyo_io_buffer *head, |
795 | const char *data) | ||
742 | { | 796 | { |
743 | unsigned int pid; | 797 | unsigned int pid; |
744 | struct tomoyo_domain_info *domain = NULL; | 798 | struct tomoyo_domain_info *domain = NULL; |
745 | bool global_pid = false; | 799 | bool global_pid = false; |
746 | 800 | if (strncmp(data, "select ", 7)) | |
747 | if (!strcmp(data, "allow_execute")) { | 801 | return false; |
748 | head->r.print_execute_only = true; | 802 | data += 7; |
749 | return true; | ||
750 | } | ||
751 | if (sscanf(data, "pid=%u", &pid) == 1 || | 803 | if (sscanf(data, "pid=%u", &pid) == 1 || |
752 | (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) { | 804 | (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) { |
753 | struct task_struct *p; | 805 | struct task_struct *p; |
@@ -818,6 +870,7 @@ static int tomoyo_delete_domain(char *domainname) | |||
818 | /** | 870 | /** |
819 | * tomoyo_write_domain2 - Write domain policy. | 871 | * tomoyo_write_domain2 - Write domain policy. |
820 | * | 872 | * |
873 | * @ns: Pointer to "struct tomoyo_policy_namespace". | ||
821 | * @list: Pointer to "struct list_head". | 874 | * @list: Pointer to "struct list_head". |
822 | * @data: Policy to be interpreted. | 875 | * @data: Policy to be interpreted. |
823 | * @is_delete: True if it is a delete request. | 876 | * @is_delete: True if it is a delete request. |
@@ -826,10 +879,12 @@ static int tomoyo_delete_domain(char *domainname) | |||
826 | * | 879 | * |
827 | * Caller holds tomoyo_read_lock(). | 880 | * Caller holds tomoyo_read_lock(). |
828 | */ | 881 | */ |
829 | static int tomoyo_write_domain2(struct list_head *list, char *data, | 882 | static int tomoyo_write_domain2(struct tomoyo_policy_namespace *ns, |
883 | struct list_head *list, char *data, | ||
830 | const bool is_delete) | 884 | const bool is_delete) |
831 | { | 885 | { |
832 | struct tomoyo_acl_param param = { | 886 | struct tomoyo_acl_param param = { |
887 | .ns = ns, | ||
833 | .list = list, | 888 | .list = list, |
834 | .data = data, | 889 | .data = data, |
835 | .is_delete = is_delete, | 890 | .is_delete = is_delete, |
@@ -862,37 +917,28 @@ static int tomoyo_write_domain2(struct list_head *list, char *data, | |||
862 | static int tomoyo_write_domain(struct tomoyo_io_buffer *head) | 917 | static int tomoyo_write_domain(struct tomoyo_io_buffer *head) |
863 | { | 918 | { |
864 | char *data = head->write_buf; | 919 | char *data = head->write_buf; |
920 | struct tomoyo_policy_namespace *ns; | ||
865 | struct tomoyo_domain_info *domain = head->w.domain; | 921 | struct tomoyo_domain_info *domain = head->w.domain; |
866 | bool is_delete = false; | 922 | const bool is_delete = head->w.is_delete; |
867 | bool is_select = false; | 923 | bool is_select = !is_delete && tomoyo_str_starts(&data, "select "); |
868 | unsigned int profile; | 924 | unsigned int profile; |
869 | 925 | if (*data == '<') { | |
870 | if (tomoyo_str_starts(&data, "delete ")) | ||
871 | is_delete = true; | ||
872 | else if (tomoyo_str_starts(&data, "select ")) | ||
873 | is_select = true; | ||
874 | if (is_select && tomoyo_select_one(head, data)) | ||
875 | return 0; | ||
876 | /* Don't allow updating policies by non manager programs. */ | ||
877 | if (!tomoyo_manager()) | ||
878 | return -EPERM; | ||
879 | if (tomoyo_domain_def(data)) { | ||
880 | domain = NULL; | 926 | domain = NULL; |
881 | if (is_delete) | 927 | if (is_delete) |
882 | tomoyo_delete_domain(data); | 928 | tomoyo_delete_domain(data); |
883 | else if (is_select) | 929 | else if (is_select) |
884 | domain = tomoyo_find_domain(data); | 930 | domain = tomoyo_find_domain(data); |
885 | else | 931 | else |
886 | domain = tomoyo_assign_domain(data, 0); | 932 | domain = tomoyo_assign_domain(data, false); |
887 | head->w.domain = domain; | 933 | head->w.domain = domain; |
888 | return 0; | 934 | return 0; |
889 | } | 935 | } |
890 | if (!domain) | 936 | if (!domain) |
891 | return -EINVAL; | 937 | return -EINVAL; |
892 | 938 | ns = domain->ns; | |
893 | if (sscanf(data, "use_profile %u", &profile) == 1 | 939 | if (sscanf(data, "use_profile %u", &profile) == 1 |
894 | && profile < TOMOYO_MAX_PROFILES) { | 940 | && profile < TOMOYO_MAX_PROFILES) { |
895 | if (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded) | 941 | if (!tomoyo_policy_loaded || ns->profile_ptr[profile]) |
896 | domain->profile = (u8) profile; | 942 | domain->profile = (u8) profile; |
897 | return 0; | 943 | return 0; |
898 | } | 944 | } |
@@ -910,7 +956,8 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head) | |||
910 | domain->transition_failed = !is_delete; | 956 | domain->transition_failed = !is_delete; |
911 | return 0; | 957 | return 0; |
912 | } | 958 | } |
913 | return tomoyo_write_domain2(&domain->acl_info_list, data, is_delete); | 959 | return tomoyo_write_domain2(ns, &domain->acl_info_list, data, |
960 | is_delete); | ||
914 | } | 961 | } |
915 | 962 | ||
916 | /** | 963 | /** |
@@ -924,9 +971,11 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head) | |||
924 | static void tomoyo_set_group(struct tomoyo_io_buffer *head, | 971 | static void tomoyo_set_group(struct tomoyo_io_buffer *head, |
925 | const char *category) | 972 | const char *category) |
926 | { | 973 | { |
927 | if (head->type == TOMOYO_EXCEPTIONPOLICY) | 974 | if (head->type == TOMOYO_EXCEPTIONPOLICY) { |
975 | tomoyo_print_namespace(head); | ||
928 | tomoyo_io_printf(head, "acl_group %u ", | 976 | tomoyo_io_printf(head, "acl_group %u ", |
929 | head->r.acl_group_index); | 977 | head->r.acl_group_index); |
978 | } | ||
930 | tomoyo_set_string(head, category); | 979 | tomoyo_set_string(head, category); |
931 | } | 980 | } |
932 | 981 | ||
@@ -956,7 +1005,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | |||
956 | for (bit = 0; bit < TOMOYO_MAX_PATH_OPERATION; bit++) { | 1005 | for (bit = 0; bit < TOMOYO_MAX_PATH_OPERATION; bit++) { |
957 | if (!(perm & (1 << bit))) | 1006 | if (!(perm & (1 << bit))) |
958 | continue; | 1007 | continue; |
959 | if (head->r.print_execute_only && | 1008 | if (head->r.print_transition_related_only && |
960 | bit != TOMOYO_TYPE_EXECUTE) | 1009 | bit != TOMOYO_TYPE_EXECUTE) |
961 | continue; | 1010 | continue; |
962 | if (first) { | 1011 | if (first) { |
@@ -970,7 +1019,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | |||
970 | if (first) | 1019 | if (first) |
971 | return true; | 1020 | return true; |
972 | tomoyo_print_name_union(head, &ptr->name); | 1021 | tomoyo_print_name_union(head, &ptr->name); |
973 | } else if (head->r.print_execute_only) { | 1022 | } else if (head->r.print_transition_related_only) { |
974 | return true; | 1023 | return true; |
975 | } else if (acl_type == TOMOYO_TYPE_PATH2_ACL) { | 1024 | } else if (acl_type == TOMOYO_TYPE_PATH2_ACL) { |
976 | struct tomoyo_path2_acl *ptr = | 1025 | struct tomoyo_path2_acl *ptr = |
@@ -1147,8 +1196,8 @@ static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head) | |||
1147 | domain = tomoyo_find_domain(cp + 1); | 1196 | domain = tomoyo_find_domain(cp + 1); |
1148 | if (strict_strtoul(data, 10, &profile)) | 1197 | if (strict_strtoul(data, 10, &profile)) |
1149 | return -EINVAL; | 1198 | return -EINVAL; |
1150 | if (domain && profile < TOMOYO_MAX_PROFILES | 1199 | if (domain && (!tomoyo_policy_loaded || |
1151 | && (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded)) | 1200 | head->w.ns->profile_ptr[(u8) profile])) |
1152 | domain->profile = (u8) profile; | 1201 | domain->profile = (u8) profile; |
1153 | return 0; | 1202 | return 0; |
1154 | } | 1203 | } |
@@ -1246,10 +1295,12 @@ static void tomoyo_read_pid(struct tomoyo_io_buffer *head) | |||
1246 | } | 1295 | } |
1247 | 1296 | ||
1248 | static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = { | 1297 | static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = { |
1249 | [TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain", | 1298 | [TOMOYO_TRANSITION_CONTROL_NO_RESET] = "no_reset_domain ", |
1250 | [TOMOYO_TRANSITION_CONTROL_INITIALIZE] = "initialize_domain", | 1299 | [TOMOYO_TRANSITION_CONTROL_RESET] = "reset_domain ", |
1251 | [TOMOYO_TRANSITION_CONTROL_NO_KEEP] = "no_keep_domain", | 1300 | [TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain ", |
1252 | [TOMOYO_TRANSITION_CONTROL_KEEP] = "keep_domain", | 1301 | [TOMOYO_TRANSITION_CONTROL_INITIALIZE] = "initialize_domain ", |
1302 | [TOMOYO_TRANSITION_CONTROL_NO_KEEP] = "no_keep_domain ", | ||
1303 | [TOMOYO_TRANSITION_CONTROL_KEEP] = "keep_domain ", | ||
1253 | }; | 1304 | }; |
1254 | 1305 | ||
1255 | static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = { | 1306 | static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = { |
@@ -1268,19 +1319,13 @@ static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = { | |||
1268 | */ | 1319 | */ |
1269 | static int tomoyo_write_exception(struct tomoyo_io_buffer *head) | 1320 | static int tomoyo_write_exception(struct tomoyo_io_buffer *head) |
1270 | { | 1321 | { |
1322 | const bool is_delete = head->w.is_delete; | ||
1271 | struct tomoyo_acl_param param = { | 1323 | struct tomoyo_acl_param param = { |
1324 | .ns = head->w.ns, | ||
1325 | .is_delete = is_delete, | ||
1272 | .data = head->write_buf, | 1326 | .data = head->write_buf, |
1273 | }; | 1327 | }; |
1274 | u8 i; | 1328 | u8 i; |
1275 | param.is_delete = tomoyo_str_starts(¶m.data, "delete "); | ||
1276 | if (!param.is_delete && tomoyo_str_starts(¶m.data, "select ") && | ||
1277 | !strcmp(param.data, "execute_only")) { | ||
1278 | head->r.print_execute_only = true; | ||
1279 | return 0; | ||
1280 | } | ||
1281 | /* Don't allow updating policies by non manager programs. */ | ||
1282 | if (!tomoyo_manager()) | ||
1283 | return -EPERM; | ||
1284 | if (tomoyo_str_starts(¶m.data, "aggregator ")) | 1329 | if (tomoyo_str_starts(¶m.data, "aggregator ")) |
1285 | return tomoyo_write_aggregator(¶m); | 1330 | return tomoyo_write_aggregator(¶m); |
1286 | for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++) | 1331 | for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++) |
@@ -1294,8 +1339,9 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head) | |||
1294 | char *data; | 1339 | char *data; |
1295 | group = simple_strtoul(param.data, &data, 10); | 1340 | group = simple_strtoul(param.data, &data, 10); |
1296 | if (group < TOMOYO_MAX_ACL_GROUPS && *data++ == ' ') | 1341 | if (group < TOMOYO_MAX_ACL_GROUPS && *data++ == ' ') |
1297 | return tomoyo_write_domain2(&tomoyo_acl_group[group], | 1342 | return tomoyo_write_domain2 |
1298 | data, param.is_delete); | 1343 | (head->w.ns, &head->w.ns->acl_group[group], |
1344 | data, is_delete); | ||
1299 | } | 1345 | } |
1300 | return -EINVAL; | 1346 | return -EINVAL; |
1301 | } | 1347 | } |
@@ -1312,7 +1358,10 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head) | |||
1312 | */ | 1358 | */ |
1313 | static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) | 1359 | static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) |
1314 | { | 1360 | { |
1315 | list_for_each_cookie(head->r.group, &tomoyo_group_list[idx]) { | 1361 | struct tomoyo_policy_namespace *ns = |
1362 | container_of(head->r.ns, typeof(*ns), namespace_list); | ||
1363 | struct list_head *list = &ns->group_list[idx]; | ||
1364 | list_for_each_cookie(head->r.group, list) { | ||
1316 | struct tomoyo_group *group = | 1365 | struct tomoyo_group *group = |
1317 | list_entry(head->r.group, typeof(*group), head.list); | 1366 | list_entry(head->r.group, typeof(*group), head.list); |
1318 | list_for_each_cookie(head->r.acl, &group->member_list) { | 1367 | list_for_each_cookie(head->r.acl, &group->member_list) { |
@@ -1322,6 +1371,7 @@ static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) | |||
1322 | continue; | 1371 | continue; |
1323 | if (!tomoyo_flush(head)) | 1372 | if (!tomoyo_flush(head)) |
1324 | return false; | 1373 | return false; |
1374 | tomoyo_print_namespace(head); | ||
1325 | tomoyo_set_string(head, tomoyo_group_name[idx]); | 1375 | tomoyo_set_string(head, tomoyo_group_name[idx]); |
1326 | tomoyo_set_string(head, group->group_name->name); | 1376 | tomoyo_set_string(head, group->group_name->name); |
1327 | if (idx == TOMOYO_PATH_GROUP) { | 1377 | if (idx == TOMOYO_PATH_GROUP) { |
@@ -1355,7 +1405,10 @@ static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) | |||
1355 | */ | 1405 | */ |
1356 | static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) | 1406 | static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) |
1357 | { | 1407 | { |
1358 | list_for_each_cookie(head->r.acl, &tomoyo_policy_list[idx]) { | 1408 | struct tomoyo_policy_namespace *ns = |
1409 | container_of(head->r.ns, typeof(*ns), namespace_list); | ||
1410 | struct list_head *list = &ns->policy_list[idx]; | ||
1411 | list_for_each_cookie(head->r.acl, list) { | ||
1359 | struct tomoyo_acl_head *acl = | 1412 | struct tomoyo_acl_head *acl = |
1360 | container_of(head->r.acl, typeof(*acl), list); | 1413 | container_of(head->r.acl, typeof(*acl), list); |
1361 | if (acl->is_deleted) | 1414 | if (acl->is_deleted) |
@@ -1367,6 +1420,7 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) | |||
1367 | { | 1420 | { |
1368 | struct tomoyo_transition_control *ptr = | 1421 | struct tomoyo_transition_control *ptr = |
1369 | container_of(acl, typeof(*ptr), head); | 1422 | container_of(acl, typeof(*ptr), head); |
1423 | tomoyo_print_namespace(head); | ||
1370 | tomoyo_set_string(head, tomoyo_transition_type | 1424 | tomoyo_set_string(head, tomoyo_transition_type |
1371 | [ptr->type]); | 1425 | [ptr->type]); |
1372 | tomoyo_set_string(head, ptr->program ? | 1426 | tomoyo_set_string(head, ptr->program ? |
@@ -1381,6 +1435,7 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) | |||
1381 | { | 1435 | { |
1382 | struct tomoyo_aggregator *ptr = | 1436 | struct tomoyo_aggregator *ptr = |
1383 | container_of(acl, typeof(*ptr), head); | 1437 | container_of(acl, typeof(*ptr), head); |
1438 | tomoyo_print_namespace(head); | ||
1384 | tomoyo_set_string(head, "aggregator "); | 1439 | tomoyo_set_string(head, "aggregator "); |
1385 | tomoyo_set_string(head, | 1440 | tomoyo_set_string(head, |
1386 | ptr->original_name->name); | 1441 | ptr->original_name->name); |
@@ -1407,6 +1462,8 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) | |||
1407 | */ | 1462 | */ |
1408 | static void tomoyo_read_exception(struct tomoyo_io_buffer *head) | 1463 | static void tomoyo_read_exception(struct tomoyo_io_buffer *head) |
1409 | { | 1464 | { |
1465 | struct tomoyo_policy_namespace *ns = | ||
1466 | container_of(head->r.ns, typeof(*ns), namespace_list); | ||
1410 | if (head->r.eof) | 1467 | if (head->r.eof) |
1411 | return; | 1468 | return; |
1412 | while (head->r.step < TOMOYO_MAX_POLICY && | 1469 | while (head->r.step < TOMOYO_MAX_POLICY && |
@@ -1423,7 +1480,7 @@ static void tomoyo_read_exception(struct tomoyo_io_buffer *head) | |||
1423 | + TOMOYO_MAX_ACL_GROUPS) { | 1480 | + TOMOYO_MAX_ACL_GROUPS) { |
1424 | head->r.acl_group_index = head->r.step - TOMOYO_MAX_POLICY | 1481 | head->r.acl_group_index = head->r.step - TOMOYO_MAX_POLICY |
1425 | - TOMOYO_MAX_GROUP; | 1482 | - TOMOYO_MAX_GROUP; |
1426 | if (!tomoyo_read_domain2(head, &tomoyo_acl_group | 1483 | if (!tomoyo_read_domain2(head, &ns->acl_group |
1427 | [head->r.acl_group_index])) | 1484 | [head->r.acl_group_index])) |
1428 | return; | 1485 | return; |
1429 | head->r.step++; | 1486 | head->r.step++; |
@@ -1484,7 +1541,8 @@ static void tomoyo_add_entry(struct tomoyo_domain_info *domain, char *header) | |||
1484 | return; | 1541 | return; |
1485 | snprintf(buffer, len - 1, "%s", cp); | 1542 | snprintf(buffer, len - 1, "%s", cp); |
1486 | tomoyo_normalize_line(buffer); | 1543 | tomoyo_normalize_line(buffer); |
1487 | tomoyo_write_domain2(&domain->acl_info_list, buffer, false); | 1544 | tomoyo_write_domain2(domain->ns, &domain->acl_info_list, buffer, |
1545 | false); | ||
1488 | kfree(buffer); | 1546 | kfree(buffer); |
1489 | } | 1547 | } |
1490 | 1548 | ||
@@ -1896,6 +1954,45 @@ int tomoyo_poll_control(struct file *file, poll_table *wait) | |||
1896 | } | 1954 | } |
1897 | 1955 | ||
1898 | /** | 1956 | /** |
1957 | * tomoyo_set_namespace_cursor - Set namespace to read. | ||
1958 | * | ||
1959 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
1960 | * | ||
1961 | * Returns nothing. | ||
1962 | */ | ||
1963 | static inline void tomoyo_set_namespace_cursor(struct tomoyo_io_buffer *head) | ||
1964 | { | ||
1965 | struct list_head *ns; | ||
1966 | if (head->type != TOMOYO_EXCEPTIONPOLICY && | ||
1967 | head->type != TOMOYO_PROFILE) | ||
1968 | return; | ||
1969 | /* | ||
1970 | * If this is the first read, or reading previous namespace finished | ||
1971 | * and has more namespaces to read, update the namespace cursor. | ||
1972 | */ | ||
1973 | ns = head->r.ns; | ||
1974 | if (!ns || (head->r.eof && ns->next != &tomoyo_namespace_list)) { | ||
1975 | /* Clearing is OK because tomoyo_flush() returned true. */ | ||
1976 | memset(&head->r, 0, sizeof(head->r)); | ||
1977 | head->r.ns = ns ? ns->next : tomoyo_namespace_list.next; | ||
1978 | } | ||
1979 | } | ||
1980 | |||
1981 | /** | ||
1982 | * tomoyo_has_more_namespace - Check for unread namespaces. | ||
1983 | * | ||
1984 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
1985 | * | ||
1986 | * Returns true if we have more entries to print, false otherwise. | ||
1987 | */ | ||
1988 | static inline bool tomoyo_has_more_namespace(struct tomoyo_io_buffer *head) | ||
1989 | { | ||
1990 | return (head->type == TOMOYO_EXCEPTIONPOLICY || | ||
1991 | head->type == TOMOYO_PROFILE) && head->r.eof && | ||
1992 | head->r.ns->next != &tomoyo_namespace_list; | ||
1993 | } | ||
1994 | |||
1995 | /** | ||
1899 | * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface. | 1996 | * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface. |
1900 | * | 1997 | * |
1901 | * @head: Pointer to "struct tomoyo_io_buffer". | 1998 | * @head: Pointer to "struct tomoyo_io_buffer". |
@@ -1919,14 +2016,54 @@ int tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer, | |||
1919 | head->read_user_buf_avail = buffer_len; | 2016 | head->read_user_buf_avail = buffer_len; |
1920 | if (tomoyo_flush(head)) | 2017 | if (tomoyo_flush(head)) |
1921 | /* Call the policy handler. */ | 2018 | /* Call the policy handler. */ |
1922 | head->read(head); | 2019 | do { |
1923 | tomoyo_flush(head); | 2020 | tomoyo_set_namespace_cursor(head); |
2021 | head->read(head); | ||
2022 | } while (tomoyo_flush(head) && | ||
2023 | tomoyo_has_more_namespace(head)); | ||
1924 | len = head->read_user_buf - buffer; | 2024 | len = head->read_user_buf - buffer; |
1925 | mutex_unlock(&head->io_sem); | 2025 | mutex_unlock(&head->io_sem); |
1926 | return len; | 2026 | return len; |
1927 | } | 2027 | } |
1928 | 2028 | ||
1929 | /** | 2029 | /** |
2030 | * tomoyo_parse_policy - Parse a policy line. | ||
2031 | * | ||
2032 | * @head: Poiter to "struct tomoyo_io_buffer". | ||
2033 | * @line: Line to parse. | ||
2034 | * | ||
2035 | * Returns 0 on success, negative value otherwise. | ||
2036 | * | ||
2037 | * Caller holds tomoyo_read_lock(). | ||
2038 | */ | ||
2039 | static int tomoyo_parse_policy(struct tomoyo_io_buffer *head, char *line) | ||
2040 | { | ||
2041 | /* Delete request? */ | ||
2042 | head->w.is_delete = !strncmp(line, "delete ", 7); | ||
2043 | if (head->w.is_delete) | ||
2044 | memmove(line, line + 7, strlen(line + 7) + 1); | ||
2045 | /* Selecting namespace to update. */ | ||
2046 | if (head->type == TOMOYO_EXCEPTIONPOLICY || | ||
2047 | head->type == TOMOYO_PROFILE) { | ||
2048 | if (*line == '<') { | ||
2049 | char *cp = strchr(line, ' '); | ||
2050 | if (cp) { | ||
2051 | *cp++ = '\0'; | ||
2052 | head->w.ns = tomoyo_assign_namespace(line); | ||
2053 | memmove(line, cp, strlen(cp) + 1); | ||
2054 | } else | ||
2055 | head->w.ns = NULL; | ||
2056 | } else | ||
2057 | head->w.ns = &tomoyo_kernel_namespace; | ||
2058 | /* Don't allow updating if namespace is invalid. */ | ||
2059 | if (!head->w.ns) | ||
2060 | return -ENOENT; | ||
2061 | } | ||
2062 | /* Do the update. */ | ||
2063 | return head->write(head); | ||
2064 | } | ||
2065 | |||
2066 | /** | ||
1930 | * tomoyo_write_control - write() for /sys/kernel/security/tomoyo/ interface. | 2067 | * tomoyo_write_control - write() for /sys/kernel/security/tomoyo/ interface. |
1931 | * | 2068 | * |
1932 | * @head: Pointer to "struct tomoyo_io_buffer". | 2069 | * @head: Pointer to "struct tomoyo_io_buffer". |
@@ -1941,27 +2078,31 @@ int tomoyo_write_control(struct tomoyo_io_buffer *head, | |||
1941 | const char __user *buffer, const int buffer_len) | 2078 | const char __user *buffer, const int buffer_len) |
1942 | { | 2079 | { |
1943 | int error = buffer_len; | 2080 | int error = buffer_len; |
1944 | int avail_len = buffer_len; | 2081 | size_t avail_len = buffer_len; |
1945 | char *cp0 = head->write_buf; | 2082 | char *cp0 = head->write_buf; |
1946 | |||
1947 | if (!head->write) | 2083 | if (!head->write) |
1948 | return -ENOSYS; | 2084 | return -ENOSYS; |
1949 | if (!access_ok(VERIFY_READ, buffer, buffer_len)) | 2085 | if (!access_ok(VERIFY_READ, buffer, buffer_len)) |
1950 | return -EFAULT; | 2086 | return -EFAULT; |
1951 | /* Don't allow updating policies by non manager programs. */ | ||
1952 | if (head->write != tomoyo_write_pid && | ||
1953 | head->write != tomoyo_write_domain && | ||
1954 | head->write != tomoyo_write_exception && !tomoyo_manager()) | ||
1955 | return -EPERM; | ||
1956 | if (mutex_lock_interruptible(&head->io_sem)) | 2087 | if (mutex_lock_interruptible(&head->io_sem)) |
1957 | return -EINTR; | 2088 | return -EINTR; |
1958 | /* Read a line and dispatch it to the policy handler. */ | 2089 | /* Read a line and dispatch it to the policy handler. */ |
1959 | while (avail_len > 0) { | 2090 | while (avail_len > 0) { |
1960 | char c; | 2091 | char c; |
1961 | if (head->w.avail >= head->writebuf_size - 1) { | 2092 | if (head->w.avail >= head->writebuf_size - 1) { |
1962 | error = -ENOMEM; | 2093 | const int len = head->writebuf_size * 2; |
1963 | break; | 2094 | char *cp = kzalloc(len, GFP_NOFS); |
1964 | } else if (get_user(c, buffer)) { | 2095 | if (!cp) { |
2096 | error = -ENOMEM; | ||
2097 | break; | ||
2098 | } | ||
2099 | memmove(cp, cp0, head->w.avail); | ||
2100 | kfree(cp0); | ||
2101 | head->write_buf = cp; | ||
2102 | cp0 = cp; | ||
2103 | head->writebuf_size = len; | ||
2104 | } | ||
2105 | if (get_user(c, buffer)) { | ||
1965 | error = -EFAULT; | 2106 | error = -EFAULT; |
1966 | break; | 2107 | break; |
1967 | } | 2108 | } |
@@ -1973,8 +2114,40 @@ int tomoyo_write_control(struct tomoyo_io_buffer *head, | |||
1973 | cp0[head->w.avail - 1] = '\0'; | 2114 | cp0[head->w.avail - 1] = '\0'; |
1974 | head->w.avail = 0; | 2115 | head->w.avail = 0; |
1975 | tomoyo_normalize_line(cp0); | 2116 | tomoyo_normalize_line(cp0); |
1976 | head->write(head); | 2117 | if (!strcmp(cp0, "reset")) { |
2118 | head->w.ns = &tomoyo_kernel_namespace; | ||
2119 | head->w.domain = NULL; | ||
2120 | memset(&head->r, 0, sizeof(head->r)); | ||
2121 | continue; | ||
2122 | } | ||
2123 | /* Don't allow updating policies by non manager programs. */ | ||
2124 | switch (head->type) { | ||
2125 | case TOMOYO_PROCESS_STATUS: | ||
2126 | /* This does not write anything. */ | ||
2127 | break; | ||
2128 | case TOMOYO_DOMAINPOLICY: | ||
2129 | if (tomoyo_select_domain(head, cp0)) | ||
2130 | continue; | ||
2131 | /* fall through */ | ||
2132 | case TOMOYO_EXCEPTIONPOLICY: | ||
2133 | if (!strcmp(cp0, "select transition_only")) { | ||
2134 | head->r.print_transition_related_only = true; | ||
2135 | continue; | ||
2136 | } | ||
2137 | /* fall through */ | ||
2138 | default: | ||
2139 | if (!tomoyo_manager()) { | ||
2140 | error = -EPERM; | ||
2141 | goto out; | ||
2142 | } | ||
2143 | } | ||
2144 | switch (tomoyo_parse_policy(head, cp0)) { | ||
2145 | case -EPERM: | ||
2146 | error = -EPERM; | ||
2147 | goto out; | ||
2148 | } | ||
1977 | } | 2149 | } |
2150 | out: | ||
1978 | mutex_unlock(&head->io_sem); | 2151 | mutex_unlock(&head->io_sem); |
1979 | return error; | 2152 | return error; |
1980 | } | 2153 | } |
@@ -2019,27 +2192,27 @@ void tomoyo_check_profile(void) | |||
2019 | struct tomoyo_domain_info *domain; | 2192 | struct tomoyo_domain_info *domain; |
2020 | const int idx = tomoyo_read_lock(); | 2193 | const int idx = tomoyo_read_lock(); |
2021 | tomoyo_policy_loaded = true; | 2194 | tomoyo_policy_loaded = true; |
2022 | /* Check all profiles currently assigned to domains are defined. */ | 2195 | printk(KERN_INFO "TOMOYO: 2.4.0\n"); |
2023 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | 2196 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { |
2024 | const u8 profile = domain->profile; | 2197 | const u8 profile = domain->profile; |
2025 | if (tomoyo_profile_ptr[profile]) | 2198 | const struct tomoyo_policy_namespace *ns = domain->ns; |
2199 | if (ns->profile_version != 20100903) | ||
2200 | printk(KERN_ERR | ||
2201 | "Profile version %u is not supported.\n", | ||
2202 | ns->profile_version); | ||
2203 | else if (!ns->profile_ptr[profile]) | ||
2204 | printk(KERN_ERR | ||
2205 | "Profile %u (used by '%s') is not defined.\n", | ||
2206 | profile, domain->domainname->name); | ||
2207 | else | ||
2026 | continue; | 2208 | continue; |
2027 | printk(KERN_ERR "You need to define profile %u before using it.\n", | 2209 | printk(KERN_ERR |
2028 | profile); | 2210 | "Userland tools for TOMOYO 2.4 must be installed and " |
2029 | printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.3/ " | 2211 | "policy must be initialized.\n"); |
2212 | printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.4/ " | ||
2030 | "for more information.\n"); | 2213 | "for more information.\n"); |
2031 | panic("Profile %u (used by '%s') not defined.\n", | 2214 | panic("STOP!"); |
2032 | profile, domain->domainname->name); | ||
2033 | } | 2215 | } |
2034 | tomoyo_read_unlock(idx); | 2216 | tomoyo_read_unlock(idx); |
2035 | if (tomoyo_profile_version != 20090903) { | ||
2036 | printk(KERN_ERR "You need to install userland programs for " | ||
2037 | "TOMOYO 2.3 and initialize policy configuration.\n"); | ||
2038 | printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.3/ " | ||
2039 | "for more information.\n"); | ||
2040 | panic("Profile version %u is not supported.\n", | ||
2041 | tomoyo_profile_version); | ||
2042 | } | ||
2043 | printk(KERN_INFO "TOMOYO: 2.3.0\n"); | ||
2044 | printk(KERN_INFO "Mandatory Access Control activated.\n"); | 2217 | printk(KERN_INFO "Mandatory Access Control activated.\n"); |
2045 | } | 2218 | } |
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 4bc3975516cb..53c8798e38b7 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
@@ -74,10 +74,6 @@ enum tomoyo_group_id { | |||
74 | TOMOYO_MAX_GROUP | 74 | TOMOYO_MAX_GROUP |
75 | }; | 75 | }; |
76 | 76 | ||
77 | /* A domain definition starts with <kernel>. */ | ||
78 | #define TOMOYO_ROOT_NAME "<kernel>" | ||
79 | #define TOMOYO_ROOT_NAME_LEN (sizeof(TOMOYO_ROOT_NAME) - 1) | ||
80 | |||
81 | /* Index numbers for type of numeric values. */ | 77 | /* Index numbers for type of numeric values. */ |
82 | enum tomoyo_value_type { | 78 | enum tomoyo_value_type { |
83 | TOMOYO_VALUE_TYPE_INVALID, | 79 | TOMOYO_VALUE_TYPE_INVALID, |
@@ -89,6 +85,8 @@ enum tomoyo_value_type { | |||
89 | /* Index numbers for domain transition control keywords. */ | 85 | /* Index numbers for domain transition control keywords. */ |
90 | enum tomoyo_transition_type { | 86 | enum tomoyo_transition_type { |
91 | /* Do not change this order, */ | 87 | /* Do not change this order, */ |
88 | TOMOYO_TRANSITION_CONTROL_NO_RESET, | ||
89 | TOMOYO_TRANSITION_CONTROL_RESET, | ||
92 | TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE, | 90 | TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE, |
93 | TOMOYO_TRANSITION_CONTROL_INITIALIZE, | 91 | TOMOYO_TRANSITION_CONTROL_INITIALIZE, |
94 | TOMOYO_TRANSITION_CONTROL_NO_KEEP, | 92 | TOMOYO_TRANSITION_CONTROL_NO_KEEP, |
@@ -246,6 +244,8 @@ struct tomoyo_shared_acl_head { | |||
246 | atomic_t users; | 244 | atomic_t users; |
247 | } __packed; | 245 | } __packed; |
248 | 246 | ||
247 | struct tomoyo_policy_namespace; | ||
248 | |||
249 | /* Structure for request info. */ | 249 | /* Structure for request info. */ |
250 | struct tomoyo_request_info { | 250 | struct tomoyo_request_info { |
251 | struct tomoyo_domain_info *domain; | 251 | struct tomoyo_domain_info *domain; |
@@ -359,6 +359,8 @@ struct tomoyo_domain_info { | |||
359 | struct list_head acl_info_list; | 359 | struct list_head acl_info_list; |
360 | /* Name of this domain. Never NULL. */ | 360 | /* Name of this domain. Never NULL. */ |
361 | const struct tomoyo_path_info *domainname; | 361 | const struct tomoyo_path_info *domainname; |
362 | /* Namespace for this domain. Never NULL. */ | ||
363 | struct tomoyo_policy_namespace *ns; | ||
362 | u8 profile; /* Profile number to use. */ | 364 | u8 profile; /* Profile number to use. */ |
363 | u8 group; /* Group number to use. */ | 365 | u8 group; /* Group number to use. */ |
364 | bool is_deleted; /* Delete flag. */ | 366 | bool is_deleted; /* Delete flag. */ |
@@ -423,6 +425,7 @@ struct tomoyo_mount_acl { | |||
423 | struct tomoyo_acl_param { | 425 | struct tomoyo_acl_param { |
424 | char *data; | 426 | char *data; |
425 | struct list_head *list; | 427 | struct list_head *list; |
428 | struct tomoyo_policy_namespace *ns; | ||
426 | bool is_delete; | 429 | bool is_delete; |
427 | }; | 430 | }; |
428 | 431 | ||
@@ -443,6 +446,7 @@ struct tomoyo_io_buffer { | |||
443 | char __user *read_user_buf; | 446 | char __user *read_user_buf; |
444 | int read_user_buf_avail; | 447 | int read_user_buf_avail; |
445 | struct { | 448 | struct { |
449 | struct list_head *ns; | ||
446 | struct list_head *domain; | 450 | struct list_head *domain; |
447 | struct list_head *group; | 451 | struct list_head *group; |
448 | struct list_head *acl; | 452 | struct list_head *acl; |
@@ -455,14 +459,16 @@ struct tomoyo_io_buffer { | |||
455 | u8 w_pos; | 459 | u8 w_pos; |
456 | bool eof; | 460 | bool eof; |
457 | bool print_this_domain_only; | 461 | bool print_this_domain_only; |
458 | bool print_execute_only; | 462 | bool print_transition_related_only; |
459 | const char *w[TOMOYO_MAX_IO_READ_QUEUE]; | 463 | const char *w[TOMOYO_MAX_IO_READ_QUEUE]; |
460 | } r; | 464 | } r; |
461 | struct { | 465 | struct { |
466 | struct tomoyo_policy_namespace *ns; | ||
462 | /* The position currently writing to. */ | 467 | /* The position currently writing to. */ |
463 | struct tomoyo_domain_info *domain; | 468 | struct tomoyo_domain_info *domain; |
464 | /* Bytes available for writing. */ | 469 | /* Bytes available for writing. */ |
465 | int avail; | 470 | int avail; |
471 | bool is_delete; | ||
466 | } w; | 472 | } w; |
467 | /* Buffer for reading. */ | 473 | /* Buffer for reading. */ |
468 | char *read_buf; | 474 | char *read_buf; |
@@ -533,8 +539,27 @@ struct tomoyo_time { | |||
533 | u8 sec; | 539 | u8 sec; |
534 | }; | 540 | }; |
535 | 541 | ||
542 | /* Structure for policy namespace. */ | ||
543 | struct tomoyo_policy_namespace { | ||
544 | /* Profile table. Memory is allocated as needed. */ | ||
545 | struct tomoyo_profile *profile_ptr[TOMOYO_MAX_PROFILES]; | ||
546 | /* List of "struct tomoyo_group". */ | ||
547 | struct list_head group_list[TOMOYO_MAX_GROUP]; | ||
548 | /* List of policy. */ | ||
549 | struct list_head policy_list[TOMOYO_MAX_POLICY]; | ||
550 | /* The global ACL referred by "use_group" keyword. */ | ||
551 | struct list_head acl_group[TOMOYO_MAX_ACL_GROUPS]; | ||
552 | /* List for connecting to tomoyo_namespace_list list. */ | ||
553 | struct list_head namespace_list; | ||
554 | /* Profile version. Currently only 20100903 is defined. */ | ||
555 | unsigned int profile_version; | ||
556 | /* Name of this namespace (e.g. "<kernel>", "</usr/sbin/httpd>" ). */ | ||
557 | const char *name; | ||
558 | }; | ||
559 | |||
536 | /********** Function prototypes. **********/ | 560 | /********** Function prototypes. **********/ |
537 | 561 | ||
562 | void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns); | ||
538 | bool tomoyo_str_starts(char **src, const char *find); | 563 | bool tomoyo_str_starts(char **src, const char *find); |
539 | const char *tomoyo_get_exe(void); | 564 | const char *tomoyo_get_exe(void); |
540 | void tomoyo_normalize_line(unsigned char *buffer); | 565 | void tomoyo_normalize_line(unsigned char *buffer); |
@@ -553,7 +578,8 @@ tomoyo_compare_name_union(const struct tomoyo_path_info *name, | |||
553 | const struct tomoyo_name_union *ptr); | 578 | const struct tomoyo_name_union *ptr); |
554 | bool tomoyo_compare_number_union(const unsigned long value, | 579 | bool tomoyo_compare_number_union(const unsigned long value, |
555 | const struct tomoyo_number_union *ptr); | 580 | const struct tomoyo_number_union *ptr); |
556 | int tomoyo_get_mode(const u8 profile, const u8 index); | 581 | int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile, |
582 | const u8 index); | ||
557 | void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) | 583 | void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) |
558 | __attribute__ ((format(printf, 2, 3))); | 584 | __attribute__ ((format(printf, 2, 3))); |
559 | bool tomoyo_correct_domain(const unsigned char *domainname); | 585 | bool tomoyo_correct_domain(const unsigned char *domainname); |
@@ -589,8 +615,11 @@ int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) | |||
589 | __attribute__ ((format(printf, 2, 3))); | 615 | __attribute__ ((format(printf, 2, 3))); |
590 | struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname); | 616 | struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname); |
591 | struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname, | 617 | struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname, |
592 | const u8 profile); | 618 | const bool transit); |
593 | struct tomoyo_profile *tomoyo_profile(const u8 profile); | 619 | struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns, |
620 | const u8 profile); | ||
621 | struct tomoyo_policy_namespace *tomoyo_assign_namespace | ||
622 | (const char *domainname); | ||
594 | struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param, | 623 | struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param, |
595 | const u8 idx); | 624 | const u8 idx); |
596 | unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain, | 625 | unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain, |
@@ -646,6 +675,8 @@ char *tomoyo_read_token(struct tomoyo_acl_param *param); | |||
646 | bool tomoyo_permstr(const char *string, const char *keyword); | 675 | bool tomoyo_permstr(const char *string, const char *keyword); |
647 | 676 | ||
648 | const char *tomoyo_yesno(const unsigned int value); | 677 | const char *tomoyo_yesno(const unsigned int value); |
678 | void tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...) | ||
679 | __attribute__ ((format(printf, 2, 3))); | ||
649 | void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt, | 680 | void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt, |
650 | va_list args); | 681 | va_list args); |
651 | void tomoyo_read_log(struct tomoyo_io_buffer *head); | 682 | void tomoyo_read_log(struct tomoyo_io_buffer *head); |
@@ -661,8 +692,6 @@ extern struct srcu_struct tomoyo_ss; | |||
661 | /* The list for "struct tomoyo_domain_info". */ | 692 | /* The list for "struct tomoyo_domain_info". */ |
662 | extern struct list_head tomoyo_domain_list; | 693 | extern struct list_head tomoyo_domain_list; |
663 | 694 | ||
664 | extern struct list_head tomoyo_policy_list[TOMOYO_MAX_POLICY]; | ||
665 | extern struct list_head tomoyo_group_list[TOMOYO_MAX_GROUP]; | ||
666 | extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; | 695 | extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; |
667 | 696 | ||
668 | /* Lock for protecting policy. */ | 697 | /* Lock for protecting policy. */ |
@@ -671,10 +700,10 @@ extern struct mutex tomoyo_policy_lock; | |||
671 | /* Has /sbin/init started? */ | 700 | /* Has /sbin/init started? */ |
672 | extern bool tomoyo_policy_loaded; | 701 | extern bool tomoyo_policy_loaded; |
673 | 702 | ||
674 | extern struct list_head tomoyo_acl_group[TOMOYO_MAX_ACL_GROUPS]; | ||
675 | |||
676 | /* The kernel's domain. */ | 703 | /* The kernel's domain. */ |
677 | extern struct tomoyo_domain_info tomoyo_kernel_domain; | 704 | extern struct tomoyo_domain_info tomoyo_kernel_domain; |
705 | extern struct tomoyo_policy_namespace tomoyo_kernel_namespace; | ||
706 | extern struct list_head tomoyo_namespace_list; | ||
678 | 707 | ||
679 | extern const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION]; | 708 | extern const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION]; |
680 | extern const char *tomoyo_mkdev_keyword[TOMOYO_MAX_MKDEV_OPERATION]; | 709 | extern const char *tomoyo_mkdev_keyword[TOMOYO_MAX_MKDEV_OPERATION]; |
@@ -809,6 +838,16 @@ static inline bool tomoyo_same_number_union | |||
809 | a->value_type[1] == b->value_type[1]; | 838 | a->value_type[1] == b->value_type[1]; |
810 | } | 839 | } |
811 | 840 | ||
841 | /** | ||
842 | * tomoyo_current_namespace - Get "struct tomoyo_policy_namespace" for current thread. | ||
843 | * | ||
844 | * Returns pointer to "struct tomoyo_policy_namespace" for current thread. | ||
845 | */ | ||
846 | static inline struct tomoyo_policy_namespace *tomoyo_current_namespace(void) | ||
847 | { | ||
848 | return tomoyo_domain()->ns; | ||
849 | } | ||
850 | |||
812 | #if defined(CONFIG_SLOB) | 851 | #if defined(CONFIG_SLOB) |
813 | 852 | ||
814 | /** | 853 | /** |
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index af5f325e2f33..71acebc747c3 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
@@ -12,9 +12,6 @@ | |||
12 | 12 | ||
13 | /* Variables definitions.*/ | 13 | /* Variables definitions.*/ |
14 | 14 | ||
15 | /* The global ACL referred by "use_group" keyword. */ | ||
16 | struct list_head tomoyo_acl_group[TOMOYO_MAX_ACL_GROUPS]; | ||
17 | |||
18 | /* The initial domain. */ | 15 | /* The initial domain. */ |
19 | struct tomoyo_domain_info tomoyo_kernel_domain; | 16 | struct tomoyo_domain_info tomoyo_kernel_domain; |
20 | 17 | ||
@@ -158,7 +155,7 @@ retry: | |||
158 | } | 155 | } |
159 | if (!retried) { | 156 | if (!retried) { |
160 | retried = true; | 157 | retried = true; |
161 | list = &tomoyo_acl_group[domain->group]; | 158 | list = &domain->ns->acl_group[domain->group]; |
162 | goto retry; | 159 | goto retry; |
163 | } | 160 | } |
164 | r->granted = false; | 161 | r->granted = false; |
@@ -167,13 +164,10 @@ retry: | |||
167 | /* The list for "struct tomoyo_domain_info". */ | 164 | /* The list for "struct tomoyo_domain_info". */ |
168 | LIST_HEAD(tomoyo_domain_list); | 165 | LIST_HEAD(tomoyo_domain_list); |
169 | 166 | ||
170 | struct list_head tomoyo_policy_list[TOMOYO_MAX_POLICY]; | ||
171 | struct list_head tomoyo_group_list[TOMOYO_MAX_GROUP]; | ||
172 | |||
173 | /** | 167 | /** |
174 | * tomoyo_last_word - Get last component of a domainname. | 168 | * tomoyo_last_word - Get last component of a domainname. |
175 | * | 169 | * |
176 | * @domainname: Domainname to check. | 170 | * @name: Domainname to check. |
177 | * | 171 | * |
178 | * Returns the last word of @domainname. | 172 | * Returns the last word of @domainname. |
179 | */ | 173 | */ |
@@ -247,7 +241,7 @@ int tomoyo_write_transition_control(struct tomoyo_acl_param *param, | |||
247 | if (!e.domainname) | 241 | if (!e.domainname) |
248 | goto out; | 242 | goto out; |
249 | } | 243 | } |
250 | param->list = &tomoyo_policy_list[TOMOYO_ID_TRANSITION_CONTROL]; | 244 | param->list = ¶m->ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL]; |
251 | error = tomoyo_update_policy(&e.head, sizeof(e), param, | 245 | error = tomoyo_update_policy(&e.head, sizeof(e), param, |
252 | tomoyo_same_transition_control); | 246 | tomoyo_same_transition_control); |
253 | out: | 247 | out: |
@@ -257,59 +251,88 @@ out: | |||
257 | } | 251 | } |
258 | 252 | ||
259 | /** | 253 | /** |
260 | * tomoyo_transition_type - Get domain transition type. | 254 | * tomoyo_scan_transition - Try to find specific domain transition type. |
261 | * | 255 | * |
262 | * @domainname: The name of domain. | 256 | * @list: Pointer to "struct list_head". |
263 | * @program: The name of program. | 257 | * @domainname: The name of current domain. |
258 | * @program: The name of requested program. | ||
259 | * @last_name: The last component of @domainname. | ||
260 | * @type: One of values in "enum tomoyo_transition_type". | ||
264 | * | 261 | * |
265 | * Returns TOMOYO_TRANSITION_CONTROL_INITIALIZE if executing @program | 262 | * Returns true if found one, false otherwise. |
266 | * reinitializes domain transition, TOMOYO_TRANSITION_CONTROL_KEEP if executing | ||
267 | * @program suppresses domain transition, others otherwise. | ||
268 | * | 263 | * |
269 | * Caller holds tomoyo_read_lock(). | 264 | * Caller holds tomoyo_read_lock(). |
270 | */ | 265 | */ |
271 | static u8 tomoyo_transition_type(const struct tomoyo_path_info *domainname, | 266 | static inline bool tomoyo_scan_transition |
272 | const struct tomoyo_path_info *program) | 267 | (const struct list_head *list, const struct tomoyo_path_info *domainname, |
268 | const struct tomoyo_path_info *program, const char *last_name, | ||
269 | const enum tomoyo_transition_type type) | ||
273 | { | 270 | { |
274 | const struct tomoyo_transition_control *ptr; | 271 | const struct tomoyo_transition_control *ptr; |
275 | const char *last_name = tomoyo_last_word(domainname->name); | 272 | list_for_each_entry_rcu(ptr, list, head.list) { |
276 | u8 type; | 273 | if (ptr->head.is_deleted || ptr->type != type) |
277 | for (type = 0; type < TOMOYO_MAX_TRANSITION_TYPE; type++) { | 274 | continue; |
278 | next: | 275 | if (ptr->domainname) { |
279 | list_for_each_entry_rcu(ptr, &tomoyo_policy_list | 276 | if (!ptr->is_last_name) { |
280 | [TOMOYO_ID_TRANSITION_CONTROL], | 277 | if (ptr->domainname != domainname) |
281 | head.list) { | 278 | continue; |
282 | if (ptr->head.is_deleted || ptr->type != type) | 279 | } else { |
283 | continue; | ||
284 | if (ptr->domainname) { | ||
285 | if (!ptr->is_last_name) { | ||
286 | if (ptr->domainname != domainname) | ||
287 | continue; | ||
288 | } else { | ||
289 | /* | ||
290 | * Use direct strcmp() since this is | ||
291 | * unlikely used. | ||
292 | */ | ||
293 | if (strcmp(ptr->domainname->name, | ||
294 | last_name)) | ||
295 | continue; | ||
296 | } | ||
297 | } | ||
298 | if (ptr->program && | ||
299 | tomoyo_pathcmp(ptr->program, program)) | ||
300 | continue; | ||
301 | if (type == TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE) { | ||
302 | /* | 280 | /* |
303 | * Do not check for initialize_domain if | 281 | * Use direct strcmp() since this is |
304 | * no_initialize_domain matched. | 282 | * unlikely used. |
305 | */ | 283 | */ |
306 | type = TOMOYO_TRANSITION_CONTROL_NO_KEEP; | 284 | if (strcmp(ptr->domainname->name, last_name)) |
307 | goto next; | 285 | continue; |
308 | } | 286 | } |
309 | goto done; | ||
310 | } | 287 | } |
288 | if (ptr->program && tomoyo_pathcmp(ptr->program, program)) | ||
289 | continue; | ||
290 | return true; | ||
291 | } | ||
292 | return false; | ||
293 | } | ||
294 | |||
295 | /** | ||
296 | * tomoyo_transition_type - Get domain transition type. | ||
297 | * | ||
298 | * @ns: Pointer to "struct tomoyo_policy_namespace". | ||
299 | * @domainname: The name of current domain. | ||
300 | * @program: The name of requested program. | ||
301 | * | ||
302 | * Returns TOMOYO_TRANSITION_CONTROL_TRANSIT if executing @program causes | ||
303 | * domain transition across namespaces, TOMOYO_TRANSITION_CONTROL_INITIALIZE if | ||
304 | * executing @program reinitializes domain transition within that namespace, | ||
305 | * TOMOYO_TRANSITION_CONTROL_KEEP if executing @program stays at @domainname , | ||
306 | * others otherwise. | ||
307 | * | ||
308 | * Caller holds tomoyo_read_lock(). | ||
309 | */ | ||
310 | static enum tomoyo_transition_type tomoyo_transition_type | ||
311 | (const struct tomoyo_policy_namespace *ns, | ||
312 | const struct tomoyo_path_info *domainname, | ||
313 | const struct tomoyo_path_info *program) | ||
314 | { | ||
315 | const char *last_name = tomoyo_last_word(domainname->name); | ||
316 | enum tomoyo_transition_type type = TOMOYO_TRANSITION_CONTROL_NO_RESET; | ||
317 | while (type < TOMOYO_MAX_TRANSITION_TYPE) { | ||
318 | const struct list_head * const list = | ||
319 | &ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL]; | ||
320 | if (!tomoyo_scan_transition(list, domainname, program, | ||
321 | last_name, type)) { | ||
322 | type++; | ||
323 | continue; | ||
324 | } | ||
325 | if (type != TOMOYO_TRANSITION_CONTROL_NO_RESET && | ||
326 | type != TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE) | ||
327 | break; | ||
328 | /* | ||
329 | * Do not check for reset_domain if no_reset_domain matched. | ||
330 | * Do not check for initialize_domain if no_initialize_domain | ||
331 | * matched. | ||
332 | */ | ||
333 | type++; | ||
334 | type++; | ||
311 | } | 335 | } |
312 | done: | ||
313 | return type; | 336 | return type; |
314 | } | 337 | } |
315 | 338 | ||
@@ -355,7 +378,7 @@ int tomoyo_write_aggregator(struct tomoyo_acl_param *param) | |||
355 | if (!e.original_name || !e.aggregated_name || | 378 | if (!e.original_name || !e.aggregated_name || |
356 | e.aggregated_name->is_patterned) /* No patterns allowed. */ | 379 | e.aggregated_name->is_patterned) /* No patterns allowed. */ |
357 | goto out; | 380 | goto out; |
358 | param->list = &tomoyo_policy_list[TOMOYO_ID_AGGREGATOR]; | 381 | param->list = ¶m->ns->policy_list[TOMOYO_ID_AGGREGATOR]; |
359 | error = tomoyo_update_policy(&e.head, sizeof(e), param, | 382 | error = tomoyo_update_policy(&e.head, sizeof(e), param, |
360 | tomoyo_same_aggregator); | 383 | tomoyo_same_aggregator); |
361 | out: | 384 | out: |
@@ -365,53 +388,171 @@ out: | |||
365 | } | 388 | } |
366 | 389 | ||
367 | /** | 390 | /** |
368 | * tomoyo_assign_domain - Create a domain. | 391 | * tomoyo_find_namespace - Find specified namespace. |
369 | * | 392 | * |
370 | * @domainname: The name of domain. | 393 | * @name: Name of namespace to find. |
371 | * @profile: Profile number to assign if the domain was newly created. | 394 | * @len: Length of @name. |
372 | * | 395 | * |
373 | * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise. | 396 | * Returns pointer to "struct tomoyo_policy_namespace" if found, |
397 | * NULL otherwise. | ||
374 | * | 398 | * |
375 | * Caller holds tomoyo_read_lock(). | 399 | * Caller holds tomoyo_read_lock(). |
376 | */ | 400 | */ |
377 | struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname, | 401 | static struct tomoyo_policy_namespace *tomoyo_find_namespace |
378 | const u8 profile) | 402 | (const char *name, const unsigned int len) |
379 | { | 403 | { |
380 | struct tomoyo_domain_info *entry; | 404 | struct tomoyo_policy_namespace *ns; |
381 | struct tomoyo_domain_info *domain = NULL; | 405 | list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) { |
382 | const struct tomoyo_path_info *saved_domainname; | 406 | if (strncmp(name, ns->name, len) || |
383 | bool found = false; | 407 | (name[len] && name[len] != ' ')) |
408 | continue; | ||
409 | return ns; | ||
410 | } | ||
411 | return NULL; | ||
412 | } | ||
384 | 413 | ||
385 | if (!tomoyo_correct_domain(domainname)) | 414 | /** |
415 | * tomoyo_assign_namespace - Create a new namespace. | ||
416 | * | ||
417 | * @domainname: Name of namespace to create. | ||
418 | * | ||
419 | * Returns pointer to "struct tomoyo_policy_namespace" on success, | ||
420 | * NULL otherwise. | ||
421 | * | ||
422 | * Caller holds tomoyo_read_lock(). | ||
423 | */ | ||
424 | struct tomoyo_policy_namespace *tomoyo_assign_namespace(const char *domainname) | ||
425 | { | ||
426 | struct tomoyo_policy_namespace *ptr; | ||
427 | struct tomoyo_policy_namespace *entry; | ||
428 | const char *cp = domainname; | ||
429 | unsigned int len = 0; | ||
430 | while (*cp && *cp++ != ' ') | ||
431 | len++; | ||
432 | ptr = tomoyo_find_namespace(domainname, len); | ||
433 | if (ptr) | ||
434 | return ptr; | ||
435 | if (len >= TOMOYO_EXEC_TMPSIZE - 10 || !tomoyo_domain_def(domainname)) | ||
386 | return NULL; | 436 | return NULL; |
387 | saved_domainname = tomoyo_get_name(domainname); | 437 | entry = kzalloc(sizeof(*entry) + len + 1, GFP_NOFS); |
388 | if (!saved_domainname) | 438 | if (!entry) |
389 | return NULL; | 439 | return NULL; |
390 | entry = kzalloc(sizeof(*entry), GFP_NOFS); | ||
391 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 440 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
392 | goto out; | 441 | goto out; |
393 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | 442 | ptr = tomoyo_find_namespace(domainname, len); |
394 | if (domain->is_deleted || | 443 | if (!ptr && tomoyo_memory_ok(entry)) { |
395 | tomoyo_pathcmp(saved_domainname, domain->domainname)) | 444 | char *name = (char *) (entry + 1); |
396 | continue; | 445 | ptr = entry; |
397 | found = true; | 446 | memmove(name, domainname, len); |
398 | break; | 447 | name[len] = '\0'; |
399 | } | 448 | entry->name = name; |
400 | if (!found && tomoyo_memory_ok(entry)) { | 449 | tomoyo_init_policy_namespace(entry); |
401 | INIT_LIST_HEAD(&entry->acl_info_list); | ||
402 | entry->domainname = saved_domainname; | ||
403 | saved_domainname = NULL; | ||
404 | entry->profile = profile; | ||
405 | list_add_tail_rcu(&entry->list, &tomoyo_domain_list); | ||
406 | domain = entry; | ||
407 | entry = NULL; | 450 | entry = NULL; |
408 | found = true; | ||
409 | } | 451 | } |
410 | mutex_unlock(&tomoyo_policy_lock); | 452 | mutex_unlock(&tomoyo_policy_lock); |
411 | out: | 453 | out: |
412 | tomoyo_put_name(saved_domainname); | ||
413 | kfree(entry); | 454 | kfree(entry); |
414 | return found ? domain : NULL; | 455 | return ptr; |
456 | } | ||
457 | |||
458 | /** | ||
459 | * tomoyo_namespace_jump - Check for namespace jump. | ||
460 | * | ||
461 | * @domainname: Name of domain. | ||
462 | * | ||
463 | * Returns true if namespace differs, false otherwise. | ||
464 | */ | ||
465 | static bool tomoyo_namespace_jump(const char *domainname) | ||
466 | { | ||
467 | const char *namespace = tomoyo_current_namespace()->name; | ||
468 | const int len = strlen(namespace); | ||
469 | return strncmp(domainname, namespace, len) || | ||
470 | (domainname[len] && domainname[len] != ' '); | ||
471 | } | ||
472 | |||
473 | /** | ||
474 | * tomoyo_assign_domain - Create a domain or a namespace. | ||
475 | * | ||
476 | * @domainname: The name of domain. | ||
477 | * @transit: True if transit to domain found or created. | ||
478 | * | ||
479 | * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise. | ||
480 | * | ||
481 | * Caller holds tomoyo_read_lock(). | ||
482 | */ | ||
483 | struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname, | ||
484 | const bool transit) | ||
485 | { | ||
486 | struct tomoyo_domain_info e = { }; | ||
487 | struct tomoyo_domain_info *entry = tomoyo_find_domain(domainname); | ||
488 | bool created = false; | ||
489 | if (entry) { | ||
490 | if (transit) { | ||
491 | /* | ||
492 | * Since namespace is created at runtime, profiles may | ||
493 | * not be created by the moment the process transits to | ||
494 | * that domain. Do not perform domain transition if | ||
495 | * profile for that domain is not yet created. | ||
496 | */ | ||
497 | if (!entry->ns->profile_ptr[entry->profile]) | ||
498 | return NULL; | ||
499 | } | ||
500 | return entry; | ||
501 | } | ||
502 | /* Requested domain does not exist. */ | ||
503 | /* Don't create requested domain if domainname is invalid. */ | ||
504 | if (strlen(domainname) >= TOMOYO_EXEC_TMPSIZE - 10 || | ||
505 | !tomoyo_correct_domain(domainname)) | ||
506 | return NULL; | ||
507 | /* | ||
508 | * Since definition of profiles and acl_groups may differ across | ||
509 | * namespaces, do not inherit "use_profile" and "use_group" settings | ||
510 | * by automatically creating requested domain upon domain transition. | ||
511 | */ | ||
512 | if (transit && tomoyo_namespace_jump(domainname)) | ||
513 | return NULL; | ||
514 | e.ns = tomoyo_assign_namespace(domainname); | ||
515 | if (!e.ns) | ||
516 | return NULL; | ||
517 | /* | ||
518 | * "use_profile" and "use_group" settings for automatically created | ||
519 | * domains are inherited from current domain. These are 0 for manually | ||
520 | * created domains. | ||
521 | */ | ||
522 | if (transit) { | ||
523 | const struct tomoyo_domain_info *domain = tomoyo_domain(); | ||
524 | e.profile = domain->profile; | ||
525 | e.group = domain->group; | ||
526 | } | ||
527 | e.domainname = tomoyo_get_name(domainname); | ||
528 | if (!e.domainname) | ||
529 | return NULL; | ||
530 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | ||
531 | goto out; | ||
532 | entry = tomoyo_find_domain(domainname); | ||
533 | if (!entry) { | ||
534 | entry = tomoyo_commit_ok(&e, sizeof(e)); | ||
535 | if (entry) { | ||
536 | INIT_LIST_HEAD(&entry->acl_info_list); | ||
537 | list_add_tail_rcu(&entry->list, &tomoyo_domain_list); | ||
538 | created = true; | ||
539 | } | ||
540 | } | ||
541 | mutex_unlock(&tomoyo_policy_lock); | ||
542 | out: | ||
543 | tomoyo_put_name(e.domainname); | ||
544 | if (entry && transit) { | ||
545 | if (created) { | ||
546 | struct tomoyo_request_info r; | ||
547 | tomoyo_init_request_info(&r, entry, | ||
548 | TOMOYO_MAC_FILE_EXECUTE); | ||
549 | r.granted = false; | ||
550 | tomoyo_write_log(&r, "use_profile %u\n", | ||
551 | entry->profile); | ||
552 | tomoyo_write_log(&r, "use_group %u\n", entry->group); | ||
553 | } | ||
554 | } | ||
555 | return entry; | ||
415 | } | 556 | } |
416 | 557 | ||
417 | /** | 558 | /** |
@@ -434,6 +575,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
434 | bool is_enforce; | 575 | bool is_enforce; |
435 | int retval = -ENOMEM; | 576 | int retval = -ENOMEM; |
436 | bool need_kfree = false; | 577 | bool need_kfree = false; |
578 | bool reject_on_transition_failure = false; | ||
437 | struct tomoyo_path_info rn = { }; /* real name */ | 579 | struct tomoyo_path_info rn = { }; /* real name */ |
438 | 580 | ||
439 | mode = tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE); | 581 | mode = tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE); |
@@ -457,8 +599,10 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
457 | /* Check 'aggregator' directive. */ | 599 | /* Check 'aggregator' directive. */ |
458 | { | 600 | { |
459 | struct tomoyo_aggregator *ptr; | 601 | struct tomoyo_aggregator *ptr; |
460 | list_for_each_entry_rcu(ptr, &tomoyo_policy_list | 602 | struct list_head *list = |
461 | [TOMOYO_ID_AGGREGATOR], head.list) { | 603 | &old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR]; |
604 | /* Check 'aggregator' directive. */ | ||
605 | list_for_each_entry_rcu(ptr, list, head.list) { | ||
462 | if (ptr->head.is_deleted || | 606 | if (ptr->head.is_deleted || |
463 | !tomoyo_path_matches_pattern(&rn, | 607 | !tomoyo_path_matches_pattern(&rn, |
464 | ptr->original_name)) | 608 | ptr->original_name)) |
@@ -492,11 +636,21 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
492 | } | 636 | } |
493 | 637 | ||
494 | /* Calculate domain to transit to. */ | 638 | /* Calculate domain to transit to. */ |
495 | switch (tomoyo_transition_type(old_domain->domainname, &rn)) { | 639 | switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname, |
640 | &rn)) { | ||
641 | case TOMOYO_TRANSITION_CONTROL_RESET: | ||
642 | /* Transit to the root of specified namespace. */ | ||
643 | snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", rn.name); | ||
644 | /* | ||
645 | * Make do_execve() fail if domain transition across namespaces | ||
646 | * has failed. | ||
647 | */ | ||
648 | reject_on_transition_failure = true; | ||
649 | break; | ||
496 | case TOMOYO_TRANSITION_CONTROL_INITIALIZE: | 650 | case TOMOYO_TRANSITION_CONTROL_INITIALIZE: |
497 | /* Transit to the child of tomoyo_kernel_domain domain. */ | 651 | /* Transit to the child of current namespace's root. */ |
498 | snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, TOMOYO_ROOT_NAME " " | 652 | snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", |
499 | "%s", rn.name); | 653 | old_domain->ns->name, rn.name); |
500 | break; | 654 | break; |
501 | case TOMOYO_TRANSITION_CONTROL_KEEP: | 655 | case TOMOYO_TRANSITION_CONTROL_KEEP: |
502 | /* Keep current domain. */ | 656 | /* Keep current domain. */ |
@@ -519,19 +673,25 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
519 | } | 673 | } |
520 | break; | 674 | break; |
521 | } | 675 | } |
522 | if (domain || strlen(tmp) >= TOMOYO_EXEC_TMPSIZE - 10) | ||
523 | goto done; | ||
524 | domain = tomoyo_find_domain(tmp); | ||
525 | if (!domain) | 676 | if (!domain) |
526 | domain = tomoyo_assign_domain(tmp, old_domain->profile); | 677 | domain = tomoyo_assign_domain(tmp, true); |
527 | done: | ||
528 | if (domain) | 678 | if (domain) |
529 | goto out; | 679 | retval = 0; |
530 | printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n", tmp); | 680 | else if (reject_on_transition_failure) { |
531 | if (is_enforce) | 681 | printk(KERN_WARNING "ERROR: Domain '%s' not ready.\n", tmp); |
532 | retval = -EPERM; | 682 | retval = -ENOMEM; |
533 | else | 683 | } else if (r.mode == TOMOYO_CONFIG_ENFORCING) |
534 | old_domain->transition_failed = true; | 684 | retval = -ENOMEM; |
685 | else { | ||
686 | retval = 0; | ||
687 | if (!old_domain->transition_failed) { | ||
688 | old_domain->transition_failed = true; | ||
689 | r.granted = false; | ||
690 | tomoyo_write_log(&r, "%s", "transition_failed\n"); | ||
691 | printk(KERN_WARNING | ||
692 | "ERROR: Domain '%s' not defined.\n", tmp); | ||
693 | } | ||
694 | } | ||
535 | out: | 695 | out: |
536 | if (!domain) | 696 | if (!domain) |
537 | domain = old_domain; | 697 | domain = old_domain; |
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 4f8526af9069..323ddc73a125 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c | |||
@@ -603,7 +603,7 @@ int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, | |||
603 | int error; | 603 | int error; |
604 | 604 | ||
605 | r->type = tomoyo_p2mac[operation]; | 605 | r->type = tomoyo_p2mac[operation]; |
606 | r->mode = tomoyo_get_mode(r->profile, r->type); | 606 | r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type); |
607 | if (r->mode == TOMOYO_CONFIG_DISABLED) | 607 | if (r->mode == TOMOYO_CONFIG_DISABLED) |
608 | return 0; | 608 | return 0; |
609 | r->param_type = TOMOYO_TYPE_PATH_ACL; | 609 | r->param_type = TOMOYO_TYPE_PATH_ACL; |
diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c index 412ee8309c23..782e844dca7f 100644 --- a/security/tomoyo/gc.c +++ b/security/tomoyo/gc.c | |||
@@ -292,15 +292,12 @@ static bool tomoyo_collect_acl(struct list_head *list) | |||
292 | static void tomoyo_collect_entry(void) | 292 | static void tomoyo_collect_entry(void) |
293 | { | 293 | { |
294 | int i; | 294 | int i; |
295 | enum tomoyo_policy_id id; | ||
296 | struct tomoyo_policy_namespace *ns; | ||
297 | int idx; | ||
295 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 298 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
296 | return; | 299 | return; |
297 | for (i = 0; i < TOMOYO_MAX_POLICY; i++) { | 300 | idx = tomoyo_read_lock(); |
298 | if (!tomoyo_collect_member(i, &tomoyo_policy_list[i])) | ||
299 | goto unlock; | ||
300 | } | ||
301 | for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++) | ||
302 | if (!tomoyo_collect_acl(&tomoyo_acl_group[i])) | ||
303 | goto unlock; | ||
304 | { | 301 | { |
305 | struct tomoyo_domain_info *domain; | 302 | struct tomoyo_domain_info *domain; |
306 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | 303 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { |
@@ -317,39 +314,49 @@ static void tomoyo_collect_entry(void) | |||
317 | goto unlock; | 314 | goto unlock; |
318 | } | 315 | } |
319 | } | 316 | } |
320 | for (i = 0; i < TOMOYO_MAX_HASH; i++) { | 317 | list_for_each_entry_rcu(ns, &tomoyo_namespace_list, namespace_list) { |
321 | struct tomoyo_name *ptr; | 318 | for (id = 0; id < TOMOYO_MAX_POLICY; id++) |
322 | list_for_each_entry_rcu(ptr, &tomoyo_name_list[i], head.list) { | 319 | if (!tomoyo_collect_member(id, &ns->policy_list[id])) |
323 | if (atomic_read(&ptr->head.users)) | ||
324 | continue; | ||
325 | if (!tomoyo_add_to_gc(TOMOYO_ID_NAME, &ptr->head.list)) | ||
326 | goto unlock; | 320 | goto unlock; |
321 | for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++) | ||
322 | if (!tomoyo_collect_acl(&ns->acl_group[i])) | ||
323 | goto unlock; | ||
324 | for (i = 0; i < TOMOYO_MAX_GROUP; i++) { | ||
325 | struct list_head *list = &ns->group_list[i]; | ||
326 | struct tomoyo_group *group; | ||
327 | switch (i) { | ||
328 | case 0: | ||
329 | id = TOMOYO_ID_PATH_GROUP; | ||
330 | break; | ||
331 | default: | ||
332 | id = TOMOYO_ID_NUMBER_GROUP; | ||
333 | break; | ||
334 | } | ||
335 | list_for_each_entry(group, list, head.list) { | ||
336 | if (!tomoyo_collect_member | ||
337 | (id, &group->member_list)) | ||
338 | goto unlock; | ||
339 | if (!list_empty(&group->member_list) || | ||
340 | atomic_read(&group->head.users)) | ||
341 | continue; | ||
342 | if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP, | ||
343 | &group->head.list)) | ||
344 | goto unlock; | ||
345 | } | ||
327 | } | 346 | } |
328 | } | 347 | } |
329 | for (i = 0; i < TOMOYO_MAX_GROUP; i++) { | 348 | for (i = 0; i < TOMOYO_MAX_HASH; i++) { |
330 | struct list_head *list = &tomoyo_group_list[i]; | 349 | struct list_head *list = &tomoyo_name_list[i]; |
331 | int id; | 350 | struct tomoyo_shared_acl_head *ptr; |
332 | struct tomoyo_group *group; | 351 | list_for_each_entry(ptr, list, list) { |
333 | switch (i) { | 352 | if (atomic_read(&ptr->users)) |
334 | case 0: | ||
335 | id = TOMOYO_ID_PATH_GROUP; | ||
336 | break; | ||
337 | default: | ||
338 | id = TOMOYO_ID_NUMBER_GROUP; | ||
339 | break; | ||
340 | } | ||
341 | list_for_each_entry(group, list, head.list) { | ||
342 | if (!tomoyo_collect_member(id, &group->member_list)) | ||
343 | goto unlock; | ||
344 | if (!list_empty(&group->member_list) || | ||
345 | atomic_read(&group->head.users)) | ||
346 | continue; | 353 | continue; |
347 | if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP, | 354 | if (!tomoyo_add_to_gc(TOMOYO_ID_NAME, &ptr->list)) |
348 | &group->head.list)) | ||
349 | goto unlock; | 355 | goto unlock; |
350 | } | 356 | } |
351 | } | 357 | } |
352 | unlock: | 358 | unlock: |
359 | tomoyo_read_unlock(idx); | ||
353 | mutex_unlock(&tomoyo_policy_lock); | 360 | mutex_unlock(&tomoyo_policy_lock); |
354 | } | 361 | } |
355 | 362 | ||
diff --git a/security/tomoyo/memory.c b/security/tomoyo/memory.c index 7a0493943d6d..39d012823f84 100644 --- a/security/tomoyo/memory.c +++ b/security/tomoyo/memory.c | |||
@@ -118,7 +118,7 @@ struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param, | |||
118 | return NULL; | 118 | return NULL; |
119 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 119 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
120 | goto out; | 120 | goto out; |
121 | list = &tomoyo_group_list[idx]; | 121 | list = ¶m->ns->group_list[idx]; |
122 | list_for_each_entry(group, list, head.list) { | 122 | list_for_each_entry(group, list, head.list) { |
123 | if (e.group_name != group->group_name) | 123 | if (e.group_name != group->group_name) |
124 | continue; | 124 | continue; |
@@ -199,27 +199,23 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name) | |||
199 | return ptr ? &ptr->entry : NULL; | 199 | return ptr ? &ptr->entry : NULL; |
200 | } | 200 | } |
201 | 201 | ||
202 | /* Initial namespace.*/ | ||
203 | struct tomoyo_policy_namespace tomoyo_kernel_namespace; | ||
204 | |||
202 | /** | 205 | /** |
203 | * tomoyo_mm_init - Initialize mm related code. | 206 | * tomoyo_mm_init - Initialize mm related code. |
204 | */ | 207 | */ |
205 | void __init tomoyo_mm_init(void) | 208 | void __init tomoyo_mm_init(void) |
206 | { | 209 | { |
207 | int idx; | 210 | int idx; |
208 | |||
209 | for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++) | ||
210 | INIT_LIST_HEAD(&tomoyo_policy_list[idx]); | ||
211 | for (idx = 0; idx < TOMOYO_MAX_GROUP; idx++) | ||
212 | INIT_LIST_HEAD(&tomoyo_group_list[idx]); | ||
213 | for (idx = 0; idx < TOMOYO_MAX_HASH; idx++) | 211 | for (idx = 0; idx < TOMOYO_MAX_HASH; idx++) |
214 | INIT_LIST_HEAD(&tomoyo_name_list[idx]); | 212 | INIT_LIST_HEAD(&tomoyo_name_list[idx]); |
213 | tomoyo_kernel_namespace.name = "<kernel>"; | ||
214 | tomoyo_init_policy_namespace(&tomoyo_kernel_namespace); | ||
215 | tomoyo_kernel_domain.ns = &tomoyo_kernel_namespace; | ||
215 | INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); | 216 | INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); |
216 | for (idx = 0; idx < TOMOYO_MAX_ACL_GROUPS; idx++) | 217 | tomoyo_kernel_domain.domainname = tomoyo_get_name("<kernel>"); |
217 | INIT_LIST_HEAD(&tomoyo_acl_group[idx]); | ||
218 | tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME); | ||
219 | list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list); | 218 | list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list); |
220 | idx = tomoyo_read_lock(); | ||
221 | if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain) | ||
222 | panic("Can't register tomoyo_kernel_domain"); | ||
223 | #if 0 | 219 | #if 0 |
224 | /* Will be replaced with tomoyo_load_builtin_policy(). */ | 220 | /* Will be replaced with tomoyo_load_builtin_policy(). */ |
225 | { | 221 | { |
@@ -230,7 +226,6 @@ void __init tomoyo_mm_init(void) | |||
230 | TOMOYO_TRANSITION_CONTROL_INITIALIZE); | 226 | TOMOYO_TRANSITION_CONTROL_INITIALIZE); |
231 | } | 227 | } |
232 | #endif | 228 | #endif |
233 | tomoyo_read_unlock(idx); | ||
234 | } | 229 | } |
235 | 230 | ||
236 | 231 | ||
diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c index bc71528ff440..fda15c1fc1c0 100644 --- a/security/tomoyo/util.c +++ b/security/tomoyo/util.c | |||
@@ -416,26 +416,21 @@ bool tomoyo_correct_path(const char *filename) | |||
416 | */ | 416 | */ |
417 | bool tomoyo_correct_domain(const unsigned char *domainname) | 417 | bool tomoyo_correct_domain(const unsigned char *domainname) |
418 | { | 418 | { |
419 | if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME, | 419 | if (!domainname || !tomoyo_domain_def(domainname)) |
420 | TOMOYO_ROOT_NAME_LEN)) | 420 | return false; |
421 | goto out; | 421 | domainname = strchr(domainname, ' '); |
422 | domainname += TOMOYO_ROOT_NAME_LEN; | 422 | if (!domainname++) |
423 | if (!*domainname) | ||
424 | return true; | 423 | return true; |
425 | if (*domainname++ != ' ') | ||
426 | goto out; | ||
427 | while (1) { | 424 | while (1) { |
428 | const unsigned char *cp = strchr(domainname, ' '); | 425 | const unsigned char *cp = strchr(domainname, ' '); |
429 | if (!cp) | 426 | if (!cp) |
430 | break; | 427 | break; |
431 | if (*domainname != '/' || | 428 | if (*domainname != '/' || |
432 | !tomoyo_correct_word2(domainname, cp - domainname)) | 429 | !tomoyo_correct_word2(domainname, cp - domainname)) |
433 | goto out; | 430 | return false; |
434 | domainname = cp + 1; | 431 | domainname = cp + 1; |
435 | } | 432 | } |
436 | return tomoyo_correct_path(domainname); | 433 | return tomoyo_correct_path(domainname); |
437 | out: | ||
438 | return false; | ||
439 | } | 434 | } |
440 | 435 | ||
441 | /** | 436 | /** |
@@ -447,7 +442,19 @@ bool tomoyo_correct_domain(const unsigned char *domainname) | |||
447 | */ | 442 | */ |
448 | bool tomoyo_domain_def(const unsigned char *buffer) | 443 | bool tomoyo_domain_def(const unsigned char *buffer) |
449 | { | 444 | { |
450 | return !strncmp(buffer, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN); | 445 | const unsigned char *cp; |
446 | int len; | ||
447 | if (*buffer != '<') | ||
448 | return false; | ||
449 | cp = strchr(buffer, ' '); | ||
450 | if (!cp) | ||
451 | len = strlen(buffer); | ||
452 | else | ||
453 | len = cp - buffer; | ||
454 | if (buffer[len - 1] != '>' || | ||
455 | !tomoyo_correct_word2(buffer + 1, len - 2)) | ||
456 | return false; | ||
457 | return true; | ||
451 | } | 458 | } |
452 | 459 | ||
453 | /** | 460 | /** |
@@ -833,22 +840,24 @@ const char *tomoyo_get_exe(void) | |||
833 | /** | 840 | /** |
834 | * tomoyo_get_mode - Get MAC mode. | 841 | * tomoyo_get_mode - Get MAC mode. |
835 | * | 842 | * |
843 | * @ns: Pointer to "struct tomoyo_policy_namespace". | ||
836 | * @profile: Profile number. | 844 | * @profile: Profile number. |
837 | * @index: Index number of functionality. | 845 | * @index: Index number of functionality. |
838 | * | 846 | * |
839 | * Returns mode. | 847 | * Returns mode. |
840 | */ | 848 | */ |
841 | int tomoyo_get_mode(const u8 profile, const u8 index) | 849 | int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile, |
850 | const u8 index) | ||
842 | { | 851 | { |
843 | u8 mode; | 852 | u8 mode; |
844 | const u8 category = TOMOYO_MAC_CATEGORY_FILE; | 853 | const u8 category = TOMOYO_MAC_CATEGORY_FILE; |
845 | if (!tomoyo_policy_loaded) | 854 | if (!tomoyo_policy_loaded) |
846 | return TOMOYO_CONFIG_DISABLED; | 855 | return TOMOYO_CONFIG_DISABLED; |
847 | mode = tomoyo_profile(profile)->config[index]; | 856 | mode = tomoyo_profile(ns, profile)->config[index]; |
848 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) | 857 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) |
849 | mode = tomoyo_profile(profile)->config[category]; | 858 | mode = tomoyo_profile(ns, profile)->config[category]; |
850 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) | 859 | if (mode == TOMOYO_CONFIG_USE_DEFAULT) |
851 | mode = tomoyo_profile(profile)->default_config; | 860 | mode = tomoyo_profile(ns, profile)->default_config; |
852 | return mode & 3; | 861 | return mode & 3; |
853 | } | 862 | } |
854 | 863 | ||
@@ -872,26 +881,11 @@ int tomoyo_init_request_info(struct tomoyo_request_info *r, | |||
872 | profile = domain->profile; | 881 | profile = domain->profile; |
873 | r->profile = profile; | 882 | r->profile = profile; |
874 | r->type = index; | 883 | r->type = index; |
875 | r->mode = tomoyo_get_mode(profile, index); | 884 | r->mode = tomoyo_get_mode(domain->ns, profile, index); |
876 | return r->mode; | 885 | return r->mode; |
877 | } | 886 | } |
878 | 887 | ||
879 | /** | 888 | /** |
880 | * tomoyo_last_word - Get last component of a line. | ||
881 | * | ||
882 | * @line: A line. | ||
883 | * | ||
884 | * Returns the last word of a line. | ||
885 | */ | ||
886 | const char *tomoyo_last_word(const char *name) | ||
887 | { | ||
888 | const char *cp = strrchr(name, ' '); | ||
889 | if (cp) | ||
890 | return cp + 1; | ||
891 | return name; | ||
892 | } | ||
893 | |||
894 | /** | ||
895 | * tomoyo_domain_quota_is_ok - Check for domain's quota. | 889 | * tomoyo_domain_quota_is_ok - Check for domain's quota. |
896 | * | 890 | * |
897 | * @r: Pointer to "struct tomoyo_request_info". | 891 | * @r: Pointer to "struct tomoyo_request_info". |
@@ -939,7 +933,7 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r) | |||
939 | if (perm & (1 << i)) | 933 | if (perm & (1 << i)) |
940 | count++; | 934 | count++; |
941 | } | 935 | } |
942 | if (count < tomoyo_profile(domain->profile)-> | 936 | if (count < tomoyo_profile(domain->ns, domain->profile)-> |
943 | pref[TOMOYO_PREF_MAX_LEARNING_ENTRY]) | 937 | pref[TOMOYO_PREF_MAX_LEARNING_ENTRY]) |
944 | return true; | 938 | return true; |
945 | if (!domain->quota_warned) { | 939 | if (!domain->quota_warned) { |