.. | .. |
---|
91 | 91 | void tomoyo_convert_time(time64_t time64, struct tomoyo_time *stamp) |
---|
92 | 92 | { |
---|
93 | 93 | struct tm tm; |
---|
| 94 | + |
---|
94 | 95 | time64_to_tm(time64, 0, &tm); |
---|
95 | 96 | stamp->sec = tm.tm_sec; |
---|
96 | 97 | stamp->min = tm.tm_min; |
---|
.. | .. |
---|
106 | 107 | * @string: String representation for permissions in foo/bar/buz format. |
---|
107 | 108 | * @keyword: Keyword to find from @string/ |
---|
108 | 109 | * |
---|
109 | | - * Returns ture if @keyword was found in @string, false otherwise. |
---|
| 110 | + * Returns true if @keyword was found in @string, false otherwise. |
---|
110 | 111 | * |
---|
111 | 112 | * This function assumes that strncmp(w1, w2, strlen(w1)) != 0 if w1 != w2. |
---|
112 | 113 | */ |
---|
113 | 114 | bool tomoyo_permstr(const char *string, const char *keyword) |
---|
114 | 115 | { |
---|
115 | 116 | const char *cp = strstr(string, keyword); |
---|
| 117 | + |
---|
116 | 118 | if (cp) |
---|
117 | 119 | return cp == string || *(cp - 1) == '/'; |
---|
118 | 120 | return false; |
---|
.. | .. |
---|
132 | 134 | { |
---|
133 | 135 | char *pos = param->data; |
---|
134 | 136 | char *del = strchr(pos, ' '); |
---|
| 137 | + |
---|
135 | 138 | if (del) |
---|
136 | 139 | *del++ = '\0'; |
---|
137 | 140 | else |
---|
.. | .. |
---|
139 | 142 | param->data = del; |
---|
140 | 143 | return pos; |
---|
141 | 144 | } |
---|
| 145 | + |
---|
| 146 | +static bool tomoyo_correct_path2(const char *filename, const size_t len); |
---|
142 | 147 | |
---|
143 | 148 | /** |
---|
144 | 149 | * tomoyo_get_domainname - Read a domainname from a line. |
---|
.. | .. |
---|
152 | 157 | { |
---|
153 | 158 | char *start = param->data; |
---|
154 | 159 | char *pos = start; |
---|
| 160 | + |
---|
155 | 161 | while (*pos) { |
---|
156 | | - if (*pos++ != ' ' || *pos++ == '/') |
---|
| 162 | + if (*pos++ != ' ' || |
---|
| 163 | + tomoyo_correct_path2(pos, strchrnul(pos, ' ') - pos)) |
---|
157 | 164 | continue; |
---|
158 | | - pos -= 2; |
---|
159 | | - *pos++ = '\0'; |
---|
| 165 | + *(pos - 1) = '\0'; |
---|
160 | 166 | break; |
---|
161 | 167 | } |
---|
162 | 168 | param->data = pos; |
---|
.. | .. |
---|
181 | 187 | const char *cp = *str; |
---|
182 | 188 | char *ep; |
---|
183 | 189 | int base = 10; |
---|
| 190 | + |
---|
184 | 191 | if (*cp == '0') { |
---|
185 | 192 | char c = *(cp + 1); |
---|
| 193 | + |
---|
186 | 194 | if (c == 'x' || c == 'X') { |
---|
187 | 195 | base = 16; |
---|
188 | 196 | cp += 2; |
---|
.. | .. |
---|
240 | 248 | struct tomoyo_name_union *ptr) |
---|
241 | 249 | { |
---|
242 | 250 | char *filename; |
---|
| 251 | + |
---|
243 | 252 | if (param->data[0] == '@') { |
---|
244 | 253 | param->data++; |
---|
245 | 254 | ptr->group = tomoyo_get_group(param, TOMOYO_PATH_GROUP); |
---|
.. | .. |
---|
266 | 275 | char *data; |
---|
267 | 276 | u8 type; |
---|
268 | 277 | unsigned long v; |
---|
| 278 | + |
---|
269 | 279 | memset(ptr, 0, sizeof(*ptr)); |
---|
270 | 280 | if (param->data[0] == '@') { |
---|
271 | 281 | param->data++; |
---|
.. | .. |
---|
429 | 439 | unsigned char c; |
---|
430 | 440 | unsigned char d; |
---|
431 | 441 | unsigned char e; |
---|
| 442 | + |
---|
432 | 443 | if (!len) |
---|
433 | 444 | goto out; |
---|
434 | 445 | while (len--) { |
---|
.. | .. |
---|
505 | 516 | } |
---|
506 | 517 | |
---|
507 | 518 | /** |
---|
| 519 | + * tomoyo_correct_path2 - Check whether the given pathname follows the naming rules. |
---|
| 520 | + * |
---|
| 521 | + * @filename: The pathname to check. |
---|
| 522 | + * @len: Length of @filename. |
---|
| 523 | + * |
---|
| 524 | + * Returns true if @filename follows the naming rules, false otherwise. |
---|
| 525 | + */ |
---|
| 526 | +static bool tomoyo_correct_path2(const char *filename, const size_t len) |
---|
| 527 | +{ |
---|
| 528 | + const char *cp1 = memchr(filename, '/', len); |
---|
| 529 | + const char *cp2 = memchr(filename, '.', len); |
---|
| 530 | + |
---|
| 531 | + return cp1 && (!cp2 || (cp1 < cp2)) && tomoyo_correct_word2(filename, len); |
---|
| 532 | +} |
---|
| 533 | + |
---|
| 534 | +/** |
---|
508 | 535 | * tomoyo_correct_path - Validate a pathname. |
---|
509 | 536 | * |
---|
510 | 537 | * @filename: The pathname to check. |
---|
.. | .. |
---|
514 | 541 | */ |
---|
515 | 542 | bool tomoyo_correct_path(const char *filename) |
---|
516 | 543 | { |
---|
517 | | - return *filename == '/' && tomoyo_correct_word(filename); |
---|
| 544 | + return tomoyo_correct_path2(filename, strlen(filename)); |
---|
518 | 545 | } |
---|
519 | 546 | |
---|
520 | 547 | /** |
---|
.. | .. |
---|
533 | 560 | return true; |
---|
534 | 561 | while (1) { |
---|
535 | 562 | const unsigned char *cp = strchr(domainname, ' '); |
---|
| 563 | + |
---|
536 | 564 | if (!cp) |
---|
537 | 565 | break; |
---|
538 | | - if (*domainname != '/' || |
---|
539 | | - !tomoyo_correct_word2(domainname, cp - domainname)) |
---|
| 566 | + if (!tomoyo_correct_path2(domainname, cp - domainname)) |
---|
540 | 567 | return false; |
---|
541 | 568 | domainname = cp + 1; |
---|
542 | 569 | } |
---|
.. | .. |
---|
554 | 581 | { |
---|
555 | 582 | const unsigned char *cp; |
---|
556 | 583 | int len; |
---|
| 584 | + |
---|
557 | 585 | if (*buffer != '<') |
---|
558 | 586 | return false; |
---|
559 | 587 | cp = strchr(buffer, ' '); |
---|
.. | .. |
---|
583 | 611 | |
---|
584 | 612 | name.name = domainname; |
---|
585 | 613 | tomoyo_fill_path_info(&name); |
---|
586 | | - list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { |
---|
| 614 | + list_for_each_entry_rcu(domain, &tomoyo_domain_list, list, |
---|
| 615 | + srcu_read_lock_held(&tomoyo_ss)) { |
---|
587 | 616 | if (!domain->is_deleted && |
---|
588 | 617 | !tomoyo_pathcmp(&name, domain->domainname)) |
---|
589 | 618 | return domain; |
---|
.. | .. |
---|
668 | 697 | { |
---|
669 | 698 | while (filename < filename_end && pattern < pattern_end) { |
---|
670 | 699 | char c; |
---|
| 700 | + int i; |
---|
| 701 | + int j; |
---|
| 702 | + |
---|
671 | 703 | if (*pattern != '\\') { |
---|
672 | 704 | if (*filename++ != *pattern++) |
---|
673 | 705 | return false; |
---|
.. | .. |
---|
676 | 708 | c = *filename; |
---|
677 | 709 | pattern++; |
---|
678 | 710 | switch (*pattern) { |
---|
679 | | - int i; |
---|
680 | | - int j; |
---|
681 | 711 | case '?': |
---|
682 | 712 | if (c == '/') { |
---|
683 | 713 | return false; |
---|
.. | .. |
---|
985 | 1015 | struct tomoyo_domain_info *domain, const u8 index) |
---|
986 | 1016 | { |
---|
987 | 1017 | u8 profile; |
---|
| 1018 | + |
---|
988 | 1019 | memset(r, 0, sizeof(*r)); |
---|
989 | 1020 | if (!domain) |
---|
990 | 1021 | domain = tomoyo_domain(); |
---|
.. | .. |
---|
1015 | 1046 | return false; |
---|
1016 | 1047 | if (!domain) |
---|
1017 | 1048 | return true; |
---|
1018 | | - list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
---|
| 1049 | + if (READ_ONCE(domain->flags[TOMOYO_DIF_QUOTA_WARNED])) |
---|
| 1050 | + return false; |
---|
| 1051 | + list_for_each_entry_rcu(ptr, &domain->acl_info_list, list, |
---|
| 1052 | + srcu_read_lock_held(&tomoyo_ss)) { |
---|
1019 | 1053 | u16 perm; |
---|
1020 | | - u8 i; |
---|
| 1054 | + |
---|
1021 | 1055 | if (ptr->is_deleted) |
---|
1022 | 1056 | continue; |
---|
| 1057 | + /* |
---|
| 1058 | + * Reading perm bitmap might race with tomoyo_merge_*() because |
---|
| 1059 | + * caller does not hold tomoyo_policy_lock mutex. But exceeding |
---|
| 1060 | + * max_learning_entry parameter by a few entries does not harm. |
---|
| 1061 | + */ |
---|
1023 | 1062 | switch (ptr->type) { |
---|
1024 | 1063 | case TOMOYO_TYPE_PATH_ACL: |
---|
1025 | | - perm = container_of(ptr, struct tomoyo_path_acl, head) |
---|
1026 | | - ->perm; |
---|
| 1064 | + perm = data_race(container_of(ptr, struct tomoyo_path_acl, head)->perm); |
---|
1027 | 1065 | break; |
---|
1028 | 1066 | case TOMOYO_TYPE_PATH2_ACL: |
---|
1029 | | - perm = container_of(ptr, struct tomoyo_path2_acl, head) |
---|
1030 | | - ->perm; |
---|
| 1067 | + perm = data_race(container_of(ptr, struct tomoyo_path2_acl, head)->perm); |
---|
1031 | 1068 | break; |
---|
1032 | 1069 | case TOMOYO_TYPE_PATH_NUMBER_ACL: |
---|
1033 | | - perm = container_of(ptr, struct tomoyo_path_number_acl, |
---|
1034 | | - head)->perm; |
---|
| 1070 | + perm = data_race(container_of(ptr, struct tomoyo_path_number_acl, head) |
---|
| 1071 | + ->perm); |
---|
1035 | 1072 | break; |
---|
1036 | 1073 | case TOMOYO_TYPE_MKDEV_ACL: |
---|
1037 | | - perm = container_of(ptr, struct tomoyo_mkdev_acl, |
---|
1038 | | - head)->perm; |
---|
| 1074 | + perm = data_race(container_of(ptr, struct tomoyo_mkdev_acl, head)->perm); |
---|
1039 | 1075 | break; |
---|
1040 | 1076 | case TOMOYO_TYPE_INET_ACL: |
---|
1041 | | - perm = container_of(ptr, struct tomoyo_inet_acl, |
---|
1042 | | - head)->perm; |
---|
| 1077 | + perm = data_race(container_of(ptr, struct tomoyo_inet_acl, head)->perm); |
---|
1043 | 1078 | break; |
---|
1044 | 1079 | case TOMOYO_TYPE_UNIX_ACL: |
---|
1045 | | - perm = container_of(ptr, struct tomoyo_unix_acl, |
---|
1046 | | - head)->perm; |
---|
| 1080 | + perm = data_race(container_of(ptr, struct tomoyo_unix_acl, head)->perm); |
---|
1047 | 1081 | break; |
---|
1048 | 1082 | case TOMOYO_TYPE_MANUAL_TASK_ACL: |
---|
1049 | 1083 | perm = 0; |
---|
.. | .. |
---|
1051 | 1085 | default: |
---|
1052 | 1086 | perm = 1; |
---|
1053 | 1087 | } |
---|
1054 | | - for (i = 0; i < 16; i++) |
---|
1055 | | - if (perm & (1 << i)) |
---|
1056 | | - count++; |
---|
| 1088 | + count += hweight16(perm); |
---|
1057 | 1089 | } |
---|
1058 | 1090 | if (count < tomoyo_profile(domain->ns, domain->profile)-> |
---|
1059 | 1091 | pref[TOMOYO_PREF_MAX_LEARNING_ENTRY]) |
---|
1060 | 1092 | return true; |
---|
1061 | | - if (!domain->flags[TOMOYO_DIF_QUOTA_WARNED]) { |
---|
1062 | | - domain->flags[TOMOYO_DIF_QUOTA_WARNED] = true; |
---|
1063 | | - /* r->granted = false; */ |
---|
1064 | | - tomoyo_write_log(r, "%s", tomoyo_dif[TOMOYO_DIF_QUOTA_WARNED]); |
---|
1065 | | - printk(KERN_WARNING "WARNING: " |
---|
1066 | | - "Domain '%s' has too many ACLs to hold. " |
---|
1067 | | - "Stopped learning mode.\n", domain->domainname->name); |
---|
1068 | | - } |
---|
| 1093 | + WRITE_ONCE(domain->flags[TOMOYO_DIF_QUOTA_WARNED], true); |
---|
| 1094 | + /* r->granted = false; */ |
---|
| 1095 | + tomoyo_write_log(r, "%s", tomoyo_dif[TOMOYO_DIF_QUOTA_WARNED]); |
---|
| 1096 | +#ifndef CONFIG_SECURITY_TOMOYO_INSECURE_BUILTIN_SETTING |
---|
| 1097 | + pr_warn("WARNING: Domain '%s' has too many ACLs to hold. Stopped learning mode.\n", |
---|
| 1098 | + domain->domainname->name); |
---|
| 1099 | +#endif |
---|
1069 | 1100 | return false; |
---|
1070 | 1101 | } |
---|