History

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.

Kees Cook committed 7 months ago

Commit 079a0281 parent 58c4ce88 files · +28 −160Browse files

Showing the changes to include (2 of 8 files). Show all

Unified · Split

2 files
  1. include/linux/fortify-string.h +0 −49
  2. include/linux/string.h +0 −3
include/linux/fortify-string.h+0−49
@@ -26,7 +26,6 @@ · 25 unmodified lines
2626 #define FORTIFY_WRITE 1
2727
2828 #define EACH_FORTIFY_FUNC(macro) \
29− macro(strncpy), \
3029 macro(strnlen), \
3130 macro(strlen), \
3231 macro(strscpy), \
@@ -95,8 +94,6 @@ extern char *__underlying_strcat(char *p, const char *q) __RENAME(strcat); · 62 unmodified lines
9594 extern char *__underlying_strcpy(char *p, const char *q) __RENAME(strcpy);
9695 extern __kernel_size_t __underlying_strlen(const char *p) __RENAME(strlen);
9796 extern char *__underlying_strncat(char *p, const char *q, __kernel_size_t count) __RENAME(strncat);
98−extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size) __RENAME(strncpy);
99−
10097 #else
10198
10299 #if defined(__SANITIZE_MEMORY__)
@@ -120,7 +117,6 @@ extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size) · 17 unmodified lines
120117 #define __underlying_strcpy __builtin_strcpy
121118 #define __underlying_strlen __builtin_strlen
122119 #define __underlying_strncat __builtin_strncat
123−#define __underlying_strncpy __builtin_strncpy
124120
125121 #endif
126122
@@ -159,50 +155,6 @@ extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size) · 32 unmodified lines
159155 (bounds) < (length) \
160156 )
161157
162−/**
163− * strncpy - Copy a string to memory with non-guaranteed NUL padding
164− *
165− * @p: pointer to destination of copy
166− * @q: pointer to NUL-terminated source string to copy
167− * @size: bytes to write at @p
168− *
169− * If strlen(@q) >= @size, the copy of @q will stop after @size bytes,
170− * and @p will NOT be NUL-terminated
171− *
172− * If strlen(@q) < @size, following the copy of @q, trailing NUL bytes
173− * will be written to @p until @size total bytes have been written.
174− *
175− * Do not use this function. While FORTIFY_SOURCE tries to avoid
176− * over-reads of @q, it cannot defend against writing unterminated
177− * results to @p. Using strncpy() remains ambiguous and fragile.
178− * Instead, please choose an alternative, so that the expectation
179− * of @p's contents is unambiguous:
180− *
181− * +--------------------+--------------------+------------+
182− * | **p** needs to be: | padded to **size** | not padded |
183− * +====================+====================+============+
184− * | NUL-terminated | strscpy_pad() | strscpy() |
185− * +--------------------+--------------------+------------+
186− * | not NUL-terminated | strtomem_pad() | strtomem() |
187− * +--------------------+--------------------+------------+
188− *
189− * Note strscpy*()'s differing return values for detecting truncation,
190− * and strtomem*()'s expectation that the destination is marked with
191− * __nonstring when it is a character array.
192− *
193− */
194−__FORTIFY_INLINE __diagnose_as(__builtin_strncpy, 1, 2, 3)
195−char *strncpy(char * const POS p, const char *q, __kernel_size_t size)
196−{
197− const size_t p_size = __member_size(p);
198−
199− if (__compiletime_lessthan(p_size, size))
200− __write_overflow();
201− if (p_size < size)
202− fortify_panic(FORTIFY_FUNC_strncpy, FORTIFY_WRITE, p_size, size, p);
203− return __underlying_strncpy(p, q, size);
204−}
205−
206158 extern __kernel_size_t __real_strnlen(const char *, __kernel_size_t) __RENAME(strnlen);
207159 /**
208160 * 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) · 600 unmodified lines
809761 #undef __underlying_strcpy
810762 #undef __underlying_strlen
811763 #undef __underlying_strncat
812−#undef __underlying_strncpy
813764
814765 #undef POS
815766 #undef POS0
include/linux/string.h+0−3
@@ -67,9 +67,6 @@ void *vmemdup_array_user(const void __user *src, size_t n, size_t size) · 66 unmodified lines
6767 #ifndef __HAVE_ARCH_STRCPY
6868 extern char * strcpy(char *,const char *);
6969 #endif
70−#ifndef __HAVE_ARCH_STRNCPY
71−extern char * strncpy(char *,const char *, __kernel_size_t);
72−#endif
7370 ssize_t sized_strscpy(char *, const char *, size_t);
7471
7572 /*

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t