diff options
| author | Kees Cook <kees@kernel.org> | 2026-03-23 01:27:25 +0000 |
|---|---|---|
| committer | Kees Cook <kees@kernel.org> | 2026-06-18 16:39:31 -0700 |
| commit | 079a028d6327e68cfa5d38b36123637b321c19a7 (patch) | |
| tree | d6bed2ef9b0f5969d1105f010d8b4a8804a13f61 /include/linux | |
| parent | 58c4ce8cd6cd1fbf1bca2e1d1f42f9e2899fa934 (diff) | |
| download | lwn-079a028d6327e68cfa5d38b36123637b321c19a7.tar.gz lwn-079a028d6327e68cfa5d38b36123637b321c19a7.zip | |
string: Remove strncpy() from the kernel
strncpy() has been a persistent source of bugs due to its ambiguous
intended usage and frequently counter-intuitive semantics: it may not
NUL-terminate the destination, and it unconditionally zero-pads to the
full length, which isn't always needed. All former callers have been
migrated[1] to:
- strscpy() for NUL-terminated destinations
- strscpy_pad() for NUL-terminated destinations needing zero-padding
- strtomem_pad() for non-NUL-terminated fixed-width fields
- memcpy_and_pad() for bounded copies with explicit padding
- memcpy() for known-length copies
Remove the generic implementation, its declaration, the FORTIFY_SOURCE
wrapper, and associated tests.
Link: https://github.com/KSPP/linux/issues/90 [1]
Signed-off-by: Kees Cook <kees@kernel.org>
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/fortify-string.h | 49 | ||||
| -rw-r--r-- | include/linux/string.h | 3 |
2 files changed, 0 insertions, 52 deletions
diff --git a/include/linux/fortify-string.h b/include/linux/fortify-string.h index 171982e53c9a..cf841dc71fef 100644 --- a/include/linux/fortify-string.h +++ b/include/linux/fortify-string.h @@ -26,7 +26,6 @@ #define FORTIFY_WRITE 1 #define EACH_FORTIFY_FUNC(macro) \ - macro(strncpy), \ macro(strnlen), \ macro(strlen), \ macro(strscpy), \ @@ -95,8 +94,6 @@ extern char *__underlying_strcat(char *p, const char *q) __RENAME(strcat); extern char *__underlying_strcpy(char *p, const char *q) __RENAME(strcpy); extern __kernel_size_t __underlying_strlen(const char *p) __RENAME(strlen); extern char *__underlying_strncat(char *p, const char *q, __kernel_size_t count) __RENAME(strncat); -extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size) __RENAME(strncpy); - #else #if defined(__SANITIZE_MEMORY__) @@ -120,7 +117,6 @@ extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size) #define __underlying_strcpy __builtin_strcpy #define __underlying_strlen __builtin_strlen #define __underlying_strncat __builtin_strncat -#define __underlying_strncpy __builtin_strncpy #endif @@ -159,50 +155,6 @@ extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size) (bounds) < (length) \ ) -/** - * strncpy - Copy a string to memory with non-guaranteed NUL padding - * - * @p: pointer to destination of copy - * @q: pointer to NUL-terminated source string to copy - * @size: bytes to write at @p - * - * If strlen(@q) >= @size, the copy of @q will stop after @size bytes, - * and @p will NOT be NUL-terminated - * - * If strlen(@q) < @size, following the copy of @q, trailing NUL bytes - * will be written to @p until @size total bytes have been written. - * - * Do not use this function. While FORTIFY_SOURCE tries to avoid - * over-reads of @q, it cannot defend against writing unterminated - * results to @p. Using strncpy() remains ambiguous and fragile. - * Instead, please choose an alternative, so that the expectation - * of @p's contents is unambiguous: - * - * +--------------------+--------------------+------------+ - * | **p** needs to be: | padded to **size** | not padded | - * +====================+====================+============+ - * | NUL-terminated | strscpy_pad() | strscpy() | - * +--------------------+--------------------+------------+ - * | not NUL-terminated | strtomem_pad() | strtomem() | - * +--------------------+--------------------+------------+ - * - * Note strscpy*()'s differing return values for detecting truncation, - * and strtomem*()'s expectation that the destination is marked with - * __nonstring when it is a character array. - * - */ -__FORTIFY_INLINE __diagnose_as(__builtin_strncpy, 1, 2, 3) -char *strncpy(char * const POS p, const char *q, __kernel_size_t size) -{ - const size_t p_size = __member_size(p); - - if (__compiletime_lessthan(p_size, size)) - __write_overflow(); - if (p_size < size) - fortify_panic(FORTIFY_FUNC_strncpy, FORTIFY_WRITE, p_size, size, p); - return __underlying_strncpy(p, q, size); -} - extern __kernel_size_t __real_strnlen(const char *, __kernel_size_t) __RENAME(strnlen); /** * strnlen - Return bounded count of characters in a NUL-terminated string @@ -809,7 +761,6 @@ char *strcpy(char * const POS p, const char * const POS q) #undef __underlying_strcpy #undef __underlying_strlen #undef __underlying_strncat -#undef __underlying_strncpy #undef POS #undef POS0 diff --git a/include/linux/string.h b/include/linux/string.h index b850bd91b3d8..5702daca4326 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -67,9 +67,6 @@ void *vmemdup_array_user(const void __user *src, size_t n, size_t size) #ifndef __HAVE_ARCH_STRCPY extern char * strcpy(char *,const char *); #endif -#ifndef __HAVE_ARCH_STRNCPY -extern char * strncpy(char *,const char *, __kernel_size_t); -#endif ssize_t sized_strscpy(char *, const char *, size_t); /* |
