Add basic sanity checking for pathological "size" arguments to
memcpy(). Besides the run-time checking benefit, this avoids
GCC trying to be very smart about value range tracking[1] when
CONFIG_PROFILE_ALL_BRANCHES=y but FORTIFY_SOURCE=n.

Link: https://lore.kernel.org/all/202505191117.C094A90F88@keescook/ [1]
Reported-by: Randy Dunlap <[email protected]>
Closes: 
https://lore.kernel.org/all/[email protected]/
Tested-by: Randy Dunlap <[email protected]>
Signed-off-by: Kees Cook <[email protected]>
---
 v2: isolate this specifically to 32-bit x86 -- doing this generally is much 
more work
 v1: https://lore.kernel.org/lkml/[email protected]/
Cc: Ingo Molnar <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Dave Hansen <[email protected]>
Cc: <[email protected]>
Cc: "H. Peter Anvin" <[email protected]>
Cc: Randy Dunlap <[email protected]>
---
 arch/x86/include/asm/string_32.h | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/string_32.h b/arch/x86/include/asm/string_32.h
index 32c0d981a82a..6e8d100d1301 100644
--- a/arch/x86/include/asm/string_32.h
+++ b/arch/x86/include/asm/string_32.h
@@ -147,7 +147,14 @@ extern void *memcpy(void *, const void *, size_t);
 
 #ifndef CONFIG_FORTIFY_SOURCE
 
-#define memcpy(t, f, n) __builtin_memcpy(t, f, n)
+#define memcpy(t, f, n)                                        \
+       ({                                              \
+               typeof(n) __n = (n);                    \
+               /* Skip impossible sizes. */            \
+               if (!(__n < 0 || __n == SIZE_MAX))      \
+                       __builtin_memcpy(t, f, __n);    \
+               (t);                                    \
+       })
 
 #endif /* !CONFIG_FORTIFY_SOURCE */
 
-- 
2.34.1


Reply via email to