.. | .. |
---|
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 |
---|