[PATCH 0/4] mm/kasan: make kasan=on|off work for all three modes

4 views
Skip to first unread message

Baoquan He

unread,
Aug 5, 2025, 2:23:49 AMAug 5
to linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, Baoquan He
Currently only hw_tags mode of kasan can be enabled or disabled with
kernel parameter kasan=on|off for built kernel. For kasan generic and
sw_tags mode, there's no way to disable them once kernel is built.
This is not convenient sometime, e.g in system kdump is configured.
When the 1st kernel has KASAN enabled and crash triggered to switch to
kdump kernel, the generic or sw_tags mode will cost much extra memory
for kasan shadow while in fact it's meaningless to have kasan in kdump
kernel.

So this patchset moves the kasan=on|off out of hw_tags scope and into
common code to make it visible in generic and sw_tags mode too. Then we
can add kasan=off in kdump kernel to reduce the unneeded meomry cost for
kasan.

Test:
=====
I only took test on x86_64 for generic mode, and on arm64 for
generic, sw_tags and hw_tags mode. All of them works well.

However when I tested sw_tags on a HPE apollo arm64 machine, it always
breaks kernel with a KASAN bug. Even w/o this patchset applied, the bug
can always be seen too.

"BUG: KASAN: invalid-access in pcpu_alloc_noprof+0x42c/0x9a8"

I haven't got root cause of the bug, will report the bug later in
another thread.
====

Baoquan He (4):
mm/kasan: add conditional checks in functions to return directly if
kasan is disabled
mm/kasan: move kasan= code to common place
mm/kasan: don't initialize kasan if it's disabled
mm/kasan: make kasan=on|off take effect for all three modes

arch/arm/mm/kasan_init.c | 6 +++++
arch/arm64/mm/kasan_init.c | 7 ++++++
arch/loongarch/mm/kasan_init.c | 5 ++++
arch/powerpc/mm/kasan/init_32.c | 8 +++++-
arch/powerpc/mm/kasan/init_book3e_64.c | 6 +++++
arch/powerpc/mm/kasan/init_book3s_64.c | 6 +++++
arch/riscv/mm/kasan_init.c | 6 +++++
arch/um/kernel/mem.c | 6 +++++
arch/x86/mm/kasan_init_64.c | 6 +++++
arch/xtensa/mm/kasan_init.c | 6 +++++
include/linux/kasan-enabled.h | 11 ++------
mm/kasan/common.c | 27 ++++++++++++++++++++
mm/kasan/generic.c | 20 +++++++++++++--
mm/kasan/hw_tags.c | 35 ++------------------------
mm/kasan/init.c | 6 +++++
mm/kasan/quarantine.c | 3 +++
mm/kasan/shadow.c | 23 ++++++++++++++++-
mm/kasan/sw_tags.c | 9 +++++++
18 files changed, 150 insertions(+), 46 deletions(-)

--
2.41.0

Baoquan He

unread,
Aug 5, 2025, 2:23:57 AMAug 5
to linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, Baoquan He
The current code only does the check if kasan is disabled for hw_tags
mode. Here add the conditional checks for functional functions of
generic mode and sw_tags mode.

This is prepared for later adding kernel parameter kasan=on|off for
all kasan modes.

Signed-off-by: Baoquan He <b...@redhat.com>
---
mm/kasan/generic.c | 20 ++++++++++++++++++--
mm/kasan/init.c | 6 ++++++
mm/kasan/quarantine.c | 3 +++
mm/kasan/shadow.c | 23 ++++++++++++++++++++++-
mm/kasan/sw_tags.c | 3 +++
5 files changed, 52 insertions(+), 3 deletions(-)

diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c
index d54e89f8c3e7..ee4ddc1e7127 100644
--- a/mm/kasan/generic.c
+++ b/mm/kasan/generic.c
@@ -165,6 +165,9 @@ static __always_inline bool check_region_inline(const void *addr,
size_t size, bool write,
unsigned long ret_ip)
{
+ if (!kasan_enabled())
+ return true;
+
if (!kasan_arch_is_ready())
return true;

@@ -203,12 +206,13 @@ bool kasan_byte_accessible(const void *addr)

void kasan_cache_shrink(struct kmem_cache *cache)
{
- kasan_quarantine_remove_cache(cache);
+ if (kasan_enabled())
+ kasan_quarantine_remove_cache(cache);
}

void kasan_cache_shutdown(struct kmem_cache *cache)
{
- if (!__kmem_cache_empty(cache))
+ if (kasan_enabled() && !__kmem_cache_empty(cache))
kasan_quarantine_remove_cache(cache);
}

@@ -228,6 +232,9 @@ void __asan_register_globals(void *ptr, ssize_t size)
int i;
struct kasan_global *globals = ptr;

+ if (!kasan_enabled())
+ return;
+
for (i = 0; i < size; i++)
register_global(&globals[i]);
}
@@ -358,6 +365,9 @@ void kasan_cache_create(struct kmem_cache *cache, unsigned int *size,
unsigned int rem_free_meta_size;
unsigned int orig_alloc_meta_offset;

+ if (!kasan_enabled())
+ return;
+
if (!kasan_requires_meta())
return;

@@ -510,6 +520,9 @@ size_t kasan_metadata_size(struct kmem_cache *cache, bool in_object)
{
struct kasan_cache *info = &cache->kasan_info;

+ if (!kasan_enabled())
+ return 0;
+
if (!kasan_requires_meta())
return 0;

@@ -535,6 +548,9 @@ void kasan_record_aux_stack(void *addr)
struct kasan_alloc_meta *alloc_meta;
void *object;

+ if (!kasan_enabled())
+ return;
+
if (is_kfence_address(addr) || !slab)
return;

diff --git a/mm/kasan/init.c b/mm/kasan/init.c
index ced6b29fcf76..43d95f329675 100644
--- a/mm/kasan/init.c
+++ b/mm/kasan/init.c
@@ -449,6 +449,9 @@ void kasan_remove_zero_shadow(void *start, unsigned long size)
unsigned long addr, end, next;
pgd_t *pgd;

+ if (!kasan_enabled())
+ return;
+
addr = (unsigned long)kasan_mem_to_shadow(start);
end = addr + (size >> KASAN_SHADOW_SCALE_SHIFT);

@@ -484,6 +487,9 @@ int kasan_add_zero_shadow(void *start, unsigned long size)
int ret;
void *shadow_start, *shadow_end;

+ if (!kasan_enabled())
+ return 0;
+
shadow_start = kasan_mem_to_shadow(start);
shadow_end = shadow_start + (size >> KASAN_SHADOW_SCALE_SHIFT);

diff --git a/mm/kasan/quarantine.c b/mm/kasan/quarantine.c
index 6958aa713c67..a6dc2c3d8a15 100644
--- a/mm/kasan/quarantine.c
+++ b/mm/kasan/quarantine.c
@@ -405,6 +405,9 @@ static int __init kasan_cpu_quarantine_init(void)
{
int ret = 0;

+ if (!kasan_enabled())
+ return 0;
+
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "mm/kasan:online",
kasan_cpu_online, kasan_cpu_offline);
if (ret < 0)
diff --git a/mm/kasan/shadow.c b/mm/kasan/shadow.c
index d2c70cd2afb1..637f2d02d2a3 100644
--- a/mm/kasan/shadow.c
+++ b/mm/kasan/shadow.c
@@ -125,6 +125,9 @@ void kasan_poison(const void *addr, size_t size, u8 value, bool init)
{
void *shadow_start, *shadow_end;

+ if (!kasan_enabled())
+ return;
+
if (!kasan_arch_is_ready())
return;

@@ -150,6 +153,9 @@ EXPORT_SYMBOL_GPL(kasan_poison);
#ifdef CONFIG_KASAN_GENERIC
void kasan_poison_last_granule(const void *addr, size_t size)
{
+ if (!kasan_enabled())
+ return;
+
if (!kasan_arch_is_ready())
return;

@@ -164,6 +170,8 @@ void kasan_unpoison(const void *addr, size_t size, bool init)
{
u8 tag = get_tag(addr);

+ if (!kasan_enabled())
+ return;
/*
* Perform shadow offset calculation based on untagged address, as
* some of the callers (e.g. kasan_unpoison_new_object) pass tagged
@@ -277,7 +285,8 @@ static int __meminit kasan_mem_notifier(struct notifier_block *nb,

static int __init kasan_memhotplug_init(void)
{
- hotplug_memory_notifier(kasan_mem_notifier, DEFAULT_CALLBACK_PRI);
+ if (kasan_enabled())
+ hotplug_memory_notifier(kasan_mem_notifier, DEFAULT_CALLBACK_PRI);

return 0;
}
@@ -390,6 +399,9 @@ int kasan_populate_vmalloc(unsigned long addr, unsigned long size)
unsigned long shadow_start, shadow_end;
int ret;

+ if (!kasan_enabled())
+ return 0;
+
if (!kasan_arch_is_ready())
return 0;

@@ -560,6 +572,9 @@ void kasan_release_vmalloc(unsigned long start, unsigned long end,
unsigned long region_start, region_end;
unsigned long size;

+ if (!kasan_enabled())
+ return;
+
if (!kasan_arch_is_ready())
return;

@@ -655,6 +670,9 @@ int kasan_alloc_module_shadow(void *addr, size_t size, gfp_t gfp_mask)
size_t shadow_size;
unsigned long shadow_start;

+ if (!kasan_enabled())
+ return 0;
+
shadow_start = (unsigned long)kasan_mem_to_shadow(addr);
scaled_size = (size + KASAN_GRANULE_SIZE - 1) >>
KASAN_SHADOW_SCALE_SHIFT;
@@ -691,6 +709,9 @@ int kasan_alloc_module_shadow(void *addr, size_t size, gfp_t gfp_mask)

void kasan_free_module_shadow(const struct vm_struct *vm)
{
+ if (!kasan_enabled())
+ return;
+
if (IS_ENABLED(CONFIG_UML))
return;

diff --git a/mm/kasan/sw_tags.c b/mm/kasan/sw_tags.c
index b9382b5b6a37..01f19bc4a326 100644
--- a/mm/kasan/sw_tags.c
+++ b/mm/kasan/sw_tags.c
@@ -78,6 +78,9 @@ bool kasan_check_range(const void *addr, size_t size, bool write,
u8 *shadow_first, *shadow_last, *shadow;
void *untagged_addr;

+ if (!kasan_enabled())
+ return true;
+
if (unlikely(size == 0))
return true;

--
2.41.0

Baoquan He

unread,
Aug 5, 2025, 2:24:00 AMAug 5
to linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, Baoquan He
This allows generic and sw_tags to be set in kernel cmdline too.

When at it, rename 'kasan_arg' to 'kasan_arg_disabled' as a bool
variable. And expose 'kasan_flag_enabled' to kasan common place
too.

This is prepared for later adding kernel parameter kasan=on|off for
all kasan modes.

Signed-off-by: Baoquan He <b...@redhat.com>
---
include/linux/kasan-enabled.h | 4 +++-
mm/kasan/common.c | 27 +++++++++++++++++++++++++++
mm/kasan/hw_tags.c | 35 ++---------------------------------
3 files changed, 32 insertions(+), 34 deletions(-)

diff --git a/include/linux/kasan-enabled.h b/include/linux/kasan-enabled.h
index 6f612d69ea0c..32f2d19f599f 100644
--- a/include/linux/kasan-enabled.h
+++ b/include/linux/kasan-enabled.h
@@ -4,10 +4,12 @@

#include <linux/static_key.h>

-#ifdef CONFIG_KASAN_HW_TAGS
+extern bool kasan_arg_disabled;

DECLARE_STATIC_KEY_FALSE(kasan_flag_enabled);

+#ifdef CONFIG_KASAN_HW_TAGS
+
static __always_inline bool kasan_enabled(void)
{
return static_branch_likely(&kasan_flag_enabled);
diff --git a/mm/kasan/common.c b/mm/kasan/common.c
index ed4873e18c75..fe6937654203 100644
--- a/mm/kasan/common.c
+++ b/mm/kasan/common.c
@@ -32,6 +32,33 @@
#include "kasan.h"
#include "../slab.h"

+/*
+ * Whether KASAN is enabled at all.
+ * The value remains false until KASAN is initialized.
+ */
+DEFINE_STATIC_KEY_FALSE(kasan_flag_enabled);
+EXPORT_SYMBOL(kasan_flag_enabled);
+
+bool kasan_arg_disabled;
+/* kasan=off/on */
+static int __init early_kasan_flag(char *arg)
+{
+ if (!arg)
+ return -EINVAL;
+
+ if (!strcmp(arg, "off"))
+ kasan_arg_disabled = true;
+ else if (!strcmp(arg, "on"))
+ kasan_arg_disabled = false;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+early_param("kasan", early_kasan_flag);
+
+
+
struct slab *kasan_addr_to_slab(const void *addr)
{
if (virt_addr_valid(addr))
diff --git a/mm/kasan/hw_tags.c b/mm/kasan/hw_tags.c
index 9a6927394b54..377e9c285a74 100644
--- a/mm/kasan/hw_tags.c
+++ b/mm/kasan/hw_tags.c
@@ -22,12 +22,6 @@

#include "kasan.h"

-enum kasan_arg {
- KASAN_ARG_DEFAULT,
- KASAN_ARG_OFF,
- KASAN_ARG_ON,
-};
-
enum kasan_arg_mode {
KASAN_ARG_MODE_DEFAULT,
KASAN_ARG_MODE_SYNC,
@@ -41,17 +35,9 @@ enum kasan_arg_vmalloc {
KASAN_ARG_VMALLOC_ON,
};

-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.
@@ -85,23 +71,6 @@ unsigned int kasan_page_alloc_sample_order = PAGE_ALLOC_SAMPLE_ORDER_DEFAULT;

DEFINE_PER_CPU(long, kasan_page_alloc_skip);

-/* kasan=off/on */
-static int __init early_kasan_flag(char *arg)
-{
- if (!arg)
- return -EINVAL;
-
- if (!strcmp(arg, "off"))
- kasan_arg = KASAN_ARG_OFF;
- else if (!strcmp(arg, "on"))
- kasan_arg = KASAN_ARG_ON;
- else
- return -EINVAL;
-
- return 0;
-}
-early_param("kasan", early_kasan_flag);
-
/* kasan.mode=sync/async/asymm */
static int __init early_kasan_mode(char *arg)
{
@@ -209,7 +178,7 @@ void kasan_init_hw_tags_cpu(void)
* When this function is called, kasan_flag_enabled is not yet
* set by kasan_init_hw_tags(). Thus, check kasan_arg instead.
*/
- if (kasan_arg == KASAN_ARG_OFF)
+ if (kasan_arg_disabled)
return;

/*
@@ -227,7 +196,7 @@ void __init kasan_init_hw_tags(void)
return;

/* If KASAN is disabled via command line, don't initialize it. */
- if (kasan_arg == KASAN_ARG_OFF)
+ if (kasan_arg_disabled)
return;

switch (kasan_arg_mode) {
--
2.41.0

Baoquan He

unread,
Aug 5, 2025, 2:24:10 AMAug 5
to linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, Baoquan He
This is mainly done in all architectures which support kasan, and also
need be done in sw_tags init funciton kasan_init_sw_tags().

And also add code to enable kasan_flag_enabled, this is for later usage.

Signed-off-by: Baoquan He <b...@redhat.com>
---
arch/arm/mm/kasan_init.c | 6 ++++++
arch/arm64/mm/kasan_init.c | 7 +++++++
arch/loongarch/mm/kasan_init.c | 5 +++++
arch/powerpc/mm/kasan/init_32.c | 8 +++++++-
arch/powerpc/mm/kasan/init_book3e_64.c | 6 ++++++
arch/powerpc/mm/kasan/init_book3s_64.c | 6 ++++++
arch/riscv/mm/kasan_init.c | 6 ++++++
arch/um/kernel/mem.c | 6 ++++++
arch/x86/mm/kasan_init_64.c | 6 ++++++
arch/xtensa/mm/kasan_init.c | 6 ++++++
mm/kasan/sw_tags.c | 6 ++++++
11 files changed, 67 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mm/kasan_init.c b/arch/arm/mm/kasan_init.c
index 111d4f703136..c764e1b9c9c5 100644
--- a/arch/arm/mm/kasan_init.c
+++ b/arch/arm/mm/kasan_init.c
@@ -212,6 +212,8 @@ void __init kasan_init(void)
phys_addr_t pa_start, pa_end;
u64 i;

+ if (kasan_arg_disabled)
+ return;
/*
* We are going to perform proper setup of shadow memory.
*
@@ -300,6 +302,10 @@ void __init kasan_init(void)
local_flush_tlb_all();

memset(kasan_early_shadow_page, 0, PAGE_SIZE);
+
+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+
pr_info("Kernel address sanitizer initialized\n");
init_task.kasan_depth = 0;
}
diff --git a/arch/arm64/mm/kasan_init.c b/arch/arm64/mm/kasan_init.c
index d541ce45daeb..0e4ffe3f5d0e 100644
--- a/arch/arm64/mm/kasan_init.c
+++ b/arch/arm64/mm/kasan_init.c
@@ -384,6 +384,9 @@ void __init kasan_populate_early_vm_area_shadow(void *start, unsigned long size)
{
unsigned long shadow_start, shadow_end;

+ if (!kasan_enabled())
+ return;
+
if (!is_vmalloc_or_module_addr(start))
return;

@@ -397,6 +400,9 @@ void __init kasan_populate_early_vm_area_shadow(void *start, unsigned long size)

void __init kasan_init(void)
{
+ if (kasan_arg_disabled)
+ return;
+
kasan_init_shadow();
kasan_init_depth();
#if defined(CONFIG_KASAN_GENERIC)
@@ -405,6 +411,7 @@ void __init kasan_init(void)
* Software and Hardware Tag-Based modes still require
* kasan_init_sw_tags() and kasan_init_hw_tags() correspondingly.
*/
+ static_branch_enable(&kasan_flag_enabled);
pr_info("KernelAddressSanitizer initialized (generic)\n");
#endif
}
diff --git a/arch/loongarch/mm/kasan_init.c b/arch/loongarch/mm/kasan_init.c
index d2681272d8f0..0c32eee6910f 100644
--- a/arch/loongarch/mm/kasan_init.c
+++ b/arch/loongarch/mm/kasan_init.c
@@ -267,6 +267,8 @@ void __init kasan_init(void)
u64 i;
phys_addr_t pa_start, pa_end;

+ if (kasan_arg_disabled)
+ return;
/*
* If PGDIR_SIZE is too large for cpu_vabits, KASAN_SHADOW_END will
* overflow UINTPTR_MAX and then looks like a user space address.
@@ -327,6 +329,9 @@ void __init kasan_init(void)
csr_write64(__pa_symbol(swapper_pg_dir), LOONGARCH_CSR_PGDH);
local_flush_tlb_all();

+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+
/* At this point kasan is fully initialized. Enable error messages */
init_task.kasan_depth = 0;
pr_info("KernelAddressSanitizer initialized.\n");
diff --git a/arch/powerpc/mm/kasan/init_32.c b/arch/powerpc/mm/kasan/init_32.c
index 03666d790a53..b0c465f3fbf5 100644
--- a/arch/powerpc/mm/kasan/init_32.c
+++ b/arch/powerpc/mm/kasan/init_32.c
@@ -141,6 +141,9 @@ void __init kasan_init(void)
u64 i;
int ret;

+ if (kasan_arg_disabled)
+ return;
+
for_each_mem_range(i, &base, &end) {
phys_addr_t top = min(end, total_lowmem);

@@ -163,6 +166,9 @@ void __init kasan_init(void)

clear_page(kasan_early_shadow_page);

+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+
/* At this point kasan is fully initialized. Enable error messages */
init_task.kasan_depth = 0;
pr_info("KASAN init done\n");
@@ -170,7 +176,7 @@ void __init kasan_init(void)

void __init kasan_late_init(void)
{
- if (IS_ENABLED(CONFIG_KASAN_VMALLOC))
+ if (IS_ENABLED(CONFIG_KASAN_VMALLOC) && kasan_enabled())
kasan_unmap_early_shadow_vmalloc();
}

diff --git a/arch/powerpc/mm/kasan/init_book3e_64.c b/arch/powerpc/mm/kasan/init_book3e_64.c
index 60c78aac0f63..1e1c10467a2b 100644
--- a/arch/powerpc/mm/kasan/init_book3e_64.c
+++ b/arch/powerpc/mm/kasan/init_book3e_64.c
@@ -111,6 +111,9 @@ void __init kasan_init(void)
u64 i;
pte_t zero_pte = pfn_pte(virt_to_pfn(kasan_early_shadow_page), PAGE_KERNEL_RO);

+ if (kasan_arg_disabled)
+ return;
+
for_each_mem_range(i, &start, &end)
kasan_init_phys_region(phys_to_virt(start), phys_to_virt(end));

@@ -125,6 +128,9 @@ void __init kasan_init(void)

memset(kasan_early_shadow_page, 0, PAGE_SIZE);

+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+
/* Enable error messages */
init_task.kasan_depth = 0;
pr_info("KASAN init done\n");
diff --git a/arch/powerpc/mm/kasan/init_book3s_64.c b/arch/powerpc/mm/kasan/init_book3s_64.c
index 7d959544c077..9c5cf2354c8b 100644
--- a/arch/powerpc/mm/kasan/init_book3s_64.c
+++ b/arch/powerpc/mm/kasan/init_book3s_64.c
@@ -56,6 +56,9 @@ void __init kasan_init(void)
u64 i;
pte_t zero_pte = pfn_pte(virt_to_pfn(kasan_early_shadow_page), PAGE_KERNEL);

+ if (kasan_arg_disabled)
+ return;
+
if (!early_radix_enabled()) {
pr_warn("KASAN not enabled as it requires radix!");
return;
@@ -94,6 +97,9 @@ void __init kasan_init(void)

static_branch_inc(&powerpc_kasan_enabled_key);

+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+
/* Enable error messages */
init_task.kasan_depth = 0;
pr_info("KASAN init done\n");
diff --git a/arch/riscv/mm/kasan_init.c b/arch/riscv/mm/kasan_init.c
index 41c635d6aca4..ac3ac227c765 100644
--- a/arch/riscv/mm/kasan_init.c
+++ b/arch/riscv/mm/kasan_init.c
@@ -485,6 +485,9 @@ void __init kasan_init(void)
phys_addr_t p_start, p_end;
u64 i;

+ if (kasan_arg_disabled)
+ return;
+
create_tmp_mapping();
csr_write(CSR_SATP, PFN_DOWN(__pa(tmp_pg_dir)) | satp_mode);

@@ -531,6 +534,9 @@ void __init kasan_init(void)
memset(kasan_early_shadow_page, KASAN_SHADOW_INIT, PAGE_SIZE);
init_task.kasan_depth = 0;

+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+
csr_write(CSR_SATP, PFN_DOWN(__pa(swapper_pg_dir)) | satp_mode);
local_flush_tlb_all();
}
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
index 76bec7de81b5..6961841daa12 100644
--- a/arch/um/kernel/mem.c
+++ b/arch/um/kernel/mem.c
@@ -26,6 +26,9 @@
int kasan_um_is_ready;
void kasan_init(void)
{
+
+ if (kasan_arg_disabled)
+ return;
/*
* kasan_map_memory will map all of the required address space and
* the host machine will allocate physical memory as necessary.
@@ -33,6 +36,9 @@ void kasan_init(void)
kasan_map_memory((void *)KASAN_SHADOW_START, KASAN_SHADOW_SIZE);
init_task.kasan_depth = 0;
kasan_um_is_ready = true;
+
+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
}

static void (*kasan_init_ptr)(void)
diff --git a/arch/x86/mm/kasan_init_64.c b/arch/x86/mm/kasan_init_64.c
index 0539efd0d216..d7e8c59da435 100644
--- a/arch/x86/mm/kasan_init_64.c
+++ b/arch/x86/mm/kasan_init_64.c
@@ -343,6 +343,9 @@ void __init kasan_init(void)
unsigned long shadow_cea_begin, shadow_cea_per_cpu_begin, shadow_cea_end;
int i;

+ if (kasan_arg_disabled)
+ return;
+
memcpy(early_top_pgt, init_top_pgt, sizeof(early_top_pgt));

/*
@@ -450,6 +453,9 @@ void __init kasan_init(void)
/* Flush TLBs again to be sure that write protection applied. */
__flush_tlb_all();

+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+
init_task.kasan_depth = 0;
pr_info("KernelAddressSanitizer initialized\n");
}
diff --git a/arch/xtensa/mm/kasan_init.c b/arch/xtensa/mm/kasan_init.c
index f39c4d83173a..4a7b77f47225 100644
--- a/arch/xtensa/mm/kasan_init.c
+++ b/arch/xtensa/mm/kasan_init.c
@@ -70,6 +70,9 @@ void __init kasan_init(void)
{
int i;

+ if (kasan_arg_disabled)
+ return;
+
BUILD_BUG_ON(KASAN_SHADOW_OFFSET != KASAN_SHADOW_START -
(KASAN_START_VADDR >> KASAN_SHADOW_SCALE_SHIFT));
BUILD_BUG_ON(VMALLOC_START < KASAN_START_VADDR);
@@ -92,6 +95,9 @@ void __init kasan_init(void)
local_flush_tlb_all();
memset(kasan_early_shadow_page, 0, PAGE_SIZE);

+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+
/* At this point kasan is fully initialized. Enable error messages. */
current->kasan_depth = 0;
pr_info("KernelAddressSanitizer initialized\n");
diff --git a/mm/kasan/sw_tags.c b/mm/kasan/sw_tags.c
index 01f19bc4a326..dd963ba4d143 100644
--- a/mm/kasan/sw_tags.c
+++ b/mm/kasan/sw_tags.c
@@ -40,11 +40,17 @@ void __init kasan_init_sw_tags(void)
{
int cpu;

+ if (kasan_arg_disabled)
+ return;
+
for_each_possible_cpu(cpu)
per_cpu(prng_state, cpu) = (u32)get_cycles();

kasan_init_tags();

+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+
pr_info("KernelAddressSanitizer initialized (sw-tags, stacktrace=%s)\n",
str_on_off(kasan_stack_collection_enabled()));
}
--
2.41.0

Baoquan He

unread,
Aug 5, 2025, 2:24:15 AMAug 5
to linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, Baoquan He
Now everything is ready, set kasan=off can disable kasan for all
three modes.

Signed-off-by: Baoquan He <b...@redhat.com>
---
include/linux/kasan-enabled.h | 11 +----------
1 file changed, 1 insertion(+), 10 deletions(-)

diff --git a/include/linux/kasan-enabled.h b/include/linux/kasan-enabled.h
index 32f2d19f599f..b5857e15ef14 100644
--- a/include/linux/kasan-enabled.h
+++ b/include/linux/kasan-enabled.h
@@ -8,30 +8,21 @@ extern bool kasan_arg_disabled;

DECLARE_STATIC_KEY_FALSE(kasan_flag_enabled);

-#ifdef CONFIG_KASAN_HW_TAGS
-
static __always_inline bool kasan_enabled(void)
{
return static_branch_likely(&kasan_flag_enabled);
}

+#ifdef CONFIG_KASAN_HW_TAGS
static inline bool kasan_hw_tags_enabled(void)
{
return kasan_enabled();
}
-
#else /* CONFIG_KASAN_HW_TAGS */
-
-static inline bool kasan_enabled(void)
-{
- return IS_ENABLED(CONFIG_KASAN);
-}
-
static inline bool kasan_hw_tags_enabled(void)
{
return false;
}
-
#endif /* CONFIG_KASAN_HW_TAGS */

#endif /* LINUX_KASAN_ENABLED_H */
--
2.41.0

SeongJae Park

unread,
Aug 6, 2025, 1:22:37 AMAug 6
to Baoquan He, SeongJae Park, linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org
Hello Baoqua,

On Tue, 5 Aug 2025 14:23:33 +0800 Baoquan He <b...@redhat.com> wrote:

> Now everything is ready, set kasan=off can disable kasan for all
> three modes.
>
> Signed-off-by: Baoquan He <b...@redhat.com>
> ---
> include/linux/kasan-enabled.h | 11 +----------
> 1 file changed, 1 insertion(+), 10 deletions(-)
>
> diff --git a/include/linux/kasan-enabled.h b/include/linux/kasan-enabled.h
> index 32f2d19f599f..b5857e15ef14 100644
> --- a/include/linux/kasan-enabled.h
> +++ b/include/linux/kasan-enabled.h
> @@ -8,30 +8,21 @@ extern bool kasan_arg_disabled;
>
> DECLARE_STATIC_KEY_FALSE(kasan_flag_enabled);
>
> -#ifdef CONFIG_KASAN_HW_TAGS
> -
> static __always_inline bool kasan_enabled(void)
> {
> return static_branch_likely(&kasan_flag_enabled);
> }

I found mm-new build fails when CONFIG_KASAN is unset as below, and 'git
bisect' points this patch.

LD .tmp_vmlinux1
ld: lib/stackdepot.o:(__jump_table+0x8): undefined reference to `kasan_flag_enabled'

Since kasna_flag_enabled is defined in mm/kasan/common.c, I confirmed diff like
below fixes this. I think it may not be a correct fix though, since I didn't
read this patchset thoroughly.

diff --git a/include/linux/kasan-enabled.h b/include/linux/kasan-enabled.h
index b5857e15ef14..a53d112b1020 100644
--- a/include/linux/kasan-enabled.h
+++ b/include/linux/kasan-enabled.h
@@ -8,11 +8,22 @@ extern bool kasan_arg_disabled;

DECLARE_STATIC_KEY_FALSE(kasan_flag_enabled);

+#ifdef CONFIG_KASAN
+
static __always_inline bool kasan_enabled(void)
{
return static_branch_likely(&kasan_flag_enabled);
}

+#else /* CONFIG_KASAN */
+
+static inline bool kasan_enabled(void)
+{
+ return false;
+}
+
+#endif
+
#ifdef CONFIG_KASAN_HW_TAGS
static inline bool kasan_hw_tags_enabled(void)
{


[...]

Thanks,
SJ

Marco Elver

unread,
Aug 6, 2025, 3:11:43 AMAug 6
to Baoquan He, linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org
You lost __ro_after_init

> +/* kasan=off/on */
> +static int __init early_kasan_flag(char *arg)
> +{
> + if (!arg)
> + return -EINVAL;
> +
> + if (!strcmp(arg, "off"))
> + kasan_arg_disabled = true;
> + else if (!strcmp(arg, "on"))
> + kasan_arg_disabled = false;
> + else
> + return -EINVAL;
> +
> + return 0;
> +}
> +early_param("kasan", early_kasan_flag);
> +
> +
> +

Why extra blank lines?

Marco Elver

unread,
Aug 6, 2025, 3:17:13 AMAug 6
to Baoquan He, linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org
On Tue, 5 Aug 2025 at 08:23, 'Baoquan He' via kasan-dev
<kasa...@googlegroups.com> wrote:
>
> Currently only hw_tags mode of kasan can be enabled or disabled with
> kernel parameter kasan=on|off for built kernel. For kasan generic and
> sw_tags mode, there's no way to disable them once kernel is built.
> This is not convenient sometime, e.g in system kdump is configured.
> When the 1st kernel has KASAN enabled and crash triggered to switch to
> kdump kernel, the generic or sw_tags mode will cost much extra memory
> for kasan shadow while in fact it's meaningless to have kasan in kdump
> kernel.

Are you using KASAN generic or SW-tags is production?
If in a test environment, is the overhead of the kdump kernel really
unacceptable?

> So this patchset moves the kasan=on|off out of hw_tags scope and into
> common code to make it visible in generic and sw_tags mode too. Then we
> can add kasan=off in kdump kernel to reduce the unneeded meomry cost for
> kasan.
>
> Test:
> =====
> I only took test on x86_64 for generic mode, and on arm64 for
> generic, sw_tags and hw_tags mode. All of them works well.

Does it also work for CONFIG_KASAN_INLINE?
> --
> You received this message because you are subscribed to the Google Groups "kasan-dev" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to kasan-dev+...@googlegroups.com.
> To view this discussion visit https://groups.google.com/d/msgid/kasan-dev/20250805062333.121553-1-bhe%40redhat.com.

Baoquan He

unread,
Aug 6, 2025, 5:36:17 AMAug 6
to SeongJae Park, linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org
Thanks a lot for the reporting and fix. The below code is great to fix
the error. I reproduced it and tested with below fix, it works.

Since there's other reviewing comments, I will merge this into v2 post.

Lorenzo Stoakes

unread,
Aug 6, 2025, 12:26:23 PMAug 6
to SeongJae Park, Baoquan He, linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org
On Tue, Aug 05, 2025 at 10:22:31PM -0700, SeongJae Park wrote:
> Hello Baoqua,
>
> On Tue, 5 Aug 2025 14:23:33 +0800 Baoquan He <b...@redhat.com> wrote:
>
> > Now everything is ready, set kasan=off can disable kasan for all
> > three modes.
> >
> > Signed-off-by: Baoquan He <b...@redhat.com>
> > ---
> > include/linux/kasan-enabled.h | 11 +----------
> > 1 file changed, 1 insertion(+), 10 deletions(-)
> >
> > diff --git a/include/linux/kasan-enabled.h b/include/linux/kasan-enabled.h
> > index 32f2d19f599f..b5857e15ef14 100644
> > --- a/include/linux/kasan-enabled.h
> > +++ b/include/linux/kasan-enabled.h
> > @@ -8,30 +8,21 @@ extern bool kasan_arg_disabled;
> >
> > DECLARE_STATIC_KEY_FALSE(kasan_flag_enabled);
> >
> > -#ifdef CONFIG_KASAN_HW_TAGS
> > -
> > static __always_inline bool kasan_enabled(void)
> > {
> > return static_branch_likely(&kasan_flag_enabled);
> > }
>
> I found mm-new build fails when CONFIG_KASAN is unset as below, and 'git
> bisect' points this patch.

Yup just hit this + bisected here.

>
> LD .tmp_vmlinux1
> ld: lib/stackdepot.o:(__jump_table+0x8): undefined reference to `kasan_flag_enabled'
>
> Since kasna_flag_enabled is defined in mm/kasan/common.c, I confirmed diff like
> below fixes this. I think it may not be a correct fix though, since I didn't
> read this patchset thoroughly.
>
> diff --git a/include/linux/kasan-enabled.h b/include/linux/kasan-enabled.h
> index b5857e15ef14..a53d112b1020 100644
> --- a/include/linux/kasan-enabled.h
> +++ b/include/linux/kasan-enabled.h
> @@ -8,11 +8,22 @@ extern bool kasan_arg_disabled;
>
> DECLARE_STATIC_KEY_FALSE(kasan_flag_enabled);
>
> +#ifdef CONFIG_KASAN
> +

Shouldn't we put this above the static key declaration?

Feels like the whole header should be included really.

> static __always_inline bool kasan_enabled(void)
> {
> return static_branch_likely(&kasan_flag_enabled);
> }
>
> +#else /* CONFIG_KASAN */
> +
> +static inline bool kasan_enabled(void)
> +{
> + return false;
> +}
> +
> +#endif
> +
> #ifdef CONFIG_KASAN_HW_TAGS
> static inline bool kasan_hw_tags_enabled(void)
> {
>
>
> [...]
>
> Thanks,
> SJ
>

Cheers, Lorenzo

Sabyrzhan Tasbolatov

unread,
Aug 6, 2025, 2:24:49 PMAug 6
to Baoquan He, linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org
On Tue, Aug 5, 2025 at 11:34 AM Baoquan He <b...@redhat.com> wrote:
>
> Now everything is ready, set kasan=off can disable kasan for all
> three modes.
>

Hello,

I've been working on this already and a different approach
with the Kconfig ARCH_DEFER_KASAN has been proposed.

Please see v4 thread.
https://lore.kernel.org/all/20250805142622.5...@gmail.com/

It also covers the printing in a single KASAN codebase, instead of
printing "KASAN intiilaized" in arch/* code.
Also covers the enabling KASAN via kasan_enable() for all 3 modes.

It's up to KASAN maintainers to choose either version.
I just need the confirmation now if I should proceed with v5,
or your version if it covers all arch and cases should be picked up.

Thanks

Andrey Ryabinin

unread,
Aug 7, 2025, 12:35:42 PMAug 7
to Baoquan He, linu...@kvack.org, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org


On 8/5/25 8:23 AM, Baoquan He wrote:
> Currently only hw_tags mode of kasan can be enabled or disabled with
> kernel parameter kasan=on|off for built kernel. For kasan generic and
> sw_tags mode, there's no way to disable them once kernel is built.
> This is not convenient sometime, e.g in system kdump is configured.
> When the 1st kernel has KASAN enabled and crash triggered to switch to
> kdump kernel, the generic or sw_tags mode will cost much extra memory
> for kasan shadow while in fact it's meaningless to have kasan in kdump
> kernel.
>

Ideally this problem should be solved by having kdump kernel with different
config. Because if we want only reliably collect crash dumps, than we probably
don't want other debug features, e.g. like VM_BUG_ON() crashing our kdump kernel.

Andrey Ryabinin

unread,
Aug 7, 2025, 1:12:56 PMAug 7
to Marco Elver, Baoquan He, linu...@kvack.org, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org


On 8/6/25 9:16 AM, Marco Elver wrote:
> On Tue, 5 Aug 2025 at 08:23, 'Baoquan He' via kasan-dev
> <kasa...@googlegroups.com> wrote:
>>
>> Currently only hw_tags mode of kasan can be enabled or disabled with
>> kernel parameter kasan=on|off for built kernel. For kasan generic and
>> sw_tags mode, there's no way to disable them once kernel is built.
>> This is not convenient sometime, e.g in system kdump is configured.
>> When the 1st kernel has KASAN enabled and crash triggered to switch to
>> kdump kernel, the generic or sw_tags mode will cost much extra memory
>> for kasan shadow while in fact it's meaningless to have kasan in kdump
>> kernel.
>
> Are you using KASAN generic or SW-tags is production?
> If in a test environment, is the overhead of the kdump kernel really
> unacceptable?
>

kdump kernel operates with limited amount of memory, whatever was provided
in 'crashkernel=' for the primary kernel. So it's quite easily can ran out of memory.

By default kdump uses same as currently running kernel, but it can be configured
to use a different one.

At least in fedora it's in /etc/sysconfig/kdump:

$ cat /etc/sysconfig/kdump
# Kernel Version string for the -kdump kernel, such as 2.6.13-1544.FC5kdump
# If no version is specified, then the init script will try to find a
# kdump kernel with the same version number as the running kernel.
KDUMP_KERNELVER=""


>> So this patchset moves the kasan=on|off out of hw_tags scope and into
>> common code to make it visible in generic and sw_tags mode too. Then we
>> can add kasan=off in kdump kernel to reduce the unneeded meomry cost for
>> kasan.
>>
>> Test:
>> =====
>> I only took test on x86_64 for generic mode, and on arm64 for
>> generic, sw_tags and hw_tags mode. All of them works well.
>
> Does it also work for CONFIG_KASAN_INLINE?
>

I think it should. Because we don't initialize init_task.kasan_depth we always
bail out in kasan_report().



Baoquan He

unread,
Aug 7, 2025, 11:22:06 PMAug 7
to Marco Elver, linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org
On 08/06/25 at 09:16am, Marco Elver wrote:
> On Tue, 5 Aug 2025 at 08:23, 'Baoquan He' via kasan-dev
> <kasa...@googlegroups.com> wrote:
> >
> > Currently only hw_tags mode of kasan can be enabled or disabled with
> > kernel parameter kasan=on|off for built kernel. For kasan generic and
> > sw_tags mode, there's no way to disable them once kernel is built.
> > This is not convenient sometime, e.g in system kdump is configured.
> > When the 1st kernel has KASAN enabled and crash triggered to switch to
> > kdump kernel, the generic or sw_tags mode will cost much extra memory
> > for kasan shadow while in fact it's meaningless to have kasan in kdump
> > kernel.
>
> Are you using KASAN generic or SW-tags is production?
> If in a test environment, is the overhead of the kdump kernel really
> unacceptable?

Thanks for checking this.

I don't use KASAN in production environment. But in Redhat, our CI will
run test cases on debug kernel with KASAN enabled by default. Then the
crashkernel setting will be uncertain. E.g usually crashkernel=256M is
enough for most of system. However, KASAN would make the crashkernel
reservation need to reach to 768M on one ampere arm64 system. This is
not the extra 1/8 of system ram as we expected because we have vmalloc
mapping to create shaddow too. In this case, QE or other kernel
developer who is not familiar with KASAN may need spend time to dig out
what's going on here. And they may need adjust crashkernel= value to get
an appropriate one to make system work. This is not good because we
don't need KASAN feature in kdump kernel at all while we need tackle the
unexpected crashkernel= setting.

This can be fixed with a very easy way, a knob to disable kasan in kdump
kernel can perfectly handle it.

>
> > So this patchset moves the kasan=on|off out of hw_tags scope and into
> > common code to make it visible in generic and sw_tags mode too. Then we
> > can add kasan=off in kdump kernel to reduce the unneeded meomry cost for
> > kasan.
> >
> > Test:
> > =====
> > I only took test on x86_64 for generic mode, and on arm64 for
> > generic, sw_tags and hw_tags mode. All of them works well.
>
> Does it also work for CONFIG_KASAN_INLINE?

Yes, Andrey said in reply, I did investigation. You can see that
KASAN_INLINE will bloat vmlinux by ~30M. This is not a big problem of
kdump kernel.

CONFIG_KASAN_OUTLINE=y
[root@ampere-mtsnow-altra-08 linux]# ll vmlinux
-rwxr-xr-x. 1 root root 124859016 Aug 6 06:08 vmlinux
[root@ampere-mtsnow-altra-08 linux]# ll /boot/vmlinuz-*
-rwxr-xr-x. 1 root root 15938048 Aug 3 00:15 /boot/vmlinuz-0-rescue-f81ab6a509e444e3857153cfa3fc6497
-rwxr-xr-x. 1 root root 15938048 Jul 23 20:00 /boot/vmlinuz-6.15.8-200.fc42.aarch64
-rwxr-xr-x. 1 root root 20644352 Aug 6 06:11 /boot/vmlinuz-6.16.0+

CONFIG_KASAN_INLINE=y
[root@ampere-mtsnow-altra-08 linux]# ll vmlinux
-rwxr-xr-x. 1 root root 150483592 Aug 6 10:53 vmlinux
[root@ampere-mtsnow-altra-08 linux]# ll /boot/vmlinuz-*
-rwxr-xr-x. 1 root root 15938048 Aug 3 00:15 /boot/vmlinuz-0-rescue-f81ab6a509e444e3857153cfa3fc6497
-rwxr-xr-x. 1 root root 15938048 Jul 23 20:00 /boot/vmlinuz-6.15.8-200.fc42.aarch64
-rwxr-xr-x. 1 root root 27779584 Aug 6 10:55 /boot/vmlinuz-6.16.0+

Baoquan He

unread,
Aug 8, 2025, 8:55:08 AMAug 8
to Andrey Ryabinin, linu...@kvack.org, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org
On 08/07/25 at 06:34pm, Andrey Ryabinin wrote:
>
>
> On 8/5/25 8:23 AM, Baoquan He wrote:
> > Currently only hw_tags mode of kasan can be enabled or disabled with
> > kernel parameter kasan=on|off for built kernel. For kasan generic and
> > sw_tags mode, there's no way to disable them once kernel is built.
> > This is not convenient sometime, e.g in system kdump is configured.
> > When the 1st kernel has KASAN enabled and crash triggered to switch to
> > kdump kernel, the generic or sw_tags mode will cost much extra memory
> > for kasan shadow while in fact it's meaningless to have kasan in kdump
> > kernel.
> >
>
> Ideally this problem should be solved by having kdump kernel with different
> config. Because if we want only reliably collect crash dumps, than we probably
> don't want other debug features, e.g. like VM_BUG_ON() crashing our kdump kernel.

Yeah, we have done that in Redhat's internal CI testing. While we still
want to switch back to let kdump take the same kernel as the 1st kernel.
Like this, we have chance to test debug kernel for vmcore dumping. In
this case, KASAN is the main barrier. For other debug features,
VM_BUG_ON() should be captured in 1st kernel's running, we won't wait to
run kdump kernel to catch it. I am planning to check and adding feature
switch for kdump to disable if it's not needed in kdump kernel. E.g I
have done in ima=on|off, and the existing 'kfence.sample_interval=0' for
kfence.

And the public kasan=on|off kernel parameter can make kasan feature more
flexible. It can be used in production environment with kasan=off, and
can switch to the same kernel to catch issues easily by stripping the
cmdline setting. As adding a cmdline is much easier than setting kernel
config and rebuild kernel.

Besides, based on this patchset, we can easily remove
kasan_arch_is_ready() by detecting the arch's support and disable
kasan_flag_enabled. And when I testing generic/sw_tags/hw_tags on arm64,
I feel if adding a kernel parameter for choosing different KASAN mode is
much more convenient than changing kernel config and rebuild. If we
choose to KASAN_OUTLINE, this even doesn't impact much in production
environment. I would like to hear your suggestion.

Thanks
Baoquan

Baoquan He

unread,
Aug 8, 2025, 9:01:59 AMAug 8
to Marco Elver, linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org
Right, thanks for careful reviewing.

>
> > +/* kasan=off/on */
> > +static int __init early_kasan_flag(char *arg)
> > +{
> > + if (!arg)
> > + return -EINVAL;
> > +
> > + if (!strcmp(arg, "off"))
> > + kasan_arg_disabled = true;
> > + else if (!strcmp(arg, "on"))
> > + kasan_arg_disabled = false;
> > + else
> > + return -EINVAL;
> > +
> > + return 0;
> > +}
> > +early_param("kasan", early_kasan_flag);
> > +
> > +
> > +
>
> Why extra blank lines?

Good catch, will remove it in v2. Thanks.

Baoquan He

unread,
Aug 8, 2025, 9:08:49 AMAug 8
to Lorenzo Stoakes, SeongJae Park, linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org
On 08/06/25 at 05:26pm, Lorenzo Stoakes wrote:
> On Tue, Aug 05, 2025 at 10:22:31PM -0700, SeongJae Park wrote:
> > Hello Baoqua,
> >
> > On Tue, 5 Aug 2025 14:23:33 +0800 Baoquan He <b...@redhat.com> wrote:
> >
> > > Now everything is ready, set kasan=off can disable kasan for all
> > > three modes.
> > >
> > > Signed-off-by: Baoquan He <b...@redhat.com>
> > > ---
> > > include/linux/kasan-enabled.h | 11 +----------
> > > 1 file changed, 1 insertion(+), 10 deletions(-)
> > >
> > > diff --git a/include/linux/kasan-enabled.h b/include/linux/kasan-enabled.h
> > > index 32f2d19f599f..b5857e15ef14 100644
> > > --- a/include/linux/kasan-enabled.h
> > > +++ b/include/linux/kasan-enabled.h
> > > @@ -8,30 +8,21 @@ extern bool kasan_arg_disabled;
> > >
> > > DECLARE_STATIC_KEY_FALSE(kasan_flag_enabled);
> > >
> > > -#ifdef CONFIG_KASAN_HW_TAGS
> > > -
> > > static __always_inline bool kasan_enabled(void)
> > > {
> > > return static_branch_likely(&kasan_flag_enabled);
> > > }
> >
> > I found mm-new build fails when CONFIG_KASAN is unset as below, and 'git
> > bisect' points this patch.
>
> Yup just hit this + bisected here.

Sorry for the trouble and thanks for reporting.

>
> >
> > LD .tmp_vmlinux1
> > ld: lib/stackdepot.o:(__jump_table+0x8): undefined reference to `kasan_flag_enabled'
> >
> > Since kasna_flag_enabled is defined in mm/kasan/common.c, I confirmed diff like
> > below fixes this. I think it may not be a correct fix though, since I didn't
> > read this patchset thoroughly.
> >
> > diff --git a/include/linux/kasan-enabled.h b/include/linux/kasan-enabled.h
> > index b5857e15ef14..a53d112b1020 100644
> > --- a/include/linux/kasan-enabled.h
> > +++ b/include/linux/kasan-enabled.h
> > @@ -8,11 +8,22 @@ extern bool kasan_arg_disabled;
> >
> > DECLARE_STATIC_KEY_FALSE(kasan_flag_enabled);
> >
> > +#ifdef CONFIG_KASAN
> > +
>
> Shouldn't we put this above the static key declaration?
>
> Feels like the whole header should be included really.

You are right, kasan_flag_enabled should be included in CONFIG_KASAN
ifdeffery scope.

Since CONFIG_KASAN_HW_TAGS depends on CONFIG_KASAN, we may not need
include below CONFIG_KASAN_HW_TAGS ifdeffery into CONFIG_KASAN ifdeffery
scope. Not sure if this is incorrect.

Thanks a lot for checking this.

Lorenzo Stoakes

unread,
Aug 8, 2025, 9:24:39 AMAug 8
to Baoquan He, SeongJae Park, linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org
On Fri, Aug 08, 2025 at 09:08:35PM +0800, Baoquan He wrote:
> On 08/06/25 at 05:26pm, Lorenzo Stoakes wrote:
> > > I found mm-new build fails when CONFIG_KASAN is unset as below, and 'git
> > > bisect' points this patch.
> >
> > Yup just hit this + bisected here.
>
> Sorry for the trouble and thanks for reporting.

No worries!

>
> >
> > >
> > > LD .tmp_vmlinux1
> > > ld: lib/stackdepot.o:(__jump_table+0x8): undefined reference to `kasan_flag_enabled'
> > >
> > > Since kasna_flag_enabled is defined in mm/kasan/common.c, I confirmed diff like
> > > below fixes this. I think it may not be a correct fix though, since I didn't
> > > read this patchset thoroughly.
> > >
> > > diff --git a/include/linux/kasan-enabled.h b/include/linux/kasan-enabled.h
> > > index b5857e15ef14..a53d112b1020 100644
> > > --- a/include/linux/kasan-enabled.h
> > > +++ b/include/linux/kasan-enabled.h
> > > @@ -8,11 +8,22 @@ extern bool kasan_arg_disabled;
> > >
> > > DECLARE_STATIC_KEY_FALSE(kasan_flag_enabled);
> > >
> > > +#ifdef CONFIG_KASAN
> > > +
> >
> > Shouldn't we put this above the static key declaration?
> >
> > Feels like the whole header should be included really.
>
> You are right, kasan_flag_enabled should be included in CONFIG_KASAN
> ifdeffery scope.

Firstly I _LOVE_ the term 'ifdeffery scope'. Fantastic :)

>
> Since CONFIG_KASAN_HW_TAGS depends on CONFIG_KASAN, we may not need
> include below CONFIG_KASAN_HW_TAGS ifdeffery into CONFIG_KASAN ifdeffery
> scope. Not sure if this is incorrect.

Well I don't think CONFIG_KASAN_HW_TAGS is necessarily implied right? So these
should remain I think, just nested in CONFIG_KASAN, should be fine.

>
> Thanks a lot for checking this.

No problem! Just ran in to it while doing other stuff in mm-new :)

Cheers, Lorenzo

Baoquan He

unread,
Aug 8, 2025, 12:00:01 PMAug 8
to Sabyrzhan Tasbolatov, linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org
On 08/06/25 at 11:24pm, Sabyrzhan Tasbolatov wrote:
> On Tue, Aug 5, 2025 at 11:34 AM Baoquan He <b...@redhat.com> wrote:
> >
> > Now everything is ready, set kasan=off can disable kasan for all
> > three modes.
> >
>
> Hello,
>
> I've been working on this already and a different approach
> with the Kconfig ARCH_DEFER_KASAN has been proposed.

Thanks for telling, I don't always watch MM mailing list, so missed your
earlier posting.

I went through your v5 series, we are doing different work. I am adding
kasan=on|off to generic/sw_tags, and have added kasan_enabled() to needed
places. In fact, based on this patchset, we can remove
kasan_arch_is_ready() more easily since in all places kasan_enabled() has
been added there. Before seeing your patches, this is what I planned to
do to remove kasan_arch_is_ready(). I will see what can be done better.
Maybe I can carry your patch in v2. I will try tomorrow.

Baoquan He

unread,
Aug 12, 2025, 8:50:00 AMAug 12
to linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, Baoquan He
Currently only hw_tags mode of kasan can be enabled or disabled with
kernel parameter kasan=on|off for built kernel. For kasan generic and
sw_tags mode, there's no way to disable them once kernel is built.
This is not convenient sometime, e.g in system kdump is configured.
When the 1st kernel has KASAN enabled and crash triggered to switch to
kdump kernel, the generic or sw_tags mode will cost much extra memory
for kasan shadow while in fact it's meaningless to have kasan in kdump
kernel.

So this patchset moves the kasan=on|off out of hw_tags scope and into
common code to make it visible in generic and sw_tags mode too. Then we
can add kasan=off in kdump kernel to reduce the unneeded meomry cost for
kasan.

Changelog:
====
v1->v2:
- Add __ro_after_init for __ro_after_init, and remove redundant blank
lines in mm/kasan/common.c. Thanks to Marco.
- Fix a code bug in <linux/kasan-enabled.h> when CONFIG_KASAN is unset,
this is found out by SeongJae and Lorenzo, and also reported by LKP
report, thanks to them.
- Add a missing kasan_enabled() checking in kasan_report(). This will
cause below KASAN report info even though kasan=off is set:
==================================================================
BUG: KASAN: stack-out-of-bounds in tick_program_event+0x130/0x150
Read of size 4 at addr ffff00005f747778 by task swapper/0/1

CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.16.0+ #8 PREEMPT(voluntary)
Hardware name: GIGABYTE R272-P30-JG/MP32-AR0-JG, BIOS F31n (SCP: 2.10.20220810) 09/30/2022
Call trace:
show_stack+0x30/0x90 (C)
dump_stack_lvl+0x7c/0xa0
print_address_description.constprop.0+0x90/0x310
print_report+0x104/0x1f0
kasan_report+0xc8/0x110
__asan_report_load4_noabort+0x20/0x30
tick_program_event+0x130/0x150
......snip...
==================================================================

- Add jump_label_init() calling before kasan_init() in setup_arch() in these
architectures: xtensa, arm. Because they currenly rely on
jump_label_init() in main() which is a little late. Then the early static
key kasan_flag_enabled in kasan_init() won't work.

- In UML architecture, change to enable kasan_flag_enabled in arch_mm_preinit()
because kasan_init() is enabled before main(), there's no chance to operate
on static key in kasan_init().

Test:
=====
In v1, I took test on x86_64 for generic mode, and on arm64 for
generic, sw_tags and hw_tags mode. All of them works well.

In v2, I only tested on arm64 for generic, sw_tags and hw_tags mode, it
works. For powerpc, I got a BOOK3S/64 machine, while it says
'KASAN not enabled as it requires radix' and KASAN is disabled. Will
look for other POWER machine to test this.
====

Baoquan He (12):
mm/kasan: add conditional checks in functions to return directly if
kasan is disabled
mm/kasan: move kasan= code to common place
mm/kasan/sw_tags: don't initialize kasan if it's disabled
arch/arm: don't initialize kasan if it's disabled
arch/arm64: don't initialize kasan if it's disabled
arch/loongarch: don't initialize kasan if it's disabled
arch/powerpc: don't initialize kasan if it's disabled
arch/riscv: don't initialize kasan if it's disabled
arch/x86: don't initialize kasan if it's disabled
arch/xtensa: don't initialize kasan if it's disabled
arch/um: don't initialize kasan if it's disabled
mm/kasan: make kasan=on|off take effect for all three modes

arch/arm/kernel/setup.c | 6 +++++
arch/arm/mm/kasan_init.c | 6 +++++
arch/arm64/mm/kasan_init.c | 7 ++++++
arch/loongarch/mm/kasan_init.c | 5 ++++
arch/powerpc/mm/kasan/init_32.c | 8 +++++-
arch/powerpc/mm/kasan/init_book3e_64.c | 6 +++++
arch/powerpc/mm/kasan/init_book3s_64.c | 6 +++++
arch/riscv/mm/kasan_init.c | 6 +++++
arch/um/kernel/mem.c | 6 +++++
arch/x86/mm/kasan_init_64.c | 6 +++++
arch/xtensa/kernel/setup.c | 1 +
arch/xtensa/mm/kasan_init.c | 6 +++++
include/linux/kasan-enabled.h | 18 ++++++-------
mm/kasan/common.c | 25 ++++++++++++++++++
mm/kasan/generic.c | 20 +++++++++++++--
mm/kasan/hw_tags.c | 35 ++------------------------
mm/kasan/init.c | 6 +++++
mm/kasan/quarantine.c | 3 +++
mm/kasan/report.c | 4 ++-
mm/kasan/shadow.c | 23 ++++++++++++++++-
mm/kasan/sw_tags.c | 9 +++++++
21 files changed, 165 insertions(+), 47 deletions(-)

--
2.41.0

Baoquan He

unread,
Aug 12, 2025, 8:50:07 AMAug 12
to linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, Baoquan He
The current code only does the check if kasan is disabled for hw_tags
mode. Here add the conditional checks for functional functions of
generic mode and sw_tags mode.

This is prepared for later adding kernel parameter kasan=on|off for
all kasan modes.

Signed-off-by: Baoquan He <b...@redhat.com>
---
mm/kasan/generic.c | 20 ++++++++++++++++++--
mm/kasan/init.c | 6 ++++++
mm/kasan/quarantine.c | 3 +++
mm/kasan/report.c | 4 +++-
mm/kasan/shadow.c | 23 ++++++++++++++++++++++-
mm/kasan/sw_tags.c | 3 +++
6 files changed, 55 insertions(+), 4 deletions(-)

diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c
index d54e89f8c3e7..8daea5892754 100644
--- a/mm/kasan/generic.c
+++ b/mm/kasan/generic.c
@@ -165,6 +165,9 @@ static __always_inline bool check_region_inline(const void *addr,
size_t size, bool write,
unsigned long ret_ip)
{
+ if (!kasan_enabled())
+ return true;
+
if (!kasan_arch_is_ready())
return true;

@@ -203,12 +206,13 @@ bool kasan_byte_accessible(const void *addr)

void kasan_cache_shrink(struct kmem_cache *cache)
{
- kasan_quarantine_remove_cache(cache);
+ if (kasan_enabled())
+ kasan_quarantine_remove_cache(cache);
}

void kasan_cache_shutdown(struct kmem_cache *cache)
{
- if (!__kmem_cache_empty(cache))
+ if (kasan_enabled() && !__kmem_cache_empty(cache))
kasan_quarantine_remove_cache(cache);
}

@@ -228,6 +232,9 @@ void __asan_register_globals(void *ptr, ssize_t size)
int i;
struct kasan_global *globals = ptr;

+ if (!kasan_enabled())
+ return;
+
for (i = 0; i < size; i++)
register_global(&globals[i]);
}
@@ -358,6 +365,9 @@ void kasan_cache_create(struct kmem_cache *cache, unsigned int *size,
unsigned int rem_free_meta_size;
unsigned int orig_alloc_meta_offset;

+ if (!kasan_enabled())
+ return;
+
if (!kasan_requires_meta())
return;

@@ -510,6 +520,9 @@ size_t kasan_metadata_size(struct kmem_cache *cache, bool in_object)
{
struct kasan_cache *info = &cache->kasan_info;

+ if (!kasan_enabled())
+ return 0;
+
if (!kasan_requires_meta())
return 0;

@@ -535,6 +548,9 @@ void kasan_record_aux_stack(void *addr)
struct kasan_alloc_meta *alloc_meta;
void *object;

+ if (!kasan_enabled())
+ return;
+
if (is_kfence_address(addr) || !slab)
return;

diff --git a/mm/kasan/init.c b/mm/kasan/init.c
index ced6b29fcf76..43d95f329675 100644
--- a/mm/kasan/init.c
+++ b/mm/kasan/init.c
@@ -449,6 +449,9 @@ void kasan_remove_zero_shadow(void *start, unsigned long size)
unsigned long addr, end, next;
pgd_t *pgd;

+ if (!kasan_enabled())
+ return;
+
addr = (unsigned long)kasan_mem_to_shadow(start);
end = addr + (size >> KASAN_SHADOW_SCALE_SHIFT);

@@ -484,6 +487,9 @@ int kasan_add_zero_shadow(void *start, unsigned long size)
int ret;
void *shadow_start, *shadow_end;

+ if (!kasan_enabled())
+ return 0;
+
shadow_start = kasan_mem_to_shadow(start);
shadow_end = shadow_start + (size >> KASAN_SHADOW_SCALE_SHIFT);

diff --git a/mm/kasan/quarantine.c b/mm/kasan/quarantine.c
index 6958aa713c67..a6dc2c3d8a15 100644
--- a/mm/kasan/quarantine.c
+++ b/mm/kasan/quarantine.c
@@ -405,6 +405,9 @@ static int __init kasan_cpu_quarantine_init(void)
{
int ret = 0;

+ if (!kasan_enabled())
+ return 0;
+
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "mm/kasan:online",
kasan_cpu_online, kasan_cpu_offline);
if (ret < 0)
diff --git a/mm/kasan/report.c b/mm/kasan/report.c
index 62c01b4527eb..884357fa74ed 100644
--- a/mm/kasan/report.c
+++ b/mm/kasan/report.c
@@ -576,7 +576,9 @@ bool kasan_report(const void *addr, size_t size, bool is_write,
unsigned long irq_flags;
struct kasan_report_info info;

- if (unlikely(report_suppressed_sw()) || unlikely(!report_enabled())) {
+ if (unlikely(report_suppressed_sw()) ||
+ unlikely(!report_enabled()) ||
+ !kasan_enabled()) {
ret = false;
goto out;
}
diff --git a/mm/kasan/shadow.c b/mm/kasan/shadow.c
index d2c70cd2afb1..637f2d02d2a3 100644
--- a/mm/kasan/shadow.c
+++ b/mm/kasan/shadow.c
@@ -125,6 +125,9 @@ void kasan_poison(const void *addr, size_t size, u8 value, bool init)
{
void *shadow_start, *shadow_end;

+ if (!kasan_enabled())
+ return;
+
if (!kasan_arch_is_ready())
return;

@@ -150,6 +153,9 @@ EXPORT_SYMBOL_GPL(kasan_poison);
#ifdef CONFIG_KASAN_GENERIC
void kasan_poison_last_granule(const void *addr, size_t size)
{
+ if (!kasan_enabled())
+ return;
+
if (!kasan_arch_is_ready())
return;

@@ -164,6 +170,8 @@ void kasan_unpoison(const void *addr, size_t size, bool init)
{
u8 tag = get_tag(addr);

+ if (!kasan_enabled())
+ return;
/*
* Perform shadow offset calculation based on untagged address, as
* some of the callers (e.g. kasan_unpoison_new_object) pass tagged
@@ -277,7 +285,8 @@ static int __meminit kasan_mem_notifier(struct notifier_block *nb,

static int __init kasan_memhotplug_init(void)
{
- hotplug_memory_notifier(kasan_mem_notifier, DEFAULT_CALLBACK_PRI);
+ if (kasan_enabled())
+ hotplug_memory_notifier(kasan_mem_notifier, DEFAULT_CALLBACK_PRI);

return 0;
}
@@ -390,6 +399,9 @@ int kasan_populate_vmalloc(unsigned long addr, unsigned long size)
unsigned long shadow_start, shadow_end;
int ret;

+ if (!kasan_enabled())
+ return 0;
+
if (!kasan_arch_is_ready())
return 0;

@@ -560,6 +572,9 @@ void kasan_release_vmalloc(unsigned long start, unsigned long end,
unsigned long region_start, region_end;
unsigned long size;

+ if (!kasan_enabled())
+ return;
+
if (!kasan_arch_is_ready())
return;

@@ -655,6 +670,9 @@ int kasan_alloc_module_shadow(void *addr, size_t size, gfp_t gfp_mask)
size_t shadow_size;
unsigned long shadow_start;

+ if (!kasan_enabled())
+ return 0;
+
shadow_start = (unsigned long)kasan_mem_to_shadow(addr);
scaled_size = (size + KASAN_GRANULE_SIZE - 1) >>
KASAN_SHADOW_SCALE_SHIFT;
@@ -691,6 +709,9 @@ int kasan_alloc_module_shadow(void *addr, size_t size, gfp_t gfp_mask)

void kasan_free_module_shadow(const struct vm_struct *vm)
{
+ if (!kasan_enabled())
+ return;
+
if (IS_ENABLED(CONFIG_UML))
return;

diff --git a/mm/kasan/sw_tags.c b/mm/kasan/sw_tags.c
index b9382b5b6a37..01f19bc4a326 100644
--- a/mm/kasan/sw_tags.c
+++ b/mm/kasan/sw_tags.c
@@ -78,6 +78,9 @@ bool kasan_check_range(const void *addr, size_t size, bool write,
u8 *shadow_first, *shadow_last, *shadow;
void *untagged_addr;

+ if (!kasan_enabled())

Baoquan He

unread,
Aug 12, 2025, 8:50:16 AMAug 12
to linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, Baoquan He
This allows generic and sw_tags to be set in kernel cmdline too.

When at it, rename 'kasan_arg' to 'kasan_arg_disabled' as a bool
variable. And expose 'kasan_flag_enabled' to kasan common place
too.

This is prepared for later adding kernel parameter kasan=on|off for
all kasan modes.

Signed-off-by: Baoquan He <b...@redhat.com>
---
include/linux/kasan-enabled.h | 4 +++-
mm/kasan/common.c | 25 +++++++++++++++++++++++++
mm/kasan/hw_tags.c | 35 ++---------------------------------
3 files changed, 30 insertions(+), 34 deletions(-)

diff --git a/include/linux/kasan-enabled.h b/include/linux/kasan-enabled.h
index 6f612d69ea0c..32f2d19f599f 100644
--- a/include/linux/kasan-enabled.h
+++ b/include/linux/kasan-enabled.h
@@ -4,10 +4,12 @@

#include <linux/static_key.h>

-#ifdef CONFIG_KASAN_HW_TAGS
+extern bool kasan_arg_disabled;

DECLARE_STATIC_KEY_FALSE(kasan_flag_enabled);

+#ifdef CONFIG_KASAN_HW_TAGS
+
static __always_inline bool kasan_enabled(void)
{
return static_branch_likely(&kasan_flag_enabled);
diff --git a/mm/kasan/common.c b/mm/kasan/common.c
index 9142964ab9c9..69a848f2a8aa 100644
--- a/mm/kasan/common.c
+++ b/mm/kasan/common.c
@@ -32,6 +32,31 @@
#include "kasan.h"
#include "../slab.h"

+/*
+ * Whether KASAN is enabled at all.
+ * The value remains false until KASAN is initialized.
+ */
+DEFINE_STATIC_KEY_FALSE(kasan_flag_enabled);
+EXPORT_SYMBOL(kasan_flag_enabled);
+
+bool kasan_arg_disabled __ro_after_init;
+/* kasan=off/on */
+static int __init early_kasan_flag(char *arg)
+{
+ if (!arg)
+ return -EINVAL;
+
+ if (!strcmp(arg, "off"))
+ kasan_arg_disabled = true;
+ else if (!strcmp(arg, "on"))
+ kasan_arg_disabled = false;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+early_param("kasan", early_kasan_flag);
+

Baoquan He

unread,
Aug 12, 2025, 8:50:22 AMAug 12
to linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, Baoquan He
And also add code to enable kasan_flag_enabled, this is for later
usage.

Signed-off-by: Baoquan He <b...@redhat.com>
---
mm/kasan/sw_tags.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/mm/kasan/sw_tags.c b/mm/kasan/sw_tags.c
index 01f19bc4a326..dd963ba4d143 100644
--- a/mm/kasan/sw_tags.c
+++ b/mm/kasan/sw_tags.c

Baoquan He

unread,
Aug 12, 2025, 8:50:32 AMAug 12
to linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, Baoquan He
And also add code to enable kasan_flag_enabled, this is for later
usage.

Here call jump_label_init() early in setup_arch() so that later
kasan_init() can enable static key kasan_flag_enabled. Put
jump_label_init() beofre parse_early_param() as other architectures
do.

Signed-off-by: Baoquan He <b...@redhat.com>
---
arch/arm/kernel/setup.c | 6 ++++++
arch/arm/mm/kasan_init.c | 6 ++++++
2 files changed, 12 insertions(+)

diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 0bfd66c7ada0..453a47a4c715 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -1135,6 +1135,12 @@ void __init setup_arch(char **cmdline_p)
early_fixmap_init();
early_ioremap_init();

+ /*
+ * Initialise the static keys early as they may be enabled by the
+ * kasan_init() or early parameters.
+ */
+ jump_label_init();
+
parse_early_param();

#ifdef CONFIG_MMU
diff --git a/arch/arm/mm/kasan_init.c b/arch/arm/mm/kasan_init.c
index 111d4f703136..c764e1b9c9c5 100644
--- a/arch/arm/mm/kasan_init.c
+++ b/arch/arm/mm/kasan_init.c
@@ -212,6 +212,8 @@ void __init kasan_init(void)
phys_addr_t pa_start, pa_end;
u64 i;

+ if (kasan_arg_disabled)
+ return;
/*
* We are going to perform proper setup of shadow memory.
*
@@ -300,6 +302,10 @@ void __init kasan_init(void)
local_flush_tlb_all();

memset(kasan_early_shadow_page, 0, PAGE_SIZE);
+
+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+
pr_info("Kernel address sanitizer initialized\n");
init_task.kasan_depth = 0;
}
--
2.41.0

Baoquan He

unread,
Aug 12, 2025, 8:50:39 AMAug 12
to linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, Baoquan He
And also add code to enable kasan_flag_enabled, this is for later
usage.

And also need skip kasan_populate_early_vm_area_shadow() if kasan
is disabled.

Signed-off-by: Baoquan He <b...@redhat.com>
---
arch/arm64/mm/kasan_init.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/arch/arm64/mm/kasan_init.c b/arch/arm64/mm/kasan_init.c
index d541ce45daeb..0e4ffe3f5d0e 100644
--- a/arch/arm64/mm/kasan_init.c
+++ b/arch/arm64/mm/kasan_init.c
@@ -384,6 +384,9 @@ void __init kasan_populate_early_vm_area_shadow(void *start, unsigned long size)
{
unsigned long shadow_start, shadow_end;

+ if (!kasan_enabled())
+ return;
+
if (!is_vmalloc_or_module_addr(start))
return;

@@ -397,6 +400,9 @@ void __init kasan_populate_early_vm_area_shadow(void *start, unsigned long size)

void __init kasan_init(void)
{
+ if (kasan_arg_disabled)
+ return;
+
kasan_init_shadow();
kasan_init_depth();
#if defined(CONFIG_KASAN_GENERIC)
@@ -405,6 +411,7 @@ void __init kasan_init(void)
* Software and Hardware Tag-Based modes still require
* kasan_init_sw_tags() and kasan_init_hw_tags() correspondingly.
*/
+ static_branch_enable(&kasan_flag_enabled);
pr_info("KernelAddressSanitizer initialized (generic)\n");
#endif
}
--
2.41.0

Baoquan He

unread,
Aug 12, 2025, 8:50:46 AMAug 12
to linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, Baoquan He
And also add code to enable kasan_flag_enabled, this is for later
usage.

Signed-off-by: Baoquan He <b...@redhat.com>
---
arch/loongarch/mm/kasan_init.c | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/arch/loongarch/mm/kasan_init.c b/arch/loongarch/mm/kasan_init.c
index d2681272d8f0..0c32eee6910f 100644
--- a/arch/loongarch/mm/kasan_init.c
+++ b/arch/loongarch/mm/kasan_init.c
@@ -267,6 +267,8 @@ void __init kasan_init(void)
u64 i;
phys_addr_t pa_start, pa_end;

+ if (kasan_arg_disabled)
+ return;
/*
* If PGDIR_SIZE is too large for cpu_vabits, KASAN_SHADOW_END will
* overflow UINTPTR_MAX and then looks like a user space address.
@@ -327,6 +329,9 @@ void __init kasan_init(void)
csr_write64(__pa_symbol(swapper_pg_dir), LOONGARCH_CSR_PGDH);
local_flush_tlb_all();

+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+
/* At this point kasan is fully initialized. Enable error messages */
init_task.kasan_depth = 0;
pr_info("KernelAddressSanitizer initialized.\n");
--
2.41.0

Baoquan He

unread,
Aug 12, 2025, 8:50:53 AMAug 12
to linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, Baoquan He
This includes 32bit, book3s/64 and book3e/64.

And also add code to enable kasan_flag_enabled, this is for later
usage.

Signed-off-by: Baoquan He <b...@redhat.com>
---
arch/powerpc/mm/kasan/init_32.c | 8 +++++++-
arch/powerpc/mm/kasan/init_book3e_64.c | 6 ++++++
arch/powerpc/mm/kasan/init_book3s_64.c | 6 ++++++
3 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/mm/kasan/init_32.c b/arch/powerpc/mm/kasan/init_32.c
index 03666d790a53..b0c465f3fbf5 100644
--- a/arch/powerpc/mm/kasan/init_32.c
+++ b/arch/powerpc/mm/kasan/init_32.c
@@ -141,6 +141,9 @@ void __init kasan_init(void)
u64 i;
int ret;

+ if (kasan_arg_disabled)
+ return;
+
for_each_mem_range(i, &base, &end) {
phys_addr_t top = min(end, total_lowmem);

@@ -163,6 +166,9 @@ void __init kasan_init(void)

clear_page(kasan_early_shadow_page);

+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+
/* At this point kasan is fully initialized. Enable error messages */
init_task.kasan_depth = 0;
pr_info("KASAN init done\n");
@@ -170,7 +176,7 @@ void __init kasan_init(void)

void __init kasan_late_init(void)
{
- if (IS_ENABLED(CONFIG_KASAN_VMALLOC))
+ if (IS_ENABLED(CONFIG_KASAN_VMALLOC) && kasan_enabled())
kasan_unmap_early_shadow_vmalloc();
}

diff --git a/arch/powerpc/mm/kasan/init_book3e_64.c b/arch/powerpc/mm/kasan/init_book3e_64.c
index 60c78aac0f63..1e1c10467a2b 100644
--- a/arch/powerpc/mm/kasan/init_book3e_64.c
+++ b/arch/powerpc/mm/kasan/init_book3e_64.c
@@ -111,6 +111,9 @@ void __init kasan_init(void)
u64 i;
pte_t zero_pte = pfn_pte(virt_to_pfn(kasan_early_shadow_page), PAGE_KERNEL_RO);

+ if (kasan_arg_disabled)
+ return;
+
for_each_mem_range(i, &start, &end)
kasan_init_phys_region(phys_to_virt(start), phys_to_virt(end));

@@ -125,6 +128,9 @@ void __init kasan_init(void)

memset(kasan_early_shadow_page, 0, PAGE_SIZE);

+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+
/* Enable error messages */
init_task.kasan_depth = 0;
pr_info("KASAN init done\n");
diff --git a/arch/powerpc/mm/kasan/init_book3s_64.c b/arch/powerpc/mm/kasan/init_book3s_64.c
index 7d959544c077..9c5cf2354c8b 100644
--- a/arch/powerpc/mm/kasan/init_book3s_64.c
+++ b/arch/powerpc/mm/kasan/init_book3s_64.c
@@ -56,6 +56,9 @@ void __init kasan_init(void)
u64 i;
pte_t zero_pte = pfn_pte(virt_to_pfn(kasan_early_shadow_page), PAGE_KERNEL);

+ if (kasan_arg_disabled)
+ return;
+
if (!early_radix_enabled()) {
pr_warn("KASAN not enabled as it requires radix!");
return;
@@ -94,6 +97,9 @@ void __init kasan_init(void)

static_branch_inc(&powerpc_kasan_enabled_key);

+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+
/* Enable error messages */
init_task.kasan_depth = 0;
pr_info("KASAN init done\n");
--
2.41.0

Baoquan He

unread,
Aug 12, 2025, 8:51:01 AMAug 12
to linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, Baoquan He
And also add code to enable kasan_flag_enabled, this is for later
usage.

Signed-off-by: Baoquan He <b...@redhat.com>
---
arch/riscv/mm/kasan_init.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/arch/riscv/mm/kasan_init.c b/arch/riscv/mm/kasan_init.c
index 41c635d6aca4..ac3ac227c765 100644
--- a/arch/riscv/mm/kasan_init.c
+++ b/arch/riscv/mm/kasan_init.c
@@ -485,6 +485,9 @@ void __init kasan_init(void)
phys_addr_t p_start, p_end;
u64 i;

+ if (kasan_arg_disabled)
+ return;
+
create_tmp_mapping();
csr_write(CSR_SATP, PFN_DOWN(__pa(tmp_pg_dir)) | satp_mode);

@@ -531,6 +534,9 @@ void __init kasan_init(void)
memset(kasan_early_shadow_page, KASAN_SHADOW_INIT, PAGE_SIZE);
init_task.kasan_depth = 0;

+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+
csr_write(CSR_SATP, PFN_DOWN(__pa(swapper_pg_dir)) | satp_mode);
local_flush_tlb_all();
}
--
2.41.0

Baoquan He

unread,
Aug 12, 2025, 8:51:06 AMAug 12
to linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, Baoquan He
And also add code to enable kasan_flag_enabled, this is for later
usage.

Signed-off-by: Baoquan He <b...@redhat.com>
---
arch/x86/mm/kasan_init_64.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/arch/x86/mm/kasan_init_64.c b/arch/x86/mm/kasan_init_64.c
index 0539efd0d216..0f2f9311e9df 100644
--- a/arch/x86/mm/kasan_init_64.c
+++ b/arch/x86/mm/kasan_init_64.c
@@ -343,6 +343,9 @@ void __init kasan_init(void)
unsigned long shadow_cea_begin, shadow_cea_per_cpu_begin, shadow_cea_end;
int i;

+ if (kasan_arg_disabled)
+ return;
+
memcpy(early_top_pgt, init_top_pgt, sizeof(early_top_pgt));

/*
@@ -450,6 +453,9 @@ void __init kasan_init(void)
/* Flush TLBs again to be sure that write protection applied. */
__flush_tlb_all();

+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+
init_task.kasan_depth = 0;
pr_info("KernelAddressSanitizer initialized\n");
}
--
2.41.0

Baoquan He

unread,
Aug 12, 2025, 8:51:16 AMAug 12
to linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, Baoquan He
And also add code to enable kasan_flag_enabled, this is for later
usage.

Here call jump_label_init() early in setup_arch() so that later
kasan_init() can enable static key kasan_flag_enabled. Put
jump_label_init() beofre parse_early_param() as other architectures
do.

Signed-off-by: Baoquan He <b...@redhat.com>
---
arch/xtensa/kernel/setup.c | 1 +
arch/xtensa/mm/kasan_init.c | 6 ++++++
2 files changed, 7 insertions(+)

diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c
index f72e280363be..aabeb23f41fa 100644
--- a/arch/xtensa/kernel/setup.c
+++ b/arch/xtensa/kernel/setup.c
@@ -352,6 +352,7 @@ void __init setup_arch(char **cmdline_p)
mem_reserve(__pa(_SecondaryResetVector_text_start),
__pa(_SecondaryResetVector_text_end));
#endif
+ jump_label_init();
parse_early_param();
bootmem_init();
kasan_init();
diff --git a/arch/xtensa/mm/kasan_init.c b/arch/xtensa/mm/kasan_init.c
index f39c4d83173a..4a7b77f47225 100644
--- a/arch/xtensa/mm/kasan_init.c
+++ b/arch/xtensa/mm/kasan_init.c
@@ -70,6 +70,9 @@ void __init kasan_init(void)
{
int i;

+ if (kasan_arg_disabled)
+ return;
+
BUILD_BUG_ON(KASAN_SHADOW_OFFSET != KASAN_SHADOW_START -
(KASAN_START_VADDR >> KASAN_SHADOW_SCALE_SHIFT));
BUILD_BUG_ON(VMALLOC_START < KASAN_START_VADDR);
@@ -92,6 +95,9 @@ void __init kasan_init(void)
local_flush_tlb_all();
memset(kasan_early_shadow_page, 0, PAGE_SIZE);

+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+
/* At this point kasan is fully initialized. Enable error messages. */
current->kasan_depth = 0;

Baoquan He

unread,
Aug 12, 2025, 8:51:24 AMAug 12
to linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, Baoquan He
And also add code to enable kasan_flag_enabled, this is for later
usage. Since kasan_init() is called before main(), enabling
kasan_flag_enabled is done in arch_mm_preinit() which is after
jump_label_init() invocation.

Signed-off-by: Baoquan He <b...@redhat.com>
---
arch/um/kernel/mem.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
index 76bec7de81b5..392a23d4ef96 100644
--- a/arch/um/kernel/mem.c
+++ b/arch/um/kernel/mem.c
@@ -26,6 +26,9 @@
int kasan_um_is_ready;
void kasan_init(void)
{
+
+ if (kasan_arg_disabled)
+ return;
/*
* kasan_map_memory will map all of the required address space and
* the host machine will allocate physical memory as necessary.
@@ -58,6 +61,9 @@ static unsigned long brk_end;

void __init arch_mm_preinit(void)
{
+ /* Safe to call after jump_label_init(). Enables KASAN. */
+ static_branch_enable(&kasan_flag_enabled);
+
/* clear the zero-page */
memset(empty_zero_page, 0, PAGE_SIZE);

--
2.41.0

Baoquan He

unread,
Aug 12, 2025, 8:51:29 AMAug 12
to linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, Baoquan He
Now everything is ready, set kasan=off can disable kasan for all
three modes.

Signed-off-by: Baoquan He <b...@redhat.com>
---
include/linux/kasan-enabled.h | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/include/linux/kasan-enabled.h b/include/linux/kasan-enabled.h
index 32f2d19f599f..21b6233f829c 100644
--- a/include/linux/kasan-enabled.h
+++ b/include/linux/kasan-enabled.h
@@ -4,34 +4,32 @@

#include <linux/static_key.h>

+#ifdef CONFIG_KASAN
extern bool kasan_arg_disabled;

DECLARE_STATIC_KEY_FALSE(kasan_flag_enabled);

-#ifdef CONFIG_KASAN_HW_TAGS
-
static __always_inline bool kasan_enabled(void)
{
return static_branch_likely(&kasan_flag_enabled);
}
+#else /* CONFIG_KASAN */
+static inline bool kasan_enabled(void)
+{
+ return false;
+}
+#endif

Baoquan He

unread,
Aug 12, 2025, 9:27:14 AMAug 12
to Lorenzo Stoakes, SeongJae Park, linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org
On 08/08/25 at 02:24pm, Lorenzo Stoakes wrote:
> On Fri, Aug 08, 2025 at 09:08:35PM +0800, Baoquan He wrote:
> > On 08/06/25 at 05:26pm, Lorenzo Stoakes wrote:
......
> > > > diff --git a/include/linux/kasan-enabled.h b/include/linux/kasan-enabled.h
> > > > index b5857e15ef14..a53d112b1020 100644
> > > > --- a/include/linux/kasan-enabled.h
> > > > +++ b/include/linux/kasan-enabled.h
> > > > @@ -8,11 +8,22 @@ extern bool kasan_arg_disabled;
> > > >
> > > > DECLARE_STATIC_KEY_FALSE(kasan_flag_enabled);
> > > >
> > > > +#ifdef CONFIG_KASAN
> > > > +
> > >
> > > Shouldn't we put this above the static key declaration?
> > >
> > > Feels like the whole header should be included really.
> >
> > You are right, kasan_flag_enabled should be included in CONFIG_KASAN
> > ifdeffery scope.
>
> Firstly I _LOVE_ the term 'ifdeffery scope'. Fantastic :)

Learned from upstream people with expertise on both english and kernel, :-)

>
> >
> > Since CONFIG_KASAN_HW_TAGS depends on CONFIG_KASAN, we may not need
> > include below CONFIG_KASAN_HW_TAGS ifdeffery into CONFIG_KASAN ifdeffery
> > scope. Not sure if this is incorrect.
>
> Well I don't think CONFIG_KASAN_HW_TAGS is necessarily implied right? So these
> should remain I think, just nested in CONFIG_KASAN, should be fine.

After investigation, I keep the CONFIG_KASAN_HW_TAGS ifdeffery scope out
of CONFIG_KASAN scope. Otherwise, I need define the dummy
kasan_hw_tags_enabled() function twice. I am personally not fan of the
style. While if that is preferred in kernel, I can change it.

#ifdef CONFIG_KASAN

#ifdef CONFIG_KASAN_HW_TAGS
......
#ifdef CONFIG_KASAN_HW_TAGS
static inline bool kasan_hw_tags_enabled(void)
{
return kasan_enabled();
}
#else /* CONFIG_KASAN_HW_TAGS */
static inline bool kasan_hw_tags_enabled(void)
{
return false;
}
#endif /* CONFIG_KASAN_HW_TAGS */
.....
#else /* CONFIG_KASAN */
static inline bool kasan_hw_tags_enabled(void)
{
return false;
}
#endif

Baoquan He

unread,
Aug 12, 2025, 9:39:29 AMAug 12
to linu...@kvack.org, alex...@rivosinc.com, agor...@linux.ibm.com, li...@armlinux.org.uk, linux-ar...@lists.infradead.org, loon...@lists.linux.dev, linuxp...@lists.ozlabs.org, linux...@lists.infradead.org, christop...@csgroup.eu, x...@kernel.org, ch...@zankel.net, jcmv...@gmail.com, linu...@lists.infradead.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com
Forgot adding related ARCH mailing list or people to CC, add them.

Baoquan He

unread,
Aug 12, 2025, 11:10:29 AMAug 12
to linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com
On 08/12/25 at 08:49pm, Baoquan He wrote:
> Currently only hw_tags mode of kasan can be enabled or disabled with
> kernel parameter kasan=on|off for built kernel. For kasan generic and
> sw_tags mode, there's no way to disable them once kernel is built.
> This is not convenient sometime, e.g in system kdump is configured.
> When the 1st kernel has KASAN enabled and crash triggered to switch to
> kdump kernel, the generic or sw_tags mode will cost much extra memory
> for kasan shadow while in fact it's meaningless to have kasan in kdump
> kernel.
>
> So this patchset moves the kasan=on|off out of hw_tags scope and into
> common code to make it visible in generic and sw_tags mode too. Then we
> can add kasan=off in kdump kernel to reduce the unneeded meomry cost for
> kasan.
>
> Changelog:
> ====
> v1->v2:
> - Add __ro_after_init for __ro_after_init, and remove redundant blank
~~~~~~~~~~~~~ s/__ro_after_init/kasan_arg_disabled/
Sorry for typo here.

Andrey Konovalov

unread,
Aug 12, 2025, 12:57:53 PMAug 12
to Baoquan He, linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com
On Tue, Aug 12, 2025 at 2:49 PM Baoquan He <b...@redhat.com> wrote:
>
> Currently only hw_tags mode of kasan can be enabled or disabled with
> kernel parameter kasan=on|off for built kernel. For kasan generic and
> sw_tags mode, there's no way to disable them once kernel is built.
> This is not convenient sometime, e.g in system kdump is configured.
> When the 1st kernel has KASAN enabled and crash triggered to switch to
> kdump kernel, the generic or sw_tags mode will cost much extra memory
> for kasan shadow while in fact it's meaningless to have kasan in kdump
> kernel.
>
> So this patchset moves the kasan=on|off out of hw_tags scope and into
> common code to make it visible in generic and sw_tags mode too. Then we
> can add kasan=off in kdump kernel to reduce the unneeded meomry cost for
> kasan.

Hi Baoquan,

Could you clarify what are you trying to achieve by disabling
Generic/SW_TAGS KASAN via command-line? Do you want not to see any
KASAN reports produced? Or gain back the performance?

Because for the no reports goal, it would be much easier to add a
command-line parameter to silent the reports.

And the performance goal can only be partially achieved, as you cannot
remove the compiler instrumentation without rebuilding the kernel.
(What are the boot times for KASAN_GENERIC=n vs KASAN_GENERIC=y +
kasan=off vs KASAN_GENERIC=y btw?)

Thank you!

Lorenzo Stoakes

unread,
Aug 12, 2025, 1:07:02 PMAug 12
to Baoquan He, SeongJae Park, linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, andre...@gmail.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org
On Tue, Aug 12, 2025 at 09:27:02PM +0800, Baoquan He wrote:
> > Firstly I _LOVE_ the term 'ifdeffery scope'. Fantastic :)
>
> Learned from upstream people with expertise on both english and kernel, :-)

:)

> After investigation, I keep the CONFIG_KASAN_HW_TAGS ifdeffery scope out
> of CONFIG_KASAN scope. Otherwise, I need define the dummy
> kasan_hw_tags_enabled() function twice. I am personally not fan of the
> style. While if that is preferred in kernel, I can change it.
>
> #ifdef CONFIG_KASAN
>
> #ifdef CONFIG_KASAN_HW_TAGS
> ......
> #ifdef CONFIG_KASAN_HW_TAGS
> static inline bool kasan_hw_tags_enabled(void)
> {
> return kasan_enabled();
> }
> #else /* CONFIG_KASAN_HW_TAGS */
> static inline bool kasan_hw_tags_enabled(void)
> {
> return false;
> }
> #endif /* CONFIG_KASAN_HW_TAGS */
> .....
> #else /* CONFIG_KASAN */
> static inline bool kasan_hw_tags_enabled(void)
> {
> return false;
> }
> #endif
>

This is fine, as CONFIG_KASAN_HW_TAGS implies CONFIG_KASAN anyway.

Andrey Konovalov

unread,
Aug 12, 2025, 1:15:07 PMAug 12
to Baoquan He, linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com
Ah, you don't want the shadow memory for kdump, sorry, I somehow missed that.

I'm not familiar with the internals of kdump, but would it be
possible/reasonable to teach kdump to ignore the KASAN shadow region?

Baoquan He

unread,
Aug 13, 2025, 7:14:17 AMAug 13
to Andrey Konovalov, linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com
Thanks a lot for checking this.

>
> Ah, you don't want the shadow memory for kdump, sorry, I somehow missed that.

Yeah, for kdump kernel, the shadow is a heavy burden, and most
importantly kasan is useless for kdump. We don't want to capture a
kernel memory bug through kdump kernel running becuase kdump is a
debugging mechanism.

>
> I'm not familiar with the internals of kdump, but would it be
> possible/reasonable to teach kdump to ignore the KASAN shadow region?

Yes, we can teach kdump to do that. Then people may hate those conditional
check "if (is_kdump_kernel())" being added in kasan code. E.g even
though we skip kasan_init(), we still need to check is_kdump_kernel()
in kasan_populate_vmalloc(), right?

Combined with the existing kasan_arch_is_ready(), it will make kasan code
ugly. I planned to add kasan_enabled() via static key
kasan_flag_enabled, then it can also easily remove kasan_arch_is_ready()
cleanly.

Andrey Konovalov

unread,
Aug 14, 2025, 1:23:16 AMAug 14
to Baoquan He, linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com
On Wed, Aug 13, 2025 at 1:14 PM 'Baoquan He' via kasan-dev
<kasa...@googlegroups.com> wrote:
>
> > I'm not familiar with the internals of kdump, but would it be
> > possible/reasonable to teach kdump to ignore the KASAN shadow region?
>
> Yes, we can teach kdump to do that. Then people may hate those conditional
> check "if (is_kdump_kernel())" being added in kasan code. E.g even
> though we skip kasan_init(), we still need to check is_kdump_kernel()
> in kasan_populate_vmalloc(), right?
>
> Combined with the existing kasan_arch_is_ready(), it will make kasan code
> ugly. I planned to add kasan_enabled() via static key
> kasan_flag_enabled, then it can also easily remove kasan_arch_is_ready()
> cleanly.

What I had in mind was something different: into the kdump code, we
add a check whether the region of memory it's trying to dump is the
KASAN shadow, and make kdump not to dump this region.

Would this work? Would this help with the issue you have?

(I assume the problem is with the virtual region that is the shadow
memory, as kdump would dump all RAM either way? If not, please clarify
what how does the "heavy burden" that the shadow memory causes
manifests.)

Thank you!

Baoquan He

unread,
Aug 14, 2025, 4:56:20 AMAug 14
to Andrey Konovalov, linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com
On 08/14/25 at 07:23am, Andrey Konovalov wrote:
> On Wed, Aug 13, 2025 at 1:14 PM 'Baoquan He' via kasan-dev
> <kasa...@googlegroups.com> wrote:
> >
> > > I'm not familiar with the internals of kdump, but would it be
> > > possible/reasonable to teach kdump to ignore the KASAN shadow region?
> >
> > Yes, we can teach kdump to do that. Then people may hate those conditional
> > check "if (is_kdump_kernel())" being added in kasan code. E.g even
> > though we skip kasan_init(), we still need to check is_kdump_kernel()
> > in kasan_populate_vmalloc(), right?
> >
> > Combined with the existing kasan_arch_is_ready(), it will make kasan code
> > ugly. I planned to add kasan_enabled() via static key
> > kasan_flag_enabled, then it can also easily remove kasan_arch_is_ready()
> > cleanly.
>
> What I had in mind was something different: into the kdump code, we
> add a check whether the region of memory it's trying to dump is the
> KASAN shadow, and make kdump not to dump this region.

Ah, I got what you mean. We probably are saying different things.

In order to record memory content of a corrupted kernel, we need reserve
a memory region during bootup of a normal kernel (usually called 1st
kernel) via kernel parameter crashkernel=nMB in advance. Then load
kernel into the crashkernel memory region, that means the region is not
usable for 1st kernel. When 1st kernel collapsed, we stop the 1st kernel
cpu/irq and warmly switch to the loaded kernel in the crashkernel memory
region (usually called kdump kernel). In kdump kernel, it boots up and
enable necessary features to read out the 1st kernel's memory content,
we usually use user space tool like makeudmpfile to filter out unwanted
memory content.

So this patchset intends to disable KASAN to decrease the crashkernel
meomry value because crashkernel is not usable for 1st kernel. As for
shadow memory of 1st kernel, we need recognize it and filter it away
in makedumpfile.

Andrey Konovalov

unread,
Aug 16, 2025, 12:50:21 AMAug 16
to Baoquan He, linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com
On Thu, Aug 14, 2025 at 10:56 AM Baoquan He <b...@redhat.com> wrote:
>
> Ah, I got what you mean. We probably are saying different things.
>
> In order to record memory content of a corrupted kernel, we need reserve
> a memory region during bootup of a normal kernel (usually called 1st
> kernel) via kernel parameter crashkernel=nMB in advance. Then load
> kernel into the crashkernel memory region, that means the region is not
> usable for 1st kernel. When 1st kernel collapsed, we stop the 1st kernel
> cpu/irq and warmly switch to the loaded kernel in the crashkernel memory
> region (usually called kdump kernel). In kdump kernel, it boots up and
> enable necessary features to read out the 1st kernel's memory content,
> we usually use user space tool like makeudmpfile to filter out unwanted
> memory content.
>
> So this patchset intends to disable KASAN to decrease the crashkernel
> meomry value because crashkernel is not usable for 1st kernel. As for
> shadow memory of 1st kernel, we need recognize it and filter it away
> in makedumpfile.

Ah, I see, thank you for the explanation!

So kdump kernel runs with the amount of RAM specified by crashkernel=.
And KASAN's shadow memory increases RAM usage, which means
crashkernel= needs to be set to a higher value for KASAN kernels. Is
my understanding of the problem correct?

Baoquan He

unread,
Aug 16, 2025, 11:41:02 PMAug 16
to Andrey Konovalov, linu...@kvack.org, ryabin...@gmail.com, gli...@google.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com
Yeah, you are quite right.

When I tested it, on x86_64 and arm64, usually I set crashkernel=256M
and it's sufficient. However, when KASAN is enabled and generic mode is
taken, I need set crashkernel=768M to make vmcore dumping succeed. In
kdump kernel, read_vmcore() uses ioremap to map the old memory of
collapsed kernel for reading out, those vmalloc-ed areas are lazily
freed and cause more shadow memory than what we usually think shadow
memory only costs 1/8 of physical RAM.

Baoquan He

unread,
Aug 20, 2025, 1:35:19 AMAug 20
to linu...@kvack.org, ryabin...@gmail.com, andre...@gmail.com, gli...@google.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, christop...@csgroup.eu, Baoquan He
Currently only hw_tags mode of kasan can be enabled or disabled with
kernel parameter kasan=on|off for built kernel. For kasan generic and
sw_tags mode, there's no way to disable them once kernel is built.
This is not convenient sometime, e.g in system kdump is configured.
When the 1st kernel has KASAN enabled and crash triggered to switch to
kdump kernel, the generic or sw_tags mode will cost much extra memory
for kasan shadow while in fact it's meaningless to have kasan in kdump
kernel.

So this patchset moves the kasan=on|off out of hw_tags scope and into
common code to make it visible in generic and sw_tags mode too. Then we
can add kasan=off in kdump kernel to reduce the unneeded meomry cost for
kasan.

Changelog:
====
v2->v3:
- Fix a building error on UML ARCH when CONFIG_KASAN is not set. The
change of fixing is appended into patch patch 11. This is reported
by LKP, thanks to them.

v1->v2:
- Add __ro_after_init for kasan_arg_disabled, and remove redundant blank
lines in mm/kasan/common.c. Thanks to Marco.
In v3, I only built UML kernel successfully w and w/o CONFIG_KASAN
setting with LKP's testing steps.
====


Baoquan He (12):
mm/kasan: add conditional checks in functions to return directly if
kasan is disabled
mm/kasan: move kasan= code to common place
mm/kasan/sw_tags: don't initialize kasan if it's disabled
arch/arm: don't initialize kasan if it's disabled
arch/arm64: don't initialize kasan if it's disabled
arch/loongarch: don't initialize kasan if it's disabled
arch/powerpc: don't initialize kasan if it's disabled
arch/riscv: don't initialize kasan if it's disabled
arch/x86: don't initialize kasan if it's disabled
arch/xtensa: don't initialize kasan if it's disabled
arch/um: don't initialize kasan if it's disabled
mm/kasan: make kasan=on|off take effect for all three modes

arch/arm/kernel/setup.c | 6 +++++
arch/arm/mm/kasan_init.c | 6 +++++
arch/arm64/mm/kasan_init.c | 7 ++++++
arch/loongarch/mm/kasan_init.c | 5 ++++
arch/powerpc/mm/kasan/init_32.c | 8 +++++-
arch/powerpc/mm/kasan/init_book3e_64.c | 6 +++++
arch/powerpc/mm/kasan/init_book3s_64.c | 6 +++++
arch/riscv/mm/kasan_init.c | 6 +++++
arch/um/kernel/mem.c | 7 ++++++
arch/x86/mm/kasan_init_64.c | 6 +++++
arch/xtensa/kernel/setup.c | 1 +
arch/xtensa/mm/kasan_init.c | 6 +++++
include/linux/kasan-enabled.h | 18 ++++++-------
mm/kasan/common.c | 25 ++++++++++++++++++
mm/kasan/generic.c | 20 +++++++++++++--
mm/kasan/hw_tags.c | 35 ++------------------------
mm/kasan/init.c | 6 +++++
mm/kasan/quarantine.c | 3 +++
mm/kasan/report.c | 4 ++-
mm/kasan/shadow.c | 23 ++++++++++++++++-
mm/kasan/sw_tags.c | 9 +++++++
21 files changed, 166 insertions(+), 47 deletions(-)

--
2.41.0

Baoquan He

unread,
Aug 20, 2025, 1:35:25 AMAug 20
to linu...@kvack.org, ryabin...@gmail.com, andre...@gmail.com, gli...@google.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, christop...@csgroup.eu, Baoquan He
The current code only does the check if kasan is disabled for hw_tags
mode. Here add the conditional checks for functional functions of
generic mode and sw_tags mode.

This is prepared for later adding kernel parameter kasan=on|off for
all kasan modes.

Signed-off-by: Baoquan He <b...@redhat.com>
---
mm/kasan/generic.c | 20 ++++++++++++++++++--
mm/kasan/init.c | 6 ++++++
mm/kasan/quarantine.c | 3 +++
mm/kasan/report.c | 4 +++-
mm/kasan/shadow.c | 23 ++++++++++++++++++++++-
mm/kasan/sw_tags.c | 3 +++
6 files changed, 55 insertions(+), 4 deletions(-)

diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c
index d54e89f8c3e7..8daea5892754 100644
--- a/mm/kasan/generic.c
+++ b/mm/kasan/generic.c
@@ -165,6 +165,9 @@ static __always_inline bool check_region_inline(const void *addr,
size_t size, bool write,
unsigned long ret_ip)
{
+ if (!kasan_enabled())
+ return true;
+
if (!kasan_arch_is_ready())
return true;

@@ -203,12 +206,13 @@ bool kasan_byte_accessible(const void *addr)

void kasan_cache_shrink(struct kmem_cache *cache)
{
- kasan_quarantine_remove_cache(cache);
+ if (kasan_enabled())
+ kasan_quarantine_remove_cache(cache);
}

void kasan_cache_shutdown(struct kmem_cache *cache)
{
- if (!__kmem_cache_empty(cache))
+ if (kasan_enabled() && !__kmem_cache_empty(cache))
kasan_quarantine_remove_cache(cache);
}

@@ -228,6 +232,9 @@ void __asan_register_globals(void *ptr, ssize_t size)
int i;
struct kasan_global *globals = ptr;

+ if (!kasan_enabled())
+ return;
+
for (i = 0; i < size; i++)
register_global(&globals[i]);
}
@@ -358,6 +365,9 @@ void kasan_cache_create(struct kmem_cache *cache, unsigned int *size,
unsigned int rem_free_meta_size;
unsigned int orig_alloc_meta_offset;

+ if (!kasan_enabled())
+ return;
+
if (!kasan_requires_meta())
return;

@@ -510,6 +520,9 @@ size_t kasan_metadata_size(struct kmem_cache *cache, bool in_object)
{
struct kasan_cache *info = &cache->kasan_info;

+ if (!kasan_enabled())
+ return 0;
+
if (!kasan_requires_meta())
return 0;

@@ -535,6 +548,9 @@ void kasan_record_aux_stack(void *addr)
struct kasan_alloc_meta *alloc_meta;
void *object;

+ if (!kasan_enabled())
+ return;
+
if (is_kfence_address(addr) || !slab)
return;

diff --git a/mm/kasan/init.c b/mm/kasan/init.c
index ced6b29fcf76..43d95f329675 100644
--- a/mm/kasan/init.c
+++ b/mm/kasan/init.c
@@ -449,6 +449,9 @@ void kasan_remove_zero_shadow(void *start, unsigned long size)
unsigned long addr, end, next;
pgd_t *pgd;

+ if (!kasan_enabled())
+ return;
+
addr = (unsigned long)kasan_mem_to_shadow(start);
end = addr + (size >> KASAN_SHADOW_SCALE_SHIFT);

@@ -484,6 +487,9 @@ int kasan_add_zero_shadow(void *start, unsigned long size)
int ret;
void *shadow_start, *shadow_end;

+ if (!kasan_enabled())
+ return 0;
+
shadow_start = kasan_mem_to_shadow(start);
shadow_end = shadow_start + (size >> KASAN_SHADOW_SCALE_SHIFT);

diff --git a/mm/kasan/quarantine.c b/mm/kasan/quarantine.c
index 6958aa713c67..a6dc2c3d8a15 100644
--- a/mm/kasan/quarantine.c
+++ b/mm/kasan/quarantine.c
@@ -405,6 +405,9 @@ static int __init kasan_cpu_quarantine_init(void)
{
int ret = 0;

+ if (!kasan_enabled())
+ return 0;
+
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "mm/kasan:online",
kasan_cpu_online, kasan_cpu_offline);
if (ret < 0)
diff --git a/mm/kasan/report.c b/mm/kasan/report.c
index 62c01b4527eb..884357fa74ed 100644
--- a/mm/kasan/report.c
+++ b/mm/kasan/report.c
@@ -576,7 +576,9 @@ bool kasan_report(const void *addr, size_t size, bool is_write,
unsigned long irq_flags;
struct kasan_report_info info;

- if (unlikely(report_suppressed_sw()) || unlikely(!report_enabled())) {
+ if (unlikely(report_suppressed_sw()) ||
+ unlikely(!report_enabled()) ||
+ !kasan_enabled()) {
ret = false;
goto out;
}
diff --git a/mm/kasan/shadow.c b/mm/kasan/shadow.c
index d2c70cd2afb1..637f2d02d2a3 100644
--- a/mm/kasan/shadow.c
+++ b/mm/kasan/shadow.c
@@ -125,6 +125,9 @@ void kasan_poison(const void *addr, size_t size, u8 value, bool init)
{
void *shadow_start, *shadow_end;

+ if (!kasan_enabled())
+ return;
+
if (!kasan_arch_is_ready())
return;

@@ -150,6 +153,9 @@ EXPORT_SYMBOL_GPL(kasan_poison);
#ifdef CONFIG_KASAN_GENERIC
void kasan_poison_last_granule(const void *addr, size_t size)
{
+ if (!kasan_enabled())
+ return;
+
if (!kasan_arch_is_ready())
return;

@@ -164,6 +170,8 @@ void kasan_unpoison(const void *addr, size_t size, bool init)
{
u8 tag = get_tag(addr);

+ if (!kasan_enabled())
+ return;
/*
* Perform shadow offset calculation based on untagged address, as
* some of the callers (e.g. kasan_unpoison_new_object) pass tagged
@@ -277,7 +285,8 @@ static int __meminit kasan_mem_notifier(struct notifier_block *nb,

static int __init kasan_memhotplug_init(void)
{
- hotplug_memory_notifier(kasan_mem_notifier, DEFAULT_CALLBACK_PRI);
+ if (kasan_enabled())
+ hotplug_memory_notifier(kasan_mem_notifier, DEFAULT_CALLBACK_PRI);

return 0;
}
@@ -390,6 +399,9 @@ int kasan_populate_vmalloc(unsigned long addr, unsigned long size)
unsigned long shadow_start, shadow_end;
int ret;

+ if (!kasan_enabled())
+ return 0;
+
if (!kasan_arch_is_ready())
return 0;

@@ -560,6 +572,9 @@ void kasan_release_vmalloc(unsigned long start, unsigned long end,
unsigned long region_start, region_end;
unsigned long size;

+ if (!kasan_enabled())
+ return;
+
if (!kasan_arch_is_ready())
return;

@@ -655,6 +670,9 @@ int kasan_alloc_module_shadow(void *addr, size_t size, gfp_t gfp_mask)
size_t shadow_size;
unsigned long shadow_start;

+ if (!kasan_enabled())
+ return 0;
+
shadow_start = (unsigned long)kasan_mem_to_shadow(addr);
scaled_size = (size + KASAN_GRANULE_SIZE - 1) >>
KASAN_SHADOW_SCALE_SHIFT;
@@ -691,6 +709,9 @@ int kasan_alloc_module_shadow(void *addr, size_t size, gfp_t gfp_mask)

void kasan_free_module_shadow(const struct vm_struct *vm)
{
+ if (!kasan_enabled())
+ return;
+
if (IS_ENABLED(CONFIG_UML))
return;

diff --git a/mm/kasan/sw_tags.c b/mm/kasan/sw_tags.c
index b9382b5b6a37..01f19bc4a326 100644
--- a/mm/kasan/sw_tags.c
+++ b/mm/kasan/sw_tags.c
@@ -78,6 +78,9 @@ bool kasan_check_range(const void *addr, size_t size, bool write,
u8 *shadow_first, *shadow_last, *shadow;
void *untagged_addr;

+ if (!kasan_enabled())

Baoquan He

unread,
Aug 20, 2025, 1:35:38 AMAug 20
to linu...@kvack.org, ryabin...@gmail.com, andre...@gmail.com, gli...@google.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, christop...@csgroup.eu, Baoquan He
This allows generic and sw_tags to be set in kernel cmdline too.

When at it, rename 'kasan_arg' to 'kasan_arg_disabled' as a bool
variable. And expose 'kasan_flag_enabled' to kasan common place
too.

This is prepared for later adding kernel parameter kasan=on|off for
all kasan modes.

Signed-off-by: Baoquan He <b...@redhat.com>
---
include/linux/kasan-enabled.h | 4 +++-
mm/kasan/common.c | 25 +++++++++++++++++++++++++
mm/kasan/hw_tags.c | 35 ++---------------------------------
3 files changed, 30 insertions(+), 34 deletions(-)

diff --git a/include/linux/kasan-enabled.h b/include/linux/kasan-enabled.h
index 6f612d69ea0c..32f2d19f599f 100644
--- a/include/linux/kasan-enabled.h
+++ b/include/linux/kasan-enabled.h
@@ -4,10 +4,12 @@

#include <linux/static_key.h>

-#ifdef CONFIG_KASAN_HW_TAGS
+extern bool kasan_arg_disabled;

DECLARE_STATIC_KEY_FALSE(kasan_flag_enabled);

+#ifdef CONFIG_KASAN_HW_TAGS
+
static __always_inline bool kasan_enabled(void)
{
return static_branch_likely(&kasan_flag_enabled);

Baoquan He

unread,
Aug 20, 2025, 1:35:48 AMAug 20
to linu...@kvack.org, ryabin...@gmail.com, andre...@gmail.com, gli...@google.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, christop...@csgroup.eu, Baoquan He
And also add code to enable kasan_flag_enabled, this is for later
usage.

Signed-off-by: Baoquan He <b...@redhat.com>
---
mm/kasan/sw_tags.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/mm/kasan/sw_tags.c b/mm/kasan/sw_tags.c
index 01f19bc4a326..dd963ba4d143 100644
--- a/mm/kasan/sw_tags.c
+++ b/mm/kasan/sw_tags.c
@@ -40,11 +40,17 @@ void __init kasan_init_sw_tags(void)
{
int cpu;

+ if (kasan_arg_disabled)
+ return;
+
for_each_possible_cpu(cpu)
per_cpu(prng_state, cpu) = (u32)get_cycles();

kasan_init_tags();

+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+

Baoquan He

unread,
Aug 20, 2025, 1:35:55 AMAug 20
to linu...@kvack.org, ryabin...@gmail.com, andre...@gmail.com, gli...@google.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, christop...@csgroup.eu, Baoquan He, linux-ar...@lists.infradead.org
And also add code to enable kasan_flag_enabled, this is for later
usage.

Here call jump_label_init() early in setup_arch() so that later
kasan_init() can enable static key kasan_flag_enabled. Put
jump_label_init() beofre parse_early_param() as other architectures
do.

Signed-off-by: Baoquan He <b...@redhat.com>
Cc: linux-ar...@lists.infradead.org
---
arch/arm/kernel/setup.c | 6 ++++++
arch/arm/mm/kasan_init.c | 6 ++++++
2 files changed, 12 insertions(+)

diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 0bfd66c7ada0..453a47a4c715 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -1135,6 +1135,12 @@ void __init setup_arch(char **cmdline_p)
early_fixmap_init();
early_ioremap_init();

+ /*
+ * Initialise the static keys early as they may be enabled by the
+ * kasan_init() or early parameters.
+ */
+ jump_label_init();
+
parse_early_param();

#ifdef CONFIG_MMU
diff --git a/arch/arm/mm/kasan_init.c b/arch/arm/mm/kasan_init.c
index 111d4f703136..c764e1b9c9c5 100644
--- a/arch/arm/mm/kasan_init.c
+++ b/arch/arm/mm/kasan_init.c
@@ -212,6 +212,8 @@ void __init kasan_init(void)
phys_addr_t pa_start, pa_end;
u64 i;

+ if (kasan_arg_disabled)
+ return;
/*
* We are going to perform proper setup of shadow memory.
*
@@ -300,6 +302,10 @@ void __init kasan_init(void)
local_flush_tlb_all();

memset(kasan_early_shadow_page, 0, PAGE_SIZE);
+
+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+

Baoquan He

unread,
Aug 20, 2025, 1:36:07 AMAug 20
to linu...@kvack.org, ryabin...@gmail.com, andre...@gmail.com, gli...@google.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, christop...@csgroup.eu, Baoquan He, linux-ar...@lists.infradead.org
And also add code to enable kasan_flag_enabled, this is for later
usage.

And also need skip kasan_populate_early_vm_area_shadow() if kasan
is disabled.

Signed-off-by: Baoquan He <b...@redhat.com>
Cc: linux-ar...@lists.infradead.org
---
arch/arm64/mm/kasan_init.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/arch/arm64/mm/kasan_init.c b/arch/arm64/mm/kasan_init.c
index d541ce45daeb..0e4ffe3f5d0e 100644
--- a/arch/arm64/mm/kasan_init.c
+++ b/arch/arm64/mm/kasan_init.c
@@ -384,6 +384,9 @@ void __init kasan_populate_early_vm_area_shadow(void *start, unsigned long size)
{
unsigned long shadow_start, shadow_end;

+ if (!kasan_enabled())
+ return;
+
if (!is_vmalloc_or_module_addr(start))
return;

@@ -397,6 +400,9 @@ void __init kasan_populate_early_vm_area_shadow(void *start, unsigned long size)

void __init kasan_init(void)
{
+ if (kasan_arg_disabled)
+ return;

Baoquan He

unread,
Aug 20, 2025, 1:36:14 AMAug 20
to linu...@kvack.org, ryabin...@gmail.com, andre...@gmail.com, gli...@google.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, christop...@csgroup.eu, Baoquan He, loon...@lists.linux.dev
And also add code to enable kasan_flag_enabled, this is for later
usage.

Signed-off-by: Baoquan He <b...@redhat.com>
Cc: loon...@lists.linux.dev
---
arch/loongarch/mm/kasan_init.c | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/arch/loongarch/mm/kasan_init.c b/arch/loongarch/mm/kasan_init.c
index d2681272d8f0..0c32eee6910f 100644
--- a/arch/loongarch/mm/kasan_init.c
+++ b/arch/loongarch/mm/kasan_init.c
@@ -267,6 +267,8 @@ void __init kasan_init(void)
u64 i;
phys_addr_t pa_start, pa_end;

+ if (kasan_arg_disabled)
+ return;
/*
* If PGDIR_SIZE is too large for cpu_vabits, KASAN_SHADOW_END will
* overflow UINTPTR_MAX and then looks like a user space address.
@@ -327,6 +329,9 @@ void __init kasan_init(void)
csr_write64(__pa_symbol(swapper_pg_dir), LOONGARCH_CSR_PGDH);
local_flush_tlb_all();

+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+
/* At this point kasan is fully initialized. Enable error messages */
init_task.kasan_depth = 0;

Baoquan He

unread,
Aug 20, 2025, 1:36:27 AMAug 20
to linu...@kvack.org, ryabin...@gmail.com, andre...@gmail.com, gli...@google.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, christop...@csgroup.eu, Baoquan He, linuxp...@lists.ozlabs.org
This includes 32bit, book3s/64 and book3e/64.

And also add code to enable kasan_flag_enabled, this is for later
usage.

Signed-off-by: Baoquan He <b...@redhat.com>
Cc: linuxp...@lists.ozlabs.org
---
arch/powerpc/mm/kasan/init_32.c | 8 +++++++-
arch/powerpc/mm/kasan/init_book3e_64.c | 6 ++++++
arch/powerpc/mm/kasan/init_book3s_64.c | 6 ++++++
3 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/mm/kasan/init_32.c b/arch/powerpc/mm/kasan/init_32.c
index 03666d790a53..b0c465f3fbf5 100644
--- a/arch/powerpc/mm/kasan/init_32.c
+++ b/arch/powerpc/mm/kasan/init_32.c
@@ -141,6 +141,9 @@ void __init kasan_init(void)
u64 i;
int ret;

+ if (kasan_arg_disabled)
+ return;
+
for_each_mem_range(i, &base, &end) {
phys_addr_t top = min(end, total_lowmem);

@@ -163,6 +166,9 @@ void __init kasan_init(void)

clear_page(kasan_early_shadow_page);

+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+
/* At this point kasan is fully initialized. Enable error messages */
init_task.kasan_depth = 0;
pr_info("KASAN init done\n");
@@ -170,7 +176,7 @@ void __init kasan_init(void)

void __init kasan_late_init(void)
{
- if (IS_ENABLED(CONFIG_KASAN_VMALLOC))
+ if (IS_ENABLED(CONFIG_KASAN_VMALLOC) && kasan_enabled())
kasan_unmap_early_shadow_vmalloc();
}

diff --git a/arch/powerpc/mm/kasan/init_book3e_64.c b/arch/powerpc/mm/kasan/init_book3e_64.c
index 60c78aac0f63..1e1c10467a2b 100644
--- a/arch/powerpc/mm/kasan/init_book3e_64.c
+++ b/arch/powerpc/mm/kasan/init_book3e_64.c
@@ -111,6 +111,9 @@ void __init kasan_init(void)
u64 i;
pte_t zero_pte = pfn_pte(virt_to_pfn(kasan_early_shadow_page), PAGE_KERNEL_RO);

+ if (kasan_arg_disabled)
+ return;
+
for_each_mem_range(i, &start, &end)
kasan_init_phys_region(phys_to_virt(start), phys_to_virt(end));

@@ -125,6 +128,9 @@ void __init kasan_init(void)

memset(kasan_early_shadow_page, 0, PAGE_SIZE);

+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+
/* Enable error messages */
init_task.kasan_depth = 0;
pr_info("KASAN init done\n");
diff --git a/arch/powerpc/mm/kasan/init_book3s_64.c b/arch/powerpc/mm/kasan/init_book3s_64.c
index 7d959544c077..9c5cf2354c8b 100644
--- a/arch/powerpc/mm/kasan/init_book3s_64.c
+++ b/arch/powerpc/mm/kasan/init_book3s_64.c
@@ -56,6 +56,9 @@ void __init kasan_init(void)
u64 i;
pte_t zero_pte = pfn_pte(virt_to_pfn(kasan_early_shadow_page), PAGE_KERNEL);

+ if (kasan_arg_disabled)
+ return;
+
if (!early_radix_enabled()) {
pr_warn("KASAN not enabled as it requires radix!");
return;
@@ -94,6 +97,9 @@ void __init kasan_init(void)

static_branch_inc(&powerpc_kasan_enabled_key);

+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+
/* Enable error messages */
init_task.kasan_depth = 0;

Baoquan He

unread,
Aug 20, 2025, 1:36:34 AMAug 20
to linu...@kvack.org, ryabin...@gmail.com, andre...@gmail.com, gli...@google.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, christop...@csgroup.eu, Baoquan He, linux...@lists.infradead.org
And also add code to enable kasan_flag_enabled, this is for later
usage.

Signed-off-by: Baoquan He <b...@redhat.com>
Cc: linux...@lists.infradead.org
---
arch/riscv/mm/kasan_init.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/arch/riscv/mm/kasan_init.c b/arch/riscv/mm/kasan_init.c
index 41c635d6aca4..ac3ac227c765 100644
--- a/arch/riscv/mm/kasan_init.c
+++ b/arch/riscv/mm/kasan_init.c
@@ -485,6 +485,9 @@ void __init kasan_init(void)
phys_addr_t p_start, p_end;
u64 i;

+ if (kasan_arg_disabled)
+ return;
+
create_tmp_mapping();
csr_write(CSR_SATP, PFN_DOWN(__pa(tmp_pg_dir)) | satp_mode);

@@ -531,6 +534,9 @@ void __init kasan_init(void)
memset(kasan_early_shadow_page, KASAN_SHADOW_INIT, PAGE_SIZE);
init_task.kasan_depth = 0;

+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+

Baoquan He

unread,
Aug 20, 2025, 1:36:41 AMAug 20
to linu...@kvack.org, ryabin...@gmail.com, andre...@gmail.com, gli...@google.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, christop...@csgroup.eu, Baoquan He, x...@kernel.org
And also add code to enable kasan_flag_enabled, this is for later
usage.

Signed-off-by: Baoquan He <b...@redhat.com>
Cc: x...@kernel.org
---
arch/x86/mm/kasan_init_64.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/arch/x86/mm/kasan_init_64.c b/arch/x86/mm/kasan_init_64.c
index 0539efd0d216..0f2f9311e9df 100644
--- a/arch/x86/mm/kasan_init_64.c
+++ b/arch/x86/mm/kasan_init_64.c
@@ -343,6 +343,9 @@ void __init kasan_init(void)
unsigned long shadow_cea_begin, shadow_cea_per_cpu_begin, shadow_cea_end;
int i;

+ if (kasan_arg_disabled)
+ return;
+
memcpy(early_top_pgt, init_top_pgt, sizeof(early_top_pgt));

/*
@@ -450,6 +453,9 @@ void __init kasan_init(void)
/* Flush TLBs again to be sure that write protection applied. */
__flush_tlb_all();

+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+
init_task.kasan_depth = 0;

Baoquan He

unread,
Aug 20, 2025, 1:36:59 AMAug 20
to linu...@kvack.org, ryabin...@gmail.com, andre...@gmail.com, gli...@google.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, christop...@csgroup.eu, Baoquan He, Chris Zankel, Max Filippov
And also add code to enable kasan_flag_enabled, this is for later
usage.

Here call jump_label_init() early in setup_arch() so that later
kasan_init() can enable static key kasan_flag_enabled. Put
jump_label_init() beofre parse_early_param() as other architectures
do.

Signed-off-by: Baoquan He <b...@redhat.com>
Cc: Chris Zankel <ch...@zankel.net>
Cc: Max Filippov <jcmv...@gmail.com>
---
arch/xtensa/kernel/setup.c | 1 +
arch/xtensa/mm/kasan_init.c | 6 ++++++
2 files changed, 7 insertions(+)

diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c
index f72e280363be..aabeb23f41fa 100644
--- a/arch/xtensa/kernel/setup.c
+++ b/arch/xtensa/kernel/setup.c
@@ -352,6 +352,7 @@ void __init setup_arch(char **cmdline_p)
mem_reserve(__pa(_SecondaryResetVector_text_start),
__pa(_SecondaryResetVector_text_end));
#endif
+ jump_label_init();
parse_early_param();
bootmem_init();
kasan_init();
diff --git a/arch/xtensa/mm/kasan_init.c b/arch/xtensa/mm/kasan_init.c
index f39c4d83173a..4a7b77f47225 100644
--- a/arch/xtensa/mm/kasan_init.c
+++ b/arch/xtensa/mm/kasan_init.c
@@ -70,6 +70,9 @@ void __init kasan_init(void)
{
int i;

+ if (kasan_arg_disabled)
+ return;
+
BUILD_BUG_ON(KASAN_SHADOW_OFFSET != KASAN_SHADOW_START -
(KASAN_START_VADDR >> KASAN_SHADOW_SCALE_SHIFT));
BUILD_BUG_ON(VMALLOC_START < KASAN_START_VADDR);
@@ -92,6 +95,9 @@ void __init kasan_init(void)
local_flush_tlb_all();
memset(kasan_early_shadow_page, 0, PAGE_SIZE);

+ /* KASAN is now initialized, enable it. */
+ static_branch_enable(&kasan_flag_enabled);
+
/* At this point kasan is fully initialized. Enable error messages. */
current->kasan_depth = 0;

Baoquan He

unread,
Aug 20, 2025, 1:37:04 AMAug 20
to linu...@kvack.org, ryabin...@gmail.com, andre...@gmail.com, gli...@google.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, christop...@csgroup.eu, Baoquan He, linu...@lists.infradead.org
And also add code to enable kasan_flag_enabled, this is for later
usage. Since kasan_init() is called before main(), enabling
kasan_flag_enabled is done in arch_mm_preinit() which is after
jump_label_init() invocation.

And also do the kasan_arg_disabled chekcing before kasan_flag_enabled
enabling to make sure kernel parameter kasan=on|off has been parsed.

Signed-off-by: Baoquan He <b...@redhat.com>
Cc: linu...@lists.infradead.org
---
arch/um/kernel/mem.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
index 76bec7de81b5..7b7f838274b5 100644
--- a/arch/um/kernel/mem.c
+++ b/arch/um/kernel/mem.c
@@ -58,6 +58,13 @@ static unsigned long brk_end;

void __init arch_mm_preinit(void)
{
+
+#ifdef CONFIG_KASAN
+ /* Safe to call after jump_label_init(). Enables KASAN. */
+ if (!kasan_arg_disabled)
+ static_branch_enable(&kasan_flag_enabled);
+#endif

Baoquan He

unread,
Aug 20, 2025, 1:37:10 AMAug 20
to linu...@kvack.org, ryabin...@gmail.com, andre...@gmail.com, gli...@google.com, dvy...@google.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, el...@google.com, snov...@gmail.com, christop...@csgroup.eu, Baoquan He
Now everything is ready, set kasan=off can disable kasan for all
three modes.

Signed-off-by: Baoquan He <b...@redhat.com>
---
include/linux/kasan-enabled.h | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/include/linux/kasan-enabled.h b/include/linux/kasan-enabled.h
index 32f2d19f599f..21b6233f829c 100644
--- a/include/linux/kasan-enabled.h
+++ b/include/linux/kasan-enabled.h
@@ -4,34 +4,32 @@

#include <linux/static_key.h>

+#ifdef CONFIG_KASAN
extern bool kasan_arg_disabled;

DECLARE_STATIC_KEY_FALSE(kasan_flag_enabled);

-#ifdef CONFIG_KASAN_HW_TAGS
-
static __always_inline bool kasan_enabled(void)
{
return static_branch_likely(&kasan_flag_enabled);
}
+#else /* CONFIG_KASAN */
+static inline bool kasan_enabled(void)
+{
+ return false;
+}
+#endif

+#ifdef CONFIG_KASAN_HW_TAGS
static inline bool kasan_hw_tags_enabled(void)
{
return kasan_enabled();
}
-
#else /* CONFIG_KASAN_HW_TAGS */
-
-static inline bool kasan_enabled(void)
-{
- return IS_ENABLED(CONFIG_KASAN);
-}
-
static inline bool kasan_hw_tags_enabled(void)
{
return false;
}

Andrey Konovalov

unread,
Sep 3, 2025, 9:22:29 AMSep 3
to Baoquan He, gli...@google.com, dvy...@google.com, el...@google.com, linu...@kvack.org, ryabin...@gmail.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, snov...@gmail.com, christop...@csgroup.eu
On Wed, Aug 20, 2025 at 7:35 AM Baoquan He <b...@redhat.com> wrote:
>
> Currently only hw_tags mode of kasan can be enabled or disabled with
> kernel parameter kasan=on|off for built kernel. For kasan generic and
> sw_tags mode, there's no way to disable them once kernel is built.
> This is not convenient sometime, e.g in system kdump is configured.
> When the 1st kernel has KASAN enabled and crash triggered to switch to
> kdump kernel, the generic or sw_tags mode will cost much extra memory
> for kasan shadow while in fact it's meaningless to have kasan in kdump
> kernel.
>
> So this patchset moves the kasan=on|off out of hw_tags scope and into
> common code to make it visible in generic and sw_tags mode too. Then we
> can add kasan=off in kdump kernel to reduce the unneeded meomry cost for
> kasan.

Continuing the discussion on the previous version: so the unwanted
extra memory usage is caused by the shadow memory for vmalloc
allocations (as they get freed lazily)? This needs to be explained in
the commit message.

If so, would it help if we make the kasan.vmalloc command-line
parameter work with the non-HW_TAGS modes (and make it do the same
thing as disabling CONFIG_KASAN_VMALLOC)?

What I don't like about introducing kasan=off for non-HW_TAGS modes is
that this parameter does not actually disable KASAN. It just
suppresses KASAN code for mapping proper shadow memory. But the
compiler-added instrumentation is still executing (and I suspect this
might break the inline instrumentation mode).

Perhaps, we could instead add a new kasan.shadow=on/off parameter to
make it more explicit that KASAN is not off, it's just that it stops
mapping shadow memory.

Dmitry, Alexander, Marco, do you have any opinion on kasan=off for
non-HW_TAGS modes?

On a side note, this series will need to be rebased onto Sabyrzhan's
patches [1] - those are close to being ready. But perhaps let's wait
for v7 first.

[1] https://lore.kernel.org/all/20250810125746.11...@gmail.com/

Baoquan He

unread,
Sep 4, 2025, 4:11:47 AMSep 4
to Andrey Konovalov, gli...@google.com, dvy...@google.com, el...@google.com, linu...@kvack.org, ryabin...@gmail.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, snov...@gmail.com, christop...@csgroup.eu
On 09/03/25 at 03:22pm, Andrey Konovalov wrote:
> On Wed, Aug 20, 2025 at 7:35 AM Baoquan He <b...@redhat.com> wrote:
> >
> > Currently only hw_tags mode of kasan can be enabled or disabled with
> > kernel parameter kasan=on|off for built kernel. For kasan generic and
> > sw_tags mode, there's no way to disable them once kernel is built.
> > This is not convenient sometime, e.g in system kdump is configured.
> > When the 1st kernel has KASAN enabled and crash triggered to switch to
> > kdump kernel, the generic or sw_tags mode will cost much extra memory
> > for kasan shadow while in fact it's meaningless to have kasan in kdump
> > kernel.
> >
> > So this patchset moves the kasan=on|off out of hw_tags scope and into
> > common code to make it visible in generic and sw_tags mode too. Then we
> > can add kasan=off in kdump kernel to reduce the unneeded meomry cost for
> > kasan.
>
> Continuing the discussion on the previous version: so the unwanted
> extra memory usage is caused by the shadow memory for vmalloc
> allocations (as they get freed lazily)? This needs to be explained in
> the commit message.

Hmm, up to now, there are two parts of big amount of memory requiring
for kernel as I observed. One is the direct memory mapping shadow of
kasan, which is 1/8 of system RAM in generic mode and 1/16 of system
RAM in sw_tags mode; the other is the shadow meomry for vmalloc which
causes meomry big meomry usage in kdump kernel because of lazy vmap
freeing. By introducing "kasan=off|on", if we specify 'kasan=off', the
former is avoided by skipping the kasan_init(), and the latter is avoided
by not build the vmalloc shadow for vmalloc.

Yes, I totally agree with you, I should have put this in cover letter
and the main patch log to explain it better.

>
> If so, would it help if we make the kasan.vmalloc command-line
> parameter work with the non-HW_TAGS modes (and make it do the same
> thing as disabling CONFIG_KASAN_VMALLOC)?
>
> What I don't like about introducing kasan=off for non-HW_TAGS modes is
> that this parameter does not actually disable KASAN. It just
> suppresses KASAN code for mapping proper shadow memory. But the
> compiler-added instrumentation is still executing (and I suspect this
> might break the inline instrumentation mode).

I may not follow your saying it doesn't disable KASAN. In this patchset,
not only do I disable the code for mapping shadow memory, but also I
skip any KASAN checking. Please see change of check_region_inline() in
mm/kasan/generic.c and kasan_check_range() in mm/kasan/sw_tags.c. It
will skip any KASAN checking when accessing memory.

Yeah, the compiler added instrumentation will be called, but the if
(!kasan_enabled()) checking will decide if going further into KASAN code
or just return directly. I tried inline mode on x86_64 and arm64, it
works well when one reviewer said inline mode could cost much more
memory, I don't see any breakage w or w/o kasan=off when this patchset
applied..

>
> Perhaps, we could instead add a new kasan.shadow=on/off parameter to
> make it more explicit that KASAN is not off, it's just that it stops
> mapping shadow memory.

Hmm, as I explained at above, kasan=off will stop mapping shadow memory,
and also stop executing KASAN code to poison/unpoison memory and check the
shadow. It may be inappropriate to say it only stops mapping shadow.

>
> Dmitry, Alexander, Marco, do you have any opinion on kasan=off for
> non-HW_TAGS modes?
>
> On a side note, this series will need to be rebased onto Sabyrzhan's
> patches [1] - those are close to being ready. But perhaps let's wait
> for v7 first.

I replied to Sabyrzhan's patchset, on top of this patchset, it's much
easier and cleaner to remove kasan_arch_is_ready(). We don't need
introduce CONFIG_ARCH_DEFER_KASAN. Please see below patchset which is
based on this patchset introducing 'kasan=off|on' to genric|sw_tags
mode.

[PATCH 0/4] mm/kasan: remove kasan_arch_is_ready()
https://lore.kernel.org/all/2025081213093...@redhat.com/T/#u

>
> [1] https://lore.kernel.org/all/20250810125746.11...@gmail.com/
>

Thanks a lot for reviewing and feedback.

Andrey Konovalov

unread,
Sep 4, 2025, 10:58:52 AMSep 4
to Baoquan He, snov...@gmail.com, gli...@google.com, dvy...@google.com, el...@google.com, linu...@kvack.org, ryabin...@gmail.com, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, christop...@csgroup.eu
On Thu, Sep 4, 2025 at 10:11 AM Baoquan He <b...@redhat.com> wrote:
>
> > If so, would it help if we make the kasan.vmalloc command-line
> > parameter work with the non-HW_TAGS modes (and make it do the same
> > thing as disabling CONFIG_KASAN_VMALLOC)?
> >
> > What I don't like about introducing kasan=off for non-HW_TAGS modes is
> > that this parameter does not actually disable KASAN. It just
> > suppresses KASAN code for mapping proper shadow memory. But the
> > compiler-added instrumentation is still executing (and I suspect this
> > might break the inline instrumentation mode).
>
> I may not follow your saying it doesn't disable KASAN. In this patchset,
> not only do I disable the code for mapping shadow memory, but also I
> skip any KASAN checking. Please see change of check_region_inline() in
> mm/kasan/generic.c and kasan_check_range() in mm/kasan/sw_tags.c. It
> will skip any KASAN checking when accessing memory.
>
> Yeah, the compiler added instrumentation will be called, but the if
> (!kasan_enabled()) checking will decide if going further into KASAN code
> or just return directly.

This all is true for the outline instrumentation mode.

However, with the inline instrumentation, check_region_inline() is not
called (in many cases, at least) and instead the compiler embeds the
instructions to calculate the shadow memory address and check its
value directly (this is why we have CONFIG_KASAN_SHADOW_OFFSET, whose
value has to be known at compile time).

> I tried inline mode on x86_64 and arm64, it
> works well when one reviewer said inline mode could cost much more
> memory, I don't see any breakage w or w/o kasan=off when this patchset
> applied..

This is interesting. I guess what happens is that we still have the
early shadow memory mapped so the shadow memory accesses inserted by
the inline instrumentation do not crash.

But have you tried running kasan=off + CONFIG_KASAN_STACK=y +
CONFIG_VMAP_STACK=y (+ CONFIG_KASAN_VMALLOC=y)? I would expect this
should causes crashes, as the early shadow is mapped as read-only and
the inline stack instrumentation will try writing into it (or do the
writes into the early shadow somehow get ignored?..).

> > Perhaps, we could instead add a new kasan.shadow=on/off parameter to
> > make it more explicit that KASAN is not off, it's just that it stops
> > mapping shadow memory.
>
> Hmm, as I explained at above, kasan=off will stop mapping shadow memory,
> and also stop executing KASAN code to poison/unpoison memory and check the
> shadow. It may be inappropriate to say it only stops mapping shadow.

That's true, but we can only achieve this for the outline instrumentation mode.

With the inline instrumentation mode, the (early) shadow memory would
still get accessed all the time even with kasan=off. Which can be
considered inappropriate, as you pointed out (though this is what
happens for vmalloc allocations when CONFIG_KASAN_VMALLOC is disabled
and it does seem to work; but the inline stack instrumentation might
be a problem).

We could limit kasan=off to only the outline instrumentation mode, but
I guess that defeats the purpose.

I'm not completely opposed to making kasan=off work with all KASAN
modes (assuming it works with the inline instrumentation), but then we
will need to thoroughly document the behavior it creates.

And let's also wait for an opinion from the other KASAN maintainers on this.

> > Dmitry, Alexander, Marco, do you have any opinion on kasan=off for
> > non-HW_TAGS modes?
> >
> > On a side note, this series will need to be rebased onto Sabyrzhan's
> > patches [1] - those are close to being ready. But perhaps let's wait
> > for v7 first.
>
> I replied to Sabyrzhan's patchset, on top of this patchset, it's much
> easier and cleaner to remove kasan_arch_is_ready(). We don't need
> introduce CONFIG_ARCH_DEFER_KASAN. Please see below patchset which is
> based on this patchset introducing 'kasan=off|on' to genric|sw_tags
> mode.

Based on a brief look, both patch series seem to be doing similar
things (except yours also allows using kasan=off for all modes).

But I like the Sabyrzhan's approach of hiding the explicit
static_branch_enable() calls under CONFIG_ARCH_DEFER_KASAN for the
architectures where they are actually required.

So I propose we moved forward with the Sabyrzhan's series and then
apply additional patches for supporting kasan=off on top (but again,
assuming they work with the inline instrumentation).

Thank you!

Andrey Ryabinin

unread,
Sep 5, 2025, 1:12:31 PMSep 5
to Andrey Konovalov, Baoquan He, snov...@gmail.com, gli...@google.com, dvy...@google.com, el...@google.com, linu...@kvack.org, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, christop...@csgroup.eu
It's not read-only, otherwise we would crash very early before full shadow
setup and won't be able to boot at all. So writes still happen, and shadow
checked, but reports are disabled.

So the patchset should work, but it's a little bit odd feature. With kasan=off we still
pay x2-x3 performance penalty of compiler instrumentation and get nothing in return.
So the usecase for this is if you don't want to compile and manage additional kernel binary
(with CONFIG_KASAN=n) and don't care about performance at all.

Andrey Konovalov

unread,
Sep 5, 2025, 2:08:53 PMSep 5
to Andrey Ryabinin, Baoquan He, snov...@gmail.com, gli...@google.com, dvy...@google.com, el...@google.com, linu...@kvack.org, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, christop...@csgroup.eu
On Fri, Sep 5, 2025 at 7:12 PM Andrey Ryabinin <ryabin...@gmail.com> wrote:
>
> > But have you tried running kasan=off + CONFIG_KASAN_STACK=y +
> > CONFIG_VMAP_STACK=y (+ CONFIG_KASAN_VMALLOC=y)? I would expect this
> > should causes crashes, as the early shadow is mapped as read-only and
> > the inline stack instrumentation will try writing into it (or do the
> > writes into the early shadow somehow get ignored?..).
> >
>
> It's not read-only, otherwise we would crash very early before full shadow
> setup and won't be able to boot at all. So writes still happen, and shadow
> checked, but reports are disabled.

Hm, I thought it worked like that, but then what threw me off just now
was seeing that zero_pte_populate()->pte_wrprotect() (on arm64) resets
the PTE_WRITE bit and sets the PTE_RDONLY bit. So I thought the
kasan_early_shadow_page is marked as read-only and then the
instrumentation is disabled for all early code that might write into
the page before the proper shadow is set up. Or am I reading this
bit-setting code wrong?

Christophe Leroy

unread,
Sep 5, 2025, 3:20:36 PMSep 5
to Andrey Konovalov, Andrey Ryabinin, Baoquan He, snov...@gmail.com, gli...@google.com, dvy...@google.com, el...@google.com, linu...@kvack.org, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com
But that zero_pte_populate() is called by kasan_init() when everything
is ready.

kasan_init()->kasan_init_shadow()->kasan_populate_early_shadow()->zero_p4d_populate()->zero_pud_populate()->zero_pmd_populate()->zero_pte_populate()

Here we are talking about the shadow set at startup kasan_early_init(),
aren't we ?

Christophe

Andrey Konovalov

unread,
Sep 5, 2025, 3:44:16 PMSep 5
to Christophe Leroy, Andrey Ryabinin, Baoquan He, snov...@gmail.com, gli...@google.com, dvy...@google.com, el...@google.com, linu...@kvack.org, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com
On Fri, Sep 5, 2025 at 9:13 PM Christophe Leroy
<christop...@csgroup.eu> wrote:
>
> > Hm, I thought it worked like that, but then what threw me off just now
> > was seeing that zero_pte_populate()->pte_wrprotect() (on arm64) resets
> > the PTE_WRITE bit and sets the PTE_RDONLY bit. So I thought the
> > kasan_early_shadow_page is marked as read-only and then the
> > instrumentation is disabled for all early code that might write into
> > the page before the proper shadow is set up. Or am I reading this
> > bit-setting code wrong?
>
> But that zero_pte_populate() is called by kasan_init() when everything
> is ready.
>
> kasan_init()->kasan_init_shadow()->kasan_populate_early_shadow()->zero_p4d_populate()->zero_pud_populate()->zero_pmd_populate()->zero_pte_populate()
>
> Here we are talking about the shadow set at startup kasan_early_init(),
> aren't we ?

Ah, you're right, thanks!

I was confused by the name of kasan_populate_early_shadow(). I think
we should rename it to kasan_populate_shadow_read_only() or something
like that and also update the comment. As this function is not
intended for populating early shadow (that is done via
kasan_early_init() in the arch code instead), we're populating normal
shadow for pages that can be accessed but whose shadow won't be
written to. Perhaps it makes sense to come up with a better name for
the kasan_early_shadow_page variable too to point out its dual
purpose.

Andrey Konovalov

unread,
Sep 5, 2025, 4:34:41 PMSep 5
to Andrey Ryabinin, Baoquan He, snov...@gmail.com, gli...@google.com, dvy...@google.com, el...@google.com, linu...@kvack.org, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, christop...@csgroup.eu
On Fri, Sep 5, 2025 at 7:12 PM Andrey Ryabinin <ryabin...@gmail.com> wrote:
>
> > But have you tried running kasan=off + CONFIG_KASAN_STACK=y +
> > CONFIG_VMAP_STACK=y (+ CONFIG_KASAN_VMALLOC=y)? I would expect this
> > should causes crashes, as the early shadow is mapped as read-only and
> > the inline stack instrumentation will try writing into it (or do the
> > writes into the early shadow somehow get ignored?..).
>
> It's not read-only, otherwise we would crash very early before full shadow
> setup and won't be able to boot at all. So writes still happen, and shadow
> checked, but reports are disabled.
>
> So the patchset should work, but it's a little bit odd feature. With kasan=off we still
> pay x2-x3 performance penalty of compiler instrumentation and get nothing in return.
> So the usecase for this is if you don't want to compile and manage additional kernel binary
> (with CONFIG_KASAN=n) and don't care about performance at all.

Ack. So kasan=off would work but it's only benefit would be to avoid
the RAM overhead.

Baoquan, I'd be in favor of implementing kasan.vmalloc=off instead of
kasan=off. This seems to both (almost) solve the RAM overhead problem
you're having (AFAIU) and also seems like a useful feature on its own
(similar to CONFIG_KASAN_VMALLOC=n but via command-line). The patches
to support kasan.vmalloc=off should also be orthogonal to the
Sabyrzhan's series.

If you feel strongly that the ~1/8th RAM overhead (coming from the
physmap shadow and the slab redzones) is still unacceptable for your
use case (noting that the performance overhead (and the constant
silent detection of false-positive bugs) would still be there), I
think you can proceed with your series (unless someone else is
against).

I also now get what you meant that with your patches for the kasan=off
support, Sabyrzhan's CONFIG_ARCH_DEFER_KASAN would not be required
anymore: as every architecture would need a kasan_enabled() check,
every architecture would effectively need the CONFIG_ARCH_DEFER_KASAN
functionality (i.e. the static key to switch off KASAN).

Nevertheless, I still like the unification of the static keys usage
and the KASAN initialization calls that the Sabyrzhan's series
introduces, so I would propose to rebase your patches on top of his
(even though you would remove CONFIG_ARCH_DEFER_KASAN, but that seems
like a simple change) or pick out the related parts from his patches
(but this might not be the best approach in case someone discovers a
reason why kasan=off is a bad idea and we need to abandon the
kasan=off series).

Andrey Konovalov

unread,
Sep 6, 2025, 9:25:30 AMSep 6
to Baoquan He, gli...@google.com, dvy...@google.com, el...@google.com, linu...@kvack.org, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, christop...@csgroup.eu, Andrey Ryabinin, snov...@gmail.com
On Fri, Sep 5, 2025 at 10:34 PM Andrey Konovalov <andre...@gmail.com> wrote:
>
> Baoquan, I'd be in favor of implementing kasan.vmalloc=off instead of
> kasan=off. This seems to both (almost) solve the RAM overhead problem
> you're having (AFAIU) and also seems like a useful feature on its own
> (similar to CONFIG_KASAN_VMALLOC=n but via command-line). The patches
> to support kasan.vmalloc=off should also be orthogonal to the
> Sabyrzhan's series.
>
> If you feel strongly that the ~1/8th RAM overhead (coming from the
> physmap shadow and the slab redzones) is still unacceptable for your
> use case (noting that the performance overhead (and the constant
> silent detection of false-positive bugs) would still be there), I
> think you can proceed with your series (unless someone else is
> against).

Hm, just realized that kasan.vmalloc=off would probably break if
CONFIG_VMAP_STACK is enabled: read-only shadow for vmalloc =>
read-only shadow for stacks => stack instrumentation will try writing
into read-only shadow and crash.

So I wonder if there's a way to avoid the lazy vmap freeing to deal
with the RAM overhead.

Baoquan He

unread,
Sep 15, 2025, 1:37:37 AM (9 days ago) Sep 15
to Andrey Konovalov, gli...@google.com, dvy...@google.com, el...@google.com, linu...@kvack.org, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, christop...@csgroup.eu, Andrey Ryabinin, snov...@gmail.com
That's a very key feature of vmalloc, lazy vmap freeing not only
integrate the virtual area freeing on one cpu at one time, but also
merge the areas and flush tlb at one time too. Please see
__purge_vmap_area_lazy() for the details. This can avoid performance
degradation when many vfree() are called.

Baoquan He

unread,
Sep 15, 2025, 5:05:35 AM (8 days ago) Sep 15
to Andrey Konovalov, Andrey Ryabinin, snov...@gmail.com, gli...@google.com, dvy...@google.com, el...@google.com, linu...@kvack.org, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, christop...@csgroup.eu
On 09/05/25 at 10:34pm, Andrey Konovalov wrote:
> On Fri, Sep 5, 2025 at 7:12 PM Andrey Ryabinin <ryabin...@gmail.com> wrote:
> >
> > > But have you tried running kasan=off + CONFIG_KASAN_STACK=y +
> > > CONFIG_VMAP_STACK=y (+ CONFIG_KASAN_VMALLOC=y)? I would expect this
> > > should causes crashes, as the early shadow is mapped as read-only and
> > > the inline stack instrumentation will try writing into it (or do the
> > > writes into the early shadow somehow get ignored?..).
> >
> > It's not read-only, otherwise we would crash very early before full shadow
> > setup and won't be able to boot at all. So writes still happen, and shadow
> > checked, but reports are disabled.
> >
> > So the patchset should work, but it's a little bit odd feature. With kasan=off we still
> > pay x2-x3 performance penalty of compiler instrumentation and get nothing in return.
> > So the usecase for this is if you don't want to compile and manage additional kernel binary
> > (with CONFIG_KASAN=n) and don't care about performance at all.

Thanks a lot for your careful reviewing, and sorry for late reply.

About kasan=off, we use static key to detect that, wondering if we will
have x2-x3 performance penalty. Not only can kdump get the benefit, but I
can think of one case where people may use kasan enabled kernel to detect
MM issues, while use kasan=off to make sure kasan code itself won't make
trouble. E.g you tested a normal kernel and it has no problem, while
kasan enabled kernel will trigger issue, sometime do we doubt kasan
code? In this case, kasan=off can prove its inonence?

This could be trivial, while I don't see much kasan=off introducing will
impact the old kasan performance and stir the current kasan implementation
code. We have got the kasan_arch_is_ready() anyway.


>
> Ack. So kasan=off would work but it's only benefit would be to avoid
> the RAM overhead.

Right, I built kernel with below configs on, kasan=off|on works very
well.

=====
CONFIG_KASAN=y
CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX=y
CONFIG_KASAN_GENERIC=y
CONFIG_KASAN_INLINE=y
CONFIG_KASAN_STACK=y
CONFIG_KASAN_VMALLOC=y
CONFIG_KASAN_KUNIT_TEST=m
...
CONFIG_VMAP_STACK=y
=====

>
> Baoquan, I'd be in favor of implementing kasan.vmalloc=off instead of
> kasan=off. This seems to both (almost) solve the RAM overhead problem
> you're having (AFAIU) and also seems like a useful feature on its own
> (similar to CONFIG_KASAN_VMALLOC=n but via command-line). The patches
> to support kasan.vmalloc=off should also be orthogonal to the
> Sabyrzhan's series.
>
> If you feel strongly that the ~1/8th RAM overhead (coming from the
> physmap shadow and the slab redzones) is still unacceptable for your
> use case (noting that the performance overhead (and the constant
> silent detection of false-positive bugs) would still be there), I
> think you can proceed with your series (unless someone else is
> against).

Yeah, that would be great if we can also avoid any not needed memory
consumption for kdump.

>
> I also now get what you meant that with your patches for the kasan=off
> support, Sabyrzhan's CONFIG_ARCH_DEFER_KASAN would not be required
> anymore: as every architecture would need a kasan_enabled() check,
> every architecture would effectively need the CONFIG_ARCH_DEFER_KASAN
> functionality (i.e. the static key to switch off KASAN).

Exactly. In this case, the code with the static key enabling or
disabling is clearer than CONFIG_ARCH_DEFER_KASAN setting or not.

>
> Nevertheless, I still like the unification of the static keys usage
> and the KASAN initialization calls that the Sabyrzhan's series
> introduces, so I would propose to rebase your patches on top of his
> (even though you would remove CONFIG_ARCH_DEFER_KASAN, but that seems
> like a simple change) or pick out the related parts from his patches
> (but this might not be the best approach in case someone discovers a
> reason why kasan=off is a bad idea and we need to abandon the
> kasan=off series).

Here I understand your reviewing policy. While I would like to explain a
little about my posting. I planned to do this job in 2023, made draft
patches on x86 for generic kasan, I dind't go further to try sw_tags
mode on arm64 because other things interrupted me. This year, I made
plan to disable some kernel features not necessary for kdump kernel,
mainly by adding kernel parameter like ima= I made, and later the
kasan=off.

aa9bb1b32594 ima: add a knob ima= to allow disabling IMA in kdump kernel

When I made patch and posted, I didn't see Sabyrzhan's patches because I
usually don't go through mm mailing list. If I saw his patch earlier, I
would have suggested him to solve this at the same time.

About Sabyrzhan's patch sereis, I have picked up part of his patches and
credit the author to Sabyrzhan in below patchset.

[PATCH 0/4] mm/kasan: remove kasan_arch_is_ready()
https://lore.kernel.org/all/2025081213093...@redhat.com/T/#u

About reposting of this series, do you think which one is preferred:

1) Firstly merge Sabyrzhan's patch series, I reverted them and apply for
my patchset.

2) Credit the author of patch 1,2,3 of this patch series to Sabyrzhan
too as below, because Sabyrzhan do the unification of the static keys
usage and the KASAN initialization calls earlier:

[PATCH v3 01/12] mm/kasan: add conditional checks in functions to return directly if kasan is disabled
[PATCH v3 02/12] mm/kasan: move kasan= code to common place
[PATCH v3 03/12] mm/kasan/sw_tags: don't initialize kasan if it's disabled

commit ac4004af0e1e8798d11c9310e500a88116d90271
Author: Baoquan He <b...@redhat.com>
Date: Mon Jan 2 08:58:36 2023 +0800

x86/kasan: check if kasan is available

commit cddd343bdbf5d0331695da8100380fc4b8b47464
Author: Baoquan He <b...@redhat.com>
Date: Sun Jan 1 20:57:51 2023 +0800

mm/kasan: allow generic and sw_tags to be set in kernel cmdline

Signed-off-by: Baoquan He <b...@redhat.com>

commit b149886995ecb2e464fee0cdd3a814035fc87226
Author: Baoquan He <b...@redhat.com>
Date: Sun Jan 1 21:07:29 2023 +0800

x86/kasan: allow to disable kasan during boot time

Andrey Konovalov

unread,
1:49 PM (3 hours ago) 1:49 PM
to Baoquan He, Andrey Ryabinin, snov...@gmail.com, gli...@google.com, dvy...@google.com, el...@google.com, linu...@kvack.org, vincenzo...@arm.com, ak...@linux-foundation.org, kasa...@googlegroups.com, linux-...@vger.kernel.org, ke...@lists.infradead.org, s...@kernel.org, lorenzo...@oracle.com, christop...@csgroup.eu
On Mon, Sep 15, 2025 at 11:05 AM Baoquan He <b...@redhat.com> wrote:
>
> > If you feel strongly that the ~1/8th RAM overhead (coming from the
> > physmap shadow and the slab redzones) is still unacceptable for your
> > use case (noting that the performance overhead (and the constant
> > silent detection of false-positive bugs) would still be there), I
> > think you can proceed with your series (unless someone else is
> > against).
>
> Yeah, that would be great if we can also avoid any not needed memory
> consumption for kdump.

Ack. Let's add support for kasan=off then.

But please describe it in detail in the KASAN documentation.

[...]

> When I made patch and posted, I didn't see Sabyrzhan's patches because I
> usually don't go through mm mailing list. If I saw his patch earlier, I
> would have suggested him to solve this at the same time.
>
> About Sabyrzhan's patch sereis, I have picked up part of his patches and
> credit the author to Sabyrzhan in below patchset.
>
> [PATCH 0/4] mm/kasan: remove kasan_arch_is_ready()
> https://lore.kernel.org/all/2025081213093...@redhat.com/T/#u
>
> About reposting of this series, do you think which one is preferred:
>
> 1) Firstly merge Sabyrzhan's patch series, I reverted them and apply for
> my patchset.
>
> 2) Credit the author of patch 1,2,3 of this patch series to Sabyrzhan
> too as below, because Sabyrzhan do the unification of the static keys
> usage and the KASAN initialization calls earlier:

Since the Sabyrzhan's patches are already in mm-stable (and I assume
will be merged during the next merge window), just rebase your changes
on top.

But also note that Sabyrzhan is planning to move out the
kasan_enabled() checks into include/linux/kasan.h (which is a clean-up
I would have also asked you to do with the kasan=off patches), so
maybe you should sync up with him wrt these changes.

Thanks!
Reply all
Reply to author
Forward
0 new messages