| .. | .. |
|---|
| 30 | 30 | */ |
|---|
| 31 | 31 | int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size, |
|---|
| 32 | 32 | struct tomoyo_acl_param *param, |
|---|
| 33 | | - bool (*check_duplicate) (const struct tomoyo_acl_head |
|---|
| 34 | | - *, |
|---|
| 35 | | - const struct tomoyo_acl_head |
|---|
| 36 | | - *)) |
|---|
| 33 | + bool (*check_duplicate)(const struct tomoyo_acl_head |
|---|
| 34 | + *, |
|---|
| 35 | + const struct tomoyo_acl_head |
|---|
| 36 | + *)) |
|---|
| 37 | 37 | { |
|---|
| 38 | 38 | int error = param->is_delete ? -ENOENT : -ENOMEM; |
|---|
| 39 | 39 | struct tomoyo_acl_head *entry; |
|---|
| .. | .. |
|---|
| 41 | 41 | |
|---|
| 42 | 42 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
|---|
| 43 | 43 | return -ENOMEM; |
|---|
| 44 | | - list_for_each_entry_rcu(entry, list, list) { |
|---|
| 44 | + list_for_each_entry_rcu(entry, list, list, |
|---|
| 45 | + srcu_read_lock_held(&tomoyo_ss)) { |
|---|
| 45 | 46 | if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS) |
|---|
| 46 | 47 | continue; |
|---|
| 47 | 48 | if (!check_duplicate(entry, new_entry)) |
|---|
| .. | .. |
|---|
| 90 | 91 | */ |
|---|
| 91 | 92 | int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, |
|---|
| 92 | 93 | struct tomoyo_acl_param *param, |
|---|
| 93 | | - bool (*check_duplicate) (const struct tomoyo_acl_info |
|---|
| 94 | | - *, |
|---|
| 95 | | - const struct tomoyo_acl_info |
|---|
| 96 | | - *), |
|---|
| 97 | | - bool (*merge_duplicate) (struct tomoyo_acl_info *, |
|---|
| 98 | | - struct tomoyo_acl_info *, |
|---|
| 99 | | - const bool)) |
|---|
| 94 | + bool (*check_duplicate)(const struct tomoyo_acl_info |
|---|
| 95 | + *, |
|---|
| 96 | + const struct tomoyo_acl_info |
|---|
| 97 | + *), |
|---|
| 98 | + bool (*merge_duplicate)(struct tomoyo_acl_info *, |
|---|
| 99 | + struct tomoyo_acl_info *, |
|---|
| 100 | + const bool)) |
|---|
| 100 | 101 | { |
|---|
| 101 | 102 | const bool is_delete = param->is_delete; |
|---|
| 102 | 103 | int error = is_delete ? -ENOENT : -ENOMEM; |
|---|
| .. | .. |
|---|
| 119 | 120 | } |
|---|
| 120 | 121 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
|---|
| 121 | 122 | goto out; |
|---|
| 122 | | - list_for_each_entry_rcu(entry, list, list) { |
|---|
| 123 | + list_for_each_entry_rcu(entry, list, list, |
|---|
| 124 | + srcu_read_lock_held(&tomoyo_ss)) { |
|---|
| 123 | 125 | if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS) |
|---|
| 124 | 126 | continue; |
|---|
| 125 | 127 | if (!tomoyo_same_acl_head(entry, new_entry) || |
|---|
| .. | .. |
|---|
| 157 | 159 | * Caller holds tomoyo_read_lock(). |
|---|
| 158 | 160 | */ |
|---|
| 159 | 161 | void tomoyo_check_acl(struct tomoyo_request_info *r, |
|---|
| 160 | | - bool (*check_entry) (struct tomoyo_request_info *, |
|---|
| 161 | | - const struct tomoyo_acl_info *)) |
|---|
| 162 | + bool (*check_entry)(struct tomoyo_request_info *, |
|---|
| 163 | + const struct tomoyo_acl_info *)) |
|---|
| 162 | 164 | { |
|---|
| 163 | 165 | const struct tomoyo_domain_info *domain = r->domain; |
|---|
| 164 | 166 | struct tomoyo_acl_info *ptr; |
|---|
| 165 | | - bool retried = false; |
|---|
| 166 | 167 | const struct list_head *list = &domain->acl_info_list; |
|---|
| 168 | + u16 i = 0; |
|---|
| 167 | 169 | |
|---|
| 168 | 170 | retry: |
|---|
| 169 | | - list_for_each_entry_rcu(ptr, list, list) { |
|---|
| 171 | + list_for_each_entry_rcu(ptr, list, list, |
|---|
| 172 | + srcu_read_lock_held(&tomoyo_ss)) { |
|---|
| 170 | 173 | if (ptr->is_deleted || ptr->type != r->param_type) |
|---|
| 171 | 174 | continue; |
|---|
| 172 | 175 | if (!check_entry(r, ptr)) |
|---|
| .. | .. |
|---|
| 177 | 180 | r->granted = true; |
|---|
| 178 | 181 | return; |
|---|
| 179 | 182 | } |
|---|
| 180 | | - if (!retried) { |
|---|
| 181 | | - retried = true; |
|---|
| 182 | | - list = &domain->ns->acl_group[domain->group]; |
|---|
| 183 | + for (; i < TOMOYO_MAX_ACL_GROUPS; i++) { |
|---|
| 184 | + if (!test_bit(i, domain->group)) |
|---|
| 185 | + continue; |
|---|
| 186 | + list = &domain->ns->acl_group[i++]; |
|---|
| 183 | 187 | goto retry; |
|---|
| 184 | 188 | } |
|---|
| 185 | 189 | r->granted = false; |
|---|
| .. | .. |
|---|
| 198 | 202 | static const char *tomoyo_last_word(const char *name) |
|---|
| 199 | 203 | { |
|---|
| 200 | 204 | const char *cp = strrchr(name, ' '); |
|---|
| 205 | + |
|---|
| 201 | 206 | if (cp) |
|---|
| 202 | 207 | return cp + 1; |
|---|
| 203 | 208 | return name; |
|---|
| .. | .. |
|---|
| 220 | 225 | const struct tomoyo_transition_control *p2 = container_of(b, |
|---|
| 221 | 226 | typeof(*p2), |
|---|
| 222 | 227 | head); |
|---|
| 228 | + |
|---|
| 223 | 229 | return p1->type == p2->type && p1->is_last_name == p2->is_last_name |
|---|
| 224 | 230 | && p1->domainname == p2->domainname |
|---|
| 225 | 231 | && p1->program == p2->program; |
|---|
| .. | .. |
|---|
| 240 | 246 | int error = param->is_delete ? -ENOENT : -ENOMEM; |
|---|
| 241 | 247 | char *program = param->data; |
|---|
| 242 | 248 | char *domainname = strstr(program, " from "); |
|---|
| 249 | + |
|---|
| 243 | 250 | if (domainname) { |
|---|
| 244 | 251 | *domainname = '\0'; |
|---|
| 245 | 252 | domainname += 6; |
|---|
| .. | .. |
|---|
| 293 | 300 | const enum tomoyo_transition_type type) |
|---|
| 294 | 301 | { |
|---|
| 295 | 302 | const struct tomoyo_transition_control *ptr; |
|---|
| 296 | | - list_for_each_entry_rcu(ptr, list, head.list) { |
|---|
| 303 | + |
|---|
| 304 | + list_for_each_entry_rcu(ptr, list, head.list, |
|---|
| 305 | + srcu_read_lock_held(&tomoyo_ss)) { |
|---|
| 297 | 306 | if (ptr->head.is_deleted || ptr->type != type) |
|---|
| 298 | 307 | continue; |
|---|
| 299 | 308 | if (ptr->domainname) { |
|---|
| .. | .. |
|---|
| 338 | 347 | { |
|---|
| 339 | 348 | const char *last_name = tomoyo_last_word(domainname->name); |
|---|
| 340 | 349 | enum tomoyo_transition_type type = TOMOYO_TRANSITION_CONTROL_NO_RESET; |
|---|
| 350 | + |
|---|
| 341 | 351 | while (type < TOMOYO_MAX_TRANSITION_TYPE) { |
|---|
| 342 | 352 | const struct list_head * const list = |
|---|
| 343 | 353 | &ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL]; |
|---|
| 354 | + |
|---|
| 344 | 355 | if (!tomoyo_scan_transition(list, domainname, program, |
|---|
| 345 | 356 | last_name, type)) { |
|---|
| 346 | 357 | type++; |
|---|
| .. | .. |
|---|
| 375 | 386 | head); |
|---|
| 376 | 387 | const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2), |
|---|
| 377 | 388 | head); |
|---|
| 389 | + |
|---|
| 378 | 390 | return p1->original_name == p2->original_name && |
|---|
| 379 | 391 | p1->aggregated_name == p2->aggregated_name; |
|---|
| 380 | 392 | } |
|---|
| .. | .. |
|---|
| 394 | 406 | int error = param->is_delete ? -ENOENT : -ENOMEM; |
|---|
| 395 | 407 | const char *original_name = tomoyo_read_token(param); |
|---|
| 396 | 408 | const char *aggregated_name = tomoyo_read_token(param); |
|---|
| 409 | + |
|---|
| 397 | 410 | if (!tomoyo_correct_word(original_name) || |
|---|
| 398 | 411 | !tomoyo_correct_path(aggregated_name)) |
|---|
| 399 | 412 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 426 | 439 | (const char *name, const unsigned int len) |
|---|
| 427 | 440 | { |
|---|
| 428 | 441 | struct tomoyo_policy_namespace *ns; |
|---|
| 442 | + |
|---|
| 429 | 443 | list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) { |
|---|
| 430 | 444 | if (strncmp(name, ns->name, len) || |
|---|
| 431 | 445 | (name[len] && name[len] != ' ')) |
|---|
| .. | .. |
|---|
| 451 | 465 | struct tomoyo_policy_namespace *entry; |
|---|
| 452 | 466 | const char *cp = domainname; |
|---|
| 453 | 467 | unsigned int len = 0; |
|---|
| 468 | + |
|---|
| 454 | 469 | while (*cp && *cp++ != ' ') |
|---|
| 455 | 470 | len++; |
|---|
| 456 | 471 | ptr = tomoyo_find_namespace(domainname, len); |
|---|
| .. | .. |
|---|
| 466 | 481 | ptr = tomoyo_find_namespace(domainname, len); |
|---|
| 467 | 482 | if (!ptr && tomoyo_memory_ok(entry)) { |
|---|
| 468 | 483 | char *name = (char *) (entry + 1); |
|---|
| 484 | + |
|---|
| 469 | 485 | ptr = entry; |
|---|
| 470 | 486 | memmove(name, domainname, len); |
|---|
| 471 | 487 | name[len] = '\0'; |
|---|
| .. | .. |
|---|
| 490 | 506 | { |
|---|
| 491 | 507 | const char *namespace = tomoyo_current_namespace()->name; |
|---|
| 492 | 508 | const int len = strlen(namespace); |
|---|
| 509 | + |
|---|
| 493 | 510 | return strncmp(domainname, namespace, len) || |
|---|
| 494 | 511 | (domainname[len] && domainname[len] != ' '); |
|---|
| 495 | 512 | } |
|---|
| .. | .. |
|---|
| 510 | 527 | struct tomoyo_domain_info e = { }; |
|---|
| 511 | 528 | struct tomoyo_domain_info *entry = tomoyo_find_domain(domainname); |
|---|
| 512 | 529 | bool created = false; |
|---|
| 530 | + |
|---|
| 513 | 531 | if (entry) { |
|---|
| 514 | 532 | if (transit) { |
|---|
| 515 | 533 | /* |
|---|
| .. | .. |
|---|
| 546 | 564 | */ |
|---|
| 547 | 565 | if (transit) { |
|---|
| 548 | 566 | const struct tomoyo_domain_info *domain = tomoyo_domain(); |
|---|
| 567 | + |
|---|
| 549 | 568 | e.profile = domain->profile; |
|---|
| 550 | | - e.group = domain->group; |
|---|
| 569 | + memcpy(e.group, domain->group, sizeof(e.group)); |
|---|
| 551 | 570 | } |
|---|
| 552 | 571 | e.domainname = tomoyo_get_name(domainname); |
|---|
| 553 | 572 | if (!e.domainname) |
|---|
| .. | .. |
|---|
| 569 | 588 | if (entry && transit) { |
|---|
| 570 | 589 | if (created) { |
|---|
| 571 | 590 | struct tomoyo_request_info r; |
|---|
| 591 | + int i; |
|---|
| 592 | + |
|---|
| 572 | 593 | tomoyo_init_request_info(&r, entry, |
|---|
| 573 | 594 | TOMOYO_MAC_FILE_EXECUTE); |
|---|
| 574 | 595 | r.granted = false; |
|---|
| 575 | 596 | tomoyo_write_log(&r, "use_profile %u\n", |
|---|
| 576 | 597 | entry->profile); |
|---|
| 577 | | - tomoyo_write_log(&r, "use_group %u\n", entry->group); |
|---|
| 598 | + for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++) |
|---|
| 599 | + if (test_bit(i, entry->group)) |
|---|
| 600 | + tomoyo_write_log(&r, "use_group %u\n", |
|---|
| 601 | + i); |
|---|
| 578 | 602 | tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES); |
|---|
| 579 | 603 | } |
|---|
| 580 | 604 | } |
|---|
| .. | .. |
|---|
| 712 | 736 | struct tomoyo_aggregator *ptr; |
|---|
| 713 | 737 | struct list_head *list = |
|---|
| 714 | 738 | &old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR]; |
|---|
| 739 | + |
|---|
| 715 | 740 | /* Check 'aggregator' directive. */ |
|---|
| 716 | 741 | candidate = &exename; |
|---|
| 717 | | - list_for_each_entry_rcu(ptr, list, head.list) { |
|---|
| 742 | + list_for_each_entry_rcu(ptr, list, head.list, |
|---|
| 743 | + srcu_read_lock_held(&tomoyo_ss)) { |
|---|
| 718 | 744 | if (ptr->head.is_deleted || |
|---|
| 719 | 745 | !tomoyo_path_matches_pattern(&exename, |
|---|
| 720 | 746 | ptr->original_name)) |
|---|
| .. | .. |
|---|
| 741 | 767 | |
|---|
| 742 | 768 | /* |
|---|
| 743 | 769 | * Check for domain transition preference if "file execute" matched. |
|---|
| 744 | | - * If preference is given, make do_execve() fail if domain transition |
|---|
| 770 | + * If preference is given, make execve() fail if domain transition |
|---|
| 745 | 771 | * has failed, for domain transition preference should be used with |
|---|
| 746 | 772 | * destination domain defined. |
|---|
| 747 | 773 | */ |
|---|
| 748 | 774 | if (ee->transition) { |
|---|
| 749 | 775 | const char *domainname = ee->transition->name; |
|---|
| 776 | + |
|---|
| 750 | 777 | reject_on_transition_failure = true; |
|---|
| 751 | 778 | if (!strcmp(domainname, "keep")) |
|---|
| 752 | 779 | goto force_keep_domain; |
|---|
| .. | .. |
|---|
| 758 | 785 | goto force_initialize_domain; |
|---|
| 759 | 786 | if (!strcmp(domainname, "parent")) { |
|---|
| 760 | 787 | char *cp; |
|---|
| 788 | + |
|---|
| 761 | 789 | strncpy(ee->tmp, old_domain->domainname->name, |
|---|
| 762 | 790 | TOMOYO_EXEC_TMPSIZE - 1); |
|---|
| 763 | 791 | cp = strrchr(ee->tmp, ' '); |
|---|
| .. | .. |
|---|
| 782 | 810 | snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", |
|---|
| 783 | 811 | candidate->name); |
|---|
| 784 | 812 | /* |
|---|
| 785 | | - * Make do_execve() fail if domain transition across namespaces |
|---|
| 813 | + * Make execve() fail if domain transition across namespaces |
|---|
| 786 | 814 | * has failed. |
|---|
| 787 | 815 | */ |
|---|
| 788 | 816 | reject_on_transition_failure = true; |
|---|
| .. | .. |
|---|
| 822 | 850 | if (domain) |
|---|
| 823 | 851 | retval = 0; |
|---|
| 824 | 852 | else if (reject_on_transition_failure) { |
|---|
| 825 | | - printk(KERN_WARNING "ERROR: Domain '%s' not ready.\n", |
|---|
| 826 | | - ee->tmp); |
|---|
| 853 | + pr_warn("ERROR: Domain '%s' not ready.\n", ee->tmp); |
|---|
| 827 | 854 | retval = -ENOMEM; |
|---|
| 828 | 855 | } else if (ee->r.mode == TOMOYO_CONFIG_ENFORCING) |
|---|
| 829 | 856 | retval = -ENOMEM; |
|---|
| .. | .. |
|---|
| 834 | 861 | ee->r.granted = false; |
|---|
| 835 | 862 | tomoyo_write_log(&ee->r, "%s", tomoyo_dif |
|---|
| 836 | 863 | [TOMOYO_DIF_TRANSITION_FAILED]); |
|---|
| 837 | | - printk(KERN_WARNING |
|---|
| 838 | | - "ERROR: Domain '%s' not defined.\n", ee->tmp); |
|---|
| 864 | + pr_warn("ERROR: Domain '%s' not defined.\n", ee->tmp); |
|---|
| 839 | 865 | } |
|---|
| 840 | 866 | } |
|---|
| 841 | 867 | out: |
|---|
| 842 | 868 | if (!domain) |
|---|
| 843 | 869 | domain = old_domain; |
|---|
| 844 | 870 | /* Update reference count on "struct tomoyo_domain_info". */ |
|---|
| 845 | | - atomic_inc(&domain->users); |
|---|
| 846 | | - bprm->cred->security = domain; |
|---|
| 871 | + { |
|---|
| 872 | + struct tomoyo_task *s = tomoyo_task(current); |
|---|
| 873 | + |
|---|
| 874 | + s->old_domain_info = s->domain_info; |
|---|
| 875 | + s->domain_info = domain; |
|---|
| 876 | + atomic_inc(&domain->users); |
|---|
| 877 | + } |
|---|
| 847 | 878 | kfree(exename.name); |
|---|
| 848 | 879 | if (!retval) { |
|---|
| 849 | 880 | ee->r.domain = domain; |
|---|
| .. | .. |
|---|
| 883 | 914 | * (represented by bprm). 'current' is the process doing |
|---|
| 884 | 915 | * the execve(). |
|---|
| 885 | 916 | */ |
|---|
| 886 | | - if (get_user_pages_remote(current, bprm->mm, pos, 1, |
|---|
| 917 | + if (get_user_pages_remote(bprm->mm, pos, 1, |
|---|
| 887 | 918 | FOLL_FORCE, &page, NULL, NULL) <= 0) |
|---|
| 888 | 919 | return false; |
|---|
| 889 | 920 | #else |
|---|