diff options
Diffstat (limited to 'security/tomoyo')
-rw-r--r-- | security/tomoyo/common.c | 230 | ||||
-rw-r--r-- | security/tomoyo/common.h | 6 | ||||
-rw-r--r-- | security/tomoyo/domain.c | 42 | ||||
-rw-r--r-- | security/tomoyo/file.c | 21 | ||||
-rw-r--r-- | security/tomoyo/realpath.c | 22 | ||||
-rw-r--r-- | security/tomoyo/tomoyo.c | 107 | ||||
-rw-r--r-- | security/tomoyo/tomoyo.h | 5 |
7 files changed, 194 insertions, 239 deletions
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index fdd1f4b8c448..e0d0354008b7 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -187,6 +187,8 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type, | |||
187 | const s8 pattern_type, const s8 end_type, | 187 | const s8 pattern_type, const s8 end_type, |
188 | const char *function) | 188 | const char *function) |
189 | { | 189 | { |
190 | const char *const start = filename; | ||
191 | bool in_repetition = false; | ||
190 | bool contains_pattern = false; | 192 | bool contains_pattern = false; |
191 | unsigned char c; | 193 | unsigned char c; |
192 | unsigned char d; | 194 | unsigned char d; |
@@ -212,9 +214,13 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type, | |||
212 | if (c == '/') | 214 | if (c == '/') |
213 | goto out; | 215 | goto out; |
214 | } | 216 | } |
215 | while ((c = *filename++) != '\0') { | 217 | while (1) { |
218 | c = *filename++; | ||
219 | if (!c) | ||
220 | break; | ||
216 | if (c == '\\') { | 221 | if (c == '\\') { |
217 | switch ((c = *filename++)) { | 222 | c = *filename++; |
223 | switch (c) { | ||
218 | case '\\': /* "\\" */ | 224 | case '\\': /* "\\" */ |
219 | continue; | 225 | continue; |
220 | case '$': /* "\$" */ | 226 | case '$': /* "\$" */ |
@@ -231,6 +237,22 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type, | |||
231 | break; /* Must not contain pattern */ | 237 | break; /* Must not contain pattern */ |
232 | contains_pattern = true; | 238 | contains_pattern = true; |
233 | continue; | 239 | continue; |
240 | case '{': /* "/\{" */ | ||
241 | if (filename - 3 < start || | ||
242 | *(filename - 3) != '/') | ||
243 | break; | ||
244 | if (pattern_type == -1) | ||
245 | break; /* Must not contain pattern */ | ||
246 | contains_pattern = true; | ||
247 | in_repetition = true; | ||
248 | continue; | ||
249 | case '}': /* "\}/" */ | ||
250 | if (*filename != '/') | ||
251 | break; | ||
252 | if (!in_repetition) | ||
253 | break; | ||
254 | in_repetition = false; | ||
255 | continue; | ||
234 | case '0': /* "\ooo" */ | 256 | case '0': /* "\ooo" */ |
235 | case '1': | 257 | case '1': |
236 | case '2': | 258 | case '2': |
@@ -246,6 +268,8 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type, | |||
246 | continue; /* pattern is not \000 */ | 268 | continue; /* pattern is not \000 */ |
247 | } | 269 | } |
248 | goto out; | 270 | goto out; |
271 | } else if (in_repetition && c == '/') { | ||
272 | goto out; | ||
249 | } else if (tomoyo_is_invalid(c)) { | 273 | } else if (tomoyo_is_invalid(c)) { |
250 | goto out; | 274 | goto out; |
251 | } | 275 | } |
@@ -254,6 +278,8 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type, | |||
254 | if (!contains_pattern) | 278 | if (!contains_pattern) |
255 | goto out; | 279 | goto out; |
256 | } | 280 | } |
281 | if (in_repetition) | ||
282 | goto out; | ||
257 | return true; | 283 | return true; |
258 | out: | 284 | out: |
259 | printk(KERN_DEBUG "%s: Invalid pathname '%s'\n", function, | 285 | printk(KERN_DEBUG "%s: Invalid pathname '%s'\n", function, |
@@ -360,33 +386,6 @@ struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname) | |||
360 | } | 386 | } |
361 | 387 | ||
362 | /** | 388 | /** |
363 | * tomoyo_path_depth - Evaluate the number of '/' in a string. | ||
364 | * | ||
365 | * @pathname: The string to evaluate. | ||
366 | * | ||
367 | * Returns path depth of the string. | ||
368 | * | ||
369 | * I score 2 for each of the '/' in the @pathname | ||
370 | * and score 1 if the @pathname ends with '/'. | ||
371 | */ | ||
372 | static int tomoyo_path_depth(const char *pathname) | ||
373 | { | ||
374 | int i = 0; | ||
375 | |||
376 | if (pathname) { | ||
377 | const char *ep = pathname + strlen(pathname); | ||
378 | if (pathname < ep--) { | ||
379 | if (*ep != '/') | ||
380 | i++; | ||
381 | while (pathname <= ep) | ||
382 | if (*ep-- == '/') | ||
383 | i += 2; | ||
384 | } | ||
385 | } | ||
386 | return i; | ||
387 | } | ||
388 | |||
389 | /** | ||
390 | * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token. | 389 | * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token. |
391 | * | 390 | * |
392 | * @filename: The string to evaluate. | 391 | * @filename: The string to evaluate. |
@@ -444,11 +443,10 @@ void tomoyo_fill_path_info(struct tomoyo_path_info *ptr) | |||
444 | ptr->is_dir = len && (name[len - 1] == '/'); | 443 | ptr->is_dir = len && (name[len - 1] == '/'); |
445 | ptr->is_patterned = (ptr->const_len < len); | 444 | ptr->is_patterned = (ptr->const_len < len); |
446 | ptr->hash = full_name_hash(name, len); | 445 | ptr->hash = full_name_hash(name, len); |
447 | ptr->depth = tomoyo_path_depth(name); | ||
448 | } | 446 | } |
449 | 447 | ||
450 | /** | 448 | /** |
451 | * tomoyo_file_matches_to_pattern2 - Pattern matching without '/' character | 449 | * tomoyo_file_matches_pattern2 - Pattern matching without '/' character |
452 | * and "\-" pattern. | 450 | * and "\-" pattern. |
453 | * | 451 | * |
454 | * @filename: The start of string to check. | 452 | * @filename: The start of string to check. |
@@ -458,10 +456,10 @@ void tomoyo_fill_path_info(struct tomoyo_path_info *ptr) | |||
458 | * | 456 | * |
459 | * Returns true if @filename matches @pattern, false otherwise. | 457 | * Returns true if @filename matches @pattern, false otherwise. |
460 | */ | 458 | */ |
461 | static bool tomoyo_file_matches_to_pattern2(const char *filename, | 459 | static bool tomoyo_file_matches_pattern2(const char *filename, |
462 | const char *filename_end, | 460 | const char *filename_end, |
463 | const char *pattern, | 461 | const char *pattern, |
464 | const char *pattern_end) | 462 | const char *pattern_end) |
465 | { | 463 | { |
466 | while (filename < filename_end && pattern < pattern_end) { | 464 | while (filename < filename_end && pattern < pattern_end) { |
467 | char c; | 465 | char c; |
@@ -519,7 +517,7 @@ static bool tomoyo_file_matches_to_pattern2(const char *filename, | |||
519 | case '*': | 517 | case '*': |
520 | case '@': | 518 | case '@': |
521 | for (i = 0; i <= filename_end - filename; i++) { | 519 | for (i = 0; i <= filename_end - filename; i++) { |
522 | if (tomoyo_file_matches_to_pattern2( | 520 | if (tomoyo_file_matches_pattern2( |
523 | filename + i, filename_end, | 521 | filename + i, filename_end, |
524 | pattern + 1, pattern_end)) | 522 | pattern + 1, pattern_end)) |
525 | return true; | 523 | return true; |
@@ -550,7 +548,7 @@ static bool tomoyo_file_matches_to_pattern2(const char *filename, | |||
550 | j++; | 548 | j++; |
551 | } | 549 | } |
552 | for (i = 1; i <= j; i++) { | 550 | for (i = 1; i <= j; i++) { |
553 | if (tomoyo_file_matches_to_pattern2( | 551 | if (tomoyo_file_matches_pattern2( |
554 | filename + i, filename_end, | 552 | filename + i, filename_end, |
555 | pattern + 1, pattern_end)) | 553 | pattern + 1, pattern_end)) |
556 | return true; | 554 | return true; |
@@ -567,7 +565,7 @@ static bool tomoyo_file_matches_to_pattern2(const char *filename, | |||
567 | } | 565 | } |
568 | 566 | ||
569 | /** | 567 | /** |
570 | * tomoyo_file_matches_to_pattern - Pattern matching without without '/' character. | 568 | * tomoyo_file_matches_pattern - Pattern matching without without '/' character. |
571 | * | 569 | * |
572 | * @filename: The start of string to check. | 570 | * @filename: The start of string to check. |
573 | * @filename_end: The end of string to check. | 571 | * @filename_end: The end of string to check. |
@@ -576,7 +574,7 @@ static bool tomoyo_file_matches_to_pattern2(const char *filename, | |||
576 | * | 574 | * |
577 | * Returns true if @filename matches @pattern, false otherwise. | 575 | * Returns true if @filename matches @pattern, false otherwise. |
578 | */ | 576 | */ |
579 | static bool tomoyo_file_matches_to_pattern(const char *filename, | 577 | static bool tomoyo_file_matches_pattern(const char *filename, |
580 | const char *filename_end, | 578 | const char *filename_end, |
581 | const char *pattern, | 579 | const char *pattern, |
582 | const char *pattern_end) | 580 | const char *pattern_end) |
@@ -589,10 +587,10 @@ static bool tomoyo_file_matches_to_pattern(const char *filename, | |||
589 | /* Split at "\-" pattern. */ | 587 | /* Split at "\-" pattern. */ |
590 | if (*pattern++ != '\\' || *pattern++ != '-') | 588 | if (*pattern++ != '\\' || *pattern++ != '-') |
591 | continue; | 589 | continue; |
592 | result = tomoyo_file_matches_to_pattern2(filename, | 590 | result = tomoyo_file_matches_pattern2(filename, |
593 | filename_end, | 591 | filename_end, |
594 | pattern_start, | 592 | pattern_start, |
595 | pattern - 2); | 593 | pattern - 2); |
596 | if (first) | 594 | if (first) |
597 | result = !result; | 595 | result = !result; |
598 | if (result) | 596 | if (result) |
@@ -600,13 +598,79 @@ static bool tomoyo_file_matches_to_pattern(const char *filename, | |||
600 | first = false; | 598 | first = false; |
601 | pattern_start = pattern; | 599 | pattern_start = pattern; |
602 | } | 600 | } |
603 | result = tomoyo_file_matches_to_pattern2(filename, filename_end, | 601 | result = tomoyo_file_matches_pattern2(filename, filename_end, |
604 | pattern_start, pattern_end); | 602 | pattern_start, pattern_end); |
605 | return first ? result : !result; | 603 | return first ? result : !result; |
606 | } | 604 | } |
607 | 605 | ||
608 | /** | 606 | /** |
607 | * tomoyo_path_matches_pattern2 - Do pathname pattern matching. | ||
608 | * | ||
609 | * @f: The start of string to check. | ||
610 | * @p: The start of pattern to compare. | ||
611 | * | ||
612 | * Returns true if @f matches @p, false otherwise. | ||
613 | */ | ||
614 | static bool tomoyo_path_matches_pattern2(const char *f, const char *p) | ||
615 | { | ||
616 | const char *f_delimiter; | ||
617 | const char *p_delimiter; | ||
618 | |||
619 | while (*f && *p) { | ||
620 | f_delimiter = strchr(f, '/'); | ||
621 | if (!f_delimiter) | ||
622 | f_delimiter = f + strlen(f); | ||
623 | p_delimiter = strchr(p, '/'); | ||
624 | if (!p_delimiter) | ||
625 | p_delimiter = p + strlen(p); | ||
626 | if (*p == '\\' && *(p + 1) == '{') | ||
627 | goto recursive; | ||
628 | if (!tomoyo_file_matches_pattern(f, f_delimiter, p, | ||
629 | p_delimiter)) | ||
630 | return false; | ||
631 | f = f_delimiter; | ||
632 | if (*f) | ||
633 | f++; | ||
634 | p = p_delimiter; | ||
635 | if (*p) | ||
636 | p++; | ||
637 | } | ||
638 | /* Ignore trailing "\*" and "\@" in @pattern. */ | ||
639 | while (*p == '\\' && | ||
640 | (*(p + 1) == '*' || *(p + 1) == '@')) | ||
641 | p += 2; | ||
642 | return !*f && !*p; | ||
643 | recursive: | ||
644 | /* | ||
645 | * The "\{" pattern is permitted only after '/' character. | ||
646 | * This guarantees that below "*(p - 1)" is safe. | ||
647 | * Also, the "\}" pattern is permitted only before '/' character | ||
648 | * so that "\{" + "\}" pair will not break the "\-" operator. | ||
649 | */ | ||
650 | if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' || | ||
651 | *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\') | ||
652 | return false; /* Bad pattern. */ | ||
653 | do { | ||
654 | /* Compare current component with pattern. */ | ||
655 | if (!tomoyo_file_matches_pattern(f, f_delimiter, p + 2, | ||
656 | p_delimiter - 2)) | ||
657 | break; | ||
658 | /* Proceed to next component. */ | ||
659 | f = f_delimiter; | ||
660 | if (!*f) | ||
661 | break; | ||
662 | f++; | ||
663 | /* Continue comparison. */ | ||
664 | if (tomoyo_path_matches_pattern2(f, p_delimiter + 1)) | ||
665 | return true; | ||
666 | f_delimiter = strchr(f, '/'); | ||
667 | } while (f_delimiter); | ||
668 | return false; /* Not matched. */ | ||
669 | } | ||
670 | |||
671 | /** | ||
609 | * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern. | 672 | * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern. |
673 | * | ||
610 | * @filename: The filename to check. | 674 | * @filename: The filename to check. |
611 | * @pattern: The pattern to compare. | 675 | * @pattern: The pattern to compare. |
612 | * | 676 | * |
@@ -615,24 +679,24 @@ static bool tomoyo_file_matches_to_pattern(const char *filename, | |||
615 | * The following patterns are available. | 679 | * The following patterns are available. |
616 | * \\ \ itself. | 680 | * \\ \ itself. |
617 | * \ooo Octal representation of a byte. | 681 | * \ooo Octal representation of a byte. |
618 | * \* More than or equals to 0 character other than '/'. | 682 | * \* Zero or more repetitions of characters other than '/'. |
619 | * \@ More than or equals to 0 character other than '/' or '.'. | 683 | * \@ Zero or more repetitions of characters other than '/' or '.'. |
620 | * \? 1 byte character other than '/'. | 684 | * \? 1 byte character other than '/'. |
621 | * \$ More than or equals to 1 decimal digit. | 685 | * \$ One or more repetitions of decimal digits. |
622 | * \+ 1 decimal digit. | 686 | * \+ 1 decimal digit. |
623 | * \X More than or equals to 1 hexadecimal digit. | 687 | * \X One or more repetitions of hexadecimal digits. |
624 | * \x 1 hexadecimal digit. | 688 | * \x 1 hexadecimal digit. |
625 | * \A More than or equals to 1 alphabet character. | 689 | * \A One or more repetitions of alphabet characters. |
626 | * \a 1 alphabet character. | 690 | * \a 1 alphabet character. |
691 | * | ||
627 | * \- Subtraction operator. | 692 | * \- Subtraction operator. |
693 | * | ||
694 | * /\{dir\}/ '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/ | ||
695 | * /dir/dir/dir/ ). | ||
628 | */ | 696 | */ |
629 | bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, | 697 | bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, |
630 | const struct tomoyo_path_info *pattern) | 698 | const struct tomoyo_path_info *pattern) |
631 | { | 699 | { |
632 | /* | ||
633 | if (!filename || !pattern) | ||
634 | return false; | ||
635 | */ | ||
636 | const char *f = filename->name; | 700 | const char *f = filename->name; |
637 | const char *p = pattern->name; | 701 | const char *p = pattern->name; |
638 | const int len = pattern->const_len; | 702 | const int len = pattern->const_len; |
@@ -640,37 +704,15 @@ bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, | |||
640 | /* If @pattern doesn't contain pattern, I can use strcmp(). */ | 704 | /* If @pattern doesn't contain pattern, I can use strcmp(). */ |
641 | if (!pattern->is_patterned) | 705 | if (!pattern->is_patterned) |
642 | return !tomoyo_pathcmp(filename, pattern); | 706 | return !tomoyo_pathcmp(filename, pattern); |
643 | /* Dont compare if the number of '/' differs. */ | 707 | /* Don't compare directory and non-directory. */ |
644 | if (filename->depth != pattern->depth) | 708 | if (filename->is_dir != pattern->is_dir) |
645 | return false; | 709 | return false; |
646 | /* Compare the initial length without patterns. */ | 710 | /* Compare the initial length without patterns. */ |
647 | if (strncmp(f, p, len)) | 711 | if (strncmp(f, p, len)) |
648 | return false; | 712 | return false; |
649 | f += len; | 713 | f += len; |
650 | p += len; | 714 | p += len; |
651 | /* Main loop. Compare each directory component. */ | 715 | return tomoyo_path_matches_pattern2(f, p); |
652 | while (*f && *p) { | ||
653 | const char *f_delimiter = strchr(f, '/'); | ||
654 | const char *p_delimiter = strchr(p, '/'); | ||
655 | if (!f_delimiter) | ||
656 | f_delimiter = f + strlen(f); | ||
657 | if (!p_delimiter) | ||
658 | p_delimiter = p + strlen(p); | ||
659 | if (!tomoyo_file_matches_to_pattern(f, f_delimiter, | ||
660 | p, p_delimiter)) | ||
661 | return false; | ||
662 | f = f_delimiter; | ||
663 | if (*f) | ||
664 | f++; | ||
665 | p = p_delimiter; | ||
666 | if (*p) | ||
667 | p++; | ||
668 | } | ||
669 | /* Ignore trailing "\*" and "\@" in @pattern. */ | ||
670 | while (*p == '\\' && | ||
671 | (*(p + 1) == '*' || *(p + 1) == '@')) | ||
672 | p += 2; | ||
673 | return !*f && !*p; | ||
674 | } | 716 | } |
675 | 717 | ||
676 | /** | 718 | /** |
@@ -1285,6 +1327,36 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, | |||
1285 | } | 1327 | } |
1286 | 1328 | ||
1287 | /** | 1329 | /** |
1330 | * tomoyo_delete_domain - Delete a domain. | ||
1331 | * | ||
1332 | * @domainname: The name of domain. | ||
1333 | * | ||
1334 | * Returns 0. | ||
1335 | */ | ||
1336 | static int tomoyo_delete_domain(char *domainname) | ||
1337 | { | ||
1338 | struct tomoyo_domain_info *domain; | ||
1339 | struct tomoyo_path_info name; | ||
1340 | |||
1341 | name.name = domainname; | ||
1342 | tomoyo_fill_path_info(&name); | ||
1343 | down_write(&tomoyo_domain_list_lock); | ||
1344 | /* Is there an active domain? */ | ||
1345 | list_for_each_entry(domain, &tomoyo_domain_list, list) { | ||
1346 | /* Never delete tomoyo_kernel_domain */ | ||
1347 | if (domain == &tomoyo_kernel_domain) | ||
1348 | continue; | ||
1349 | if (domain->is_deleted || | ||
1350 | tomoyo_pathcmp(domain->domainname, &name)) | ||
1351 | continue; | ||
1352 | domain->is_deleted = true; | ||
1353 | break; | ||
1354 | } | ||
1355 | up_write(&tomoyo_domain_list_lock); | ||
1356 | return 0; | ||
1357 | } | ||
1358 | |||
1359 | /** | ||
1288 | * tomoyo_write_domain_policy - Write domain policy. | 1360 | * tomoyo_write_domain_policy - Write domain policy. |
1289 | * | 1361 | * |
1290 | * @head: Pointer to "struct tomoyo_io_buffer". | 1362 | * @head: Pointer to "struct tomoyo_io_buffer". |
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 6d6ba09af457..92169d29b2db 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
@@ -56,9 +56,6 @@ struct tomoyo_page_buffer { | |||
56 | * (5) "is_patterned" is a bool which is true if "name" contains wildcard | 56 | * (5) "is_patterned" is a bool which is true if "name" contains wildcard |
57 | * characters, false otherwise. This allows TOMOYO to use "hash" and | 57 | * characters, false otherwise. This allows TOMOYO to use "hash" and |
58 | * strcmp() for string comparison if "is_patterned" is false. | 58 | * strcmp() for string comparison if "is_patterned" is false. |
59 | * (6) "depth" is calculated using the number of "/" characters in "name". | ||
60 | * This allows TOMOYO to avoid comparing two pathnames which never match | ||
61 | * (e.g. whether "/var/www/html/index.html" matches "/tmp/sh-thd-\$"). | ||
62 | */ | 59 | */ |
63 | struct tomoyo_path_info { | 60 | struct tomoyo_path_info { |
64 | const char *name; | 61 | const char *name; |
@@ -66,7 +63,6 @@ struct tomoyo_path_info { | |||
66 | u16 const_len; /* = tomoyo_const_part_length(name) */ | 63 | u16 const_len; /* = tomoyo_const_part_length(name) */ |
67 | bool is_dir; /* = tomoyo_strendswith(name, "/") */ | 64 | bool is_dir; /* = tomoyo_strendswith(name, "/") */ |
68 | bool is_patterned; /* = tomoyo_path_contains_pattern(name) */ | 65 | bool is_patterned; /* = tomoyo_path_contains_pattern(name) */ |
69 | u16 depth; /* = tomoyo_path_depth(name) */ | ||
70 | }; | 66 | }; |
71 | 67 | ||
72 | /* | 68 | /* |
@@ -339,8 +335,6 @@ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain); | |||
339 | const char *tomoyo_get_msg(const bool is_enforce); | 335 | const char *tomoyo_get_msg(const bool is_enforce); |
340 | /* Convert single path operation to operation name. */ | 336 | /* Convert single path operation to operation name. */ |
341 | const char *tomoyo_sp2keyword(const u8 operation); | 337 | const char *tomoyo_sp2keyword(const u8 operation); |
342 | /* Delete a domain. */ | ||
343 | int tomoyo_delete_domain(char *data); | ||
344 | /* Create "alias" entry in exception policy. */ | 338 | /* Create "alias" entry in exception policy. */ |
345 | int tomoyo_write_alias_policy(char *data, const bool is_delete); | 339 | int tomoyo_write_alias_policy(char *data, const bool is_delete); |
346 | /* | 340 | /* |
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 1d8b16960576..fcf52accce2b 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
@@ -717,38 +717,6 @@ int tomoyo_write_alias_policy(char *data, const bool is_delete) | |||
717 | return tomoyo_update_alias_entry(data, cp, is_delete); | 717 | return tomoyo_update_alias_entry(data, cp, is_delete); |
718 | } | 718 | } |
719 | 719 | ||
720 | /* Domain create/delete handler. */ | ||
721 | |||
722 | /** | ||
723 | * tomoyo_delete_domain - Delete a domain. | ||
724 | * | ||
725 | * @domainname: The name of domain. | ||
726 | * | ||
727 | * Returns 0. | ||
728 | */ | ||
729 | int tomoyo_delete_domain(char *domainname) | ||
730 | { | ||
731 | struct tomoyo_domain_info *domain; | ||
732 | struct tomoyo_path_info name; | ||
733 | |||
734 | name.name = domainname; | ||
735 | tomoyo_fill_path_info(&name); | ||
736 | down_write(&tomoyo_domain_list_lock); | ||
737 | /* Is there an active domain? */ | ||
738 | list_for_each_entry(domain, &tomoyo_domain_list, list) { | ||
739 | /* Never delete tomoyo_kernel_domain */ | ||
740 | if (domain == &tomoyo_kernel_domain) | ||
741 | continue; | ||
742 | if (domain->is_deleted || | ||
743 | tomoyo_pathcmp(domain->domainname, &name)) | ||
744 | continue; | ||
745 | domain->is_deleted = true; | ||
746 | break; | ||
747 | } | ||
748 | up_write(&tomoyo_domain_list_lock); | ||
749 | return 0; | ||
750 | } | ||
751 | |||
752 | /** | 720 | /** |
753 | * tomoyo_find_or_assign_new_domain - Create a domain. | 721 | * tomoyo_find_or_assign_new_domain - Create a domain. |
754 | * | 722 | * |
@@ -818,13 +786,11 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | |||
818 | /** | 786 | /** |
819 | * tomoyo_find_next_domain - Find a domain. | 787 | * tomoyo_find_next_domain - Find a domain. |
820 | * | 788 | * |
821 | * @bprm: Pointer to "struct linux_binprm". | 789 | * @bprm: Pointer to "struct linux_binprm". |
822 | * @next_domain: Pointer to pointer to "struct tomoyo_domain_info". | ||
823 | * | 790 | * |
824 | * Returns 0 on success, negative value otherwise. | 791 | * Returns 0 on success, negative value otherwise. |
825 | */ | 792 | */ |
826 | int tomoyo_find_next_domain(struct linux_binprm *bprm, | 793 | int tomoyo_find_next_domain(struct linux_binprm *bprm) |
827 | struct tomoyo_domain_info **next_domain) | ||
828 | { | 794 | { |
829 | /* | 795 | /* |
830 | * This function assumes that the size of buffer returned by | 796 | * This function assumes that the size of buffer returned by |
@@ -946,9 +912,11 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm, | |||
946 | tomoyo_set_domain_flag(old_domain, false, | 912 | tomoyo_set_domain_flag(old_domain, false, |
947 | TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED); | 913 | TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED); |
948 | out: | 914 | out: |
915 | if (!domain) | ||
916 | domain = old_domain; | ||
917 | bprm->cred->security = domain; | ||
949 | tomoyo_free(real_program_name); | 918 | tomoyo_free(real_program_name); |
950 | tomoyo_free(symlink_program_name); | 919 | tomoyo_free(symlink_program_name); |
951 | *next_domain = domain ? domain : old_domain; | ||
952 | tomoyo_free(tmp); | 920 | tomoyo_free(tmp); |
953 | return retval; | 921 | return retval; |
954 | } | 922 | } |
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 5ae3a571559f..8346938809b1 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c | |||
@@ -1096,27 +1096,6 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * | |||
1096 | } | 1096 | } |
1097 | 1097 | ||
1098 | /** | 1098 | /** |
1099 | * tomoyo_check_file_perm - Check permission for sysctl()'s "read" and "write". | ||
1100 | * | ||
1101 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
1102 | * @filename: Filename to check. | ||
1103 | * @perm: Mode ("read" or "write" or "read/write"). | ||
1104 | * Returns 0 on success, negative value otherwise. | ||
1105 | */ | ||
1106 | int tomoyo_check_file_perm(struct tomoyo_domain_info *domain, | ||
1107 | const char *filename, const u8 perm) | ||
1108 | { | ||
1109 | struct tomoyo_path_info name; | ||
1110 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); | ||
1111 | |||
1112 | if (!mode) | ||
1113 | return 0; | ||
1114 | name.name = filename; | ||
1115 | tomoyo_fill_path_info(&name); | ||
1116 | return tomoyo_check_file_perm2(domain, &name, perm, "sysctl", mode); | ||
1117 | } | ||
1118 | |||
1119 | /** | ||
1120 | * tomoyo_check_exec_perm - Check permission for "execute". | 1099 | * tomoyo_check_exec_perm - Check permission for "execute". |
1121 | * | 1100 | * |
1122 | * @domain: Pointer to "struct tomoyo_domain_info". | 1101 | * @domain: Pointer to "struct tomoyo_domain_info". |
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 5f2e33263371..18369d497eb8 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c | |||
@@ -13,6 +13,8 @@ | |||
13 | #include <linux/mount.h> | 13 | #include <linux/mount.h> |
14 | #include <linux/mnt_namespace.h> | 14 | #include <linux/mnt_namespace.h> |
15 | #include <linux/fs_struct.h> | 15 | #include <linux/fs_struct.h> |
16 | #include <linux/hash.h> | ||
17 | |||
16 | #include "common.h" | 18 | #include "common.h" |
17 | #include "realpath.h" | 19 | #include "realpath.h" |
18 | 20 | ||
@@ -108,6 +110,15 @@ int tomoyo_realpath_from_path2(struct path *path, char *newname, | |||
108 | spin_unlock(&dcache_lock); | 110 | spin_unlock(&dcache_lock); |
109 | path_put(&root); | 111 | path_put(&root); |
110 | path_put(&ns_root); | 112 | path_put(&ns_root); |
113 | /* Prepend "/proc" prefix if using internal proc vfs mount. */ | ||
114 | if (!IS_ERR(sp) && (path->mnt->mnt_parent == path->mnt) && | ||
115 | (strcmp(path->mnt->mnt_sb->s_type->name, "proc") == 0)) { | ||
116 | sp -= 5; | ||
117 | if (sp >= newname) | ||
118 | memcpy(sp, "/proc", 5); | ||
119 | else | ||
120 | sp = ERR_PTR(-ENOMEM); | ||
121 | } | ||
111 | } | 122 | } |
112 | if (IS_ERR(sp)) | 123 | if (IS_ERR(sp)) |
113 | error = PTR_ERR(sp); | 124 | error = PTR_ERR(sp); |
@@ -263,7 +274,8 @@ static unsigned int tomoyo_quota_for_savename; | |||
263 | * table. Frequency of appending strings is very low. So we don't need | 274 | * table. Frequency of appending strings is very low. So we don't need |
264 | * large (e.g. 64k) hash size. 256 will be sufficient. | 275 | * large (e.g. 64k) hash size. 256 will be sufficient. |
265 | */ | 276 | */ |
266 | #define TOMOYO_MAX_HASH 256 | 277 | #define TOMOYO_HASH_BITS 8 |
278 | #define TOMOYO_MAX_HASH (1u<<TOMOYO_HASH_BITS) | ||
267 | 279 | ||
268 | /* | 280 | /* |
269 | * tomoyo_name_entry is a structure which is used for linking | 281 | * tomoyo_name_entry is a structure which is used for linking |
@@ -315,6 +327,7 @@ const struct tomoyo_path_info *tomoyo_save_name(const char *name) | |||
315 | struct tomoyo_free_memory_block_list *fmb; | 327 | struct tomoyo_free_memory_block_list *fmb; |
316 | int len; | 328 | int len; |
317 | char *cp; | 329 | char *cp; |
330 | struct list_head *head; | ||
318 | 331 | ||
319 | if (!name) | 332 | if (!name) |
320 | return NULL; | 333 | return NULL; |
@@ -325,9 +338,10 @@ const struct tomoyo_path_info *tomoyo_save_name(const char *name) | |||
325 | return NULL; | 338 | return NULL; |
326 | } | 339 | } |
327 | hash = full_name_hash((const unsigned char *) name, len - 1); | 340 | hash = full_name_hash((const unsigned char *) name, len - 1); |
341 | head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; | ||
342 | |||
328 | mutex_lock(&lock); | 343 | mutex_lock(&lock); |
329 | list_for_each_entry(ptr, &tomoyo_name_list[hash % TOMOYO_MAX_HASH], | 344 | list_for_each_entry(ptr, head, list) { |
330 | list) { | ||
331 | if (hash == ptr->entry.hash && !strcmp(name, ptr->entry.name)) | 345 | if (hash == ptr->entry.hash && !strcmp(name, ptr->entry.name)) |
332 | goto out; | 346 | goto out; |
333 | } | 347 | } |
@@ -365,7 +379,7 @@ const struct tomoyo_path_info *tomoyo_save_name(const char *name) | |||
365 | tomoyo_fill_path_info(&ptr->entry); | 379 | tomoyo_fill_path_info(&ptr->entry); |
366 | fmb->ptr += len; | 380 | fmb->ptr += len; |
367 | fmb->len -= len; | 381 | fmb->len -= len; |
368 | list_add_tail(&ptr->list, &tomoyo_name_list[hash % TOMOYO_MAX_HASH]); | 382 | list_add_tail(&ptr->list, head); |
369 | if (fmb->len == 0) { | 383 | if (fmb->len == 0) { |
370 | list_del(&fmb->list); | 384 | list_del(&fmb->list); |
371 | kfree(fmb); | 385 | kfree(fmb); |
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 3194d09fe0f4..8a00ade85166 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c | |||
@@ -14,6 +14,12 @@ | |||
14 | #include "tomoyo.h" | 14 | #include "tomoyo.h" |
15 | #include "realpath.h" | 15 | #include "realpath.h" |
16 | 16 | ||
17 | static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) | ||
18 | { | ||
19 | new->security = NULL; | ||
20 | return 0; | ||
21 | } | ||
22 | |||
17 | static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, | 23 | static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, |
18 | gfp_t gfp) | 24 | gfp_t gfp) |
19 | { | 25 | { |
@@ -25,6 +31,15 @@ static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, | |||
25 | return 0; | 31 | return 0; |
26 | } | 32 | } |
27 | 33 | ||
34 | static void tomoyo_cred_transfer(struct cred *new, const struct cred *old) | ||
35 | { | ||
36 | /* | ||
37 | * Since "struct tomoyo_domain_info *" is a sharable pointer, | ||
38 | * we don't need to duplicate. | ||
39 | */ | ||
40 | new->security = old->security; | ||
41 | } | ||
42 | |||
28 | static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) | 43 | static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) |
29 | { | 44 | { |
30 | int rc; | 45 | int rc; |
@@ -61,14 +76,8 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm) | |||
61 | * Execute permission is checked against pathname passed to do_execve() | 76 | * Execute permission is checked against pathname passed to do_execve() |
62 | * using current domain. | 77 | * using current domain. |
63 | */ | 78 | */ |
64 | if (!domain) { | 79 | if (!domain) |
65 | struct tomoyo_domain_info *next_domain = NULL; | 80 | return tomoyo_find_next_domain(bprm); |
66 | int retval = tomoyo_find_next_domain(bprm, &next_domain); | ||
67 | |||
68 | if (!retval) | ||
69 | bprm->cred->security = next_domain; | ||
70 | return retval; | ||
71 | } | ||
72 | /* | 81 | /* |
73 | * Read permission is checked against interpreters using next domain. | 82 | * Read permission is checked against interpreters using next domain. |
74 | * '1' is the result of open_to_namei_flags(O_RDONLY). | 83 | * '1' is the result of open_to_namei_flags(O_RDONLY). |
@@ -76,83 +85,6 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm) | |||
76 | return tomoyo_check_open_permission(domain, &bprm->file->f_path, 1); | 85 | return tomoyo_check_open_permission(domain, &bprm->file->f_path, 1); |
77 | } | 86 | } |
78 | 87 | ||
79 | #ifdef CONFIG_SYSCTL | ||
80 | |||
81 | static int tomoyo_prepend(char **buffer, int *buflen, const char *str) | ||
82 | { | ||
83 | int namelen = strlen(str); | ||
84 | |||
85 | if (*buflen < namelen) | ||
86 | return -ENOMEM; | ||
87 | *buflen -= namelen; | ||
88 | *buffer -= namelen; | ||
89 | memcpy(*buffer, str, namelen); | ||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | /** | ||
94 | * tomoyo_sysctl_path - return the realpath of a ctl_table. | ||
95 | * @table: pointer to "struct ctl_table". | ||
96 | * | ||
97 | * Returns realpath(3) of the @table on success. | ||
98 | * Returns NULL on failure. | ||
99 | * | ||
100 | * This function uses tomoyo_alloc(), so the caller must call tomoyo_free() | ||
101 | * if this function didn't return NULL. | ||
102 | */ | ||
103 | static char *tomoyo_sysctl_path(struct ctl_table *table) | ||
104 | { | ||
105 | int buflen = TOMOYO_MAX_PATHNAME_LEN; | ||
106 | char *buf = tomoyo_alloc(buflen); | ||
107 | char *end = buf + buflen; | ||
108 | int error = -ENOMEM; | ||
109 | |||
110 | if (!buf) | ||
111 | return NULL; | ||
112 | |||
113 | *--end = '\0'; | ||
114 | buflen--; | ||
115 | while (table) { | ||
116 | char num[32]; | ||
117 | const char *sp = table->procname; | ||
118 | |||
119 | if (!sp) { | ||
120 | memset(num, 0, sizeof(num)); | ||
121 | snprintf(num, sizeof(num) - 1, "=%d=", table->ctl_name); | ||
122 | sp = num; | ||
123 | } | ||
124 | if (tomoyo_prepend(&end, &buflen, sp) || | ||
125 | tomoyo_prepend(&end, &buflen, "/")) | ||
126 | goto out; | ||
127 | table = table->parent; | ||
128 | } | ||
129 | if (tomoyo_prepend(&end, &buflen, "/proc/sys")) | ||
130 | goto out; | ||
131 | error = tomoyo_encode(buf, end - buf, end); | ||
132 | out: | ||
133 | if (!error) | ||
134 | return buf; | ||
135 | tomoyo_free(buf); | ||
136 | return NULL; | ||
137 | } | ||
138 | |||
139 | static int tomoyo_sysctl(struct ctl_table *table, int op) | ||
140 | { | ||
141 | int error; | ||
142 | char *name; | ||
143 | |||
144 | op &= MAY_READ | MAY_WRITE; | ||
145 | if (!op) | ||
146 | return 0; | ||
147 | name = tomoyo_sysctl_path(table); | ||
148 | if (!name) | ||
149 | return -ENOMEM; | ||
150 | error = tomoyo_check_file_perm(tomoyo_domain(), name, op); | ||
151 | tomoyo_free(name); | ||
152 | return error; | ||
153 | } | ||
154 | #endif | ||
155 | |||
156 | static int tomoyo_path_truncate(struct path *path, loff_t length, | 88 | static int tomoyo_path_truncate(struct path *path, loff_t length, |
157 | unsigned int time_attrs) | 89 | unsigned int time_attrs) |
158 | { | 90 | { |
@@ -268,12 +200,11 @@ static int tomoyo_dentry_open(struct file *f, const struct cred *cred) | |||
268 | */ | 200 | */ |
269 | static struct security_operations tomoyo_security_ops = { | 201 | static struct security_operations tomoyo_security_ops = { |
270 | .name = "tomoyo", | 202 | .name = "tomoyo", |
203 | .cred_alloc_blank = tomoyo_cred_alloc_blank, | ||
271 | .cred_prepare = tomoyo_cred_prepare, | 204 | .cred_prepare = tomoyo_cred_prepare, |
205 | .cred_transfer = tomoyo_cred_transfer, | ||
272 | .bprm_set_creds = tomoyo_bprm_set_creds, | 206 | .bprm_set_creds = tomoyo_bprm_set_creds, |
273 | .bprm_check_security = tomoyo_bprm_check_security, | 207 | .bprm_check_security = tomoyo_bprm_check_security, |
274 | #ifdef CONFIG_SYSCTL | ||
275 | .sysctl = tomoyo_sysctl, | ||
276 | #endif | ||
277 | .file_fcntl = tomoyo_file_fcntl, | 208 | .file_fcntl = tomoyo_file_fcntl, |
278 | .dentry_open = tomoyo_dentry_open, | 209 | .dentry_open = tomoyo_dentry_open, |
279 | .path_truncate = tomoyo_path_truncate, | 210 | .path_truncate = tomoyo_path_truncate, |
diff --git a/security/tomoyo/tomoyo.h b/security/tomoyo/tomoyo.h index 0fd588a629cf..ed758325b1ae 100644 --- a/security/tomoyo/tomoyo.h +++ b/security/tomoyo/tomoyo.h | |||
@@ -18,8 +18,6 @@ struct inode; | |||
18 | struct linux_binprm; | 18 | struct linux_binprm; |
19 | struct pt_regs; | 19 | struct pt_regs; |
20 | 20 | ||
21 | int tomoyo_check_file_perm(struct tomoyo_domain_info *domain, | ||
22 | const char *filename, const u8 perm); | ||
23 | int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, | 21 | int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, |
24 | const struct tomoyo_path_info *filename); | 22 | const struct tomoyo_path_info *filename); |
25 | int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | 23 | int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, |
@@ -31,8 +29,7 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info *domain, | |||
31 | struct path *path2); | 29 | struct path *path2); |
32 | int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, | 30 | int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, |
33 | struct file *filp); | 31 | struct file *filp); |
34 | int tomoyo_find_next_domain(struct linux_binprm *bprm, | 32 | int tomoyo_find_next_domain(struct linux_binprm *bprm); |
35 | struct tomoyo_domain_info **next_domain); | ||
36 | 33 | ||
37 | /* Index numbers for Access Controls. */ | 34 | /* Index numbers for Access Controls. */ |
38 | 35 | ||