string.h: Introduce memset_after() for wiping trailing members/padding
authorKees Cook <keescook@chromium.org>
Tue, 18 May 2021 03:16:57 +0000 (20:16 -0700)
committerKees Cook <keescook@chromium.org>
Mon, 18 Oct 2021 19:28:52 +0000 (12:28 -0700)
A common idiom in kernel code is to wipe the contents of a structure
after a given member. This is especially useful in places where there is
trailing padding. These open-coded cases are usually difficult to read
and very sensitive to struct layout changes. Introduce a new helper,
memset_after() that takes the target struct instance, the byte to write,
and the member name after which the zeroing should start.

Cc: Steffen Klassert <steffen.klassert@secunet.com>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Jakub Kicinski <kuba@kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Francis Laniel <laniel_francis@privacyrequired.com>
Cc: Vincenzo Frascino <vincenzo.frascino@arm.com>
Cc: Daniel Axtens <dja@axtens.net>
Cc: netdev@vger.kernel.org
Signed-off-by: Kees Cook <keescook@chromium.org>
include/linux/string.h
lib/memcpy_kunit.c

index ac1c769..da490c2 100644 (file)
@@ -271,6 +271,23 @@ static inline void memcpy_and_pad(void *dest, size_t dest_len,
                memcpy(dest, src, dest_len);
 }
 
+/**
+ * memset_after - Set a value after a struct member to the end of a struct
+ *
+ * @obj: Address of target struct instance
+ * @v: Byte value to repeatedly write
+ * @member: after which struct member to start writing bytes
+ *
+ * This is good for clearing padding following the given member.
+ */
+#define memset_after(obj, v, member)                                   \
+({                                                                     \
+       u8 *__ptr = (u8 *)(obj);                                        \
+       typeof(v) __val = (v);                                          \
+       memset(__ptr + offsetofend(typeof(*(obj)), member), __val,      \
+              sizeof(*(obj)) - offsetofend(typeof(*(obj)), member));   \
+})
+
 /**
  * str_has_prefix - Test if a string has a given prefix
  * @str: The string to test
index 8b2109b..5c5b4f3 100644 (file)
@@ -215,6 +215,13 @@ static void memset_test(struct kunit *test)
                          0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
                        },
        };
+       struct some_bytes after = {
+               .data = { 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x72,
+                         0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72,
+                         0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72,
+                         0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72,
+                       },
+       };
        struct some_bytes dest = { };
        int count, value;
        u8 *ptr;
@@ -245,6 +252,12 @@ static void memset_test(struct kunit *test)
        ptr += 8;
        memset(ptr++, value++, count++);
        compare("argument side-effects", dest, three);
+
+       /* Verify memset_after() */
+       dest = control;
+       memset_after(&dest, 0x72, three);
+       compare("memset_after()", dest, after);
+
 #undef TEST_OP
 }