History

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.

Kees Cook committed 5 years ago

Commit cfecea61 parent c80d92f7 files · +208 −204Browse files

Showing the changes to lib/string.c (1 of 7 files). Show all

Unified · Split

lib/string.c+6−204
@@ -6,20 +6,15 @@ · 5 unmodified lines
6 */6 */
7 7
8/*8/*
9 * stupid library routines.. The optimized versions should generally be found9 * 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
238EXPORT_SYMBOL(strscpy);233EXPORT_SYMBOL(strscpy);
239#endif234#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 */
261ssize_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}
273EXPORT_SYMBOL(strscpy_pad);
274
275/**236/**
276 * stpcpy - copy a string from src to dest returning a pointer to the new end237 * 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
514EXPORT_SYMBOL(strnchr);475EXPORT_SYMBOL(strnchr);
515#endif476#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 */
523char *skip_spaces(const char *str)
524{
525 while (isspace(*str))
526 ++str;
527 return (char *)str;
528}
529EXPORT_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 */
539char *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}
555EXPORT_SYMBOL(strim);
556
557#ifndef __HAVE_ARCH_STRLEN478#ifndef __HAVE_ARCH_STRLEN
558/**479/**
559 * strlen - Find the length of a string480 * strlen - Find the length of a string
@@ -688,101 +609,6 @@ char *strsep(char **s, const char *ct) · 128 unmodified lines
688EXPORT_SYMBOL(strsep);609EXPORT_SYMBOL(strsep);
689#endif610#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 */
701bool 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}
716EXPORT_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 */
735int 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}
750EXPORT_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 */
769int __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}
784EXPORT_SYMBOL(__sysfs_match_string);
785
786#ifndef __HAVE_ARCH_MEMSET612#ifndef __HAVE_ARCH_MEMSET
787/**613/**
788 * memset - Fill a region of memory with the given value614 * 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}
1143EXPORT_SYMBOL(memchr_inv);969EXPORT_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 */
1153char *strreplace(char *s, char old, char new)
1154{
1155 for (; *s; ++s)
1156 if (*s == old)
1157 *s = new;
1158 return s;
1159}
1160EXPORT_SYMBOL(strreplace);
1161
1162void fortify_panic(const char *name)
1163{
1164 pr_emerg("detected buffer overflow in %s\n", name);
1165 BUG();
1166}
1167EXPORT_SYMBOL(fortify_panic);