[PATCH v2 00/11] kasan: unify kasan_arch_is_ready with kasan_enabled

Sabyrzhan Tasbolatov posted 11 patches 3 months, 1 week ago
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(-)
[PATCH v2 00/11] kasan: unify kasan_arch_is_ready with kasan_enabled
Posted by Sabyrzhan Tasbolatov 3 months, 1 week ago
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
Re: [PATCH v2 00/11] kasan: unify kasan_arch_is_ready with kasan_enabled
Posted by Christophe Leroy 3 months, 1 week ago

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(-)
> 

Re: [PATCH v2 00/11] kasan: unify kasan_arch_is_ready with kasan_enabled
Posted by Andrey Konovalov 3 months, 1 week ago
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/
Re: [PATCH v2 00/11] kasan: unify kasan_arch_is_ready with kasan_enabled
Posted by Sabyrzhan Tasbolatov 3 months, 1 week ago
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/
Re: [PATCH v2 00/11] kasan: unify kasan_arch_is_ready with kasan_enabled
Posted by Andrey Konovalov 3 months, 1 week ago
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/
Re: [PATCH v2 00/11] kasan: unify kasan_arch_is_ready with kasan_enabled
Posted by Heiko Carstens 3 months, 1 week ago
> > > 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");
 }
Re: [PATCH v2 00/11] kasan: unify kasan_arch_is_ready with kasan_enabled
Posted by Christophe Leroy 3 months, 1 week ago

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");
>   }

Re: [PATCH v2 00/11] kasan: unify kasan_arch_is_ready with kasan_enabled
Posted by Heiko Carstens 3 months, 1 week ago
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.