arch/arm/mm/kasan_init.c | 2 +- arch/arm64/mm/kasan_init.c | 4 +--- arch/loongarch/include/asm/kasan.h | 7 ------- arch/loongarch/mm/kasan_init.c | 7 ++----- arch/powerpc/include/asm/kasan.h | 13 ------------- arch/powerpc/mm/kasan/init_32.c | 2 +- arch/powerpc/mm/kasan/init_book3e_64.c | 2 +- arch/powerpc/mm/kasan/init_book3s_64.c | 6 +----- arch/riscv/mm/kasan_init.c | 1 + arch/s390/kernel/early.c | 3 ++- arch/um/include/asm/kasan.h | 5 ----- arch/um/kernel/mem.c | 4 ++-- arch/x86/mm/kasan_init_64.c | 2 +- arch/xtensa/mm/kasan_init.c | 2 +- include/linux/kasan-enabled.h | 22 ++++++++++++++++------ include/linux/kasan.h | 6 ++++++ mm/kasan/common.c | 15 +++++++++++---- mm/kasan/generic.c | 17 ++++++++++++++--- mm/kasan/hw_tags.c | 7 ------- mm/kasan/kasan.h | 6 ------ mm/kasan/shadow.c | 15 +++------------ mm/kasan/sw_tags.c | 2 ++ 22 files changed, 66 insertions(+), 84 deletions(-)
This patch series unifies the kasan_arch_is_ready() and kasan_enabled() interfaces by extending the existing kasan_enabled() infrastructure to work consistently across all KASAN modes (Generic, SW_TAGS, HW_TAGS). Currently, kasan_enabled() only works for HW_TAGS mode using a static key, while other modes either return IS_ENABLED(CONFIG_KASAN) (compile-time constant) or rely on architecture-specific kasan_arch_is_ready() implementations with custom static keys and global variables. This leads to: - Code duplication across architectures - Inconsistent runtime behavior between KASAN modes - Architecture-specific readiness tracking After this series: - All KASAN modes use the same kasan_flag_enabled static key - Consistent runtime enable/disable behavior across modes - Simplified architecture code with unified kasan_init_generic() calls - Elimination of arch specific kasan_arch_is_ready() implementations - Unified vmalloc integration using kasan_enabled() checks This addresses the bugzilla issue [1] about making kasan_flag_enabled and kasan_enabled() work for Generic mode, and extends it to provide true unification across all modes. [1] https://bugzilla.kernel.org/show_bug.cgi?id=217049 === Current mainline KUnit status To see if there is any regression, I've tested first on the following commit 739a6c93cc75 ("Merge tag 'nfsd-6.16-1' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux"). Tested via compiling a kernel with CONFIG_KASAN_KUNIT_TEST and running QEMU VM. There are failing tests in SW_TAGS and GENERIC modes in arm64: arm64 CONFIG_KASAN_HW_TAGS: # kasan: pass:62 fail:0 skip:13 total:75 # Totals: pass:62 fail:0 skip:13 total:75 ok 1 kasan arm64 CONFIG_KASAN_SW_TAGS=y: # kasan: pass:65 fail:1 skip:9 total:75 # Totals: pass:65 fail:1 skip:9 total:75 not ok 1 kasan # kasan_strings: EXPECTATION FAILED at mm/kasan/kasan_test_c.c:1598 KASAN failure expected in "strscpy(ptr, src + KASAN_GRANULE_SIZE, KASAN_GRANULE_SIZE)", but none occurred arm64 CONFIG_KASAN_GENERIC=y, CONFIG_KASAN_OUTLINE=y: # kasan: pass:61 fail:1 skip:13 total:75 # Totals: pass:61 fail:1 skip:13 total:75 not ok 1 kasan # same failure as above x86_64 CONFIG_KASAN_GENERIC=y: # kasan: pass:58 fail:0 skip:17 total:75 # Totals: pass:58 fail:0 skip:17 total:75 ok 1 kasan === Testing with patches Testing in v2: - Compiled every affected arch with no errors: $ make CC=clang LD=ld.lld AR=llvm-ar NM=llvm-nm STRIP=llvm-strip \ OBJCOPY=llvm-objcopy OBJDUMP=llvm-objdump READELF=llvm-readelf \ HOSTCC=clang HOSTCXX=clang++ HOSTAR=llvm-ar HOSTLD=ld.lld \ ARCH=$ARCH $ clang --version ClangBuiltLinux clang version 19.1.4 Target: x86_64-unknown-linux-gnu Thread model: posix - make ARCH=um produces the warning during compiling: MODPOST Module.symvers WARNING: modpost: vmlinux: section mismatch in reference: \ kasan_init+0x43 (section: .ltext) -> \ kasan_init_generic (section: .init.text) AFAIU, it's due to the code in arch/um/kernel/mem.c, where kasan_init() is placed in own section ".kasan_init", which calls kasan_init_generic() which is marked with "__init". - Booting via qemu-system- and running KUnit tests: * arm64 (GENERIC, HW_TAGS, SW_TAGS): no regression, same above results. * x86_64 (GENERIC): no regression, no errors === NB I haven't tested the kernel boot on the following arch. due to the absence of qemu-system- support on those arch on my machine, so I defer this to relevant arch people to test KASAN initialization: - loongarch - s390 - um - xtensa - powerpc - riscv Code changes in v2: - Replace the order of patches. Move "kasan: replace kasan_arch_is_ready with kasan_enabled" at the end to keep the compatibility. - arch/arm, arch/riscv: add 2 arch. missed in v1 - arch/powerpc: add kasan_init_generic() in other kasan_init() calls: arch/powerpc/mm/kasan/init_32.c arch/powerpc/mm/kasan/init_book3e_64.c - arch/um: add the proper header `#include <linux/kasan.h>`. Tested via compiling with no errors. In the v1 arch/um changes were acked-by Johannes Berg, though I don't include it due to the changed code in v2. - arch/powerpc: add back `#ifdef CONFIG_KASAN` deleted in v1 and tested the compilation. - arch/loongarch: update git commit message about non-standard flow of calling kasan_init_generic() Sabyrzhan Tasbolatov (11): kasan: unify static kasan_flag_enabled across modes kasan/arm64: call kasan_init_generic in kasan_init kasan/arm: call kasan_init_generic in kasan_init kasan/xtensa: call kasan_init_generic in kasan_init kasan/loongarch: call kasan_init_generic in kasan_init kasan/um: call kasan_init_generic in kasan_init kasan/x86: call kasan_init_generic in kasan_init kasan/s390: call kasan_init_generic in kasan_init kasan/powerpc: call kasan_init_generic in kasan_init kasan/riscv: call kasan_init_generic in kasan_init kasan: replace kasan_arch_is_ready with kasan_enabled arch/arm/mm/kasan_init.c | 2 +- arch/arm64/mm/kasan_init.c | 4 +--- arch/loongarch/include/asm/kasan.h | 7 ------- arch/loongarch/mm/kasan_init.c | 7 ++----- arch/powerpc/include/asm/kasan.h | 13 ------------- arch/powerpc/mm/kasan/init_32.c | 2 +- arch/powerpc/mm/kasan/init_book3e_64.c | 2 +- arch/powerpc/mm/kasan/init_book3s_64.c | 6 +----- arch/riscv/mm/kasan_init.c | 1 + arch/s390/kernel/early.c | 3 ++- arch/um/include/asm/kasan.h | 5 ----- arch/um/kernel/mem.c | 4 ++-- arch/x86/mm/kasan_init_64.c | 2 +- arch/xtensa/mm/kasan_init.c | 2 +- include/linux/kasan-enabled.h | 22 ++++++++++++++++------ include/linux/kasan.h | 6 ++++++ mm/kasan/common.c | 15 +++++++++++---- mm/kasan/generic.c | 17 ++++++++++++++--- mm/kasan/hw_tags.c | 7 ------- mm/kasan/kasan.h | 6 ------ mm/kasan/shadow.c | 15 +++------------ mm/kasan/sw_tags.c | 2 ++ 22 files changed, 66 insertions(+), 84 deletions(-) -- 2.34.1
Le 26/06/2025 à 17:31, Sabyrzhan Tasbolatov a écrit : > This patch series unifies the kasan_arch_is_ready() and kasan_enabled() > interfaces by extending the existing kasan_enabled() infrastructure to > work consistently across all KASAN modes (Generic, SW_TAGS, HW_TAGS). > > Currently, kasan_enabled() only works for HW_TAGS mode using a static key, > while other modes either return IS_ENABLED(CONFIG_KASAN) (compile-time > constant) or rely on architecture-specific kasan_arch_is_ready() > implementations with custom static keys and global variables. > > This leads to: > - Code duplication across architectures > - Inconsistent runtime behavior between KASAN modes > - Architecture-specific readiness tracking You should also consider refactoring ARCH_DISABLE_KASAN_INLINE, there is a high dependency between deferring KASAN readiness and not supporting inline KASAN. > > After this series: > - All KASAN modes use the same kasan_flag_enabled static key > - Consistent runtime enable/disable behavior across modes > - Simplified architecture code with unified kasan_init_generic() calls > - Elimination of arch specific kasan_arch_is_ready() implementations > - Unified vmalloc integration using kasan_enabled() checks I dislike that modes which can be enabled from the very begining now also depends on the static key being enabled later. The size is increased for no valid reason: $ size vmlinux.kasan* text data bss dec hex filename 13965336 6716942 494912 21177190 1432366 vmlinux.kasan0 ==> outline KASAN before your patch 13965496 6718422 494944 21178862 14329ee vmlinux.kasan1 ==> outline KASAN after your patch 13965336 6716942 494912 21177190 1432366 vmlinux.kasan2 ==> outline KASAN after your patch + below change 32517472 6716958 494912 39729342 25e38be vmlinux.kasani0 ==> inline KASAN before your patch 32518848 6718438 494944 39732230 25e4406 vmlinux.kasani1 ==> inline KASAN after your patch 32517536 6716958 494912 39729406 25e38fe vmlinux.kasani2 ==> inline KASAN after your patch + below change Below change (atop you series) only makes use of static key when needed: diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index c3e0cc83f120..7a8e5db603cc 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -122,6 +122,7 @@ config PPC # Please keep this list sorted alphabetically. # select ARCH_32BIT_OFF_T if PPC32 + select ARCH_DEFER_KASAN if PPC_RADIX_MMU select ARCH_DISABLE_KASAN_INLINE if PPC_RADIX_MMU select ARCH_DMA_DEFAULT_COHERENT if !NOT_COHERENT_CACHE select ARCH_ENABLE_MEMORY_HOTPLUG @@ -219,7 +220,7 @@ config PPC 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_DEFERED 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 diff --git a/include/linux/kasan-enabled.h b/include/linux/kasan-enabled.h index 2436eb45cfee..fda86e77fe4f 100644 --- a/include/linux/kasan-enabled.h +++ b/include/linux/kasan-enabled.h @@ -4,7 +4,7 @@ #include <linux/static_key.h> -#ifdef CONFIG_KASAN +#ifdef CONFIG_KASAN_DEFER /* * Global runtime flag. Starts âfalseâ; switched to âtrueâ by @@ -17,13 +17,21 @@ static __always_inline bool kasan_enabled(void) return static_branch_likely(&kasan_flag_enabled); } -#else /* !CONFIG_KASAN */ +static inline void kasan_enable(void) +{ + static_branch_enable(&kasan_flag_enabled); +} + +#else /* !CONFIG_KASAN_DEFER */ static __always_inline bool kasan_enabled(void) { - return false; + return IS_ENABLED(CONFIG_KASAN); } +static inline void kasan_enable(void) +{ +} #endif /* CONFIG_KASAN */ #ifdef CONFIG_KASAN_HW_TAGS diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan index f82889a830fa..e0c300f55c07 100644 --- a/lib/Kconfig.kasan +++ b/lib/Kconfig.kasan @@ -13,6 +13,9 @@ config HAVE_ARCH_KASAN_HW_TAGS config HAVE_ARCH_KASAN_VMALLOC bool +config ARCH_DEFER_KASAN + bool + config ARCH_DISABLE_KASAN_INLINE bool help @@ -58,6 +61,9 @@ config CC_HAS_KASAN_MEMINTRINSIC_PREFIX help The compiler is able to prefix memintrinsics with __asan or __hwasan. +config KASAN_DIFER + def_bool ARCH_DIFER_KASAN + choice prompt "KASAN mode" default KASAN_GENERIC diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 0f3648335a6b..01f56eed9d20 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -36,8 +36,10 @@ * Definition of the unified static key declared in kasan-enabled.h. * This provides consistent runtime enable/disable across all KASAN modes. */ +#ifdef CONFIG_KASAN_DEFER DEFINE_STATIC_KEY_FALSE(kasan_flag_enabled); EXPORT_SYMBOL(kasan_flag_enabled); +#endif struct slab *kasan_addr_to_slab(const void *addr) { diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c index a3b112868be7..516b49accc4f 100644 --- a/mm/kasan/generic.c +++ b/mm/kasan/generic.c @@ -42,7 +42,7 @@ */ void __init kasan_init_generic(void) { - static_branch_enable(&kasan_flag_enabled); + kasan_enable(); pr_info("KernelAddressSanitizer initialized (generic)\n"); } diff --git a/mm/kasan/hw_tags.c b/mm/kasan/hw_tags.c index 8e819fc4a260..c8289a3feabf 100644 --- a/mm/kasan/hw_tags.c +++ b/mm/kasan/hw_tags.c @@ -253,7 +253,7 @@ void __init kasan_init_hw_tags(void) kasan_init_tags(); /* KASAN is now initialized, enable it. */ - static_branch_enable(&kasan_flag_enabled); + kasan_enable(); pr_info("KernelAddressSanitizer initialized (hw-tags, mode=%s, vmalloc=%s, stacktrace=%s)\n", kasan_mode_info(), diff --git a/mm/kasan/sw_tags.c b/mm/kasan/sw_tags.c index 525bc91e2fcd..275bcbbf6120 100644 --- a/mm/kasan/sw_tags.c +++ b/mm/kasan/sw_tags.c @@ -45,7 +45,7 @@ void __init kasan_init_sw_tags(void) kasan_init_tags(); - static_branch_enable(&kasan_flag_enabled); + kasan_enable(); pr_info("KernelAddressSanitizer initialized (sw-tags, stacktrace=%s)\n", str_on_off(kasan_stack_collection_enabled())); > > This addresses the bugzilla issue [1] about making > kasan_flag_enabled and kasan_enabled() work for Generic mode, > and extends it to provide true unification across all modes. > > [1] https://bugzilla.kernel.org/show_bug.cgi?id=217049 > > === Current mainline KUnit status > > To see if there is any regression, I've tested first on the following > commit 739a6c93cc75 ("Merge tag 'nfsd-6.16-1' of > git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux"). > > Tested via compiling a kernel with CONFIG_KASAN_KUNIT_TEST and running > QEMU VM. There are failing tests in SW_TAGS and GENERIC modes in arm64: > > arm64 CONFIG_KASAN_HW_TAGS: > # kasan: pass:62 fail:0 skip:13 total:75 > # Totals: pass:62 fail:0 skip:13 total:75 > ok 1 kasan > > arm64 CONFIG_KASAN_SW_TAGS=y: > # kasan: pass:65 fail:1 skip:9 total:75 > # Totals: pass:65 fail:1 skip:9 total:75 > not ok 1 kasan > # kasan_strings: EXPECTATION FAILED at mm/kasan/kasan_test_c.c:1598 > KASAN failure expected in "strscpy(ptr, src + KASAN_GRANULE_SIZE, KASAN_GRANULE_SIZE)", but none occurred > > arm64 CONFIG_KASAN_GENERIC=y, CONFIG_KASAN_OUTLINE=y: > # kasan: pass:61 fail:1 skip:13 total:75 > # Totals: pass:61 fail:1 skip:13 total:75 > not ok 1 kasan > # same failure as above > > x86_64 CONFIG_KASAN_GENERIC=y: > # kasan: pass:58 fail:0 skip:17 total:75 > # Totals: pass:58 fail:0 skip:17 total:75 > ok 1 kasan > > === Testing with patches > > Testing in v2: > > - Compiled every affected arch with no errors: > > $ make CC=clang LD=ld.lld AR=llvm-ar NM=llvm-nm STRIP=llvm-strip \ > OBJCOPY=llvm-objcopy OBJDUMP=llvm-objdump READELF=llvm-readelf \ > HOSTCC=clang HOSTCXX=clang++ HOSTAR=llvm-ar HOSTLD=ld.lld \ > ARCH=$ARCH > > $ clang --version > ClangBuiltLinux clang version 19.1.4 > Target: x86_64-unknown-linux-gnu > Thread model: posix > > - make ARCH=um produces the warning during compiling: > MODPOST Module.symvers > WARNING: modpost: vmlinux: section mismatch in reference: \ > kasan_init+0x43 (section: .ltext) -> \ > kasan_init_generic (section: .init.text) > > AFAIU, it's due to the code in arch/um/kernel/mem.c, where kasan_init() > is placed in own section ".kasan_init", which calls kasan_init_generic() > which is marked with "__init". > > - Booting via qemu-system- and running KUnit tests: > > * arm64 (GENERIC, HW_TAGS, SW_TAGS): no regression, same above results. > * x86_64 (GENERIC): no regression, no errors > > === NB > > I haven't tested the kernel boot on the following arch. due to the absence > of qemu-system- support on those arch on my machine, so I defer this to > relevant arch people to test KASAN initialization: > - loongarch > - s390 > - um > - xtensa > - powerpc > - riscv > > Code changes in v2: > - Replace the order of patches. Move "kasan: replace kasan_arch_is_ready > with kasan_enabled" at the end to keep the compatibility. > - arch/arm, arch/riscv: add 2 arch. missed in v1 > - arch/powerpc: add kasan_init_generic() in other kasan_init() calls: > arch/powerpc/mm/kasan/init_32.c > arch/powerpc/mm/kasan/init_book3e_64.c > - arch/um: add the proper header `#include <linux/kasan.h>`. Tested > via compiling with no errors. In the v1 arch/um changes were acked-by > Johannes Berg, though I don't include it due to the changed code in v2. > - arch/powerpc: add back `#ifdef CONFIG_KASAN` deleted in v1 and tested > the compilation. > - arch/loongarch: update git commit message about non-standard flow of > calling kasan_init_generic() > > Sabyrzhan Tasbolatov (11): > kasan: unify static kasan_flag_enabled across modes > kasan/arm64: call kasan_init_generic in kasan_init > kasan/arm: call kasan_init_generic in kasan_init > kasan/xtensa: call kasan_init_generic in kasan_init > kasan/loongarch: call kasan_init_generic in kasan_init > kasan/um: call kasan_init_generic in kasan_init > kasan/x86: call kasan_init_generic in kasan_init > kasan/s390: call kasan_init_generic in kasan_init > kasan/powerpc: call kasan_init_generic in kasan_init > kasan/riscv: call kasan_init_generic in kasan_init > kasan: replace kasan_arch_is_ready with kasan_enabled > > arch/arm/mm/kasan_init.c | 2 +- > arch/arm64/mm/kasan_init.c | 4 +--- > arch/loongarch/include/asm/kasan.h | 7 ------- > arch/loongarch/mm/kasan_init.c | 7 ++----- > arch/powerpc/include/asm/kasan.h | 13 ------------- > arch/powerpc/mm/kasan/init_32.c | 2 +- > arch/powerpc/mm/kasan/init_book3e_64.c | 2 +- > arch/powerpc/mm/kasan/init_book3s_64.c | 6 +----- > arch/riscv/mm/kasan_init.c | 1 + > arch/s390/kernel/early.c | 3 ++- > arch/um/include/asm/kasan.h | 5 ----- > arch/um/kernel/mem.c | 4 ++-- > arch/x86/mm/kasan_init_64.c | 2 +- > arch/xtensa/mm/kasan_init.c | 2 +- > include/linux/kasan-enabled.h | 22 ++++++++++++++++------ > include/linux/kasan.h | 6 ++++++ > mm/kasan/common.c | 15 +++++++++++---- > mm/kasan/generic.c | 17 ++++++++++++++--- > mm/kasan/hw_tags.c | 7 ------- > mm/kasan/kasan.h | 6 ------ > mm/kasan/shadow.c | 15 +++------------ > mm/kasan/sw_tags.c | 2 ++ > 22 files changed, 66 insertions(+), 84 deletions(-) >
On Thu, Jun 26, 2025 at 5:32 PM Sabyrzhan Tasbolatov <snovitoll@gmail.com> wrote: > > This patch series unifies the kasan_arch_is_ready() and kasan_enabled() > interfaces by extending the existing kasan_enabled() infrastructure to > work consistently across all KASAN modes (Generic, SW_TAGS, HW_TAGS). > > Currently, kasan_enabled() only works for HW_TAGS mode using a static key, > while other modes either return IS_ENABLED(CONFIG_KASAN) (compile-time > constant) or rely on architecture-specific kasan_arch_is_ready() > implementations with custom static keys and global variables. > > This leads to: > - Code duplication across architectures > - Inconsistent runtime behavior between KASAN modes > - Architecture-specific readiness tracking > > After this series: > - All KASAN modes use the same kasan_flag_enabled static key > - Consistent runtime enable/disable behavior across modes > - Simplified architecture code with unified kasan_init_generic() calls > - Elimination of arch specific kasan_arch_is_ready() implementations > - Unified vmalloc integration using kasan_enabled() checks > > This addresses the bugzilla issue [1] about making > kasan_flag_enabled and kasan_enabled() work for Generic mode, > and extends it to provide true unification across all modes. > > [1] https://bugzilla.kernel.org/show_bug.cgi?id=217049 Hi Sabyrzhan, Thank you for working on this! One aspect that is missing from the patches is moving the kasan_arch_is_ready() calls into the include/linux/kasan.h (this is not explicitly mentioned in the issue, but this is what the "adding __wrappers" part is about). Another thing that needs careful consideration is whether it's possible to combine kasan_arch_is_ready() and kasan_enabled() into the same check logically at all. There's one issue mentioned in [1]: > In kasan_cache_create() we unconditionally allocate a metadata buffer, > but the kasan_init_slab_obj() call to initialise it is guarded by > kasan_enabled(). But later parts of the code only check the presence of > the buffer before using it, so bad things happen if kasan_enabled() > later turns on (I was getting some error about invalid lock state). And there might be other callbacks that should be executed even before kasan_init_...() completes. But then for the HW_TAGS mode, if kasan_enabled() is off, then we don't want to execute any callbacks. So maybe we do actually need a separate static key for kasan_arch_is_ready(). But even if so, it still makes sense to move kasan_arch_is_ready() into the __wrappers for the affected callbacks. Thanks! [1] https://lore.kernel.org/linux-mm/CA+fCnZf7JqTH46C7oG2Wk9NnLU7hgiVDEK0EA8RAtyr-KgkHdg@mail.gmail.com/
On Sat, Jun 28, 2025 at 3:57 PM Andrey Konovalov <andreyknvl@gmail.com> wrote: > > On Thu, Jun 26, 2025 at 5:32 PM Sabyrzhan Tasbolatov > <snovitoll@gmail.com> wrote: > > > > This patch series unifies the kasan_arch_is_ready() and kasan_enabled() > > interfaces by extending the existing kasan_enabled() infrastructure to > > work consistently across all KASAN modes (Generic, SW_TAGS, HW_TAGS). > > > > Currently, kasan_enabled() only works for HW_TAGS mode using a static key, > > while other modes either return IS_ENABLED(CONFIG_KASAN) (compile-time > > constant) or rely on architecture-specific kasan_arch_is_ready() > > implementations with custom static keys and global variables. > > > > This leads to: > > - Code duplication across architectures > > - Inconsistent runtime behavior between KASAN modes > > - Architecture-specific readiness tracking > > > > After this series: > > - All KASAN modes use the same kasan_flag_enabled static key > > - Consistent runtime enable/disable behavior across modes > > - Simplified architecture code with unified kasan_init_generic() calls > > - Elimination of arch specific kasan_arch_is_ready() implementations > > - Unified vmalloc integration using kasan_enabled() checks > > > > This addresses the bugzilla issue [1] about making > > kasan_flag_enabled and kasan_enabled() work for Generic mode, > > and extends it to provide true unification across all modes. > > > > [1] https://bugzilla.kernel.org/show_bug.cgi?id=217049 > > Hi Sabyrzhan, > > Thank you for working on this! > > One aspect that is missing from the patches is moving the > kasan_arch_is_ready() calls into the include/linux/kasan.h (this is > not explicitly mentioned in the issue, but this is what the "adding > __wrappers" part is about). > > Another thing that needs careful consideration is whether it's > possible to combine kasan_arch_is_ready() and kasan_enabled() into the > same check logically at all. There's one issue mentioned in [1]: Hello, I've removed kasan_arch_is_ready() at all in this series: [PATCH v2 11/11] kasan: replace kasan_arch_is_ready with kasan_enabled Is it not what's expected by unification? > > > In kasan_cache_create() we unconditionally allocate a metadata buffer, > > but the kasan_init_slab_obj() call to initialise it is guarded by > > kasan_enabled(). But later parts of the code only check the presence of > > the buffer before using it, so bad things happen if kasan_enabled() > > later turns on (I was getting some error about invalid lock state). > > And there might be other callbacks that should be executed even before > kasan_init_...() completes. But then for the HW_TAGS mode, if > kasan_enabled() is off, then we don't want to execute any callbacks. > > So maybe we do actually need a separate static key for > kasan_arch_is_ready(). But even if so, it still makes sense to move > kasan_arch_is_ready() into the __wrappers for the affected callbacks. > > Thanks! > > [1] https://lore.kernel.org/linux-mm/CA+fCnZf7JqTH46C7oG2Wk9NnLU7hgiVDEK0EA8RAtyr-KgkHdg@mail.gmail.com/
On Sat, Jun 28, 2025 at 3:25 PM Sabyrzhan Tasbolatov <snovitoll@gmail.com> wrote: > > On Sat, Jun 28, 2025 at 3:57 PM Andrey Konovalov <andreyknvl@gmail.com> wrote: > > > > On Thu, Jun 26, 2025 at 5:32 PM Sabyrzhan Tasbolatov > > <snovitoll@gmail.com> wrote: > > > > > > This patch series unifies the kasan_arch_is_ready() and kasan_enabled() > > > interfaces by extending the existing kasan_enabled() infrastructure to > > > work consistently across all KASAN modes (Generic, SW_TAGS, HW_TAGS). > > > > > > Currently, kasan_enabled() only works for HW_TAGS mode using a static key, > > > while other modes either return IS_ENABLED(CONFIG_KASAN) (compile-time > > > constant) or rely on architecture-specific kasan_arch_is_ready() > > > implementations with custom static keys and global variables. > > > > > > This leads to: > > > - Code duplication across architectures > > > - Inconsistent runtime behavior between KASAN modes > > > - Architecture-specific readiness tracking > > > > > > After this series: > > > - All KASAN modes use the same kasan_flag_enabled static key > > > - Consistent runtime enable/disable behavior across modes > > > - Simplified architecture code with unified kasan_init_generic() calls > > > - Elimination of arch specific kasan_arch_is_ready() implementations > > > - Unified vmalloc integration using kasan_enabled() checks > > > > > > This addresses the bugzilla issue [1] about making > > > kasan_flag_enabled and kasan_enabled() work for Generic mode, > > > and extends it to provide true unification across all modes. > > > > > > [1] https://bugzilla.kernel.org/show_bug.cgi?id=217049 > > > > Hi Sabyrzhan, > > > > Thank you for working on this! > > > > One aspect that is missing from the patches is moving the > > kasan_arch_is_ready() calls into the include/linux/kasan.h (this is > > not explicitly mentioned in the issue, but this is what the "adding > > __wrappers" part is about). > > > > Another thing that needs careful consideration is whether it's > > possible to combine kasan_arch_is_ready() and kasan_enabled() into the > > same check logically at all. There's one issue mentioned in [1]: > > Hello, > I've removed kasan_arch_is_ready() at all in this series: > [PATCH v2 11/11] kasan: replace kasan_arch_is_ready with kasan_enabled > > Is it not what's expected by unification? I guess the issue description diverged a bit from what needs to be done, sorry about that. The core 2 things I wanted to address with the unification are: 1. Avoid spraying kasan_arch_is_ready() throughout the KASAN implementation and move these checks into include/linux/kasan.h (and add __wrappers when required). 2. Avoid architectures redefining the same kasan_enabled global variable/static key. Initially, I thought that s/kasan_arch_is_ready/kasan_enabled + simply moving the calls into affected include/linux/kasan.h functions would be enough. But then, based on [1], turns out it's not that simple. So now, I think we likely still need two separate checks/flags: kasan_enabled() that controls whether KASAN is enabled at all and kasan_arch_is_ready() that gets turned on by kasan_init() when shadow is initialized (should we rename it to kasan_shadow_initialized()?). But then we can still move kasan_arch_is_ready() into include/linux/kasan.h and use the proper combination of checks for each affected function before calling __wrappers. And we can still remove the duplicated flags/keys code from the arch code. [1] https://lore.kernel.org/linux-mm/CA+fCnZf7JqTH46C7oG2Wk9NnLU7hgiVDEK0EA8RAtyr-KgkHdg@mail.gmail.com/
> > > Another thing that needs careful consideration is whether it's > > > possible to combine kasan_arch_is_ready() and kasan_enabled() into the > > > same check logically at all. There's one issue mentioned in [1]: > > > > Hello, > > I've removed kasan_arch_is_ready() at all in this series: > > [PATCH v2 11/11] kasan: replace kasan_arch_is_ready with kasan_enabled > > > > Is it not what's expected by unification? > > I guess the issue description diverged a bit from what needs to be > done, sorry about that. > > The core 2 things I wanted to address with the unification are: > > 1. Avoid spraying kasan_arch_is_ready() throughout the KASAN > implementation and move these checks into include/linux/kasan.h (and > add __wrappers when required). > > 2. Avoid architectures redefining the same kasan_enabled global > variable/static key. > > Initially, I thought that s/kasan_arch_is_ready/kasan_enabled + simply > moving the calls into affected include/linux/kasan.h functions would > be enough. But then, based on [1], turns out it's not that simple. > > So now, I think we likely still need two separate checks/flags: > kasan_enabled() that controls whether KASAN is enabled at all and > kasan_arch_is_ready() that gets turned on by kasan_init() when shadow > is initialized (should we rename it to kasan_shadow_initialized()?). > But then we can still move kasan_arch_is_ready() into > include/linux/kasan.h and use the proper combination of checks for > each affected function before calling __wrappers. And we can still > remove the duplicated flags/keys code from the arch code. FWIW, as Alexander Gordeev already mentioned: this series breaks s390, since the static_branch_enable() call in kasan_init_generic() is now called way too early, and it isn't necessary at all. Which, as far as I understand, may be the case for other architectures as well. s390 sets up the required KASAN mappings in the decompressor and can start with KASAN enabled nearly from the beginning. So something like below on top of this series would address that. Given that this series is about to be reworked this is just for illustration :) diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 0c16dc443e2f..c2f51ac39a91 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -172,6 +172,7 @@ config S390 select HAVE_ARCH_JUMP_LABEL select HAVE_ARCH_JUMP_LABEL_RELATIVE select HAVE_ARCH_KASAN + select HAVE_ARCH_KASAN_EARLY select HAVE_ARCH_KASAN_VMALLOC select HAVE_ARCH_KCSAN select HAVE_ARCH_KMSAN diff --git a/include/linux/kasan-enabled.h b/include/linux/kasan-enabled.h index 2436eb45cfee..049270a2269f 100644 --- a/include/linux/kasan-enabled.h +++ b/include/linux/kasan-enabled.h @@ -10,7 +10,11 @@ * Global runtime flag. Starts ‘false’; switched to ‘true’ by * the appropriate kasan_init_*() once KASAN is fully initialized. */ +#ifdef CONFIG_HAVE_ARCH_KASAN_EARLY +DECLARE_STATIC_KEY_TRUE(kasan_flag_enabled); +#else DECLARE_STATIC_KEY_FALSE(kasan_flag_enabled); +#endif static __always_inline bool kasan_enabled(void) { diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan index f82889a830fa..1407374e83b9 100644 --- a/lib/Kconfig.kasan +++ b/lib/Kconfig.kasan @@ -4,6 +4,13 @@ config HAVE_ARCH_KASAN bool +config HAVE_ARCH_KASAN_EARLY + bool + help + Architectures should select this if KASAN mappings are setup in + the decompressor and when the kernel can run very early with + KASAN enabled. + config HAVE_ARCH_KASAN_SW_TAGS bool diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 0f3648335a6b..2aae0ce659b4 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -36,7 +36,11 @@ * Definition of the unified static key declared in kasan-enabled.h. * This provides consistent runtime enable/disable across all KASAN modes. */ +#ifdef CONFIG_HAVE_ARCH_KASAN_EARLY +DEFINE_STATIC_KEY_TRUE(kasan_flag_enabled); +#else DEFINE_STATIC_KEY_FALSE(kasan_flag_enabled); +#endif EXPORT_SYMBOL(kasan_flag_enabled); struct slab *kasan_addr_to_slab(const void *addr) diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c index a3b112868be7..455376d5f1c3 100644 --- a/mm/kasan/generic.c +++ b/mm/kasan/generic.c @@ -42,7 +42,8 @@ */ void __init kasan_init_generic(void) { - static_branch_enable(&kasan_flag_enabled); + if (!IS_ENABLED(CONFIG_HAVE_ARCH_KASAN_EARLY)) + static_branch_enable(&kasan_flag_enabled); pr_info("KernelAddressSanitizer initialized (generic)\n"); }
Le 01/07/2025 à 12:15, Heiko Carstens a écrit : >>>> Another thing that needs careful consideration is whether it's >>>> possible to combine kasan_arch_is_ready() and kasan_enabled() into the >>>> same check logically at all. There's one issue mentioned in [1]: >>> >>> Hello, >>> I've removed kasan_arch_is_ready() at all in this series: >>> [PATCH v2 11/11] kasan: replace kasan_arch_is_ready with kasan_enabled >>> >>> Is it not what's expected by unification? >> >> I guess the issue description diverged a bit from what needs to be >> done, sorry about that. >> >> The core 2 things I wanted to address with the unification are: >> >> 1. Avoid spraying kasan_arch_is_ready() throughout the KASAN >> implementation and move these checks into include/linux/kasan.h (and >> add __wrappers when required). >> >> 2. Avoid architectures redefining the same kasan_enabled global >> variable/static key. >> >> Initially, I thought that s/kasan_arch_is_ready/kasan_enabled + simply >> moving the calls into affected include/linux/kasan.h functions would >> be enough. But then, based on [1], turns out it's not that simple. >> >> So now, I think we likely still need two separate checks/flags: >> kasan_enabled() that controls whether KASAN is enabled at all and >> kasan_arch_is_ready() that gets turned on by kasan_init() when shadow >> is initialized (should we rename it to kasan_shadow_initialized()?). >> But then we can still move kasan_arch_is_ready() into >> include/linux/kasan.h and use the proper combination of checks for >> each affected function before calling __wrappers. And we can still >> remove the duplicated flags/keys code from the arch code. > > FWIW, as Alexander Gordeev already mentioned: this series breaks s390, > since the static_branch_enable() call in kasan_init_generic() is now > called way too early, and it isn't necessary at all. Which, as far as > I understand, may be the case for other architectures as well. s390 > sets up the required KASAN mappings in the decompressor and can start > with KASAN enabled nearly from the beginning. > > So something like below on top of this series would address > that. Given that this series is about to be reworked this is just for > illustration :) I had the same kind of comment on powerpc/32. Allthough this series work on powerpc32 as is, it is overkill because it adds code and data for static branches for no real benefit. Your patch below is simpler than what I proposed, but it keeps the static branches so the overhead remains. I also proposed a change, it goes further by removing the static branch for architectures that don't need it, see https://patchwork.ozlabs.org/project/linuxppc-dev/cover/20250626153147.145312-1-snovitoll@gmail.com/#3537388 . Feedback welcome. Christophe > > diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig > index 0c16dc443e2f..c2f51ac39a91 100644 > --- a/arch/s390/Kconfig > +++ b/arch/s390/Kconfig > @@ -172,6 +172,7 @@ config S390 > select HAVE_ARCH_JUMP_LABEL > select HAVE_ARCH_JUMP_LABEL_RELATIVE > select HAVE_ARCH_KASAN > + select HAVE_ARCH_KASAN_EARLY > select HAVE_ARCH_KASAN_VMALLOC > select HAVE_ARCH_KCSAN > select HAVE_ARCH_KMSAN > diff --git a/include/linux/kasan-enabled.h b/include/linux/kasan-enabled.h > index 2436eb45cfee..049270a2269f 100644 > --- a/include/linux/kasan-enabled.h > +++ b/include/linux/kasan-enabled.h > @@ -10,7 +10,11 @@ > * Global runtime flag. Starts ‘false’; switched to ‘true’ by > * the appropriate kasan_init_*() once KASAN is fully initialized. > */ > +#ifdef CONFIG_HAVE_ARCH_KASAN_EARLY > +DECLARE_STATIC_KEY_TRUE(kasan_flag_enabled); > +#else > DECLARE_STATIC_KEY_FALSE(kasan_flag_enabled); > +#endif > > static __always_inline bool kasan_enabled(void) > { > diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan > index f82889a830fa..1407374e83b9 100644 > --- a/lib/Kconfig.kasan > +++ b/lib/Kconfig.kasan > @@ -4,6 +4,13 @@ > config HAVE_ARCH_KASAN > bool > > +config HAVE_ARCH_KASAN_EARLY > + bool > + help > + Architectures should select this if KASAN mappings are setup in > + the decompressor and when the kernel can run very early with > + KASAN enabled. > + > config HAVE_ARCH_KASAN_SW_TAGS > bool > > diff --git a/mm/kasan/common.c b/mm/kasan/common.c > index 0f3648335a6b..2aae0ce659b4 100644 > --- a/mm/kasan/common.c > +++ b/mm/kasan/common.c > @@ -36,7 +36,11 @@ > * Definition of the unified static key declared in kasan-enabled.h. > * This provides consistent runtime enable/disable across all KASAN modes. > */ > +#ifdef CONFIG_HAVE_ARCH_KASAN_EARLY > +DEFINE_STATIC_KEY_TRUE(kasan_flag_enabled); > +#else > DEFINE_STATIC_KEY_FALSE(kasan_flag_enabled); > +#endif > EXPORT_SYMBOL(kasan_flag_enabled); > > struct slab *kasan_addr_to_slab(const void *addr) > diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c > index a3b112868be7..455376d5f1c3 100644 > --- a/mm/kasan/generic.c > +++ b/mm/kasan/generic.c > @@ -42,7 +42,8 @@ > */ > void __init kasan_init_generic(void) > { > - static_branch_enable(&kasan_flag_enabled); > + if (!IS_ENABLED(CONFIG_HAVE_ARCH_KASAN_EARLY)) > + static_branch_enable(&kasan_flag_enabled); > > pr_info("KernelAddressSanitizer initialized (generic)\n"); > }
On Tue, Jul 01, 2025 at 12:25:32PM +0200, Christophe Leroy wrote: > Your patch below is simpler than what I proposed, but it keeps the static > branches so the overhead remains. > > I also proposed a change, it goes further by removing the static branch for > architectures that don't need it, see https://patchwork.ozlabs.org/project/linuxppc-dev/cover/20250626153147.145312-1-snovitoll@gmail.com/#3537388 > . Feedback welcome. Yes, removing the static branches during compile time is of course even better.
© 2016 - 2025 Red Hat, Inc.