Patch "string.h: Introduce memtostr() and memtostr_pad()" has been added to the 6.8-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    string.h: Introduce memtostr() and memtostr_pad()

to the 6.8-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     string.h-introduce-memtostr-and-memtostr_pad.patch
and it can be found in the queue-6.8 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 24886cff3753f911e9ace4304613d5d72b3162d4
Author: Kees Cook <keescook@xxxxxxxxxxxx>
Date:   Tue Apr 9 19:31:50 2024 -0700

    string.h: Introduce memtostr() and memtostr_pad()
    
    [ Upstream commit 0efc5990bca540b8d438fda23db3a72efa733eb0 ]
    
    Another ambiguous use of strncpy() is to copy from strings that may not
    be NUL-terminated. These cases depend on having the destination buffer
    be explicitly larger than the source buffer's maximum size, having
    the size of the copy exactly match the source buffer's maximum size,
    and for the destination buffer to get explicitly NUL terminated.
    
    This usually happens when parsing protocols or hardware character arrays
    that are not guaranteed to be NUL-terminated. The code pattern is
    effectively this:
    
            char dest[sizeof(src) + 1];
    
            strncpy(dest, src, sizeof(src));
            dest[sizeof(dest) - 1] = '\0';
    
    In practice it usually looks like:
    
    struct from_hardware {
            ...
            char name[HW_NAME_SIZE] __nonstring;
            ...
    };
    
            struct from_hardware *p = ...;
            char name[HW_NAME_SIZE + 1];
    
            strncpy(name, p->name, HW_NAME_SIZE);
            name[NW_NAME_SIZE] = '\0';
    
    This cannot be replaced with:
    
            strscpy(name, p->name, sizeof(name));
    
    because p->name is smaller and not NUL-terminated, so FORTIFY will
    trigger when strnlen(p->name, sizeof(name)) is used. And it cannot be
    replaced with:
    
            strscpy(name, p->name, sizeof(p->name));
    
    because then "name" may contain a 1 character early truncation of
    p->name.
    
    Provide an unambiguous interface for converting a maybe not-NUL-terminated
    string to a NUL-terminated string, with compile-time buffer size checking
    so that it can never fail at runtime: memtostr() and memtostr_pad(). Also
    add KUnit tests for both.
    
    Link: https://lore.kernel.org/r/20240410023155.2100422-1-keescook@xxxxxxxxxxxx
    Signed-off-by: Kees Cook <keescook@xxxxxxxxxxxx>
    Stable-dep-of: 5bb288c4abc2 ("scsi: mptfusion: Avoid possible run-time warning with long manufacturer strings")
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/include/linux/string.h b/include/linux/string.h
index ab148d8dbfc14..a0e80e9e1ab5f 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -345,6 +345,55 @@ void memcpy_and_pad(void *dest, size_t dest_len, const void *src, size_t count,
 	memcpy(dest, src, strnlen(src, min(_src_len, _dest_len)));	\
 } while (0)
 
+/**
+ * memtostr - Copy a possibly non-NUL-term string to a NUL-term string
+ * @dest: Pointer to destination NUL-terminates string
+ * @src: Pointer to character array (likely marked as __nonstring)
+ *
+ * This is a replacement for strncpy() uses where the source is not
+ * a NUL-terminated string.
+ *
+ * Note that sizes of @dest and @src must be known at compile-time.
+ */
+#define memtostr(dest, src)	do {					\
+	const size_t _dest_len = __builtin_object_size(dest, 1);	\
+	const size_t _src_len = __builtin_object_size(src, 1);		\
+	const size_t _src_chars = strnlen(src, _src_len);		\
+	const size_t _copy_len = min(_dest_len - 1, _src_chars);	\
+									\
+	BUILD_BUG_ON(!__builtin_constant_p(_dest_len) ||		\
+		     !__builtin_constant_p(_src_len) ||			\
+		     _dest_len == 0 || _dest_len == (size_t)-1 ||	\
+		     _src_len == 0 || _src_len == (size_t)-1);		\
+	memcpy(dest, src, _copy_len);					\
+	dest[_copy_len] = '\0';						\
+} while (0)
+
+/**
+ * memtostr_pad - Copy a possibly non-NUL-term string to a NUL-term string
+ *                with NUL padding in the destination
+ * @dest: Pointer to destination NUL-terminates string
+ * @src: Pointer to character array (likely marked as __nonstring)
+ *
+ * This is a replacement for strncpy() uses where the source is not
+ * a NUL-terminated string.
+ *
+ * Note that sizes of @dest and @src must be known at compile-time.
+ */
+#define memtostr_pad(dest, src)		do {				\
+	const size_t _dest_len = __builtin_object_size(dest, 1);	\
+	const size_t _src_len = __builtin_object_size(src, 1);		\
+	const size_t _src_chars = strnlen(src, _src_len);		\
+	const size_t _copy_len = min(_dest_len - 1, _src_chars);	\
+									\
+	BUILD_BUG_ON(!__builtin_constant_p(_dest_len) ||		\
+		     !__builtin_constant_p(_src_len) ||			\
+		     _dest_len == 0 || _dest_len == (size_t)-1 ||	\
+		     _src_len == 0 || _src_len == (size_t)-1);		\
+	memcpy(dest, src, _copy_len);					\
+	memset(&dest[_copy_len], 0, _dest_len - _copy_len);		\
+} while (0)
+
 /**
  * memset_after - Set a value after a struct member to the end of a struct
  *




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux