Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

lib/string: Add strscpy_pad() function

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>

authored by

Tobin C. Harding and committed by
Shuah Khan
458a3bf8 6b1a4d5b

+44 -7
+4
include/linux/string.h
··· 31 31 #ifndef __HAVE_ARCH_STRSCPY 32 32 ssize_t strscpy(char *, const char *, size_t); 33 33 #endif 34 + 35 + /* Wraps calls to strscpy()/memset(), no arch specific code required */ 36 + ssize_t strscpy_pad(char *dest, const char *src, size_t count); 37 + 34 38 #ifndef __HAVE_ARCH_STRCAT 35 39 extern char * strcat(char *, const char *); 36 40 #endif
+40 -7
lib/string.c
··· 159 159 * @src: Where to copy the string from 160 160 * @count: Size of destination buffer 161 161 * 162 - * Copy the string, or as much of it as fits, into the dest buffer. 163 - * The routine returns the number of characters copied (not including 164 - * the trailing NUL) or -E2BIG if the destination buffer wasn't big enough. 165 - * The behavior is undefined if the string buffers overlap. 166 - * The destination buffer is always NUL terminated, unless it's zero-sized. 162 + * Copy the string, or as much of it as fits, into the dest buffer. The 163 + * behavior is undefined if the string buffers overlap. The destination 164 + * buffer is always NUL terminated, unless it's zero-sized. 167 165 * 168 166 * Preferred to strlcpy() since the API doesn't require reading memory 169 167 * from the src string beyond the specified "count" bytes, and since ··· 171 173 * 172 174 * Preferred to strncpy() since it always returns a valid string, and 173 175 * doesn't unnecessarily force the tail of the destination buffer to be 174 - * zeroed. If the zeroing is desired, it's likely cleaner to use strscpy() 175 - * with an overflow test, then just memset() the tail of the dest buffer. 176 + * zeroed. If zeroing is desired please use strscpy_pad(). 177 + * 178 + * Return: The number of characters copied (not including the trailing 179 + * %NUL) or -E2BIG if the destination buffer wasn't big enough. 176 180 */ 177 181 ssize_t strscpy(char *dest, const char *src, size_t count) 178 182 { ··· 236 236 } 237 237 EXPORT_SYMBOL(strscpy); 238 238 #endif 239 + 240 + /** 241 + * strscpy_pad() - Copy a C-string into a sized buffer 242 + * @dest: Where to copy the string to 243 + * @src: Where to copy the string from 244 + * @count: Size of destination buffer 245 + * 246 + * Copy the string, or as much of it as fits, into the dest buffer. The 247 + * behavior is undefined if the string buffers overlap. The destination 248 + * buffer is always %NUL terminated, unless it's zero-sized. 249 + * 250 + * If the source string is shorter than the destination buffer, zeros 251 + * the tail of the destination buffer. 252 + * 253 + * For full explanation of why you may want to consider using the 254 + * 'strscpy' functions please see the function docstring for strscpy(). 255 + * 256 + * Return: The number of characters copied (not including the trailing 257 + * %NUL) or -E2BIG if the destination buffer wasn't big enough. 258 + */ 259 + ssize_t strscpy_pad(char *dest, const char *src, size_t count) 260 + { 261 + ssize_t written; 262 + 263 + written = strscpy(dest, src, count); 264 + if (written < 0 || written == count - 1) 265 + return written; 266 + 267 + memset(dest + written + 1, 0, count - written - 1); 268 + 269 + return written; 270 + } 271 + EXPORT_SYMBOL(strscpy_pad); 239 272 240 273 #ifndef __HAVE_ARCH_STRCAT 241 274 /**