mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
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>
This commit is contained in:
parent
c80d92fbb6
commit
cfecea6ead
@ -5,6 +5,7 @@
|
|||||||
* Small subset of simple string routines
|
* Small subset of simple string routines
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define __NO_FORTIFY
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -8,6 +8,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define IN_ARCH_STRING_C 1
|
#define IN_ARCH_STRING_C 1
|
||||||
|
#ifndef __NO_FORTIFY
|
||||||
|
# define __NO_FORTIFY
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
#undef CONFIG_KASAN
|
#undef CONFIG_KASAN
|
||||||
#undef CONFIG_KASAN_GENERIC
|
#undef CONFIG_KASAN_GENERIC
|
||||||
|
|
||||||
|
#define __NO_FORTIFY
|
||||||
|
|
||||||
/* cpu_feature_enabled() cannot be used this early */
|
/* cpu_feature_enabled() cannot be used this early */
|
||||||
#define USE_EARLY_PGTABLE_L5
|
#define USE_EARLY_PGTABLE_L5
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
#include "misc.h"
|
||||||
#include <linux/efi.h>
|
#include <linux/efi.h>
|
||||||
#include <asm/e820/types.h>
|
#include <asm/e820/types.h>
|
||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
* strings.
|
* strings.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define __NO_FORTIFY
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
|
|
||||||
|
210
lib/string.c
210
lib/string.c
@ -6,20 +6,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* stupid library routines.. The optimized versions should generally be found
|
* This file should be used only for "library" routines that may have
|
||||||
* as inline code in <asm-xx/string.h>
|
* alternative implementations on specific architectures (generally
|
||||||
|
* found in <asm-xx/string.h>), or get overloaded by FORTIFY_SOURCE.
|
||||||
|
* (Specifically, this file is built with __NO_FORTIFY.)
|
||||||
*
|
*
|
||||||
* These are buggy as well..
|
* Other helper functions should live in string_helpers.c.
|
||||||
*
|
|
||||||
* * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de>
|
|
||||||
* - Added strsep() which will replace strtok() soon (because strsep() is
|
|
||||||
* reentrant and should be faster). Use only strsep() in new code, please.
|
|
||||||
*
|
|
||||||
* * Sat Feb 09 2002, Jason Thomas <jason@topic.com.au>,
|
|
||||||
* Matthew Hawkins <matt@mh.dropbear.id.au>
|
|
||||||
* - Kissed strtok() goodbye
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define __NO_FORTIFY
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/ctype.h>
|
#include <linux/ctype.h>
|
||||||
@ -238,40 +233,6 @@ ssize_t strscpy(char *dest, const char *src, size_t count)
|
|||||||
EXPORT_SYMBOL(strscpy);
|
EXPORT_SYMBOL(strscpy);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
|
||||||
* strscpy_pad() - Copy a C-string into a sized buffer
|
|
||||||
* @dest: Where to copy the string to
|
|
||||||
* @src: Where to copy the string from
|
|
||||||
* @count: Size of destination buffer
|
|
||||||
*
|
|
||||||
* Copy the string, or as much of it as fits, into the dest buffer. The
|
|
||||||
* behavior is undefined if the string buffers overlap. The destination
|
|
||||||
* buffer is always %NUL terminated, unless it's zero-sized.
|
|
||||||
*
|
|
||||||
* If the source string is shorter than the destination buffer, zeros
|
|
||||||
* the tail of the destination buffer.
|
|
||||||
*
|
|
||||||
* For full explanation of why you may want to consider using the
|
|
||||||
* 'strscpy' functions please see the function docstring for strscpy().
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* * The number of characters copied (not including the trailing %NUL)
|
|
||||||
* * -E2BIG if count is 0 or @src was truncated.
|
|
||||||
*/
|
|
||||||
ssize_t strscpy_pad(char *dest, const char *src, size_t count)
|
|
||||||
{
|
|
||||||
ssize_t written;
|
|
||||||
|
|
||||||
written = strscpy(dest, src, count);
|
|
||||||
if (written < 0 || written == count - 1)
|
|
||||||
return written;
|
|
||||||
|
|
||||||
memset(dest + written + 1, 0, count - written - 1);
|
|
||||||
|
|
||||||
return written;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(strscpy_pad);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* stpcpy - copy a string from src to dest returning a pointer to the new end
|
* stpcpy - copy a string from src to dest returning a pointer to the new end
|
||||||
* of dest, including src's %NUL-terminator. May overrun dest.
|
* of dest, including src's %NUL-terminator. May overrun dest.
|
||||||
@ -514,46 +475,6 @@ char *strnchr(const char *s, size_t count, int c)
|
|||||||
EXPORT_SYMBOL(strnchr);
|
EXPORT_SYMBOL(strnchr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
|
||||||
* skip_spaces - Removes leading whitespace from @str.
|
|
||||||
* @str: The string to be stripped.
|
|
||||||
*
|
|
||||||
* Returns a pointer to the first non-whitespace character in @str.
|
|
||||||
*/
|
|
||||||
char *skip_spaces(const char *str)
|
|
||||||
{
|
|
||||||
while (isspace(*str))
|
|
||||||
++str;
|
|
||||||
return (char *)str;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(skip_spaces);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* strim - Removes leading and trailing whitespace from @s.
|
|
||||||
* @s: The string to be stripped.
|
|
||||||
*
|
|
||||||
* Note that the first trailing whitespace is replaced with a %NUL-terminator
|
|
||||||
* in the given string @s. Returns a pointer to the first non-whitespace
|
|
||||||
* character in @s.
|
|
||||||
*/
|
|
||||||
char *strim(char *s)
|
|
||||||
{
|
|
||||||
size_t size;
|
|
||||||
char *end;
|
|
||||||
|
|
||||||
size = strlen(s);
|
|
||||||
if (!size)
|
|
||||||
return s;
|
|
||||||
|
|
||||||
end = s + size - 1;
|
|
||||||
while (end >= s && isspace(*end))
|
|
||||||
end--;
|
|
||||||
*(end + 1) = '\0';
|
|
||||||
|
|
||||||
return skip_spaces(s);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(strim);
|
|
||||||
|
|
||||||
#ifndef __HAVE_ARCH_STRLEN
|
#ifndef __HAVE_ARCH_STRLEN
|
||||||
/**
|
/**
|
||||||
* strlen - Find the length of a string
|
* strlen - Find the length of a string
|
||||||
@ -688,101 +609,6 @@ char *strsep(char **s, const char *ct)
|
|||||||
EXPORT_SYMBOL(strsep);
|
EXPORT_SYMBOL(strsep);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
|
||||||
* sysfs_streq - return true if strings are equal, modulo trailing newline
|
|
||||||
* @s1: one string
|
|
||||||
* @s2: another string
|
|
||||||
*
|
|
||||||
* This routine returns true iff two strings are equal, treating both
|
|
||||||
* NUL and newline-then-NUL as equivalent string terminations. It's
|
|
||||||
* geared for use with sysfs input strings, which generally terminate
|
|
||||||
* with newlines but are compared against values without newlines.
|
|
||||||
*/
|
|
||||||
bool sysfs_streq(const char *s1, const char *s2)
|
|
||||||
{
|
|
||||||
while (*s1 && *s1 == *s2) {
|
|
||||||
s1++;
|
|
||||||
s2++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*s1 == *s2)
|
|
||||||
return true;
|
|
||||||
if (!*s1 && *s2 == '\n' && !s2[1])
|
|
||||||
return true;
|
|
||||||
if (*s1 == '\n' && !s1[1] && !*s2)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(sysfs_streq);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* match_string - matches given string in an array
|
|
||||||
* @array: array of strings
|
|
||||||
* @n: number of strings in the array or -1 for NULL terminated arrays
|
|
||||||
* @string: string to match with
|
|
||||||
*
|
|
||||||
* This routine will look for a string in an array of strings up to the
|
|
||||||
* n-th element in the array or until the first NULL element.
|
|
||||||
*
|
|
||||||
* Historically the value of -1 for @n, was used to search in arrays that
|
|
||||||
* are NULL terminated. However, the function does not make a distinction
|
|
||||||
* when finishing the search: either @n elements have been compared OR
|
|
||||||
* the first NULL element was found.
|
|
||||||
*
|
|
||||||
* Return:
|
|
||||||
* index of a @string in the @array if matches, or %-EINVAL otherwise.
|
|
||||||
*/
|
|
||||||
int match_string(const char * const *array, size_t n, const char *string)
|
|
||||||
{
|
|
||||||
int index;
|
|
||||||
const char *item;
|
|
||||||
|
|
||||||
for (index = 0; index < n; index++) {
|
|
||||||
item = array[index];
|
|
||||||
if (!item)
|
|
||||||
break;
|
|
||||||
if (!strcmp(item, string))
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(match_string);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* __sysfs_match_string - matches given string in an array
|
|
||||||
* @array: array of strings
|
|
||||||
* @n: number of strings in the array or -1 for NULL terminated arrays
|
|
||||||
* @str: string to match with
|
|
||||||
*
|
|
||||||
* Returns index of @str in the @array or -EINVAL, just like match_string().
|
|
||||||
* Uses sysfs_streq instead of strcmp for matching.
|
|
||||||
*
|
|
||||||
* This routine will look for a string in an array of strings up to the
|
|
||||||
* n-th element in the array or until the first NULL element.
|
|
||||||
*
|
|
||||||
* Historically the value of -1 for @n, was used to search in arrays that
|
|
||||||
* are NULL terminated. However, the function does not make a distinction
|
|
||||||
* when finishing the search: either @n elements have been compared OR
|
|
||||||
* the first NULL element was found.
|
|
||||||
*/
|
|
||||||
int __sysfs_match_string(const char * const *array, size_t n, const char *str)
|
|
||||||
{
|
|
||||||
const char *item;
|
|
||||||
int index;
|
|
||||||
|
|
||||||
for (index = 0; index < n; index++) {
|
|
||||||
item = array[index];
|
|
||||||
if (!item)
|
|
||||||
break;
|
|
||||||
if (sysfs_streq(item, str))
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(__sysfs_match_string);
|
|
||||||
|
|
||||||
#ifndef __HAVE_ARCH_MEMSET
|
#ifndef __HAVE_ARCH_MEMSET
|
||||||
/**
|
/**
|
||||||
* memset - Fill a region of memory with the given value
|
* 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)
|
|||||||
return check_bytes8(start, value, bytes % 8);
|
return check_bytes8(start, value, bytes % 8);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(memchr_inv);
|
EXPORT_SYMBOL(memchr_inv);
|
||||||
|
|
||||||
/**
|
|
||||||
* strreplace - Replace all occurrences of character in string.
|
|
||||||
* @s: The string to operate on.
|
|
||||||
* @old: The character being replaced.
|
|
||||||
* @new: The character @old is replaced with.
|
|
||||||
*
|
|
||||||
* Returns pointer to the nul byte at the end of @s.
|
|
||||||
*/
|
|
||||||
char *strreplace(char *s, char old, char new)
|
|
||||||
{
|
|
||||||
for (; *s; ++s)
|
|
||||||
if (*s == old)
|
|
||||||
*s = new;
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(strreplace);
|
|
||||||
|
|
||||||
void fortify_panic(const char *name)
|
|
||||||
{
|
|
||||||
pr_emerg("detected buffer overflow in %s\n", name);
|
|
||||||
BUG();
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(fortify_panic);
|
|
||||||
|
@ -696,3 +696,196 @@ void kfree_strarray(char **array, size_t n)
|
|||||||
kfree(array);
|
kfree(array);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(kfree_strarray);
|
EXPORT_SYMBOL_GPL(kfree_strarray);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* strscpy_pad() - Copy a C-string into a sized buffer
|
||||||
|
* @dest: Where to copy the string to
|
||||||
|
* @src: Where to copy the string from
|
||||||
|
* @count: Size of destination buffer
|
||||||
|
*
|
||||||
|
* Copy the string, or as much of it as fits, into the dest buffer. The
|
||||||
|
* behavior is undefined if the string buffers overlap. The destination
|
||||||
|
* buffer is always %NUL terminated, unless it's zero-sized.
|
||||||
|
*
|
||||||
|
* If the source string is shorter than the destination buffer, zeros
|
||||||
|
* the tail of the destination buffer.
|
||||||
|
*
|
||||||
|
* For full explanation of why you may want to consider using the
|
||||||
|
* 'strscpy' functions please see the function docstring for strscpy().
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* * The number of characters copied (not including the trailing %NUL)
|
||||||
|
* * -E2BIG if count is 0 or @src was truncated.
|
||||||
|
*/
|
||||||
|
ssize_t strscpy_pad(char *dest, const char *src, size_t count)
|
||||||
|
{
|
||||||
|
ssize_t written;
|
||||||
|
|
||||||
|
written = strscpy(dest, src, count);
|
||||||
|
if (written < 0 || written == count - 1)
|
||||||
|
return written;
|
||||||
|
|
||||||
|
memset(dest + written + 1, 0, count - written - 1);
|
||||||
|
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(strscpy_pad);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* skip_spaces - Removes leading whitespace from @str.
|
||||||
|
* @str: The string to be stripped.
|
||||||
|
*
|
||||||
|
* Returns a pointer to the first non-whitespace character in @str.
|
||||||
|
*/
|
||||||
|
char *skip_spaces(const char *str)
|
||||||
|
{
|
||||||
|
while (isspace(*str))
|
||||||
|
++str;
|
||||||
|
return (char *)str;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(skip_spaces);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* strim - Removes leading and trailing whitespace from @s.
|
||||||
|
* @s: The string to be stripped.
|
||||||
|
*
|
||||||
|
* Note that the first trailing whitespace is replaced with a %NUL-terminator
|
||||||
|
* in the given string @s. Returns a pointer to the first non-whitespace
|
||||||
|
* character in @s.
|
||||||
|
*/
|
||||||
|
char *strim(char *s)
|
||||||
|
{
|
||||||
|
size_t size;
|
||||||
|
char *end;
|
||||||
|
|
||||||
|
size = strlen(s);
|
||||||
|
if (!size)
|
||||||
|
return s;
|
||||||
|
|
||||||
|
end = s + size - 1;
|
||||||
|
while (end >= s && isspace(*end))
|
||||||
|
end--;
|
||||||
|
*(end + 1) = '\0';
|
||||||
|
|
||||||
|
return skip_spaces(s);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(strim);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sysfs_streq - return true if strings are equal, modulo trailing newline
|
||||||
|
* @s1: one string
|
||||||
|
* @s2: another string
|
||||||
|
*
|
||||||
|
* This routine returns true iff two strings are equal, treating both
|
||||||
|
* NUL and newline-then-NUL as equivalent string terminations. It's
|
||||||
|
* geared for use with sysfs input strings, which generally terminate
|
||||||
|
* with newlines but are compared against values without newlines.
|
||||||
|
*/
|
||||||
|
bool sysfs_streq(const char *s1, const char *s2)
|
||||||
|
{
|
||||||
|
while (*s1 && *s1 == *s2) {
|
||||||
|
s1++;
|
||||||
|
s2++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*s1 == *s2)
|
||||||
|
return true;
|
||||||
|
if (!*s1 && *s2 == '\n' && !s2[1])
|
||||||
|
return true;
|
||||||
|
if (*s1 == '\n' && !s1[1] && !*s2)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(sysfs_streq);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* match_string - matches given string in an array
|
||||||
|
* @array: array of strings
|
||||||
|
* @n: number of strings in the array or -1 for NULL terminated arrays
|
||||||
|
* @string: string to match with
|
||||||
|
*
|
||||||
|
* This routine will look for a string in an array of strings up to the
|
||||||
|
* n-th element in the array or until the first NULL element.
|
||||||
|
*
|
||||||
|
* Historically the value of -1 for @n, was used to search in arrays that
|
||||||
|
* are NULL terminated. However, the function does not make a distinction
|
||||||
|
* when finishing the search: either @n elements have been compared OR
|
||||||
|
* the first NULL element was found.
|
||||||
|
*
|
||||||
|
* Return:
|
||||||
|
* index of a @string in the @array if matches, or %-EINVAL otherwise.
|
||||||
|
*/
|
||||||
|
int match_string(const char * const *array, size_t n, const char *string)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
const char *item;
|
||||||
|
|
||||||
|
for (index = 0; index < n; index++) {
|
||||||
|
item = array[index];
|
||||||
|
if (!item)
|
||||||
|
break;
|
||||||
|
if (!strcmp(item, string))
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(match_string);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __sysfs_match_string - matches given string in an array
|
||||||
|
* @array: array of strings
|
||||||
|
* @n: number of strings in the array or -1 for NULL terminated arrays
|
||||||
|
* @str: string to match with
|
||||||
|
*
|
||||||
|
* Returns index of @str in the @array or -EINVAL, just like match_string().
|
||||||
|
* Uses sysfs_streq instead of strcmp for matching.
|
||||||
|
*
|
||||||
|
* This routine will look for a string in an array of strings up to the
|
||||||
|
* n-th element in the array or until the first NULL element.
|
||||||
|
*
|
||||||
|
* Historically the value of -1 for @n, was used to search in arrays that
|
||||||
|
* are NULL terminated. However, the function does not make a distinction
|
||||||
|
* when finishing the search: either @n elements have been compared OR
|
||||||
|
* the first NULL element was found.
|
||||||
|
*/
|
||||||
|
int __sysfs_match_string(const char * const *array, size_t n, const char *str)
|
||||||
|
{
|
||||||
|
const char *item;
|
||||||
|
int index;
|
||||||
|
|
||||||
|
for (index = 0; index < n; index++) {
|
||||||
|
item = array[index];
|
||||||
|
if (!item)
|
||||||
|
break;
|
||||||
|
if (sysfs_streq(item, str))
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(__sysfs_match_string);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* strreplace - Replace all occurrences of character in string.
|
||||||
|
* @s: The string to operate on.
|
||||||
|
* @old: The character being replaced.
|
||||||
|
* @new: The character @old is replaced with.
|
||||||
|
*
|
||||||
|
* Returns pointer to the nul byte at the end of @s.
|
||||||
|
*/
|
||||||
|
char *strreplace(char *s, char old, char new)
|
||||||
|
{
|
||||||
|
for (; *s; ++s)
|
||||||
|
if (*s == old)
|
||||||
|
*s = new;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(strreplace);
|
||||||
|
|
||||||
|
void fortify_panic(const char *name)
|
||||||
|
{
|
||||||
|
pr_emerg("detected buffer overflow in %s\n", name);
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(fortify_panic);
|
||||||
|
Loading…
Reference in New Issue
Block a user