mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 00:28:52 +02:00 
			
		
		
		
	string: Allow 2-argument strscpy()
Using sizeof(dst) for the "size" argument in strscpy() is the
overwhelmingly common case. Instead of requiring this everywhere, allow a
2-argument version to be used that will use the sizeof() internally. There
are other functions in the kernel with optional arguments[1], so this
isn't unprecedented, and improves readability. Update and relocate the
kern-doc for strscpy() too, and drop __HAVE_ARCH_STRSCPY as it is unused.
Adjust ARCH=um build to notice the changed export name, as it doesn't
do full header includes for the string helpers.
This could additionally let us save a few hundred lines of code:
 1177 files changed, 2455 insertions(+), 3026 deletions(-)
with a treewide cleanup using Coccinelle:
@needless_arg@
expression DST, SRC;
@@
        strscpy(DST, SRC
-, sizeof(DST)
        )
Link: https://elixir.bootlin.com/linux/v6.7/source/include/linux/pci.h#L1517 [1]
Reviewed-by: Justin Stitt <justinstitt@google.com>
Cc: Andy Shevchenko <andy@kernel.org>
Cc: linux-hardening@vger.kernel.org
Signed-off-by: Kees Cook <keescook@chromium.org>
			
			
This commit is contained in:
		
							parent
							
								
									f478898e0a
								
							
						
					
					
						commit
						e6584c3964
					
				
					 4 changed files with 41 additions and 28 deletions
				
			
		|  | @ -51,7 +51,8 @@ static inline int printk(const char *fmt, ...) | |||
| 
 | ||||
| extern int in_aton(char *str); | ||||
| extern size_t strlcat(char *, const char *, size_t); | ||||
| extern size_t strscpy(char *, const char *, size_t); | ||||
| extern size_t sized_strscpy(char *, const char *, size_t); | ||||
| #define strscpy(dst, src, size)	sized_strscpy(dst, src, size) | ||||
| 
 | ||||
| /* Copied from linux/compiler-gcc.h since we can't include it directly */ | ||||
| #define barrier() __asm__ __volatile__("": : :"memory") | ||||
|  |  | |||
|  | @ -215,26 +215,8 @@ __kernel_size_t __fortify_strlen(const char * const POS p) | |||
| } | ||||
| 
 | ||||
