[PATCH 1/2] Add strscpy() as a new string copy primitive

From: Chris Metcalf
Date: Fri Aug 29 2014 - 14:42:14 EST


Both strncpy and strlcpy suffer from the fact that they do
partial copies of strings into the destination when the target
buffer is too small. This is frequently pointless since an
overflow of the target buffer may make the result invalid.

strncpy() makes it relatively hard to even detect the error
condition, and with strlcpy() you have to duplicate the buffer
size parameter to test to see if the result exceeds it.
By returning zero in the failure case, we both make testing
for it easy, and by simply not copying anything in that case,
we make it mandatory for callers to test the error code.

To catch lazy programmers who don't check, we also place a NUL at
the start of the destination buffer (if there is space) to
ensure that the result is an invalid string.

Reviewed-by: Randy Dunlap <rdunlap@xxxxxxxxxxxxx>
Reviewed-by: Rickard Strandqvist <rickard_strandqvist@xxxxxxxxxxxxxxxxxx>
Signed-off-by: Chris Metcalf <cmetcalf@xxxxxxxxxx>
---
include/linux/string.h | 3 +++
lib/string.c | 29 +++++++++++++++++++++++++++++
2 files changed, 32 insertions(+)

diff --git a/include/linux/string.h b/include/linux/string.h
index d36977e029af..b9e9b2b5f6c6 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -25,6 +25,9 @@ extern char * strncpy(char *,const char *, __kernel_size_t);
#ifndef __HAVE_ARCH_STRLCPY
size_t strlcpy(char *, const char *, size_t);
#endif
+#ifndef __HAVE_ARCH_STRSCPY
+size_t strscpy(char *, const char *, size_t);
+#endif
#ifndef __HAVE_ARCH_STRCAT
extern char * strcat(char *, const char *);
#endif
diff --git a/lib/string.c b/lib/string.c
index 992bf30af759..bbd67b3343dc 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -160,6 +160,35 @@ size_t strlcpy(char *dest, const char *src, size_t size)
EXPORT_SYMBOL(strlcpy);
#endif

+#ifndef __HAVE_ARCH_STRSCPY
+/**
+ * strscpy - Copy a C-string into a sized buffer, but only if it fits
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @size: size of destination buffer
+ *
+ * Use this routine to avoid copying too-long strings.
+ * The routine returns the total number of bytes copied
+ * (including the trailing NUL) or zero if the buffer wasn't
+ * big enough. To ensure that programmers pay attention
+ * to the return code, the destination has a single NUL
+ * written at the front (if size is non-zero) when the
+ * buffer is not big enough.
+ */
+size_t strscpy(char *dest, const char *src, size_t size)
+{
+ size_t len = strnlen(src, size) + 1;
+ if (len > size) {
+ if (size)
+ dest[0] = '\0';
+ return 0;
+ }
+ memcpy(dest, src, len);
+ return len;
+}
+EXPORT_SYMBOL(strscpy);
+#endif
+
#ifndef __HAVE_ARCH_STRCAT
/**
* strcat - Append one %NUL-terminated string to another
--
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/