On Wed, Sep 16, 2026 at 11:17:36AM -0500, Andrey Ryabinin wrote: > "Mukesh Kumar Chaurasiya (IBM)" <[email protected]> writes: > > Hi, > I fed this patch to an AI for review, and the review results are included > below. > Please take a look. From my side, I agree with all of the points > raised by AI in the > review, and I think they all need to be addressed. There is also a diff with > the suggested changes at the very end of this mail. > > Hey Andrey,
Thanks for the effort. > > powerpc unconditionally selects GENERIC_ENTRY. The GENERIC_ENTRY > > infrastructure relies on the compiler emitting __asan_mem*() calls at > > instrumented mem*() sites rather than plain memset/memcpy/memmove, so > > that entry/exit paths calling those functions are not instrumented. > > > > [ ... ] > > > > When GENERIC_ENTRY is set, both guards suppress the C wrappers for > > memset/memcpy/memmove and the __underlying_mem*() redirections. This > > is only safe when the compiler supports the prefixed __asan_mem*() > > intrinsics. On older toolchains (e.g. GCC 9) that lack this support, > > plain mem*() calls from instrumented code fall through to the raw > > assembly implementations in mem_64.S / copy_32.S, completely bypassing > > the KASAN shadow check. > > > > Other arches with GENERIC_ENTRY (x86, s390, loongarch, riscv) do not > > hit this because their CI toolchains are always new enough to support > > the prefix flag. > > > > [ ... ] > > > > Reported-by: Venkat Rao Bagalkote <[email protected]> > > Closes: > > https://lore.kernel.org/all/[email protected] > > Tested-by: Venkat Rao Bagalkote <[email protected]> > > Signed-off-by: Mukesh Kumar Chaurasiya (IBM) <[email protected]> > > The thread in the Closes: link is about an early boot hang, but the > commit message only describes mem*() calls bypassing the shadow check. > Bypassed checks would lose coverage, not hang the machine. Is the > mechanism of the hang understood? > > Looking at the state before this commit, the !CC_HAS_KASAN_MEMINTRINSIC_PREFIX > macros that bee25f97ad24 ("powerpc: Enable GENERIC_ENTRY feature") added to > asm/kasan.h emit two ELFv2 global entry points back to back: > > #define _GLOBAL_TOC_KASAN(fn) > _GLOBAL_TOC(fn); > _GLOBAL_TOC(__##fn) > > With the _GLOBAL_TOC() definition from asm/ppc_asm.h that expands, for > memcpy_64.S, to: > > memcpy: > 0: addis r2,r12,(.TOC.-0b)@ha > addi r2,r2,(.TOC.-0b)@l > .localentry memcpy,.-memcpy <- local entry is memcpy+8 > __memcpy: > 0: addis r2,r12,(.TOC.-0b)@ha <- this is memcpy+8 > addi r2,r2,(.TOC.-0b)@l > .localentry __memcpy,.-__memcpy > > Assembling exactly that for powerpc64le gives memcpy st_other 0x60 > (local entry offset 8), and memcpy+8 is the __memcpy TOC prologue. > > Every same-TOC caller of memcpy() or memmove() is resolved by the > linker to the local entry, so it lands on that second prologue with r12 > holding whatever the caller left there, and returns with r2 pointing > at garbage. Same-TOC callers do not reload r2 after the call. With > GENERIC_ENTRY, mm/kasan/shadow.c no longer provides memcpy(), so on a > toolchain without the prefix parameter every instrumented file calls > the memcpy symbol directly and hits this. That matches an early hang > that only shows up with GCC 9. > > This commit makes the hang go away because the dual-entry macro is > deleted, but the commit message attributes the fix to something else. > Could the message describe the r2 corruption, and since this repairs a > regression from the GENERIC_ENTRY conversion, should it carry: > > Fixes: bee25f97ad24 ("powerpc: Enable GENERIC_ENTRY feature") Yeah the commit message needs to clearly specify the corruption of r2, and the Fixes tag should be there. > > On the claim that other GENERIC_ENTRY architectures "do not hit this > because their CI toolchains are always new enough": x86, s390, riscv > and loongarch with GCC 8 to 12 build exactly the same configuration, > CONFIG_KASAN=y without CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX, and > run with mem*() unchecked. scripts/Makefile.kasan documents that as > the intended behaviour: > > # Instrument memcpy/memset/memmove calls by using instrumented __asan_mem*() > # instead. With compilers that don't support this option, compiler-inserted > # memintrinsics won't be checked by KASAN on GENERIC_ENTRY architectures. > > and mm/kasan/kasan_test_c.c skips the affected tests with "Test > requires checked mem*()". So the situation the message describes is > the accepted upstream state for old toolchains, not something specific > to powerpc. > > > diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig > > index 2580e27e4328..b27ed9739eea 100644 > > --- a/arch/powerpc/Kconfig > > +++ b/arch/powerpc/Kconfig > > @@ -7,6 +7,10 @@ config CC_HAS_ELFV2 > > config CC_HAS_PREFIXED > > def_bool PPC64 && $(cc-option, -mcpu=power10 -mprefixed) > > > > +config PPC_CC_HAS_KASAN_MEMINTRINSIC_PREFIX > > + def_bool (CC_IS_CLANG && $(cc-option,-fsanitize=kernel-address -mllvm > > -asan-kernel-mem-intrinsic-prefix=1)) || \ > > + (CC_IS_GCC && $(cc-option,-fsanitize=kernel-address --param > > asan-kernel-mem-intrinsic-prefix=1)) > > + > > config CC_HAS_PCREL > > # Clang has a bug (https://github.com/llvm/llvm-project/issues/62372) > > # where pcrel code is not generated if -msoft-float, -mno-altivec, or > > [ ... ] > > > @@ -220,9 +224,9 @@ config PPC > > select HAVE_ARCH_HUGE_VMAP if PPC_RADIX_MMU || PPC_8xx > > select HAVE_ARCH_JUMP_LABEL > > select HAVE_ARCH_JUMP_LABEL_RELATIVE > > - select HAVE_ARCH_KASAN if PPC32 && PAGE_SHIFT <= 14 > > - select HAVE_ARCH_KASAN if PPC_RADIX_MMU > > - select HAVE_ARCH_KASAN if PPC_BOOK3E_64 > > + select HAVE_ARCH_KASAN if PPC32 && PAGE_SHIFT <= 14 && > > PPC_CC_HAS_KASAN_MEMINTRINSIC_PREFIX > > + select HAVE_ARCH_KASAN if PPC_RADIX_MMU && > > PPC_CC_HAS_KASAN_MEMINTRINSIC_PREFIX > > + select HAVE_ARCH_KASAN if PPC_BOOK3E_64 && > > PPC_CC_HAS_KASAN_MEMINTRINSIC_PREFIX > > select HAVE_ARCH_KASAN_VMALLOC if HAVE_ARCH_KASAN > > select HAVE_ARCH_KCSAN > > select HAVE_ARCH_KFENCE if ARCH_SUPPORTS_DEBUG_PAGEALLOC > > This drops KASAN from powerpc entirely for GCC 8 through 12, which are > inside the supported range in Documentation/process/changes.rst (GNU C > 8.1 minimum). An existing .config with CONFIG_KASAN=y silently loses > it on olddefconfig once HAVE_ARCH_KASAN is no longer selected. > > Given that the actual breakage is the broken memcpy/memmove entry > points, is it necessary to go this far? Keeping one _GLOBAL_TOC() > prologue for __memcpy and making memcpy a plain alias of it (a second > label plus a matching .localentry, or a global entry that branches to > __memcpy) would restore the pre-GENERIC_ENTRY behaviour, with mem*() > unchecked on old compilers exactly like the other GENERIC_ENTRY > architectures. That also keeps a Fixes-tagged backport candidate from > removing a feature on stable kernels. > Ok, yeah this is too aggressive. I will rectify this in next revision. > > > diff --git a/arch/powerpc/include/asm/kasan.h > > b/arch/powerpc/include/asm/kasan.h > > index a690e7da53c2..d62756b87ba4 100644 > > --- a/arch/powerpc/include/asm/kasan.h > > +++ b/arch/powerpc/include/asm/kasan.h > > @@ -2,20 +2,9 @@ > > #ifndef __ASM_KASAN_H > > #define __ASM_KASAN_H > > > > -#if defined(CONFIG_KASAN) && > > !defined(CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX) > > -#define _GLOBAL_KASAN(fn) \ > > - _GLOBAL(fn); \ > > - _GLOBAL(__##fn) > > -#define _GLOBAL_TOC_KASAN(fn) \ > > - _GLOBAL_TOC(fn); \ > > - _GLOBAL_TOC(__##fn) > > -#define EXPORT_SYMBOL_KASAN(fn) \ > > - EXPORT_SYMBOL(__##fn) > > -#else /* CONFIG_KASAN && !CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX */ > > #define _GLOBAL_KASAN(fn) _GLOBAL(fn) > > #define _GLOBAL_TOC_KASAN(fn) _GLOBAL_TOC(fn) > > #define EXPORT_SYMBOL_KASAN(fn) > > -#endif /* CONFIG_KASAN && !CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX */ > > > > #ifndef __ASSEMBLER__ > > > > this isn't a bug, but after this change _GLOBAL_KASAN(), _GLOBAL_TOC_KASAN() > and EXPORT_SYMBOL_KASAN() are unconditional identity macros with a single > empty one. Should the five users in mem_64.S, memcpy_64.S and copy_32.S > switch to _GLOBAL()/_GLOBAL_TOC() and the macros go away? > > Related leftover: arch/powerpc/kernel/prom_init_check.sh still has > > has_renamed_memintrinsics() > { > grep -q "^CONFIG_KASAN=y$" "${KCONFIG_CONFIG}" && \ > ! grep -q > "^CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX=y" "${KCONFIG_CONFIG}" > } > > if has_renamed_memintrinsics > then > MEM_FUNCS="__memcpy __memset" > > which can no longer be true on powerpc after this commit. Should that > branch be removed in the same cleanup? > Yes it should be. It's a dead code now. > > diff --git a/arch/powerpc/include/asm/string.h > > b/arch/powerpc/include/asm/string.h > > index 1981bd4036b5..72b5c93a2b84 100644 > > --- a/arch/powerpc/include/asm/string.h > > +++ b/arch/powerpc/include/asm/string.h > > @@ -29,29 +29,10 @@ extern void * memchr(const void *,int,__kernel_size_t); > > void memcpy_flushcache(void *dest, const void *src, size_t size); > > > > #ifdef CONFIG_KASAN > > -/* __mem variants are used by KASAN to implement instrumented > > meminstrinsics. */ > > -#ifdef CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX > > +/* Used by mm/kasan/shadow.c as raw backends to bypass KASAN checking. */ > > #define __memset memset > > this isn't a bug, but the new comment names only mm/kasan/shadow.c. > The same __memset()/__memcpy() names are used by mm/kasan/generic.c as > well (DEFINE_ASAN_SET_SHADOW() and release_alloc_meta()), so would > "used by mm/kasan as raw backends" be more accurate? > > > --- > diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig > index b27ed9739eea..2580e27e4328 100644 > --- a/arch/powerpc/Kconfig > +++ b/arch/powerpc/Kconfig > @@ -7,10 +7,6 @@ config CC_HAS_ELFV2 > config CC_HAS_PREFIXED > def_bool PPC64 && $(cc-option, -mcpu=power10 -mprefixed) > > -config PPC_CC_HAS_KASAN_MEMINTRINSIC_PREFIX > - def_bool (CC_IS_CLANG && $(cc-option,-fsanitize=kernel-address > -mllvm -asan-kernel-mem-intrinsic-prefix=1)) || \ > - (CC_IS_GCC && $(cc-option,-fsanitize=kernel-address --param > asan-kernel-mem-intrinsic-prefix=1)) > - > config CC_HAS_PCREL > # Clang has a bug (https://github.com/llvm/llvm-project/issues/62372) > # where pcrel code is not generated if -msoft-float, -mno-altivec, or > @@ -224,9 +220,9 @@ config PPC > select HAVE_ARCH_HUGE_VMAP if PPC_RADIX_MMU || PPC_8xx > select HAVE_ARCH_JUMP_LABEL > select HAVE_ARCH_JUMP_LABEL_RELATIVE > - select HAVE_ARCH_KASAN if PPC32 && PAGE_SHIFT <= 14 && > PPC_CC_HAS_KASAN_MEMINTRINSIC_PREFIX > - select HAVE_ARCH_KASAN if PPC_RADIX_MMU && > PPC_CC_HAS_KASAN_MEMINTRINSIC_PREFIX > - select HAVE_ARCH_KASAN if PPC_BOOK3E_64 && > PPC_CC_HAS_KASAN_MEMINTRINSIC_PREFIX > + select HAVE_ARCH_KASAN if PPC32 && PAGE_SHIFT <= 14 > + select HAVE_ARCH_KASAN if PPC_RADIX_MMU > + select HAVE_ARCH_KASAN if PPC_BOOK3E_64 > select HAVE_ARCH_KASAN_VMALLOC if HAVE_ARCH_KASAN > select HAVE_ARCH_KCSAN > select HAVE_ARCH_KFENCE if ARCH_SUPPORTS_DEBUG_PAGEALLOC > diff --git a/arch/powerpc/include/asm/kasan.h > b/arch/powerpc/include/asm/kasan.h > index d62756b87ba4..599a9e02af02 100644 > --- a/arch/powerpc/include/asm/kasan.h > +++ b/arch/powerpc/include/asm/kasan.h > @@ -2,10 +2,6 @@ > #ifndef __ASM_KASAN_H > #define __ASM_KASAN_H > > -#define _GLOBAL_KASAN(fn) _GLOBAL(fn) > -#define _GLOBAL_TOC_KASAN(fn) _GLOBAL_TOC(fn) > -#define EXPORT_SYMBOL_KASAN(fn) > - > #ifndef __ASSEMBLER__ > > #include <asm/page.h> > diff --git a/arch/powerpc/kernel/prom_init_check.sh > b/arch/powerpc/kernel/prom_init_check.sh > index 3090b97258ae..3155cc722e48 100644 > --- a/arch/powerpc/kernel/prom_init_check.sh > +++ b/arch/powerpc/kernel/prom_init_check.sh > @@ -13,21 +13,8 @@ > # If you really need to reference something from prom_init.o add > # it to the list below: > > -has_renamed_memintrinsics() > -{ > - grep -q "^CONFIG_KASAN=y$" "${KCONFIG_CONFIG}" && \ > - ! grep -q "^CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX=y" > "${KCONFIG_CONFIG}" > -} > - > -if has_renamed_memintrinsics > -then > - MEM_FUNCS="__memcpy __memset" > -else > - MEM_FUNCS="memcpy memset" > -fi > - > WHITELIST="add_reloc_offset __bss_start __bss_stop copy_and_flush > -_end enter_prom $MEM_FUNCS reloc_offset __secondary_hold > +_end enter_prom memcpy memset reloc_offset __secondary_hold > __secondary_hold_acknowledge __secondary_hold_spinloop __start > logo_linux_clut224 btext_prepare_BAT > reloc_got2 kernstart_addr memstart_addr linux_banner _stext > diff --git a/arch/powerpc/lib/copy_32.S b/arch/powerpc/lib/copy_32.S > index 933b685e7ab6..97eb9ca0cc23 100644 > --- a/arch/powerpc/lib/copy_32.S > +++ b/arch/powerpc/lib/copy_32.S > @@ -10,7 +10,6 @@ > #include <asm/errno.h> > #include <asm/ppc_asm.h> > #include <asm/code-patching-asm.h> > -#include <asm/kasan.h> > > #define COPY_16_BYTES \ > lwz r7,4(r4); \ > @@ -87,7 +86,7 @@ EXPORT_SYMBOL(memset16) > * We therefore skip the optimised bloc that uses dcbz. This jump is > * replaced by a nop once cache is active. This is done in machine_init() > */ > -_GLOBAL_KASAN(memset) > +_GLOBAL(memset) > cmplwi 0,r5,4 > blt 7f > > @@ -147,7 +146,6 @@ _GLOBAL_KASAN(memset) > bdnz 9b > blr > EXPORT_SYMBOL(memset) > -EXPORT_SYMBOL_KASAN(memset) > > /* > * This version uses dcbz on the complete cache lines in the > @@ -160,12 +158,12 @@ EXPORT_SYMBOL_KASAN(memset) > * We therefore jump to generic_memcpy which doesn't use dcbz. This jump is > * replaced by a nop once cache is active. This is done in machine_init() > */ > -_GLOBAL_KASAN(memmove) > +_GLOBAL(memmove) > cmplw 0,r3,r4 > bgt backwards_memcpy > /* fall through */ > > -_GLOBAL_KASAN(memcpy) > +_GLOBAL(memcpy) > 1: b generic_memcpy > patch_site 1b, patch__memcpy_nocache > > @@ -241,8 +239,6 @@ _GLOBAL_KASAN(memcpy) > 65: blr > EXPORT_SYMBOL(memcpy) > EXPORT_SYMBOL(memmove) > -EXPORT_SYMBOL_KASAN(memcpy) > -EXPORT_SYMBOL_KASAN(memmove) > > generic_memcpy: > srwi. r7,r5,3 > diff --git a/arch/powerpc/lib/mem_64.S b/arch/powerpc/lib/mem_64.S > index 6fd06cd20faa..40eaedd31486 100644 > --- a/arch/powerpc/lib/mem_64.S > +++ b/arch/powerpc/lib/mem_64.S > @@ -8,7 +8,6 @@ > #include <asm/processor.h> > #include <asm/errno.h> > #include <asm/ppc_asm.h> > -#include <asm/kasan.h> > > #ifndef CONFIG_KASAN > _GLOBAL(__memset16) > @@ -29,7 +28,7 @@ EXPORT_SYMBOL(__memset32) > EXPORT_SYMBOL(__memset64) > #endif > > -_GLOBAL_KASAN(memset) > +_GLOBAL(memset) > neg r0,r3 > rlwimi r4,r4,8,16,23 > andi. r0,r0,7 /* # bytes to be 8-byte aligned */ > @@ -95,9 +94,8 @@ _GLOBAL_KASAN(memset) > stb r4,0(r6) > blr > EXPORT_SYMBOL(memset) > -EXPORT_SYMBOL_KASAN(memset) > > -_GLOBAL_TOC_KASAN(memmove) > +_GLOBAL_TOC(memmove) > cmplw 0,r3,r4 > bgt backwards_memcpy > b memcpy > @@ -139,4 +137,3 @@ _GLOBAL(backwards_memcpy) > mtctr r7 > b 1b > EXPORT_SYMBOL(memmove) > -EXPORT_SYMBOL_KASAN(memmove) > diff --git a/arch/powerpc/lib/memcpy_64.S b/arch/powerpc/lib/memcpy_64.S > index b5a67e20143f..0cedd455231a 100644 > --- a/arch/powerpc/lib/memcpy_64.S > +++ b/arch/powerpc/lib/memcpy_64.S > @@ -7,7 +7,6 @@ > #include <asm/ppc_asm.h> > #include <asm/asm-compat.h> > #include <asm/feature-fixups.h> > -#include <asm/kasan.h> > > #ifndef SELFTEST_CASE > /* For big-endian, 0 == most CPUs, 1 == POWER6, 2 == Cell */ > @@ -15,7 +14,7 @@ > #endif > > .align 7 > -_GLOBAL_TOC_KASAN(memcpy) > +_GLOBAL_TOC(memcpy) > BEGIN_FTR_SECTION > #ifdef __LITTLE_ENDIAN__ > cmpdi cr7,r5,0 > @@ -227,4 +226,3 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD) > blr > #endif > EXPORT_SYMBOL(memcpy) > -EXPORT_SYMBOL_KASAN(memcpy) Yeah this seems like it could work. Letme try this. Thanks, Mukesh

