[PATCH v3 00/12] kasan: unify kasan_arch_is_ready() and remove arch-specific implementations
flat view
STALE454d
SUPERSEDED
From: Sabyrzhan Tasbolatov <hidden>
Date: 2025-07-17 14:27:42
Also in:
linux-mm, linux-riscv, linux-s390, linux-um, lkml, loongarch
Subsystem:
arm port, arm64 port (aarch64 architecture), kasan, library code, linux for powerpc (32-bit and 64-bit), loongarch, memory management, risc-v architecture, s390 architecture, tensilica xtensa port (xtensa), the rest, user-mode linux (uml), x86 architecture (32-bit and 64-bit), x86 mm · Maintainers:
Russell King, Catalin Marinas, Will Deacon, Andrey Ryabinin, Andrew Morton, Madhavan Srinivasan, Huacai Chen, Paul Walmsley, Palmer Dabbelt, Albert Ou, Heiko Carstens, Vasily Gorbik, Alexander Gordeev, Chris Zankel, Max Filippov, Linus Torvalds, Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, Andy Lutomirski, Peter Zijlstra
This patch series addresses the fragmentation in KASAN initialization
across architectures by introducing a unified approach that eliminates
duplicate static keys and arch-specific kasan_arch_is_ready()
implementations.
The core issue is that different architectures have inconsistent approaches
to KASAN readiness tracking:
- PowerPC, LoongArch, and um arch, each implement own kasan_arch_is_ready()
- Only HW_TAGS mode had a unified static key (kasan_flag_enabled)
- Generic and SW_TAGS modes relied on arch-specific solutions
or always-on behavior
This series implements two-level approach:
1. kasan_enabled() - compile-time check for KASAN configuration
2. kasan_shadow_initialized() - runtime check for shadow memory readiness
Key improvements:
- Unified static key infrastructure across all KASAN modes
- Runtime overhead only for architectures that actually need it
- Compile-time optimization for arch. with early KASAN initialization
- Complete elimination of arch-specific kasan_arch_is_ready()
- Consistent interface and reduced code duplication
Previous v2 thread: https://lore.kernel.org/all/20250626153147.145312-1-snovitoll@gmail.com/ (local)
Changes in v3 (sorry for the 3-week gap):
0. Included in TO, CC only KASAN devs and people who commented in v2.
1. Addressed Andrey Konovalov's feedback:
- Kept separate kasan_enabled() and kasan_shadow_initialized() functions
- Added proper __wrapper functions with clean separation
2. Addressed Christophe Leroy's performance comments:
- CONFIG_ARCH_DEFER_KASAN is only selected by architectures that need it
- No static key overhead for architectures that can enable KASAN early
- PowerPC 32-bit and book3e get compile-time optimization
3. Addressed Heiko Carstens and Alexander Gordeev s390 comments:
- s390 doesn't select ARCH_DEFER_KASAN (no unnecessary static key overhead)
- kasan_enable() is a no-op for architectures with early KASAN setup
4. Improved wrapper architecture:
- All existing wrapper functions in include/linux/kasan.h now check both
kasan_enabled() && kasan_shadow_initialized()
- Internal implementation functions focus purely on core functionality
- Shadow readiness logic is centralized in headers per Andrey's guidance
Architecture-specific changes:
- PowerPC radix MMU: selects ARCH_DEFER_KASAN for runtime control
- LoongArch: selects ARCH_DEFER_KASAN, removes custom kasan_early_stage
- um: selects ARCH_DEFER_KASAN, removes kasan_um_is_ready
- Other architectures: get compile-time optimization, no runtime overhead
The series maintains full backward compatibility while providing optimal
performance for each architecture's needs.
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=217049
=== Current mainline KUnit status
To see if there is any regression, I've 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 v3:
- 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
Sabyrzhan Tasbolatov (12):
lib/kasan: introduce CONFIG_ARCH_DEFER_KASAN option
kasan: unify static kasan_flag_enabled across modes
kasan/powerpc: select ARCH_DEFER_KASAN and call kasan_init_generic
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: select ARCH_DEFER_KASAN and call kasan_init_generic
kasan/um: select ARCH_DEFER_KASAN and call kasan_init_generic
kasan/x86: call kasan_init_generic in kasan_init
kasan/s390: call kasan_init_generic in kasan_init
kasan/riscv: call kasan_init_generic in kasan_init
kasan: add shadow checks to wrappers and rename kasan_arch_is_ready
arch/arm/mm/kasan_init.c | 2 +-
arch/arm64/mm/kasan_init.c | 4 +--
arch/loongarch/Kconfig | 1 +
arch/loongarch/include/asm/kasan.h | 7 -----
arch/loongarch/mm/kasan_init.c | 7 ++---
arch/powerpc/Kconfig | 1 +
arch/powerpc/include/asm/kasan.h | 12 --------
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/Kconfig | 1 +
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 | 34 ++++++++++++++++-----
include/linux/kasan.h | 42 ++++++++++++++++++++------
lib/Kconfig.kasan | 8 +++++
mm/kasan/common.c | 18 +++++++----
mm/kasan/generic.c | 23 ++++++++------
mm/kasan/hw_tags.c | 9 +-----
mm/kasan/kasan.h | 36 ++++++++++++++++------
mm/kasan/shadow.c | 32 +++++---------------
mm/kasan/sw_tags.c | 2 ++
26 files changed, 146 insertions(+), 120 deletions(-)
--
2.34.1