Historically, the runtime static key kasan_flag_enabled existed only for
CONFIG_KASAN_HW_TAGS mode. Generic and SW_TAGS modes either relied on
architecture-specific kasan_arch_is_ready() implementations or evaluated
KASAN checks unconditionally, leading to code duplication.
This patch unifies the approach by:
1. Moving kasan_flag_enabled declaration under CONFIG_KASAN (all modes)
instead of only CONFIG_KASAN_HW_TAGS
2. Moving the static key definition to common.c for shared usage
3. Adding kasan_init_generic() function that enables the static key and
handles initialization for Generic mode
4. Updating SW_TAGS mode to enable the unified static key
5. Removing the duplicate static key definition from HW_TAGS
After this change, all KASAN modes use the same underlying static key
infrastructure. The kasan_enabled() function now provides consistent
runtime enable behavior across Generic, SW_TAGS, and HW_TAGS modes.
This maintains a backward compatibility - existing architecture code
continues to work unchanged, but now benefits from the unified runtime
control mechanism. The architecture-specific kasan_arch_is_ready()
implementations can be gradually replaced with calls to the new
kasan_init_generic() function.
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218315
Signed-off-by: Sabyrzhan Tasbolatov <snovitoll@gmail.com>
---
include/linux/kasan-enabled.h | 10 ++++++++--
include/linux/kasan.h | 6 ++++++
mm/kasan/common.c | 7 +++++++
mm/kasan/generic.c | 11 +++++++++++
mm/kasan/hw_tags.c | 7 -------
mm/kasan/sw_tags.c | 2 ++
6 files changed, 34 insertions(+), 9 deletions(-)
diff --git a/include/linux/kasan-enabled.h b/include/linux/kasan-enabled.h
index 6f612d69ea0..2b1351c30c6 100644
--- a/include/linux/kasan-enabled.h
+++ b/include/linux/kasan-enabled.h
@@ -4,9 +4,15 @@
#include <linux/static_key.h>
-#ifdef CONFIG_KASAN_HW_TAGS
-
+#ifdef CONFIG_KASAN
+/*
+ * Global runtime flag. Starts ‘false’; switched to ‘true’ by
+ * the appropriate kasan_init_*() once KASAN is fully initialized.
+ */
DECLARE_STATIC_KEY_FALSE(kasan_flag_enabled);
+#endif
+
+#ifdef CONFIG_KASAN_HW_TAGS
static __always_inline bool kasan_enabled(void)
{
diff --git a/include/linux/kasan.h b/include/linux/kasan.h
index 890011071f2..51a8293d1af 100644
--- a/include/linux/kasan.h
+++ b/include/linux/kasan.h
@@ -543,6 +543,12 @@ void kasan_report_async(void);
#endif /* CONFIG_KASAN_HW_TAGS */
+#ifdef CONFIG_KASAN_GENERIC
+void __init kasan_init_generic(void);
+#else
+static inline void kasan_init_generic(void) { }
+#endif
+
#ifdef CONFIG_KASAN_SW_TAGS
void __init kasan_init_sw_tags(void);
#else
diff --git a/mm/kasan/common.c b/mm/kasan/common.c
index ed4873e18c7..525194da25f 100644
--- a/mm/kasan/common.c
+++ b/mm/kasan/common.c
@@ -32,6 +32,13 @@
#include "kasan.h"
#include "../slab.h"
+/*
+ * Definition of the unified static key declared in kasan-enabled.h.
+ * This provides consistent runtime enable/disable across all KASAN modes.
+ */
+DEFINE_STATIC_KEY_FALSE(kasan_flag_enabled);
+EXPORT_SYMBOL(kasan_flag_enabled);
+
struct slab *kasan_addr_to_slab(const void *addr)
{
if (virt_addr_valid(addr))
diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c
index d54e89f8c3e..32c432df24a 100644
--- a/mm/kasan/generic.c
+++ b/mm/kasan/generic.c
@@ -36,6 +36,17 @@
#include "kasan.h"
#include "../slab.h"
+/*
+ * Initialize Generic KASAN and enable runtime checks.
+ * This should be called from arch kasan_init() once shadow memory is ready.
+ */
+void __init kasan_init_generic(void)
+{
+ static_branch_enable(&kasan_flag_enabled);
+
+ pr_info("KernelAddressSanitizer initialized (generic)\n");
+}
+
/*
* All functions below always inlined so compiler could
* perform better optimizations in each of __asan_loadX/__assn_storeX
diff --git a/mm/kasan/hw_tags.c b/mm/kasan/hw_tags.c
index 9a6927394b5..8e819fc4a26 100644
--- a/mm/kasan/hw_tags.c
+++ b/mm/kasan/hw_tags.c
@@ -45,13 +45,6 @@ static enum kasan_arg kasan_arg __ro_after_init;
static enum kasan_arg_mode kasan_arg_mode __ro_after_init;
static enum kasan_arg_vmalloc kasan_arg_vmalloc __initdata;
-/*
- * Whether KASAN is enabled at all.
- * The value remains false until KASAN is initialized by kasan_init_hw_tags().
- */
-DEFINE_STATIC_KEY_FALSE(kasan_flag_enabled);
-EXPORT_SYMBOL(kasan_flag_enabled);
-
/*
* Whether the selected mode is synchronous, asynchronous, or asymmetric.
* Defaults to KASAN_MODE_SYNC.
diff --git a/mm/kasan/sw_tags.c b/mm/kasan/sw_tags.c
index b9382b5b6a3..525bc91e2fc 100644
--- a/mm/kasan/sw_tags.c
+++ b/mm/kasan/sw_tags.c
@@ -45,6 +45,8 @@ void __init kasan_init_sw_tags(void)
kasan_init_tags();
+ static_branch_enable(&kasan_flag_enabled);
+
pr_info("KernelAddressSanitizer initialized (sw-tags, stacktrace=%s)\n",
str_on_off(kasan_stack_collection_enabled()));
}
--
2.34.1
On Thu, Jun 26, 2025 at 08:31:37PM +0500, Sabyrzhan Tasbolatov wrote: Hi Sabyrzhan, > diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c > index d54e89f8c3e..32c432df24a 100644 > --- a/mm/kasan/generic.c > +++ b/mm/kasan/generic.c > @@ -36,6 +36,17 @@ > #include "kasan.h" > #include "../slab.h" > > +/* > + * Initialize Generic KASAN and enable runtime checks. > + * This should be called from arch kasan_init() once shadow memory is ready. > + */ > +void __init kasan_init_generic(void) > +{ > + static_branch_enable(&kasan_flag_enabled); s390 crashes at this line, when the whole series is applied. FWIW, it looks like kasan is called while its state is not yet finalized. E.g. whether calling __asan_report_store4_noabort() before kasan_init_generic() is expected? 32e0a54: c0 e5 fe a9 70 56 brasl %r14,80eb00 <__asan_report_store4_noabort> 32e0a5a: c4 28 ff cb bb a3 lgrl %r2,2c581a0 <_GLOBAL_OFFSET_TABLE_+0x70c0> sort_extable(__start_amode31_ex_table, __stop_amode31_ex_table); 32e0a60: a5 ac 00 1c llihh %r10,28 init_task.kasan_depth = 0; 32e0a64: e3 40 2b c8 01 71 lay %r4,7112(%r2) 32e0a6a: e5 4c 40 00 00 00 mvhi 0(%r4),0 kasan_init_generic(); 32e0a70: c0 e5 00 01 e7 3c brasl %r14,331d8e8 <kasan_init_generic> > + pr_info("KernelAddressSanitizer initialized (generic)\n"); > +} Thanks!
On Mon, 30 Jun 2025 14:31:00 +0200 Alexander Gordeev <agordeev@linux.ibm.com> wrote: > > +/* > > + * Initialize Generic KASAN and enable runtime checks. > > + * This should be called from arch kasan_init() once shadow memory is ready. > > + */ > > +void __init kasan_init_generic(void) > > +{ > > + static_branch_enable(&kasan_flag_enabled); > > s390 crashes at this line, when the whole series is applied. oop. Thanks, I'll demote this seres to the mm-new branch for now, which takes it out of linux-next.
On Mon, Jun 30, 2025 at 02:31:00PM +0200, Alexander Gordeev wrote: > On Thu, Jun 26, 2025 at 08:31:37PM +0500, Sabyrzhan Tasbolatov wrote: > > Hi Sabyrzhan, > > > diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c > > index d54e89f8c3e..32c432df24a 100644 > > --- a/mm/kasan/generic.c > > +++ b/mm/kasan/generic.c > > @@ -36,6 +36,17 @@ > > #include "kasan.h" > > #include "../slab.h" > > > > +/* > > + * Initialize Generic KASAN and enable runtime checks. > > + * This should be called from arch kasan_init() once shadow memory is ready. > > + */ > > +void __init kasan_init_generic(void) > > +{ > > + static_branch_enable(&kasan_flag_enabled); > > s390 crashes at this line, when the whole series is applied. > > FWIW, it looks like kasan is called while its state is not yet finalized. > E.g. whether calling __asan_report_store4_noabort() before kasan_init_generic() > is expected? It crashes because with this conversion a call to static_branch_enable() is introduced. This one get's called way before jump_label_init() init has been called. Therefore the STATIC_KEY_CHECK_USE() in static_key_enable_cpuslocked() triggers. This again tries to emit a warning. Due to lack of console support that early the kernel crashes. One possible solution would be to move the kasan init function to arch/s390/kernel/setup.c, after jump_label_init() has been called. If we want this, is a different question. It seems to work, so I see no reason for not doing that. Vasily, since you did nearly all of the KASAN work for s390, do you have any opinion about this?
On Mon, Jun 30, 2025 at 04:39:34PM +0200, Heiko Carstens wrote: > > > +/* > > > + * Initialize Generic KASAN and enable runtime checks. > > > + * This should be called from arch kasan_init() once shadow memory is ready. > > > + */ > > > +void __init kasan_init_generic(void) > > > +{ > > > + static_branch_enable(&kasan_flag_enabled); > > > > s390 crashes at this line, when the whole series is applied. > > > > FWIW, it looks like kasan is called while its state is not yet finalized. > > E.g. whether calling __asan_report_store4_noabort() before kasan_init_generic() > > is expected? > > It crashes because with this conversion a call to static_branch_enable() is > introduced. This one get's called way before jump_label_init() init has been > called. Therefore the STATIC_KEY_CHECK_USE() in static_key_enable_cpuslocked() > triggers. > > This again tries to emit a warning. Due to lack of console support that early > the kernel crashes. > > One possible solution would be to move the kasan init function to > arch/s390/kernel/setup.c, after jump_label_init() has been called. > If we want this, is a different question. > > It seems to work, so I see no reason for not doing that. IIRC, we wanted to have kasan coverage as early as possible. Delaying it past jump_label_init() leaves out pretty big chunk of code? > Vasily, since you did nearly all of the KASAN work for s390, do you have any > opinion about this?
© 2016 - 2025 Red Hat, Inc.