[PATCH v2 2/4] x86/kmsan: Use the per-CPU area base for metadata lookup
From: Viorel Cernateanu via B4 Relay
Date: Sun Nov 01 2026 - 12:05:13 EST
From: Viorel Cernateanu <vrilutza@xxxxxxxxx>
The per-CPU entry areas start at CPU_ENTRY_AREA_PER_CPU, one page
above CPU_ENTRY_AREA_BASE, after the read-only IDT page.
arch_kmsan_get_meta_or_null() computes the CPU number relative to
CPU_ENTRY_AREA_BASE. With the areas laid out in CPU order, this
attributes the last page of each CPU's area to the next CPU. The
subsequent offset check rejects the address, so KMSAN cannot find
its metadata. At the end of the populated area, the lookup can also
select a CPU that is not possible.
Compute the CPU number relative to CPU_ENTRY_AREA_PER_CPU and
exclude the IDT page from the lookup. Check that the resulting CPU
is within nr_cpu_ids and possible before accessing its per-CPU data.
Remove the always-false negative check on the unsigned offset.
Fixes: ce732a7520b0 ("x86: kmsan: handle CPU entry area")
Signed-off-by: Viorel Cernateanu <vrilutza@xxxxxxxxx>
---
arch/x86/include/asm/kmsan.h | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/arch/x86/include/asm/kmsan.h b/arch/x86/include/asm/kmsan.h
index d91b37f5b4bb..c6715b2db0dc 100644
--- a/arch/x86/include/asm/kmsan.h
+++ b/arch/x86/include/asm/kmsan.h
@@ -13,6 +13,7 @@
#include <asm/cpu_entry_area.h>
#include <asm/processor.h>
+#include <linux/cpumask.h>
#include <linux/mmzone.h>
DECLARE_PER_CPU(char[CPU_ENTRY_AREA_SIZE], cpu_entry_area_shadow);
@@ -32,14 +33,17 @@ static inline void *arch_kmsan_get_meta_or_null(void *addr, bool is_origin)
unsigned long addr64 = (unsigned long)addr;
char *metadata_array;
unsigned long off;
- int cpu;
+ unsigned int cpu;
- if ((addr64 < CPU_ENTRY_AREA_BASE) ||
- (addr64 >= (CPU_ENTRY_AREA_BASE + CPU_ENTRY_AREA_MAP_SIZE)))
+ /* The per-CPU areas start after the read-only IDT page. */
+ if (addr64 < CPU_ENTRY_AREA_PER_CPU ||
+ addr64 >= CPU_ENTRY_AREA_BASE + CPU_ENTRY_AREA_MAP_SIZE)
+ return NULL;
+ cpu = (addr64 - CPU_ENTRY_AREA_PER_CPU) / CPU_ENTRY_AREA_SIZE;
+ if (cpu >= nr_cpu_ids || !cpu_possible(cpu))
return NULL;
- cpu = (addr64 - CPU_ENTRY_AREA_BASE) / CPU_ENTRY_AREA_SIZE;
off = addr64 - (unsigned long)get_cpu_entry_area(cpu);
- if ((off < 0) || (off >= CPU_ENTRY_AREA_SIZE))
+ if (off >= CPU_ENTRY_AREA_SIZE)
return NULL;
metadata_array = is_origin ? cpu_entry_area_origin :
cpu_entry_area_shadow;
--
2.53.0