Skip to content

Commit

Permalink
string: Allow 2-argument strscpy()
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Kees Cook committed Feb 21, 2024
1 parent f478898 commit e6584c3
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 28 deletions.
3 changes: 2 additions & 1 deletion arch/um/include/shared/user.h
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
22 changes: 2 additions & 20 deletions include/linux/fortify-string.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
38 changes: 35 additions & 3 deletions include/linux/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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
Expand Down
6 changes: 2 additions & 4 deletions lib/string.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit e6584c3

Please sign in to comment.