Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

lib/string: Move helper functions out of string.c

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.

Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: Andy Lavr <andy.lavr@gmail.com>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Alexey Dobriyan <adobriyan@gmail.com>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
Cc: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Acked-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Kees Cook <keescook@chromium.org>

+208 -204
+1
arch/arm/boot/compressed/string.c
··· 5 5 * Small subset of simple string routines 6 6 */ 7 7 8 + #define __NO_FORTIFY 8 9 #include <linux/string.h> 9 10 10 11 /*
+3
arch/s390/lib/string.c
··· 8 8 */ 9 9 10 10 #define IN_ARCH_STRING_C 1 11 + #ifndef __NO_FORTIFY 12 + # define __NO_FORTIFY 13 + #endif 11 14 12 15 #include <linux/types.h> 13 16 #include <linux/string.h>
+2
arch/x86/boot/compressed/misc.h
··· 14 14 #undef CONFIG_KASAN 15 15 #undef CONFIG_KASAN_GENERIC 16 16 17 + #define __NO_FORTIFY 18 + 17 19 /* cpu_feature_enabled() cannot be used this early */ 18 20 #define USE_EARLY_PGTABLE_L5 19 21
+2
arch/x86/boot/compressed/pgtable_64.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include "misc.h" 1 3 #include <linux/efi.h> 2 4 #include <asm/e820/types.h> 3 5 #include <asm/processor.h>
+1
arch/x86/lib/string_32.c
··· 11 11 * strings. 12 12 */ 13 13 14 + #define __NO_FORTIFY 14 15 #include <linux/string.h> 15 16 #include <linux/export.h> 16 17
+6 -204
lib/string.c
··· 6 6 */ 7 7 8 8 /* 9 - * stupid library routines.. The optimized versions should generally be found 10 - * as inline code in <asm-xx/string.h> 9 + * This file should be used only for "library" routines that may have 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.. 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 14 + * Other helper functions should live in string_helpers.c. 21 15 */ 22 16 17 + #define __NO_FORTIFY 23 18 #include <linux/types.h> 24 19 #include <linux/string.h> 25 20 #include <linux/ctype.h> ··· 232 237 } 233 238 EXPORT_SYMBOL(strscpy); 234 239 #endif 235 - 236 - /** 237 - * strscpy_pad() - Copy a C-string into a sized buffer 238 - * @dest: Where to copy the string to 239 - * @src: Where to copy the string from 240 - * @count: Size of destination buffer 241 - * 242 - * Copy the string, or as much of it as fits, into the dest buffer. The 243 - * behavior is undefined if the string buffers overlap. The destination 244 - * buffer is always %NUL terminated, unless it's zero-sized. 245 - * 246 - * If the source string is shorter than the destination buffer, zeros 247 - * the tail of the destination buffer. 248 - * 249 - * For full explanation of why you may want to consider using the 250 - * 'strscpy' functions please see the function docstring for strscpy(). 251 - * 252 - * Returns: 253 - * * The number of characters copied (not including the trailing %NUL) 254 - * * -E2BIG if count is 0 or @src was truncated. 255 - */ 256 - ssize_t strscpy_pad(char *dest, const char *src, size_t count) 257 - { 258 - ssize_t written; 259 - 260 - written = strscpy(dest, src, count); 261 - if (written < 0 || written == count - 1) 262 - return written; 263 - 264 - memset(dest + written + 1, 0, count - written - 1); 265 - 266 - return written; 267 - } 268 - EXPORT_SYMBOL(strscpy_pad); 269 240 270 241 /** 271 242 * stpcpy - copy a string from src to dest returning a pointer to the new end ··· 475 514 EXPORT_SYMBOL(strnchr); 476 515 #endif 477 516 478 - /** 479 - * skip_spaces - Removes leading whitespace from @str. 480 - * @str: The string to be stripped. 481 - * 482 - * Returns a pointer to the first non-whitespace character in @str. 483 - */ 484 - char *skip_spaces(const char *str) 485 - { 486 - while (isspace(*str)) 487 - ++str; 488 - return (char *)str; 489 - } 490 - EXPORT_SYMBOL(skip_spaces); 491 - 492 - /** 493 - * strim - Removes leading and trailing whitespace from @s. 494 - * @s: The string to be stripped. 495 - * 496 - * Note that the first trailing whitespace is replaced with a %NUL-terminator 497 - * in the given string @s. Returns a pointer to the first non-whitespace 498 - * character in @s. 499 - */ 500 - char *strim(char *s) 501 - { 502 - size_t size; 503 - char *end; 504 - 505 - size = strlen(s); 506 - if (!size) 507 - return s; 508 - 509 - end = s + size - 1; 510 - while (end >= s && isspace(*end)) 511 - end--; 512 - *(end + 1) = '\0'; 513 - 514 - return skip_spaces(s); 515 - } 516 - EXPORT_SYMBOL(strim); 517 - 518 517 #ifndef __HAVE_ARCH_STRLEN 519 518 /** 520 519 * strlen - Find the length of a string ··· 608 687 } 609 688 EXPORT_SYMBOL(strsep); 610 689 #endif 611 - 612 - /** 613 - * sysfs_streq - return true if strings are equal, modulo trailing newline 614 - * @s1: one string 615 - * @s2: another string 616 - * 617 - * This routine returns true iff two strings are equal, treating both 618 - * NUL and newline-then-NUL as equivalent string terminations. It's 619 - * geared for use with sysfs input strings, which generally terminate 620 - * with newlines but are compared against values without newlines. 621 - */ 622 - bool sysfs_streq(const char *s1, const char *s2) 623 - { 624 - while (*s1 && *s1 == *s2) { 625 - s1++; 626 - s2++; 627 - } 628 - 629 - if (*s1 == *s2) 630 - return true; 631 - if (!*s1 && *s2 == '\n' && !s2[1]) 632 - return true; 633 - if (*s1 == '\n' && !s1[1] && !*s2) 634 - return true; 635 - return false; 636 - } 637 - EXPORT_SYMBOL(sysfs_streq); 638 - 639 - /** 640 - * match_string - matches given string in an array 641 - * @array: array of strings 642 - * @n: number of strings in the array or -1 for NULL terminated arrays 643 - * @string: string to match with 644 - * 645 - * This routine will look for a string in an array of strings up to the 646 - * n-th element in the array or until the first NULL element. 647 - * 648 - * Historically the value of -1 for @n, was used to search in arrays that 649 - * are NULL terminated. However, the function does not make a distinction 650 - * when finishing the search: either @n elements have been compared OR 651 - * the first NULL element was found. 652 - * 653 - * Return: 654 - * index of a @string in the @array if matches, or %-EINVAL otherwise. 655 - */ 656 - int match_string(const char * const *array, size_t n, const char *string) 657 - { 658 - int index; 659 - const char *item; 660 - 661 - for (index = 0; index < n; index++) { 662 - item = array[index]; 663 - if (!item) 664 - break; 665 - if (!strcmp(item, string)) 666 - return index; 667 - } 668 - 669 - return -EINVAL; 670 - } 671 - EXPORT_SYMBOL(match_string); 672 - 673 - /** 674 - * __sysfs_match_string - matches given string in an array 675 - * @array: array of strings 676 - * @n: number of strings in the array or -1 for NULL terminated arrays 677 - * @str: string to match with 678 - * 679 - * Returns index of @str in the @array or -EINVAL, just like match_string(). 680 - * Uses sysfs_streq instead of strcmp for matching. 681 - * 682 - * This routine will look for a string in an array of strings up to the 683 - * n-th element in the array or until the first NULL element. 684 - * 685 - * Historically the value of -1 for @n, was used to search in arrays that 686 - * are NULL terminated. However, the function does not make a distinction 687 - * when finishing the search: either @n elements have been compared OR 688 - * the first NULL element was found. 689 - */ 690 - int __sysfs_match_string(const char * const *array, size_t n, const char *str) 691 - { 692 - const char *item; 693 - int index; 694 - 695 - for (index = 0; index < n; index++) { 696 - item = array[index]; 697 - if (!item) 698 - break; 699 - if (sysfs_streq(item, str)) 700 - return index; 701 - } 702 - 703 - return -EINVAL; 704 - } 705 - EXPORT_SYMBOL(__sysfs_match_string); 706 690 707 691 #ifndef __HAVE_ARCH_MEMSET 708 692 /** ··· 967 1141 return check_bytes8(start, value, bytes % 8); 968 1142 } 969 1143 EXPORT_SYMBOL(memchr_inv); 970 - 971 - /** 972 - * strreplace - Replace all occurrences of character in string. 973 - * @s: The string to operate on. 974 - * @old: The character being replaced. 975 - * @new: The character @old is replaced with. 976 - * 977 - * Returns pointer to the nul byte at the end of @s. 978 - */ 979 - char *strreplace(char *s, char old, char new) 980 - { 981 - for (; *s; ++s) 982 - if (*s == old) 983 - *s = new; 984 - return s; 985 - } 986 - EXPORT_SYMBOL(strreplace); 987 - 988 - void fortify_panic(const char *name) 989 - { 990 - pr_emerg("detected buffer overflow in %s\n", name); 991 - BUG(); 992 - } 993 - EXPORT_SYMBOL(fortify_panic);
+193
lib/string_helpers.c
··· 696 696 kfree(array); 697 697 } 698 698 EXPORT_SYMBOL_GPL(kfree_strarray); 699 + 700 + /** 701 + * strscpy_pad() - Copy a C-string into a sized buffer 702 + * @dest: Where to copy the string to 703 + * @src: Where to copy the string from 704 + * @count: Size of destination buffer 705 + * 706 + * Copy the string, or as much of it as fits, into the dest buffer. The 707 + * behavior is undefined if the string buffers overlap. The destination 708 + * buffer is always %NUL terminated, unless it's zero-sized. 709 + * 710 + * If the source string is shorter than the destination buffer, zeros 711 + * the tail of the destination buffer. 712 + * 713 + * For full explanation of why you may want to consider using the 714 + * 'strscpy' functions please see the function docstring for strscpy(). 715 + * 716 + * Returns: 717 + * * The number of characters copied (not including the trailing %NUL) 718 + * * -E2BIG if count is 0 or @src was truncated. 719 + */ 720 + ssize_t strscpy_pad(char *dest, const char *src, size_t count) 721 + { 722 + ssize_t written; 723 + 724 + written = strscpy(dest, src, count); 725 + if (written < 0 || written == count - 1) 726 + return written; 727 + 728 + memset(dest + written + 1, 0, count - written - 1); 729 + 730 + return written; 731 + } 732 + EXPORT_SYMBOL(strscpy_pad); 733 + 734 + /** 735 + * skip_spaces - Removes leading whitespace from @str. 736 + * @str: The string to be stripped. 737 + * 738 + * Returns a pointer to the first non-whitespace character in @str. 739 + */ 740 + char *skip_spaces(const char *str) 741 + { 742 + while (isspace(*str)) 743 + ++str; 744 + return (char *)str; 745 + } 746 + EXPORT_SYMBOL(skip_spaces); 747 + 748 + /** 749 + * strim - Removes leading and trailing whitespace from @s. 750 + * @s: The string to be stripped. 751 + * 752 + * Note that the first trailing whitespace is replaced with a %NUL-terminator 753 + * in the given string @s. Returns a pointer to the first non-whitespace 754 + * character in @s. 755 + */ 756 + char *strim(char *s) 757 + { 758 + size_t size; 759 + char *end; 760 + 761 + size = strlen(s); 762 + if (!size) 763 + return s; 764 + 765 + end = s + size - 1; 766 + while (end >= s && isspace(*end)) 767 + end--; 768 + *(end + 1) = '\0'; 769 + 770 + return skip_spaces(s); 771 + } 772 + EXPORT_SYMBOL(strim); 773 + 774 + /** 775 + * sysfs_streq - return true if strings are equal, modulo trailing newline 776 + * @s1: one string 777 + * @s2: another string 778 + * 779 + * This routine returns true iff two strings are equal, treating both 780 + * NUL and newline-then-NUL as equivalent string terminations. It's 781 + * geared for use with sysfs input strings, which generally terminate 782 + * with newlines but are compared against values without newlines. 783 + */ 784 + bool sysfs_streq(const char *s1, const char *s2) 785 + { 786 + while (*s1 && *s1 == *s2) { 787 + s1++; 788 + s2++; 789 + } 790 + 791 + if (*s1 == *s2) 792 + return true; 793 + if (!*s1 && *s2 == '\n' && !s2[1]) 794 + return true; 795 + if (*s1 == '\n' && !s1[1] && !*s2) 796 + return true; 797 + return false; 798 + } 799 + EXPORT_SYMBOL(sysfs_streq); 800 + 801 + /** 802 + * match_string - matches given string in an array 803 + * @array: array of strings 804 + * @n: number of strings in the array or -1 for NULL terminated arrays 805 + * @string: string to match with 806 + * 807 + * This routine will look for a string in an array of strings up to the 808 + * n-th element in the array or until the first NULL element. 809 + * 810 + * Historically the value of -1 for @n, was used to search in arrays that 811 + * are NULL terminated. However, the function does not make a distinction 812 + * when finishing the search: either @n elements have been compared OR 813 + * the first NULL element was found. 814 + * 815 + * Return: 816 + * index of a @string in the @array if matches, or %-EINVAL otherwise. 817 + */ 818 + int match_string(const char * const *array, size_t n, const char *string) 819 + { 820 + int index; 821 + const char *item; 822 + 823 + for (index = 0; index < n; index++) { 824 + item = array[index]; 825 + if (!item) 826 + break; 827 + if (!strcmp(item, string)) 828 + return index; 829 + } 830 + 831 + return -EINVAL; 832 + } 833 + EXPORT_SYMBOL(match_string); 834 + 835 + /** 836 + * __sysfs_match_string - matches given string in an array 837 + * @array: array of strings 838 + * @n: number of strings in the array or -1 for NULL terminated arrays 839 + * @str: string to match with 840 + * 841 + * Returns index of @str in the @array or -EINVAL, just like match_string(). 842 + * Uses sysfs_streq instead of strcmp for matching. 843 + * 844 + * This routine will look for a string in an array of strings up to the 845 + * n-th element in the array or until the first NULL element. 846 + * 847 + * Historically the value of -1 for @n, was used to search in arrays that 848 + * are NULL terminated. However, the function does not make a distinction 849 + * when finishing the search: either @n elements have been compared OR 850 + * the first NULL element was found. 851 + */ 852 + int __sysfs_match_string(const char * const *array, size_t n, const char *str) 853 + { 854 + const char *item; 855 + int index; 856 + 857 + for (index = 0; index < n; index++) { 858 + item = array[index]; 859 + if (!item) 860 + break; 861 + if (sysfs_streq(item, str)) 862 + return index; 863 + } 864 + 865 + return -EINVAL; 866 + } 867 + EXPORT_SYMBOL(__sysfs_match_string); 868 + 869 + /** 870 + * strreplace - Replace all occurrences of character in string. 871 + * @s: The string to operate on. 872 + * @old: The character being replaced. 873 + * @new: The character @old is replaced with. 874 + * 875 + * Returns pointer to the nul byte at the end of @s. 876 + */ 877 + char *strreplace(char *s, char old, char new) 878 + { 879 + for (; *s; ++s) 880 + if (*s == old) 881 + *s = new; 882 + return s; 883 + } 884 + EXPORT_SYMBOL(strreplace); 885 + 886 + void fortify_panic(const char *name) 887 + { 888 + pr_emerg("detected buffer overflow in %s\n", name); 889 + BUG(); 890 + } 891 + EXPORT_SYMBOL(fortify_panic);