From 4797632f4f1d8af4e0670adcb97bf9800dc3beca Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 17 May 2021 20:16:57 -0700 Subject: [PATCH] string.h: Introduce memset_after() for wiping trailing members/padding 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 Cc: Herbert Xu Cc: "David S. Miller" Cc: Jakub Kicinski Cc: Andrew Morton Cc: Francis Laniel Cc: Vincenzo Frascino Cc: Daniel Axtens Cc: netdev@vger.kernel.org Signed-off-by: Kees Cook --- include/linux/string.h | 17 +++++++++++++++++ lib/memcpy_kunit.c | 13 +++++++++++++ 2 files changed, 30 insertions(+) diff --git a/include/linux/string.h b/include/linux/string.h index ac1c769a5a80..da490c2154a9 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -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 diff --git a/lib/memcpy_kunit.c b/lib/memcpy_kunit.c index 8b2109bb62df..5c5b4f3221d9 100644 --- a/lib/memcpy_kunit.c +++ b/lib/memcpy_kunit.c @@ -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 }