[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20210818060533.3569517-38-keescook@chromium.org>
Date: Tue, 17 Aug 2021 23:05:07 -0700
From: Kees Cook <keescook@...omium.org>
To: linux-kernel@...r.kernel.org
Cc: Kees Cook <keescook@...omium.org>,
Steffen Klassert <steffen.klassert@...unet.com>,
Herbert Xu <herbert@...dor.apana.org.au>,
"David S. Miller" <davem@...emloft.net>,
Jakub Kicinski <kuba@...nel.org>,
Andrew Morton <akpm@...ux-foundation.org>,
Francis Laniel <laniel_francis@...vacyrequired.com>,
Vincenzo Frascino <vincenzo.frascino@....com>,
Daniel Axtens <dja@...ens.net>, netdev@...r.kernel.org,
"Gustavo A. R. Silva" <gustavoars@...nel.org>,
Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
linux-wireless@...r.kernel.org, dri-devel@...ts.freedesktop.org,
linux-staging@...ts.linux.dev, linux-block@...r.kernel.org,
linux-kbuild@...r.kernel.org, clang-built-linux@...glegroups.com,
Rasmus Villemoes <linux@...musvillemoes.dk>,
linux-hardening@...r.kernel.org
Subject: [PATCH v2 37/63] 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.
Additionally adds memset_startat() for wiping trailing members _starting_
at a specific member instead of after a member, which is more readable
in certain circumstances, but doesn't include any preceding padding.
Cc: Steffen Klassert <steffen.klassert@...unet.com>
Cc: Herbert Xu <herbert@...dor.apana.org.au>
Cc: "David S. Miller" <davem@...emloft.net>
Cc: Jakub Kicinski <kuba@...nel.org>
Cc: Andrew Morton <akpm@...ux-foundation.org>
Cc: Francis Laniel <laniel_francis@...vacyrequired.com>
Cc: Vincenzo Frascino <vincenzo.frascino@....com>
Cc: Daniel Axtens <dja@...ens.net>
Cc: netdev@...r.kernel.org
Signed-off-by: Kees Cook <keescook@...omium.org>
---
include/linux/string.h | 29 +++++++++++++++++++++++++++++
lib/test_memcpy.c | 24 ++++++++++++++++++++++++
2 files changed, 53 insertions(+)
diff --git a/include/linux/string.h b/include/linux/string.h
index cbe889e404e2..fe56a1774207 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -272,6 +272,35 @@ static __always_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) do { \
+ memset((u8 *)(obj) + offsetofend(typeof(*(obj)), member), v, \
+ sizeof(*(obj)) - offsetofend(typeof(*(obj)), member)); \
+} while (0)
+
+/**
+ * memset_startat - Set a value starting at a member to the end of a struct
+ *
+ * @obj: Address of target struct instance
+ * @v: Byte value to repeatedly write
+ * @member: struct member to start writing at
+ *
+ * Note that if there is padding between the prior member and the target
+ * member, memset_after() should be used to clear the prior padding.
+ */
+#define memset_startat(obj, v, member) do { \
+ memset((u8 *)(obj) + offsetof(typeof(*(obj)), member), v, \
+ sizeof(*(obj)) - offsetof(typeof(*(obj)), member)); \
+} while (0)
+
/**
* str_has_prefix - Test if a string has a given prefix
* @str: The string to test
diff --git a/lib/test_memcpy.c b/lib/test_memcpy.c
index be192b8e82b7..50bc99552a17 100644
--- a/lib/test_memcpy.c
+++ b/lib/test_memcpy.c
@@ -215,6 +215,20 @@ 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 startat = {
+ .data = { 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79,
+ 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79,
+ 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79,
+ },
+ };
struct some_bytes dest = { };
int count, value;
u8 *ptr;
@@ -245,6 +259,16 @@ 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);
+
+ /* Verify memset_startat() */
+ dest = control;
+ memset_startat(&dest, 0x79, four);
+ compare("memset_startat()", dest, startat);
#undef TEST_OP
}
--
2.30.2
Powered by blists - more mailing lists