| From 322fc73a4c278c1ffb086f99f2e35c318d5a4baa Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 5 Apr 2019 12:58:58 +1100 |
| Subject: lib/string: Add strscpy_pad() function |
| |
| From: Tobin C. Harding <tobin@kernel.org> |
| |
| [ Upstream commit 458a3bf82df4fe1f951d0f52b1e0c1e9d5a88a3b ] |
| |
| We have a function to copy strings safely and we have a function to copy |
| strings and zero the tail of the destination (if source string is |
| shorter than destination buffer) but we do not have a function to do |
| both at once. This means developers must write this themselves if they |
| desire this functionality. This is a chore, and also leaves us open to |
| off by one errors unnecessarily. |
| |
| Add a function that calls strscpy() then memset()s the tail to zero if |
| the source string is shorter than the destination buffer. |
| |
| Acked-by: Kees Cook <keescook@chromium.org> |
| Signed-off-by: Tobin C. Harding <tobin@kernel.org> |
| Signed-off-by: Shuah Khan <shuah@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| include/linux/string.h | 4 ++++ |
| lib/string.c | 47 +++++++++++++++++++++++++++++++++++------- |
| 2 files changed, 44 insertions(+), 7 deletions(-) |
| |
| diff --git a/include/linux/string.h b/include/linux/string.h |
| index 870268d42ae7d..7da409760cf18 100644 |
| --- a/include/linux/string.h |
| +++ b/include/linux/string.h |
| @@ -28,6 +28,10 @@ size_t strlcpy(char *, const char *, size_t); |
| #ifndef __HAVE_ARCH_STRSCPY |
| 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); |
| + |
| #ifndef __HAVE_ARCH_STRCAT |
| extern char * strcat(char *, const char *); |
| #endif |
| diff --git a/lib/string.c b/lib/string.c |
| index 7f4baad6fb193..4351ec43cd6b8 100644 |
| --- a/lib/string.c |
| +++ b/lib/string.c |
| @@ -157,11 +157,9 @@ EXPORT_SYMBOL(strlcpy); |
| * @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 routine returns the number of characters copied (not including |
| - * the trailing NUL) or -E2BIG if the destination buffer wasn't big enough. |
| - * The behavior is undefined if the string buffers overlap. |
| - * The destination buffer is always NUL terminated, unless it's zero-sized. |
| + * 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. |
| * |
| * Preferred to strlcpy() since the API doesn't require reading memory |
| * from the src string beyond the specified "count" bytes, and since |
| @@ -171,8 +169,10 @@ EXPORT_SYMBOL(strlcpy); |
| * |
| * Preferred to strncpy() since it always returns a valid string, and |
| * doesn't unnecessarily force the tail of the destination buffer to be |
| - * zeroed. If the zeroing is desired, it's likely cleaner to use strscpy() |
| - * with an overflow test, then just memset() the tail of the dest buffer. |
| + * zeroed. If zeroing is desired please use strscpy_pad(). |
| + * |
| + * Return: The number of characters copied (not including the trailing |
| + * %NUL) or -E2BIG if the destination buffer wasn't big enough. |
| */ |
| ssize_t strscpy(char *dest, const char *src, size_t count) |
| { |
| @@ -259,6 +259,39 @@ char *stpcpy(char *__restrict__ dest, const char *__restrict__ src) |
| } |
| EXPORT_SYMBOL(stpcpy); |
| |
| +/** |
| + * 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(). |
| + * |
| + * Return: The number of characters copied (not including the trailing |
| + * %NUL) or -E2BIG if the destination buffer wasn't big enough. |
| + */ |
| +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); |
| + |
| #ifndef __HAVE_ARCH_STRCAT |
| /** |
| * strcat - Append one %NUL-terminated string to another |
| -- |
| 2.27.0 |
| |