Re: linux-next: Tree for May 16 (security/landlock/ruleset.c)
From: Mickaël Salaün <mic@digikod.net>
Date: 2025-05-20 14:54:31
Also in:
linux-next, lkml
On Mon, May 19, 2025 at 12:15:30PM -0700, Kees Cook wrote:
On Mon, May 19, 2025 at 08:41:17PM +0200, Mickaël Salaün wrote:quoted
On Mon, May 19, 2025 at 11:19:53AM -0700, Kees Cook wrote:quoted
On Mon, May 19, 2025 at 05:29:30PM +0200, Mickaël Salaün wrote:quoted
On Fri, May 16, 2025 at 07:54:14PM -0700, Randy Dunlap wrote:quoted
On 5/16/25 3:24 AM, Stephen Rothwell wrote:quoted
Hi all, Changes since 20250515:Thanks for the report. It is the same warning as reported here: https://lore.kernel.org/all/202501040747.S3LYfvYq-lkp@intel.com/ (local) I don't know what the actual issue is though.quoted
on i386: In file included from ../arch/x86/include/asm/string.h:3, from ../include/linux/string.h:65, from ../include/linux/bitmap.h:13, from ../include/linux/cpumask.h:12, from ../include/linux/smp.h:13, from ../include/linux/lockdep.h:14, from ../security/landlock/ruleset.c:16: ../security/landlock/ruleset.c: In function 'create_rule': ../arch/x86/include/asm/string_32.h:150:25: warning: '__builtin_memcpy' accessing 4294967295 bytes at offsets 20 and 0 overlaps 6442450943 bytes at offset -2147483648 [-Wrestrict] 150 | #define memcpy(t, f, n) __builtin_memcpy(t, f, n) | ^~~~~~~~~~~~~~~~~~~~~~~~~ ../security/landlock/ruleset.c:137:9: note: in expansion of macro 'memcpy' 137 | memcpy(new_rule->layers, layers, | ^~~~~~ Full randconfig file is attached.The trigger appears to be CONFIG_PROFILE_ALL_BRANCHES, and GCC getting tricked into thinking check_mul_overflow() returns true: In file included from ../arch/x86/include/asm/string.h:3, from ../include/linux/string.h:65, from ../include/linux/bitmap.h:13, from ../include/linux/cpumask.h:12, from ../include/linux/smp.h:13, from ../include/linux/lockdep.h:14, from ../security/landlock/ruleset.c:16: ../security/landlock/ruleset.c: In function 'create_rule': ../arch/x86/include/asm/string_32.h:150:25: warning: '__builtin_memcpy' accessing 4294967295 bytes at offsets 0 and 0 overlaps 6442450943 bytes at offset -2147483648 [-Wrestrict] 150 | #define memcpy(t, f, n) __builtin_memcpy(t, f, n) | ^~~~~~~~~~~~~~~~~~~~~~~~~ ../security/landlock/ruleset.c:137:9: note: in expansion of macro 'memcpy' 137 | memcpy(new_rule->layers, layers, | ^~~~~~ 'create_rule': event 1 ../include/linux/compiler.h:69:46: 68 | (cond) ? \ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 69 | (__if_trace.miss_hit[1]++,1) : \ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~ | | | (1) when the condition is evaluated to true 70 | (__if_trace.miss_hit[0]++,0); \ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ../include/linux/compiler.h:57:69: note: in expansion of macro '__trace_if_value' 57 | #define __trace_if_var(cond) (__builtin_constant_p(cond) ? (cond) : __trace_if_value(cond)) | ^~~~~~~~~~~~~~~~ ../include/linux/compiler.h:55:28: note: in expansion of macro '__trace_if_var' 55 | #define if(cond, ...) if ( __trace_if_var( !!(cond , ## __VA_ARGS__) ) ) | ^~~~~~~~~~~~~~ ../include/linux/overflow.h:270:9: note: in expansion of macro 'if' 270 | if (check_mul_overflow(factor1, factor2, &bytes)) | ^~ 'create_rule': event 2 ../arch/x86/include/asm/string_32.h:150:25: 150 | #define memcpy(t, f, n) __builtin_memcpy(t, f, n) | ^~~~~~~~~~~~~~~~~~~~~~~~~ | | | (2) out of array bounds here ../security/landlock/ruleset.c:137:9: note: in expansion of macro 'memcpy' 137 | memcpy(new_rule->layers, layers, | ^~~~~~ make[1]: Leaving directory '/srv/code/gcc-bug'That's interesting...quoted
I'll take a look at ways to make either the overflow macros or memcpy robust against this kind of weirdness...Thanks!I'm doing some build testing, but the below patch makes GCC happy. Alternatively we could make CONFIG_PROFILE_ALL_BRANCHES=y depend on CONFIG_FORTIFY_SOURCE=y ... From 6fbf66fdfd0a7dac809b77faafdd72c60112bb8d Mon Sep 17 00:00:00 2001 From: Kees Cook <kees@kernel.org> Date: Mon, 19 May 2025 11:52:06 -0700 Subject: [PATCH] string.h: Provide basic sanity checks for fallback memcpy() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of defining memcpy() in terms of __builtin_memcpy() deep in arch/x86/include/asm/string_32.h, notice that it is needed up in the general string.h, as done with other common C String APIs. This allows us to 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.
It works for me but I couldn't reproduce the issue. I tried with CONFIG_PROFILE_ALL_BRANCHES=y and CONFIG_FORTIFY_SOURCE=n but it always works without a warning. I'm using GCC 15. Is it specific to a version of GCC?
quoted hunk ↗ jump to hunk
Link: https://lore.kernel.org/all/202505191117.C094A90F88@keescook/ (local) [1] Reported-by: kernel test robot <redacted> Closes: https://lore.kernel.org/all/202501040747.S3LYfvYq-lkp@intel.com/ (local) Reported-by: Randy Dunlap <redacted> Closes: https://lore.kernel.org/all/e3754f69-1dea-4542-8de0-a567a14fb95b@infradead.org/ (local) Signed-off-by: Kees Cook <kees@kernel.org> --- Cc: "Mickaël Salaün" <mic@digikod.net> Cc: Thomas Gleixner <redacted> Cc: Ingo Molnar <mingo@redhat.com> Cc: Borislav Petkov <bp@alien8.de> Cc: Dave Hansen <dave.hansen@linux.intel.com> Cc: <x86@kernel.org> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Andy Shevchenko <andy@kernel.org> Cc: Uros Bizjak <redacted> Cc: <redacted> --- arch/x86/include/asm/string_32.h | 6 ------ include/linux/string.h | 13 +++++++++++++ 2 files changed, 13 insertions(+), 6 deletions(-)diff --git a/arch/x86/include/asm/string_32.h b/arch/x86/include/asm/string_32.h index e9cce169bb4c..74397c95fa37 100644 --- a/arch/x86/include/asm/string_32.h +++ b/arch/x86/include/asm/string_32.h@@ -145,12 +145,6 @@ static __always_inline void *__constant_memcpy(void *to, const void *from, #define __HAVE_ARCH_MEMCPY extern void *memcpy(void *, const void *, size_t); -#ifndef CONFIG_FORTIFY_SOURCE - -#define memcpy(t, f, n) __builtin_memcpy(t, f, n) - -#endif /* !CONFIG_FORTIFY_SOURCE */ - #define __HAVE_ARCH_MEMMOVE void *memmove(void *dest, const void *src, size_t n);diff --git a/include/linux/string.h b/include/linux/string.h index 01621ad0f598..ffcee31a14f9 100644 --- a/include/linux/string.h +++ b/include/linux/string.h@@ -3,6 +3,7 @@ #define _LINUX_STRING_H_ #include <linux/args.h> +#include <linux/bug.h> #include <linux/array_size.h> #include <linux/cleanup.h> /* for DEFINE_FREE() */ #include <linux/compiler.h> /* for inline */@@ -390,7 +391,19 @@ static inline const char *kbasename(const char *path) #if !defined(__NO_FORTIFY) && defined(__OPTIMIZE__) && defined(CONFIG_FORTIFY_SOURCE) #include <linux/fortify-string.h> +#else +/* Basic sanity checking even without FORTIFY_SOURCE */ +# ifndef __HAVE_ARCH_MEMCPY +# define memcpy(t, f, n) \ + do { \ + typeof(n) __n = (n); \ + /* Skip impossible sizes. */ \ + if (!WARN_ON(__n < 0 || __n == SIZE_MAX)) \ + __builtin_memcpy(t, f, __n); \ + } while (0) +# endif #endif + #ifndef unsafe_memcpy #define unsafe_memcpy(dst, src, bytes, justification) \ memcpy(dst, src, bytes)-- 2.34.1 -- Kees Cook