[PATCH v2 01/11] kasan: unify static kasan_flag_enabled across modes

Sabyrzhan Tasbolatov posted 11 patches 3 months, 1 week ago
[PATCH v2 01/11] kasan: unify static kasan_flag_enabled across modes
Posted by Sabyrzhan Tasbolatov 3 months, 1 week ago
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

Re: [PATCH v2 01/11] kasan: unify static kasan_flag_enabled across modes
Posted by Alexander Gordeev 3 months, 1 week ago
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!
Re: [PATCH v2 01/11] kasan: unify static kasan_flag_enabled across modes
Posted by Andrew Morton 3 months, 1 week ago
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.
Re: [PATCH v2 01/11] kasan: unify static kasan_flag_enabled across modes
Posted by Heiko Carstens 3 months, 1 week ago
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?
Re: [PATCH v2 01/11] kasan: unify static kasan_flag_enabled across modes
Posted by Alexander Gordeev 3 months, 1 week ago
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?