Commit f478898e authored by Kees Cook's avatar Kees Cook
Browse files

string: Redefine strscpy_pad() as a macro



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: default avatarJustin Stitt <justinstitt@google.com>
Signed-off-by: default avatarKees Cook <keescook@chromium.org>
parent 557f8c58
Loading
Loading
Loading
Loading
+31 −2
Original line number Diff line number Diff line
@@ -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 *);
+0 −34
Original line number Diff line number Diff line
@@ -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.