The core functions of string.c are those that may be implemented by per-architecture functions, or overloaded by FORTIFY_SOURCE. As a result, it needs to be built with __NO_FORTIFY. Without this, macros will collide with function declarations. This was accidentally working due to -ffreestanding (on some architectures). Make this deterministic by explicitly setting __NO_FORTIFY and move all the helper functions into string_helpers.c so that they gain the fortification coverage they had been missing.
Showing the changes to lib/string.c (1 of 7 files). Show all
Unified · Split
| @@ -6,20 +6,15 @@ · 5 unmodified lines | |||
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | /* | 8 | /* |
| 9 | * stupid library routines.. The optimized versions should generally be found | 9 | * This file should be used only for "library" routines that may have |
| 10 | * as inline code in <asm-xx/string.h> | 10 | * alternative implementations on specific architectures (generally |
| 11 | * found in <asm-xx/string.h>), or get overloaded by FORTIFY_SOURCE. | ||
| 12 | * (Specifically, this file is built with __NO_FORTIFY.) | ||
| 11 | * | 13 | * |
| 12 | * These are buggy as well.. | 14 | * Other helper functions should live in string_helpers.c. |
| 13 | * | ||
| 14 | * * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de> | ||
| 15 | * - Added strsep() which will replace strtok() soon (because strsep() is | ||
| 16 | * reentrant and should be faster). Use only strsep() in new code, please. | ||
| 17 | * | ||
| 18 | * * Sat Feb 09 2002, Jason Thomas <jason@topic.com.au>, | ||
| 19 | * Matthew Hawkins <matt@mh.dropbear.id.au> | ||
| 20 | * - Kissed strtok() goodbye | ||
| 21 | */ | 15 | */ |
| 22 | 16 | ||
| 17 | #define __NO_FORTIFY | ||
| 23 | #include <linux/types.h> | 18 | #include <linux/types.h> |
| 24 | #include <linux/string.h> | 19 | #include <linux/string.h> |
| 25 | #include <linux/ctype.h> | 20 | #include <linux/ctype.h> |
| @@ -238,40 +233,6 @@ ssize_t strscpy(char *dest, const char *src, size_t count) · 212 unmodified lines | |||
| 238 | EXPORT_SYMBOL(strscpy); | 233 | EXPORT_SYMBOL(strscpy); |
| 239 | #endif | 234 | #endif |
| 240 | 235 | ||
| 241 | /** | ||
| 242 | * strscpy_pad() - Copy a C-string into a sized buffer | ||
| 243 | * @dest: Where to copy the string to | ||
| 244 | * @src: Where to copy the string from | ||
| 245 | * @count: Size of destination buffer | ||
| 246 | * | ||
| 247 | * Copy the string, or as much of it as fits, into the dest buffer. The | ||
| 248 | * behavior is undefined if the string buffers overlap. The destination | ||
| 249 | * buffer is always %NUL terminated, unless it's zero-sized. | ||
| 250 | * | ||
| 251 | * If the source string is shorter than the destination buffer, zeros | ||
| 252 | * the tail of the destination buffer. | ||
| 253 | * | ||
| 254 | * For full explanation of why you may want to consider using the | ||
| 255 | * 'strscpy' functions please see the function docstring for strscpy(). | ||
| 256 | * | ||
| 257 | * Returns: | ||
| 258 | * * The number of characters copied (not including the trailing %NUL) | ||
| 259 | * * -E2BIG if count is 0 or @src was truncated. | ||
| 260 | */ | ||
| 261 | ssize_t strscpy_pad(char *dest, const char *src, size_t count) | ||
| 262 | { | ||
| 263 | ssize_t written; | ||
| 264 | |||
| 265 | written = strscpy(dest, src, count); | ||
| 266 | if (written < 0 || written == count - 1) | ||
| 267 | return written; | ||
| 268 | |||
| 269 | memset(dest + written + 1, 0, count - written - 1); | ||
| 270 | |||
| 271 | return written; | ||
| 272 | } | ||
| 273 | EXPORT_SYMBOL(strscpy_pad); | ||
| 274 | |||
| 275 | /** | 236 | /** |
| 276 | * stpcpy - copy a string from src to dest returning a pointer to the new end | 237 | * stpcpy - copy a string from src to dest returning a pointer to the new end |
| 277 | * of dest, including src's %NUL-terminator. May overrun dest. | 238 | * of dest, including src's %NUL-terminator. May overrun dest. |
| @@ -514,46 +475,6 @@ char *strnchr(const char *s, size_t count, int c) · 236 unmodified lines | |||
| 514 | EXPORT_SYMBOL(strnchr); | 475 | EXPORT_SYMBOL(strnchr); |
| 515 | #endif | 476 | #endif |
| 516 | 477 | ||
| 517 | /** | ||
| 518 | * skip_spaces - Removes leading whitespace from @str. | ||
| 519 | * @str: The string to be stripped. | ||
| 520 | * | ||
| 521 | * Returns a pointer to the first non-whitespace character in @str. | ||
| 522 | */ | ||
| 523 | char *skip_spaces(const char *str) | ||
| 524 | { | ||
| 525 | while (isspace(*str)) | ||
| 526 | ++str; | ||
| 527 | return (char *)str; | ||
| 528 | } | ||
| 529 | EXPORT_SYMBOL(skip_spaces); | ||
| 530 | |||
| 531 | /** | ||
| 532 | * strim - Removes leading and trailing whitespace from @s. | ||
| 533 | * @s: The string to be stripped. | ||
| 534 | * | ||
| 535 | * Note that the first trailing whitespace is replaced with a %NUL-terminator | ||
| 536 | * in the given string @s. Returns a pointer to the first non-whitespace | ||
| 537 | * character in @s. | ||
| 538 | */ | ||
| 539 | char *strim(char *s) | ||
| 540 | { | ||
| 541 | size_t size; | ||
| 542 | char *end; | ||
| 543 | |||
| 544 | size = strlen(s); | ||
| 545 | if (!size) | ||
| 546 | return s; | ||
| 547 | |||
| 548 | end = s + size - 1; | ||
| 549 | while (end >= s && isspace(*end)) | ||
| 550 | end--; | ||
| 551 | *(end + 1) = '\0'; | ||
| 552 | |||
| 553 | return skip_spaces(s); | ||
| 554 | } | ||
| 555 | EXPORT_SYMBOL(strim); | ||
| 556 | |||
| 557 | #ifndef __HAVE_ARCH_STRLEN | 478 | #ifndef __HAVE_ARCH_STRLEN |
| 558 | /** | 479 | /** |
| 559 | * strlen - Find the length of a string | 480 | * strlen - Find the length of a string |
| @@ -688,101 +609,6 @@ char *strsep(char **s, const char *ct) · 128 unmodified lines | |||
| 688 | EXPORT_SYMBOL(strsep); | 609 | EXPORT_SYMBOL(strsep); |
| 689 | #endif | 610 | #endif |
| 690 | 611 | ||
| 691 | /** | ||
| 692 | * sysfs_streq - return true if strings are equal, modulo trailing newline | ||
| 693 | * @s1: one string | ||
| 694 | * @s2: another string | ||
| 695 | * | ||
| 696 | * This routine returns true iff two strings are equal, treating both | ||
| 697 | * NUL and newline-then-NUL as equivalent string terminations. It's | ||
| 698 | * geared for use with sysfs input strings, which generally terminate | ||
| 699 | * with newlines but are compared against values without newlines. | ||
| 700 | */ | ||
| 701 | bool sysfs_streq(const char *s1, const char *s2) | ||
| 702 | { | ||
| 703 | while (*s1 && *s1 == *s2) { | ||
| 704 | s1++; | ||
| 705 | s2++; | ||
| 706 | } | ||
| 707 | |||
| 708 | if (*s1 == *s2) | ||
| 709 | return true; | ||
| 710 | if (!*s1 && *s2 == '\n' && !s2[1]) | ||
| 711 | return true; | ||
| 712 | if (*s1 == '\n' && !s1[1] && !*s2) | ||
| 713 | return true; | ||
| 714 | return false; | ||
| 715 | } | ||
| 716 | EXPORT_SYMBOL(sysfs_streq); | ||
| 717 | |||
| 718 | /** | ||
| 719 | * match_string - matches given string in an array | ||
| 720 | * @array: array of strings | ||
| 721 | * @n: number of strings in the array or -1 for NULL terminated arrays | ||
| 722 | * @string: string to match with | ||
| 723 | * | ||
| 724 | * This routine will look for a string in an array of strings up to the | ||
| 725 | * n-th element in the array or until the first NULL element. | ||
| 726 | * | ||
| 727 | * Historically the value of -1 for @n, was used to search in arrays that | ||
| 728 | * are NULL terminated. However, the function does not make a distinction | ||
| 729 | * when finishing the search: either @n elements have been compared OR | ||
| 730 | * the first NULL element was found. | ||
| 731 | * | ||
| 732 | * Return: | ||
| 733 | * index of a @string in the @array if matches, or %-EINVAL otherwise. | ||
| 734 | */ | ||
| 735 | int match_string(const char * const *array, size_t n, const char *string) | ||
| 736 | { | ||
| 737 | int index; | ||
| 738 | const char *item; | ||
| 739 | |||
| 740 | for (index = 0; index < n; index++) { | ||
| 741 | item = array[index]; | ||
| 742 | if (!item) | ||
| 743 | break; | ||
| 744 | if (!strcmp(item, string)) | ||
| 745 | return index; | ||
| 746 | } | ||
| 747 | |||
| 748 | return -EINVAL; | ||
| 749 | } | ||
| 750 | EXPORT_SYMBOL(match_string); | ||
| 751 | |||
| 752 | /** | ||
| 753 | * __sysfs_match_string - matches given string in an array | ||
| 754 | * @array: array of strings | ||
| 755 | * @n: number of strings in the array or -1 for NULL terminated arrays | ||
| 756 | * @str: string to match with | ||
| 757 | * | ||
| 758 | * Returns index of @str in the @array or -EINVAL, just like match_string(). | ||
| 759 | * Uses sysfs_streq instead of strcmp for matching. | ||
| 760 | * | ||
| 761 | * This routine will look for a string in an array of strings up to the | ||
| 762 | * n-th element in the array or until the first NULL element. | ||
| 763 | * | ||
| 764 | * Historically the value of -1 for @n, was used to search in arrays that | ||
| 765 | * are NULL terminated. However, the function does not make a distinction | ||
| 766 | * when finishing the search: either @n elements have been compared OR | ||
| 767 | * the first NULL element was found. | ||
| 768 | */ | ||
| 769 | int __sysfs_match_string(const char * const *array, size_t n, const char *str) | ||
| 770 | { | ||
| 771 | const char *item; | ||
| 772 | int index; | ||
| 773 | |||
| 774 | for (index = 0; index < n; index++) { | ||
| 775 | item = array[index]; | ||
| 776 | if (!item) | ||
| 777 | break; | ||
| 778 | if (sysfs_streq(item, str)) | ||
| 779 | return index; | ||
| 780 | } | ||
| 781 | |||
| 782 | return -EINVAL; | ||
| 783 | } | ||
| 784 | EXPORT_SYMBOL(__sysfs_match_string); | ||
| 785 | |||
| 786 | #ifndef __HAVE_ARCH_MEMSET | 612 | #ifndef __HAVE_ARCH_MEMSET |
| 787 | /** | 613 | /** |
| 788 | * memset - Fill a region of memory with the given value | 614 | * memset - Fill a region of memory with the given value |
| @@ -1141,27 +967,3 @@ void *memchr_inv(const void *start, int c, size_t bytes) · 352 unmodified lines | |||
| 1141 | return check_bytes8(start, value, bytes % 8); | 967 | return check_bytes8(start, value, bytes % 8); |
| 1142 | } | 968 | } |
| 1143 | EXPORT_SYMBOL(memchr_inv); | 969 | EXPORT_SYMBOL(memchr_inv); |
| 1144 | |||
| 1145 | /** | ||
| 1146 | * strreplace - Replace all occurrences of character in string. | ||
| 1147 | * @s: The string to operate on. | ||
| 1148 | * @old: The character being replaced. | ||
| 1149 | * @new: The character @old is replaced with. | ||
| 1150 | * | ||
| 1151 | * Returns pointer to the nul byte at the end of @s. | ||
| 1152 | */ | ||
| 1153 | char *strreplace(char *s, char old, char new) | ||
| 1154 | { | ||
| 1155 | for (; *s; ++s) | ||
| 1156 | if (*s == old) | ||
| 1157 | *s = new; | ||
| 1158 | return s; | ||
| 1159 | } | ||
| 1160 | EXPORT_SYMBOL(strreplace); | ||
| 1161 | |||
| 1162 | void fortify_panic(const char *name) | ||
| 1163 | { | ||
| 1164 | pr_emerg("detected buffer overflow in %s\n", name); | ||
| 1165 | BUG(); | ||
| 1166 | } | ||
| 1167 | EXPORT_SYMBOL(fortify_panic); | ||