| /* Defined after fortified strnlen() to reuse it. */ | ||||
| extern ssize_t __real_strscpy(char *, const char *, size_t) __RENAME(strscpy); | ||||
| /**
 | ||||
|  * strscpy - Copy a C-string into a sized buffer | ||||
|  * | ||||
|  * @p: Where to copy the string to | ||||
|  * @q: Where to copy the string from | ||||
|  * @size: Size of destination buffer | ||||
|  * | ||||
|  * Copy the source string @q, or as much of it as fits, into the destination | ||||
|  * @p buffer. The behavior is undefined if the string buffers overlap. The | ||||
|  * destination @p buffer is always NUL terminated, unless it's zero-sized. | ||||
|  * | ||||
|  * Preferred to strncpy() since it always returns a valid string, and | ||||
|  * doesn't unnecessarily force the tail of the destination buffer to be | ||||
|  * zero padded. If padding is desired please use strscpy_pad(). | ||||
|  * | ||||
|  * Returns the number of characters copied in @p (not including the | ||||
|  * trailing %NUL) or -E2BIG if @size is 0 or the copy of @q was truncated. | ||||
|  */ | ||||
| __FORTIFY_INLINE ssize_t strscpy(char * const POS p, const char * const POS q, size_t size) | ||||
| extern ssize_t __real_strscpy(char *, const char *, size_t) __RENAME(sized_strscpy); | ||||
| __FORTIFY_INLINE ssize_t sized_strscpy(char * const POS p, const char * const POS q, size_t size) | ||||
| { | ||||
| 	/* Use string size rather than possible enclosing struct size. */ | ||||
| 	const size_t p_size = __member_size(p); | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| #ifndef _LINUX_STRING_H_ | ||||
| #define _LINUX_STRING_H_ | ||||
| 
 | ||||
| #include <linux/args.h> | ||||
| #include <linux/array_size.h> | ||||
| #include <linux/compiler.h>	/* for inline */ | ||||
| #include <linux/types.h>	/* for size_t */ | ||||
|  | @ -66,9 +67,40 @@ extern char * strcpy(char *,const char *); | |||
| #ifndef __HAVE_ARCH_STRNCPY | ||||
| extern char * strncpy(char *,const char *, __kernel_size_t); | ||||
| #endif | ||||
| #ifndef __HAVE_ARCH_STRSCPY | ||||
| ssize_t strscpy(char *, const char *, size_t); | ||||
| #endif | ||||
| ssize_t sized_strscpy(char *, const char *, size_t); | ||||
| 
 | ||||
| /*
 | ||||
|  * The 2 argument style can only be used when dst is an array with a | ||||
|  * known size. | ||||
|  */ | ||||
| #define __strscpy0(dst, src, ...)	\ | ||||
| 	sized_strscpy(dst, src, sizeof(dst) + __must_be_array(dst)) | ||||
| #define __strscpy1(dst, src, size)	sized_strscpy(dst, src, size) | ||||
| 
 | ||||
| /**
 | ||||
|  * strscpy - Copy a C-string into a sized buffer | ||||
|  * @dst: Where to copy the string to | ||||
|  * @src: Where to copy the string from | ||||
|  * @...: Size of destination buffer (optional) | ||||
|  * | ||||
|  * Copy the source string @src, or as much of it as fits, into the | ||||
|  * destination @dst buffer. The behavior is undefined if the string | ||||
|  * buffers overlap. The destination @dst buffer is always NUL terminated, | ||||
|  * unless it's zero-sized. | ||||
|  * | ||||
|  * The size argument @... is only required when @dst is not an array, or | ||||
|  * when the copy needs to be smaller than sizeof(@dst). | ||||
|  * | ||||
|  * Preferred to strncpy() since it always returns a valid string, and | ||||
|  * doesn't unnecessarily force the tail of the destination buffer to be | ||||
|  * zero padded. If padding is desired please use strscpy_pad(). | ||||
|  * | ||||
|  * Returns the number of characters copied in @dst (not including the | ||||
|  * trailing %NUL) or -E2BIG if @size is 0 or the copy from @src was | ||||
|  * truncated. | ||||
|  */ | ||||
| #define strscpy(dst, src, ...)	\ | ||||
| 	CONCATENATE(__strscpy, COUNT_ARGS(__VA_ARGS__))(dst, src, __VA_ARGS__) | ||||
| 
 | ||||
| /**
 | ||||
|  * strscpy_pad() - Copy a C-string into a sized buffer | ||||
|  |  | |||
|  | @ -104,8 +104,7 @@ char *strncpy(char *dest, const char *src, size_t count) | |||
| EXPORT_SYMBOL(strncpy); | ||||
| #endif | ||||
| 
 | ||||
| #ifndef __HAVE_ARCH_STRSCPY | ||||
| ssize_t strscpy(char *dest, const char *src, size_t count) | ||||
| ssize_t sized_strscpy(char *dest, const char *src, size_t count) | ||||
| { | ||||
| 	const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS; | ||||
| 	size_t max = count; | ||||
|  | @ -171,8 +170,7 @@ ssize_t strscpy(char *dest, const char *src, size_t count) | |||
| 
 | ||||
| 	return -E2BIG; | ||||
| } | ||||
| EXPORT_SYMBOL(strscpy); | ||||
| #endif | ||||
| EXPORT_SYMBOL(sized_strscpy); | ||||
| 
 | ||||
| /**
 | ||||
|  * stpcpy - copy a string from src to dest returning a pointer to the new end | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Kees Cook
						Kees Cook