[PATCH] fix
From: Lorenzo Stoakes (ARM)
Date: Fri Aug 07 2026 - 11:23:40 EST
---
arch/x86/kernel/alternative.c | 39 ++++++++++++++++++++++++++++++++---
1 file changed, 36 insertions(+), 3 deletions(-)
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 62936a3bde19..cafcac95e90e 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -6,6 +6,9 @@
#include <linux/vmalloc.h>
#include <linux/memory.h>
#include <linux/execmem.h>
+#include <linux/cleanup.h>
+#include <linux/kgdb.h>
+#include <linux/mmap_lock.h>
#include <asm/text-patching.h>
#include <asm/insn.h>
@@ -2543,6 +2546,30 @@ static void text_poke_memset(void *dst, const void *src, size_t len)
typedef void text_poke_f(void *dst, const void *src, size_t len);
+static void poke_vmalloc_pages(struct page **pages, void *addr,
+ bool cross_page_boundary)
+{
+ pages[0] = vmalloc_to_page(addr);
+ if (cross_page_boundary)
+ pages[1] = vmalloc_to_page(addr + PAGE_SIZE);
+}
+
+static void poke_vmalloc_pages_safe(struct page **pages, void *addr,
+ bool cross_page_boundary)
+{
+ /*
+ * execmem ROX ranges are shared between modules and can be collapsed to
+ * huge PMD entries, and this collapse can happen concurrently with a
+ * racing set_memory_rox().
+ *
+ * Prevent vmalloc_to_page() from racing by acquiring an init_mm read
+ * lock which pairs with the init_mm write lock in
+ * cpa_collapse_large_pages().
+ */
+ guard(mmap_read_lock)(&init_mm);
+ poke_vmalloc_pages(pages, addr, cross_page_boundary);
+}
+
static void *__text_poke(text_poke_f func, void *addr, const void *src, size_t len)
{
bool cross_page_boundary = offset_in_page(addr) + len > PAGE_SIZE;
@@ -2560,9 +2587,15 @@ static void *__text_poke(text_poke_f func, void *addr, const void *src, size_t l
BUG_ON(!after_bootmem);
if (!core_kernel_text((unsigned long)addr)) {
- pages[0] = vmalloc_to_page(addr);
- if (cross_page_boundary)
- pages[1] = vmalloc_to_page(addr + PAGE_SIZE);
+ /*
+ * If called from kgdb cannot sleep, but all other CPUs stopped
+ * anyway so safe.
+ */
+ if (in_dbg_master())
+ poke_vmalloc_pages(pages, addr, cross_page_boundary);
+ else
+ poke_vmalloc_pages_safe(pages, addr,
+ cross_page_boundary);
} else {
pages[0] = virt_to_page(addr);
WARN_ON(!PageReserved(pages[0]));
--
2.55.0