string: Redefine strscpy_pad() as a macro
authorKees Cook <keescook@chromium.org>
Fri, 2 Feb 2024 11:18:14 +0000 (03:18 -0800)
committerKees Cook <keescook@chromium.org>
Wed, 21 Feb 2024 04:47:31 +0000 (20:47 -0800)
In preparation for making strscpy_pad()'s 3rd argument optional, redefine
it as a macro. This also has the benefit of allowing greater FORITFY
introspection, as it couldn't see into the strscpy() nor the memset()
within strscpy_pad().

Cc: Andy Shevchenko <andy@kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: <linux-hardening@vger.kernel.org>
Reviewed-by: Justin Stitt <justinstitt@google.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
include/linux/string.h
lib/string_helpers.c

index ab148d8dbfc146d2aed178b694f33506d06bfd05..78b28004c5ba761e6aa9cf514c2cbbee5ee8af1a 100644 (file)
@@ -70,8 +70,37 @@ extern char * strncpy(char *,const char *, __kernel_size_t);
 ssize_t strscpy(char *, const char *, size_t);
 #endif
 
-/* Wraps calls to strscpy()/memset(), no arch specific code required */
-ssize_t strscpy_pad(char *dest, const char *src, size_t count);
+/**
+ * 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, the
+ * remaining bytes in the buffer will be filled with %NUL bytes.
+ *
+ * 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 %NULs)
+ * * -E2BIG if count is 0 or @src was truncated.
+ */
+#define strscpy_pad(dest, src, count)  ({                      \
+       char *__dst = (dest);                                           \
+       const char *__src = (src);                                      \
+       const size_t __count = (count);                                 \
+       ssize_t __wrote;                                                \
+                                                                       \
+       __wrote = strscpy(__dst, __src, __count);                       \
+       if (__wrote >= 0 && __wrote < __count)                          \
+               memset(__dst + __wrote + 1, 0, __count - __wrote - 1);  \
+       __wrote;                                                        \
+})
 
 #ifndef __HAVE_ARCH_STRCAT
 extern char * strcat(char *, const char *);
index 7713f73e66b0f35ba40966f78694f7d4d6326b42..606c3099013fdd363098394adf88f4a679a03daa 100644 (file)
@@ -825,40 +825,6 @@ char **devm_kasprintf_strarray(struct device *dev, const char *prefix, size_t n)
 }
 EXPORT_SYMBOL_GPL(devm_kasprintf_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.