linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/5] Fixes for ITS mitigation and execmem
@ 2025-06-03 11:14 Mike Rapoport
  2025-06-03 11:14 ` [PATCH 1/5] x86/mm/pat: don't collapse pages without PSE set Mike Rapoport
                   ` (5 more replies)
  0 siblings, 6 replies; 16+ messages in thread
From: Mike Rapoport @ 2025-06-03 11:14 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Borislav Petkov, Dave Hansen, Ingo Molnar,
	J�rgen Gro�, Mike Rapoport, H. Peter Anvin,
	Thomas Gleixner, Xin Li, linux-kernel, stable, x86

From: "Mike Rapoport (Microsoft)" <rppt@kernel.org>

Hi,

Jürgen Groß reported some bugs in interaction of ITS mitigation with
execmem [1] when running on a Xen PV guest.

These patches fix the issue by moving all the permissions management of
ITS memory allocated from execmem into ITS code.

I didn't test on a real Xen PV guest, but I emulated !PSE variant by
force-disabling the ROX cache in x86::execmem_arch_setup().

Peter, I took liberty to put your SoB in the patch that actually
implements the execmem permissions management in ITS, please let me know
if I need to update something about the authorship.

The patches are against v6.15.
They are also available in git:
https://web.git.kernel.org/pub/scm/linux/kernel/git/rppt/linux.git/log/?h=its-execmem/v1

[1] https://lore.kernel.org/all/20250528123557.12847-2-jgross@suse.com/

Juergen Gross (1):
  x86/mm/pat: don't collapse pages without PSE set

Mike Rapoport (Microsoft) (3):
  x86/Kconfig: only enable ROX cache in execmem when STRICT_MODULE_RWX is set
  x86/its: move its_pages array to struct mod_arch_specific
  Revert "mm/execmem: Unify early execmem_cache behaviour"

Peter Zijlstra (Intel) (1):
  x86/its: explicitly manage permissions for ITS pages

 arch/x86/Kconfig              |  2 +-
 arch/x86/include/asm/module.h |  8 ++++
 arch/x86/kernel/alternative.c | 89 ++++++++++++++++++++++++++---------
 arch/x86/mm/init_32.c         |  3 --
 arch/x86/mm/init_64.c         |  3 --
 arch/x86/mm/pat/set_memory.c  |  3 ++
 include/linux/execmem.h       |  8 +---
 include/linux/module.h        |  5 --
 mm/execmem.c                  | 40 ++--------------
 9 files changed, 82 insertions(+), 79 deletions(-)


base-commit: 0ff41df1cb268fc69e703a08a57ee14ae967d0ca
-- 
2.47.2


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 1/5] x86/mm/pat: don't collapse pages without PSE set
  2025-06-03 11:14 [PATCH 0/5] Fixes for ITS mitigation and execmem Mike Rapoport
@ 2025-06-03 11:14 ` Mike Rapoport
  2025-06-03 11:14 ` [PATCH 2/5] x86/Kconfig: only enable ROX cache in execmem when STRICT_MODULE_RWX is set Mike Rapoport
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: Mike Rapoport @ 2025-06-03 11:14 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Borislav Petkov, Dave Hansen, Ingo Molnar,
	J�rgen Gro�, Mike Rapoport, H. Peter Anvin,
	Thomas Gleixner, Xin Li, linux-kernel, stable, x86

From: Juergen Gross <jgross@suse.com>

Collapsing pages to a leaf PMD or PUD should be done only if
X86_FEATURE_PSE is available, which is not the case when running e.g.
as a Xen PV guest.

Cc: stable@vger.kernel.org
Fixes: 41d88484c71c ("x86/mm/pat: restore large ROX pages after fragmentation")
Signed-off-by: Juergen Gross <jgross@suse.com>
Link: https://lore.kernel.org/r/20250528123557.12847-3-jgross@suse.com
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
---
 arch/x86/mm/pat/set_memory.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
index def3d9284254..9292f835cf5a 100644
--- a/arch/x86/mm/pat/set_memory.c
+++ b/arch/x86/mm/pat/set_memory.c
@@ -1257,6 +1257,9 @@ static int collapse_pmd_page(pmd_t *pmd, unsigned long addr,
 	pgprot_t pgprot;
 	int i = 0;
 
+	if (!cpu_feature_enabled(X86_FEATURE_PSE))
+		return 0;
+
 	addr &= PMD_MASK;
 	pte = pte_offset_kernel(pmd, addr);
 	first = *pte;
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 2/5] x86/Kconfig: only enable ROX cache in execmem when STRICT_MODULE_RWX is set
  2025-06-03 11:14 [PATCH 0/5] Fixes for ITS mitigation and execmem Mike Rapoport
  2025-06-03 11:14 ` [PATCH 1/5] x86/mm/pat: don't collapse pages without PSE set Mike Rapoport
@ 2025-06-03 11:14 ` Mike Rapoport
  2025-06-11  9:30   ` [tip: x86/urgent] " tip-bot2 for Mike Rapoport (Microsoft)
  2025-06-03 11:14 ` [PATCH 3/5] x86/its: move its_pages array to struct mod_arch_specific Mike Rapoport
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 16+ messages in thread
From: Mike Rapoport @ 2025-06-03 11:14 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Borislav Petkov, Dave Hansen, Ingo Molnar,
	J�rgen Gro�, Mike Rapoport, H. Peter Anvin,
	Thomas Gleixner, Xin Li, linux-kernel, stable, x86

From: "Mike Rapoport (Microsoft)" <rppt@kernel.org>

Currently ROX cache in execmem is enabled regardless of
STRICT_MODULE_RWX setting. This breaks an assumption that module memory
is writable when STRICT_MODULE_RWX is disabled, for instance for kernel
debuggin.

Only enable ROX cache in execmem when STRICT_MODULE_RWX is set to
restore the original behaviour of module text permissions.

Fixes: 64f6a4e10c05 ("x86: re-enable EXECMEM_ROX support")
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
---
 arch/x86/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index e21cca404943..47932d5f4499 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -88,7 +88,7 @@ config X86
 	select ARCH_HAS_DMA_OPS			if GART_IOMMU || XEN
 	select ARCH_HAS_EARLY_DEBUG		if KGDB
 	select ARCH_HAS_ELF_RANDOMIZE
-	select ARCH_HAS_EXECMEM_ROX		if X86_64
+	select ARCH_HAS_EXECMEM_ROX		if X86_64 && STRICT_MODULE_RWX
 	select ARCH_HAS_FAST_MULTIPLIER
 	select ARCH_HAS_FORTIFY_SOURCE
 	select ARCH_HAS_GCOV_PROFILE_ALL
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 3/5] x86/its: move its_pages array to struct mod_arch_specific
  2025-06-03 11:14 [PATCH 0/5] Fixes for ITS mitigation and execmem Mike Rapoport
  2025-06-03 11:14 ` [PATCH 1/5] x86/mm/pat: don't collapse pages without PSE set Mike Rapoport
  2025-06-03 11:14 ` [PATCH 2/5] x86/Kconfig: only enable ROX cache in execmem when STRICT_MODULE_RWX is set Mike Rapoport
@ 2025-06-03 11:14 ` Mike Rapoport
  2025-06-11  9:30   ` [tip: x86/urgent] " tip-bot2 for Mike Rapoport (Microsoft)
  2025-06-03 11:14 ` [PATCH 4/5] x86/its: explicitly manage permissions for ITS pages Mike Rapoport
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 16+ messages in thread
From: Mike Rapoport @ 2025-06-03 11:14 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Borislav Petkov, Dave Hansen, Ingo Molnar,
	J�rgen Gro�, Mike Rapoport, H. Peter Anvin,
	Thomas Gleixner, Xin Li, linux-kernel, stable, x86

From: "Mike Rapoport (Microsoft)" <rppt@kernel.org>

The of pages with ITS thunks allocated for modules are tracked by an
array in 'struct module'.

Since this is very architecture specific data structure, move it to
'struct mod_arch_specific'.

No functional changes.

Fixes: 872df34d7c51 ("x86/its: Use dynamic thunks for indirect branches")
Suggested-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
---
 arch/x86/include/asm/module.h |  8 ++++++++
 arch/x86/kernel/alternative.c | 19 ++++++++++---------
 include/linux/module.h        |  5 -----
 3 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/arch/x86/include/asm/module.h b/arch/x86/include/asm/module.h
index e988bac0a4a1..3c2de4ce3b10 100644
--- a/arch/x86/include/asm/module.h
+++ b/arch/x86/include/asm/module.h
@@ -5,12 +5,20 @@
 #include <asm-generic/module.h>
 #include <asm/orc_types.h>
 
+struct its_array {
+#ifdef CONFIG_MITIGATION_ITS
+	void **pages;
+	int num;
+#endif
+};
+
 struct mod_arch_specific {
 #ifdef CONFIG_UNWINDER_ORC
 	unsigned int num_orcs;
 	int *orc_unwind_ip;
 	struct orc_entry *orc_unwind;
 #endif
+	struct its_array its_pages;
 };
 
 #endif /* _ASM_X86_MODULE_H */
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 45bcff181cba..372ef5dff631 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -195,8 +195,8 @@ void its_fini_mod(struct module *mod)
 	its_page = NULL;
 	mutex_unlock(&text_mutex);
 
-	for (int i = 0; i < mod->its_num_pages; i++) {
-		void *page = mod->its_page_array[i];
+	for (int i = 0; i < mod->arch.its_pages.num; i++) {
+		void *page = mod->arch.its_pages.pages[i];
 		execmem_restore_rox(page, PAGE_SIZE);
 	}
 }
@@ -206,11 +206,11 @@ void its_free_mod(struct module *mod)
 	if (!cpu_feature_enabled(X86_FEATURE_INDIRECT_THUNK_ITS))
 		return;
 
-	for (int i = 0; i < mod->its_num_pages; i++) {
-		void *page = mod->its_page_array[i];
+	for (int i = 0; i < mod->arch.its_pages.num; i++) {
+		void *page = mod->arch.its_pages.pages[i];
 		execmem_free(page);
 	}
-	kfree(mod->its_page_array);
+	kfree(mod->arch.its_pages.pages);
 }
 #endif /* CONFIG_MODULES */
 
@@ -223,14 +223,15 @@ static void *its_alloc(void)
 
 #ifdef CONFIG_MODULES
 	if (its_mod) {
-		void *tmp = krealloc(its_mod->its_page_array,
-				     (its_mod->its_num_pages+1) * sizeof(void *),
+		struct its_array *pages = &its_mod->arch.its_pages;
+		void *tmp = krealloc(pages->pages,
+				     (pages->num+1) * sizeof(void *),
 				     GFP_KERNEL);
 		if (!tmp)
 			return NULL;
 
-		its_mod->its_page_array = tmp;
-		its_mod->its_page_array[its_mod->its_num_pages++] = page;
+		pages->pages = tmp;
+		pages->pages[pages->num++] = page;
 
 		execmem_make_temp_rw(page, PAGE_SIZE);
 	}
diff --git a/include/linux/module.h b/include/linux/module.h
index 8050f77c3b64..b3329110d668 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -586,11 +586,6 @@ struct module {
 	atomic_t refcnt;
 #endif
 
-#ifdef CONFIG_MITIGATION_ITS
-	int its_num_pages;
-	void **its_page_array;
-#endif
-
 #ifdef CONFIG_CONSTRUCTORS
 	/* Constructor functions. */
 	ctor_fn_t *ctors;
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 4/5] x86/its: explicitly manage permissions for ITS pages
  2025-06-03 11:14 [PATCH 0/5] Fixes for ITS mitigation and execmem Mike Rapoport
                   ` (2 preceding siblings ...)
  2025-06-03 11:14 ` [PATCH 3/5] x86/its: move its_pages array to struct mod_arch_specific Mike Rapoport
@ 2025-06-03 11:14 ` Mike Rapoport
  2025-06-03 13:58   ` Peter Zijlstra
                     ` (2 more replies)
  2025-06-03 11:14 ` [PATCH 5/5] Revert "mm/execmem: Unify early execmem_cache behaviour" Mike Rapoport
  2025-06-10  6:00 ` [PATCH 0/5] Fixes for ITS mitigation and execmem Jürgen Groß
  5 siblings, 3 replies; 16+ messages in thread
From: Mike Rapoport @ 2025-06-03 11:14 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Borislav Petkov, Dave Hansen, Ingo Molnar,
	J�rgen Gro�, Mike Rapoport, H. Peter Anvin,
	Thomas Gleixner, Xin Li, linux-kernel, stable, x86

From: "Peter Zijlstra (Intel)" <peterz@infradead.org>

execmem_alloc() sets permissions differently depending on the kernel
configuration, CPU support for PSE and whether a page is allocated
before or after mark_rodata_ro().

Add tracking for pages allocated for ITS when patching the core kernel
and make sure the permissions for ITS pages are explicitly managed for
both kernel and module allocations.

Fixes: 872df34d7c51 ("x86/its: Use dynamic thunks for indirect branches")
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Co-developed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
---
 arch/x86/kernel/alternative.c | 84 ++++++++++++++++++++++++++---------
 1 file changed, 63 insertions(+), 21 deletions(-)

diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 372ef5dff631..8289e9e1f954 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -138,6 +138,25 @@ static struct module *its_mod;
 #endif
 static void *its_page;
 static unsigned int its_offset;
+struct its_array its_pages;
+
+static void *__its_alloc(struct its_array *pages)
+{
+	void *page __free(execmem) = execmem_alloc(EXECMEM_MODULE_TEXT, PAGE_SIZE);
+
+	if (!page)
+		return NULL;
+
+	void *tmp = krealloc(pages->pages, (pages->num+1) * sizeof(void *),
+			     GFP_KERNEL);
+	if (!tmp)
+		return NULL;
+
+	pages->pages = tmp;
+	pages->pages[pages->num++] = page;
+
+	return no_free_ptr(page);
+}
 
 /* Initialize a thunk with the "jmp *reg; int3" instructions. */
 static void *its_init_thunk(void *thunk, int reg)
@@ -173,6 +192,21 @@ static void *its_init_thunk(void *thunk, int reg)
 	return thunk + offset;
 }
 
+static void its_pages_protect(struct its_array *pages)
+{
+	for (int i = 0; i < pages->num; i++) {
+		void *page = pages->pages[i];
+		execmem_restore_rox(page, PAGE_SIZE);
+	}
+}
+
+static void its_fini_core(void)
+{
+	if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX))
+		its_pages_protect(&its_pages);
+	kfree(its_pages.pages);
+}
+
 #ifdef CONFIG_MODULES
 void its_init_mod(struct module *mod)
 {
@@ -195,10 +229,8 @@ void its_fini_mod(struct module *mod)
 	its_page = NULL;
 	mutex_unlock(&text_mutex);
 
-	for (int i = 0; i < mod->arch.its_pages.num; i++) {
-		void *page = mod->arch.its_pages.pages[i];
-		execmem_restore_rox(page, PAGE_SIZE);
-	}
+	if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
+		its_pages_protect(&mod->arch.its_pages);
 }
 
 void its_free_mod(struct module *mod)
@@ -212,32 +244,38 @@ void its_free_mod(struct module *mod)
 	}
 	kfree(mod->arch.its_pages.pages);
 }
-#endif /* CONFIG_MODULES */
 
-static void *its_alloc(void)
+static void *its_alloc_mod(void)
 {
-	void *page __free(execmem) = execmem_alloc(EXECMEM_MODULE_TEXT, PAGE_SIZE);
+	void *page = __its_alloc(&its_mod->arch.its_pages);
 
-	if (!page)
-		return NULL;
+	if (page)
+		execmem_make_temp_rw(page, PAGE_SIZE);
 
-#ifdef CONFIG_MODULES
-	if (its_mod) {
-		struct its_array *pages = &its_mod->arch.its_pages;
-		void *tmp = krealloc(pages->pages,
-				     (pages->num+1) * sizeof(void *),
-				     GFP_KERNEL);
-		if (!tmp)
-			return NULL;
+	return page;
+}
+#endif /* CONFIG_MODULES */
 
-		pages->pages = tmp;
-		pages->pages[pages->num++] = page;
+static void *its_alloc_core(void)
+{
+	void *page = __its_alloc(&its_pages);
 
+	if (page) {
 		execmem_make_temp_rw(page, PAGE_SIZE);
+		set_memory_x((unsigned long)page, 1);
 	}
+
+	return page;
+}
+
+static void *its_alloc(void)
+{
+#ifdef CONFIG_MODULES
+	if (its_mod)
+		return its_alloc_mod();
 #endif /* CONFIG_MODULES */
 
-	return no_free_ptr(page);
+	return its_alloc_core();
 }
 
 static void *its_allocate_thunk(int reg)
@@ -291,7 +329,9 @@ u8 *its_static_thunk(int reg)
 	return thunk;
 }
 
-#endif
+#else
+static inline void its_fini_core(void) {}
+#endif /* CONFIG_MITIGATION_ITS */
 
 /*
  * Nomenclature for variable names to simplify and clarify this code and ease
@@ -2368,6 +2408,8 @@ void __init alternative_instructions(void)
 	apply_retpolines(__retpoline_sites, __retpoline_sites_end);
 	apply_returns(__return_sites, __return_sites_end);
 
+	its_fini_core();
+
 	/*
 	 * Adjust all CALL instructions to point to func()-10, including
 	 * those in .altinstr_replacement.
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 5/5] Revert "mm/execmem: Unify early execmem_cache behaviour"
  2025-06-03 11:14 [PATCH 0/5] Fixes for ITS mitigation and execmem Mike Rapoport
                   ` (3 preceding siblings ...)
  2025-06-03 11:14 ` [PATCH 4/5] x86/its: explicitly manage permissions for ITS pages Mike Rapoport
@ 2025-06-03 11:14 ` Mike Rapoport
  2025-06-11  9:30   ` [tip: x86/urgent] " tip-bot2 for Mike Rapoport (Microsoft)
  2025-06-10  6:00 ` [PATCH 0/5] Fixes for ITS mitigation and execmem Jürgen Groß
  5 siblings, 1 reply; 16+ messages in thread
From: Mike Rapoport @ 2025-06-03 11:14 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Borislav Petkov, Dave Hansen, Ingo Molnar,
	J�rgen Gro�, Mike Rapoport, H. Peter Anvin,
	Thomas Gleixner, Xin Li, linux-kernel, stable, x86

From: "Mike Rapoport (Microsoft)" <rppt@kernel.org>

The commit d6d1e3e6580c ("mm/execmem: Unify early execmem_cache
behaviour") changed early behaviour of execemem ROX cache to allow its
usage in early x86 code that allocates text pages when
CONFIG_MITGATION_ITS is enabled.

The permission management of the pages allocated from execmem for ITS
mitigation is now completely contained in arch/x86/kernel/alternatives.c
and therefore there is no need to special case early allocations in
execmem.

This reverts commit d6d1e3e6580ca35071ad474381f053cbf1fb6414.

Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
---
 arch/x86/mm/init_32.c   |  3 ---
 arch/x86/mm/init_64.c   |  3 ---
 include/linux/execmem.h |  8 +-------
 mm/execmem.c            | 40 +++-------------------------------------
 4 files changed, 4 insertions(+), 50 deletions(-)

diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index bb8d99e717b9..148eba50265a 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -30,7 +30,6 @@
 #include <linux/initrd.h>
 #include <linux/cpumask.h>
 #include <linux/gfp.h>
-#include <linux/execmem.h>
 
 #include <asm/asm.h>
 #include <asm/bios_ebda.h>
@@ -756,8 +755,6 @@ void mark_rodata_ro(void)
 	pr_info("Write protecting kernel text and read-only data: %luk\n",
 		size >> 10);
 
-	execmem_cache_make_ro();
-
 	kernel_set_to_readonly = 1;
 
 #ifdef CONFIG_CPA_DEBUG
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index 949a447f75ec..7c4f6f591f2b 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -34,7 +34,6 @@
 #include <linux/gfp.h>
 #include <linux/kcore.h>
 #include <linux/bootmem_info.h>
-#include <linux/execmem.h>
 
 #include <asm/processor.h>
 #include <asm/bios_ebda.h>
@@ -1392,8 +1391,6 @@ void mark_rodata_ro(void)
 	       (end - start) >> 10);
 	set_memory_ro(start, (end - start) >> PAGE_SHIFT);
 
-	execmem_cache_make_ro();
-
 	kernel_set_to_readonly = 1;
 
 	/*
diff --git a/include/linux/execmem.h b/include/linux/execmem.h
index ca42d5e46ccc..3be35680a54f 100644
--- a/include/linux/execmem.h
+++ b/include/linux/execmem.h
@@ -54,7 +54,7 @@ enum execmem_range_flags {
 	EXECMEM_ROX_CACHE	= (1 << 1),
 };
 
-#if defined(CONFIG_ARCH_HAS_EXECMEM_ROX) && defined(CONFIG_EXECMEM)
+#ifdef CONFIG_ARCH_HAS_EXECMEM_ROX
 /**
  * execmem_fill_trapping_insns - set memory to contain instructions that
  *				 will trap
@@ -94,15 +94,9 @@ int execmem_make_temp_rw(void *ptr, size_t size);
  * Return: 0 on success or negative error code on failure.
  */
 int execmem_restore_rox(void *ptr, size_t size);
-
-/*
- * Called from mark_readonly(), where the system transitions to ROX.
- */
-void execmem_cache_make_ro(void);
 #else
 static inline int execmem_make_temp_rw(void *ptr, size_t size) { return 0; }
 static inline int execmem_restore_rox(void *ptr, size_t size) { return 0; }
-static inline void execmem_cache_make_ro(void) { }
 #endif
 
 /**
diff --git a/mm/execmem.c b/mm/execmem.c
index 6f7a2653b280..e6c4f5076ca8 100644
--- a/mm/execmem.c
+++ b/mm/execmem.c
@@ -254,34 +254,6 @@ static void *__execmem_cache_alloc(struct execmem_range *range, size_t size)
 	return ptr;
 }
 
-static bool execmem_cache_rox = false;
-
-void execmem_cache_make_ro(void)
-{
-	struct maple_tree *free_areas = &execmem_cache.free_areas;
-	struct maple_tree *busy_areas = &execmem_cache.busy_areas;
-	MA_STATE(mas_free, free_areas, 0, ULONG_MAX);
-	MA_STATE(mas_busy, busy_areas, 0, ULONG_MAX);
-	struct mutex *mutex = &execmem_cache.mutex;
-	void *area;
-
-	execmem_cache_rox = true;
-
-	mutex_lock(mutex);
-
-	mas_for_each(&mas_free, area, ULONG_MAX) {
-		unsigned long pages = mas_range_len(&mas_free) >> PAGE_SHIFT;
-		set_memory_ro(mas_free.index, pages);
-	}
-
-	mas_for_each(&mas_busy, area, ULONG_MAX) {
-		unsigned long pages = mas_range_len(&mas_busy) >> PAGE_SHIFT;
-		set_memory_ro(mas_busy.index, pages);
-	}
-
-	mutex_unlock(mutex);
-}
-
 static int execmem_cache_populate(struct execmem_range *range, size_t size)
 {
 	unsigned long vm_flags = VM_ALLOW_HUGE_VMAP;
@@ -302,15 +274,9 @@ static int execmem_cache_populate(struct execmem_range *range, size_t size)
 	/* fill memory with instructions that will trap */
 	execmem_fill_trapping_insns(p, alloc_size, /* writable = */ true);
 
-	if (execmem_cache_rox) {
-		err = set_memory_rox((unsigned long)p, vm->nr_pages);
-		if (err)
-			goto err_free_mem;
-	} else {
-		err = set_memory_x((unsigned long)p, vm->nr_pages);
-		if (err)
-			goto err_free_mem;
-	}
+	err = set_memory_rox((unsigned long)p, vm->nr_pages);
+	if (err)
+		goto err_free_mem;
 
 	err = execmem_cache_add(p, alloc_size);
 	if (err)
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH 4/5] x86/its: explicitly manage permissions for ITS pages
  2025-06-03 11:14 ` [PATCH 4/5] x86/its: explicitly manage permissions for ITS pages Mike Rapoport
@ 2025-06-03 13:58   ` Peter Zijlstra
  2025-06-03 14:36     ` Mike Rapoport
  2025-06-05  9:23   ` Nikolay Borisov
  2025-06-11  9:30   ` [tip: x86/urgent] " tip-bot2 for Peter Zijlstra (Intel)
  2 siblings, 1 reply; 16+ messages in thread
From: Peter Zijlstra @ 2025-06-03 13:58 UTC (permalink / raw)
  To: Mike Rapoport
  Cc: Borislav Petkov, Dave Hansen, Ingo Molnar, J�rgen Gro,
	H. Peter Anvin, Thomas Gleixner, Xin Li, linux-kernel, stable,
	x86

On Tue, Jun 03, 2025 at 02:14:44PM +0300, Mike Rapoport wrote:
> From: "Peter Zijlstra (Intel)" <peterz@infradead.org>
> 
> execmem_alloc() sets permissions differently depending on the kernel
> configuration, CPU support for PSE and whether a page is allocated
> before or after mark_rodata_ro().
> 
> Add tracking for pages allocated for ITS when patching the core kernel
> and make sure the permissions for ITS pages are explicitly managed for
> both kernel and module allocations.
> 
> Fixes: 872df34d7c51 ("x86/its: Use dynamic thunks for indirect branches")
> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
> Co-developed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> ---

How about something like this on top?

--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -121,7 +121,6 @@ struct its_array its_pages;
 static void *__its_alloc(struct its_array *pages)
 {
 	void *page __free(execmem) = execmem_alloc(EXECMEM_MODULE_TEXT, PAGE_SIZE);
-
 	if (!page)
 		return NULL;
 
@@ -172,6 +171,9 @@ static void *its_init_thunk(void *thunk,
 
 static void its_pages_protect(struct its_array *pages)
 {
+	if (!IS_ENABLED(CONFIG_STRICT_KERNEL_RWX))
+		return;
+
 	for (int i = 0; i < pages->num; i++) {
 		void *page = pages->pages[i];
 		execmem_restore_rox(page, PAGE_SIZE);
@@ -180,8 +182,7 @@ static void its_pages_protect(struct its
 
 static void its_fini_core(void)
 {
-	if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX))
-		its_pages_protect(&its_pages);
+	its_pages_protect(&its_pages);
 	kfree(its_pages.pages);
 }
 
@@ -207,8 +208,7 @@ void its_fini_mod(struct module *mod)
 	its_page = NULL;
 	mutex_unlock(&text_mutex);
 
-	if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
-		its_pages_protect(&mod->arch.its_pages);
+	its_pages_protect(&mod->arch.its_pages);
 }
 
 void its_free_mod(struct module *mod)
@@ -222,40 +222,29 @@ void its_free_mod(struct module *mod)
 	}
 	kfree(mod->arch.its_pages.pages);
 }
+#endif /* CONFIG_MODULES */
 
-static void *its_alloc_mod(void)
+static void *its_alloc(void)
 {
-	void *page = __its_alloc(&its_mod->arch.its_pages);
-
-	if (page)
-		execmem_make_temp_rw(page, PAGE_SIZE);
+	struct its_array *pages = &its_pages;
+	void *page;
 
-	return page;
-}
-#endif /* CONFIG_MODULES */
+#ifdef CONFIG_MODULE
+	if (its_mod)
+		pages = &its_mod->arch.its_pages;
+#endif
 
-static void *its_alloc_core(void)
-{
-	void *page = __its_alloc(&its_pages);
+	page = __its_alloc(pages);
+	if (!page)
+		return NULL;
 
-	if (page) {
-		execmem_make_temp_rw(page, PAGE_SIZE);
+	execmem_make_temp_rw(page, PAGE_SIZE);
+	if (pages == &its_pages)
 		set_memory_x((unsigned long)page, 1);
-	}
 
 	return page;
 }
 
-static void *its_alloc(void)
-{
-#ifdef CONFIG_MODULES
-	if (its_mod)
-		return its_alloc_mod();
-#endif /* CONFIG_MODULES */
-
-	return its_alloc_core();
-}
-
 static void *its_allocate_thunk(int reg)
 {
 	int size = 3 + (reg / 8);

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 4/5] x86/its: explicitly manage permissions for ITS pages
  2025-06-03 13:58   ` Peter Zijlstra
@ 2025-06-03 14:36     ` Mike Rapoport
  2025-06-03 14:45       ` Peter Zijlstra
  2025-06-11 21:09       ` Chuck Zmudzinski
  0 siblings, 2 replies; 16+ messages in thread
From: Mike Rapoport @ 2025-06-03 14:36 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Borislav Petkov, Dave Hansen, Ingo Molnar, J�rgen Gro,
	H. Peter Anvin, Thomas Gleixner, Xin Li, linux-kernel, stable,
	x86

On Tue, Jun 03, 2025 at 03:58:45PM +0200, Peter Zijlstra wrote:
> On Tue, Jun 03, 2025 at 02:14:44PM +0300, Mike Rapoport wrote:
> > From: "Peter Zijlstra (Intel)" <peterz@infradead.org>
> > 
> > execmem_alloc() sets permissions differently depending on the kernel
> > configuration, CPU support for PSE and whether a page is allocated
> > before or after mark_rodata_ro().
> > 
> > Add tracking for pages allocated for ITS when patching the core kernel
> > and make sure the permissions for ITS pages are explicitly managed for
> > both kernel and module allocations.
> > 
> > Fixes: 872df34d7c51 ("x86/its: Use dynamic thunks for indirect branches")
> > Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
> > Co-developed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> > Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> > ---
> 
> How about something like this on top?

Works for me :)

> --- a/arch/x86/kernel/alternative.c
> +++ b/arch/x86/kernel/alternative.c
> @@ -121,7 +121,6 @@ struct its_array its_pages;
>  static void *__its_alloc(struct its_array *pages)
>  {
>  	void *page __free(execmem) = execmem_alloc(EXECMEM_MODULE_TEXT, PAGE_SIZE);
> -
>  	if (!page)
>  		return NULL;
>  
> @@ -172,6 +171,9 @@ static void *its_init_thunk(void *thunk,
>  
>  static void its_pages_protect(struct its_array *pages)
>  {
> +	if (!IS_ENABLED(CONFIG_STRICT_KERNEL_RWX))
> +		return;
> +

But modules generally use STRICT_MODULE_RWX.
Do you want to make the its pages stricter than normal module text?

>  	for (int i = 0; i < pages->num; i++) {
>  		void *page = pages->pages[i];
>  		execmem_restore_rox(page, PAGE_SIZE);
> @@ -180,8 +182,7 @@ static void its_pages_protect(struct its
>  
>  static void its_fini_core(void)
>  {
> -	if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX))
> -		its_pages_protect(&its_pages);
> +	its_pages_protect(&its_pages);
>  	kfree(its_pages.pages);
>  }
>  
> @@ -207,8 +208,7 @@ void its_fini_mod(struct module *mod)
>  	its_page = NULL;
>  	mutex_unlock(&text_mutex);
>  
> -	if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
> -		its_pages_protect(&mod->arch.its_pages);
> +	its_pages_protect(&mod->arch.its_pages);
>  }

-- 
Sincerely yours,
Mike.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 4/5] x86/its: explicitly manage permissions for ITS pages
  2025-06-03 14:36     ` Mike Rapoport
@ 2025-06-03 14:45       ` Peter Zijlstra
  2025-06-11 21:09       ` Chuck Zmudzinski
  1 sibling, 0 replies; 16+ messages in thread
From: Peter Zijlstra @ 2025-06-03 14:45 UTC (permalink / raw)
  To: Mike Rapoport
  Cc: Borislav Petkov, Dave Hansen, Ingo Molnar, J�rgen Gro,
	H. Peter Anvin, Thomas Gleixner, Xin Li, linux-kernel, stable,
	x86

On Tue, Jun 03, 2025 at 05:36:41PM +0300, Mike Rapoport wrote:

> >  static void its_pages_protect(struct its_array *pages)
> >  {
> > +	if (!IS_ENABLED(CONFIG_STRICT_KERNEL_RWX))
> > +		return;
> > +
> 
> But modules generally use STRICT_MODULE_RWX.

Oh, I can't read anymore :-( I'll undo that one.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 4/5] x86/its: explicitly manage permissions for ITS pages
  2025-06-03 11:14 ` [PATCH 4/5] x86/its: explicitly manage permissions for ITS pages Mike Rapoport
  2025-06-03 13:58   ` Peter Zijlstra
@ 2025-06-05  9:23   ` Nikolay Borisov
  2025-06-11  9:30   ` [tip: x86/urgent] " tip-bot2 for Peter Zijlstra (Intel)
  2 siblings, 0 replies; 16+ messages in thread
From: Nikolay Borisov @ 2025-06-05  9:23 UTC (permalink / raw)
  To: Mike Rapoport, Peter Zijlstra
  Cc: Borislav Petkov, Dave Hansen, Ingo Molnar,
	J�rgen Gro�, H. Peter Anvin, Thomas Gleixner,
	Xin Li, linux-kernel, stable, x86



On 6/3/25 14:14, Mike Rapoport wrote:
> From: "Peter Zijlstra (Intel)" <peterz@infradead.org>
> 
> execmem_alloc() sets permissions differently depending on the kernel
> configuration, CPU support for PSE and whether a page is allocated
> before or after mark_rodata_ro().
> 
> Add tracking for pages allocated for ITS when patching the core kernel
> and make sure the permissions for ITS pages are explicitly managed for
> both kernel and module allocations.
> 
> Fixes: 872df34d7c51 ("x86/its: Use dynamic thunks for indirect branches")
> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
> Co-developed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>

Reviewed-by: Nikolay Borisov <nik.borisov@suse.com>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/5] Fixes for ITS mitigation and execmem
  2025-06-03 11:14 [PATCH 0/5] Fixes for ITS mitigation and execmem Mike Rapoport
                   ` (4 preceding siblings ...)
  2025-06-03 11:14 ` [PATCH 5/5] Revert "mm/execmem: Unify early execmem_cache behaviour" Mike Rapoport
@ 2025-06-10  6:00 ` Jürgen Groß
  5 siblings, 0 replies; 16+ messages in thread
From: Jürgen Groß @ 2025-06-10  6:00 UTC (permalink / raw)
  To: Mike Rapoport, Peter Zijlstra
  Cc: Borislav Petkov, Dave Hansen, Ingo Molnar, H. Peter Anvin,
	Thomas Gleixner, Xin Li, linux-kernel, stable, x86


[-- Attachment #1.1.1: Type: text/plain, Size: 2131 bytes --]

On 03.06.25 13:14, Mike Rapoport wrote:
> From: "Mike Rapoport (Microsoft)" <rppt@kernel.org>
> 
> Hi,
> 
> Jürgen Groß reported some bugs in interaction of ITS mitigation with
> execmem [1] when running on a Xen PV guest.
> 
> These patches fix the issue by moving all the permissions management of
> ITS memory allocated from execmem into ITS code.
> 
> I didn't test on a real Xen PV guest, but I emulated !PSE variant by
> force-disabling the ROX cache in x86::execmem_arch_setup().
> 
> Peter, I took liberty to put your SoB in the patch that actually
> implements the execmem permissions management in ITS, please let me know
> if I need to update something about the authorship.
> 
> The patches are against v6.15.
> They are also available in git:
> https://web.git.kernel.org/pub/scm/linux/kernel/git/rppt/linux.git/log/?h=its-execmem/v1
> 
> [1] https://lore.kernel.org/all/20250528123557.12847-2-jgross@suse.com/
> 
> Juergen Gross (1):
>    x86/mm/pat: don't collapse pages without PSE set
> 
> Mike Rapoport (Microsoft) (3):
>    x86/Kconfig: only enable ROX cache in execmem when STRICT_MODULE_RWX is set
>    x86/its: move its_pages array to struct mod_arch_specific
>    Revert "mm/execmem: Unify early execmem_cache behaviour"
> 
> Peter Zijlstra (Intel) (1):
>    x86/its: explicitly manage permissions for ITS pages
> 
>   arch/x86/Kconfig              |  2 +-
>   arch/x86/include/asm/module.h |  8 ++++
>   arch/x86/kernel/alternative.c | 89 ++++++++++++++++++++++++++---------
>   arch/x86/mm/init_32.c         |  3 --
>   arch/x86/mm/init_64.c         |  3 --
>   arch/x86/mm/pat/set_memory.c  |  3 ++
>   include/linux/execmem.h       |  8 +---
>   include/linux/module.h        |  5 --
>   mm/execmem.c                  | 40 ++--------------
>   9 files changed, 82 insertions(+), 79 deletions(-)
> 
> 
> base-commit: 0ff41df1cb268fc69e703a08a57ee14ae967d0ca

I have tested this series to work in a Xen PV dom0 with ITS mitigation
being active. I didn't apply any of Peter's suggested add-ons.

Tested-by: Juergen Gross <jgross@suse.com>


Juergen

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3743 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [tip: x86/urgent] Revert "mm/execmem: Unify early execmem_cache behaviour"
  2025-06-03 11:14 ` [PATCH 5/5] Revert "mm/execmem: Unify early execmem_cache behaviour" Mike Rapoport
@ 2025-06-11  9:30   ` tip-bot2 for Mike Rapoport (Microsoft)
  0 siblings, 0 replies; 16+ messages in thread
From: tip-bot2 for Mike Rapoport (Microsoft) @ 2025-06-11  9:30 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: Mike Rapoport (Microsoft), Peter Zijlstra (Intel), stable, x86,
	linux-kernel

The following commit has been merged into the x86/urgent branch of tip:

Commit-ID:     7cd9a11dd0c3d1dd225795ed1b5b53132888e7b5
Gitweb:        https://git.kernel.org/tip/7cd9a11dd0c3d1dd225795ed1b5b53132888e7b5
Author:        Mike Rapoport (Microsoft) <rppt@kernel.org>
AuthorDate:    Tue, 03 Jun 2025 14:14:45 +03:00
Committer:     Peter Zijlstra <peterz@infradead.org>
CommitterDate: Wed, 11 Jun 2025 11:20:52 +02:00

Revert "mm/execmem: Unify early execmem_cache behaviour"

The commit d6d1e3e6580c ("mm/execmem: Unify early execmem_cache
behaviour") changed early behaviour of execemem ROX cache to allow its
usage in early x86 code that allocates text pages when
CONFIG_MITGATION_ITS is enabled.

The permission management of the pages allocated from execmem for ITS
mitigation is now completely contained in arch/x86/kernel/alternatives.c
and therefore there is no need to special case early allocations in
execmem.

This reverts commit d6d1e3e6580ca35071ad474381f053cbf1fb6414.

Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: stable@vger.kernel.org
Link: https://lkml.kernel.org/r/20250603111446.2609381-6-rppt@kernel.org
---
 arch/x86/mm/init_32.c   |  3 +---
 arch/x86/mm/init_64.c   |  3 +---
 include/linux/execmem.h |  8 +-------
 mm/execmem.c            | 40 +++-------------------------------------
 4 files changed, 4 insertions(+), 50 deletions(-)

diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index 607d6a2..8a34fff 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -30,7 +30,6 @@
 #include <linux/initrd.h>
 #include <linux/cpumask.h>
 #include <linux/gfp.h>
-#include <linux/execmem.h>
 
 #include <asm/asm.h>
 #include <asm/bios_ebda.h>
@@ -749,8 +748,6 @@ void mark_rodata_ro(void)
 	pr_info("Write protecting kernel text and read-only data: %luk\n",
 		size >> 10);
 
-	execmem_cache_make_ro();
-
 	kernel_set_to_readonly = 1;
 
 #ifdef CONFIG_CPA_DEBUG
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index ee66fae..fdb6cab 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -34,7 +34,6 @@
 #include <linux/gfp.h>
 #include <linux/kcore.h>
 #include <linux/bootmem_info.h>
-#include <linux/execmem.h>
 
 #include <asm/processor.h>
 #include <asm/bios_ebda.h>
@@ -1392,8 +1391,6 @@ void mark_rodata_ro(void)
 	       (end - start) >> 10);
 	set_memory_ro(start, (end - start) >> PAGE_SHIFT);
 
-	execmem_cache_make_ro();
-
 	kernel_set_to_readonly = 1;
 
 	/*
diff --git a/include/linux/execmem.h b/include/linux/execmem.h
index ca42d5e..3be3568 100644
--- a/include/linux/execmem.h
+++ b/include/linux/execmem.h
@@ -54,7 +54,7 @@ enum execmem_range_flags {
 	EXECMEM_ROX_CACHE	= (1 << 1),
 };
 
-#if defined(CONFIG_ARCH_HAS_EXECMEM_ROX) && defined(CONFIG_EXECMEM)
+#ifdef CONFIG_ARCH_HAS_EXECMEM_ROX
 /**
  * execmem_fill_trapping_insns - set memory to contain instructions that
  *				 will trap
@@ -94,15 +94,9 @@ int execmem_make_temp_rw(void *ptr, size_t size);
  * Return: 0 on success or negative error code on failure.
  */
 int execmem_restore_rox(void *ptr, size_t size);
-
-/*
- * Called from mark_readonly(), where the system transitions to ROX.
- */
-void execmem_cache_make_ro(void);
 #else
 static inline int execmem_make_temp_rw(void *ptr, size_t size) { return 0; }
 static inline int execmem_restore_rox(void *ptr, size_t size) { return 0; }
-static inline void execmem_cache_make_ro(void) { }
 #endif
 
 /**
diff --git a/mm/execmem.c b/mm/execmem.c
index 9720ac2..2b683e7 100644
--- a/mm/execmem.c
+++ b/mm/execmem.c
@@ -254,34 +254,6 @@ out_unlock:
 	return ptr;
 }
 
-static bool execmem_cache_rox = false;
-
-void execmem_cache_make_ro(void)
-{
-	struct maple_tree *free_areas = &execmem_cache.free_areas;
-	struct maple_tree *busy_areas = &execmem_cache.busy_areas;
-	MA_STATE(mas_free, free_areas, 0, ULONG_MAX);
-	MA_STATE(mas_busy, busy_areas, 0, ULONG_MAX);
-	struct mutex *mutex = &execmem_cache.mutex;
-	void *area;
-
-	execmem_cache_rox = true;
-
-	mutex_lock(mutex);
-
-	mas_for_each(&mas_free, area, ULONG_MAX) {
-		unsigned long pages = mas_range_len(&mas_free) >> PAGE_SHIFT;
-		set_memory_ro(mas_free.index, pages);
-	}
-
-	mas_for_each(&mas_busy, area, ULONG_MAX) {
-		unsigned long pages = mas_range_len(&mas_busy) >> PAGE_SHIFT;
-		set_memory_ro(mas_busy.index, pages);
-	}
-
-	mutex_unlock(mutex);
-}
-
 static int execmem_cache_populate(struct execmem_range *range, size_t size)
 {
 	unsigned long vm_flags = VM_ALLOW_HUGE_VMAP;
@@ -302,15 +274,9 @@ static int execmem_cache_populate(struct execmem_range *range, size_t size)
 	/* fill memory with instructions that will trap */
 	execmem_fill_trapping_insns(p, alloc_size, /* writable = */ true);
 
-	if (execmem_cache_rox) {
-		err = set_memory_rox((unsigned long)p, vm->nr_pages);
-		if (err)
-			goto err_free_mem;
-	} else {
-		err = set_memory_x((unsigned long)p, vm->nr_pages);
-		if (err)
-			goto err_free_mem;
-	}
+	err = set_memory_rox((unsigned long)p, vm->nr_pages);
+	if (err)
+		goto err_free_mem;
 
 	err = execmem_cache_add(p, alloc_size);
 	if (err)

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [tip: x86/urgent] x86/its: explicitly manage permissions for ITS pages
  2025-06-03 11:14 ` [PATCH 4/5] x86/its: explicitly manage permissions for ITS pages Mike Rapoport
  2025-06-03 13:58   ` Peter Zijlstra
  2025-06-05  9:23   ` Nikolay Borisov
@ 2025-06-11  9:30   ` tip-bot2 for Peter Zijlstra (Intel)
  2 siblings, 0 replies; 16+ messages in thread
From: tip-bot2 for Peter Zijlstra (Intel) @ 2025-06-11  9:30 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: Peter Zijlstra (Intel), Mike Rapoport (Microsoft),
	Nikolay Borisov, stable, x86, linux-kernel

The following commit has been merged into the x86/urgent branch of tip:

Commit-ID:     a82b26451de126a5ae130361081986bc459afe9b
Gitweb:        https://git.kernel.org/tip/a82b26451de126a5ae130361081986bc459afe9b
Author:        Peter Zijlstra (Intel) <peterz@infradead.org>
AuthorDate:    Tue, 03 Jun 2025 14:14:44 +03:00
Committer:     Peter Zijlstra <peterz@infradead.org>
CommitterDate: Wed, 11 Jun 2025 11:20:52 +02:00

x86/its: explicitly manage permissions for ITS pages

execmem_alloc() sets permissions differently depending on the kernel
configuration, CPU support for PSE and whether a page is allocated
before or after mark_rodata_ro().

Add tracking for pages allocated for ITS when patching the core kernel
and make sure the permissions for ITS pages are explicitly managed for
both kernel and module allocations.

Fixes: 872df34d7c51 ("x86/its: Use dynamic thunks for indirect branches")
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Co-developed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Nikolay Borisov <nik.borisov@suse.com>
Cc: stable@vger.kernel.org
Link: https://lkml.kernel.org/r/20250603111446.2609381-5-rppt@kernel.org
---
 arch/x86/kernel/alternative.c | 74 +++++++++++++++++++++++-----------
 1 file changed, 52 insertions(+), 22 deletions(-)

diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index b50fe6c..6455f7f 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -116,6 +116,24 @@ static struct module *its_mod;
 #endif
 static void *its_page;
 static unsigned int its_offset;
+struct its_array its_pages;
+
+static void *__its_alloc(struct its_array *pages)
+{
+	void *page __free(execmem) = execmem_alloc(EXECMEM_MODULE_TEXT, PAGE_SIZE);
+	if (!page)
+		return NULL;
+
+	void *tmp = krealloc(pages->pages, (pages->num+1) * sizeof(void *),
+			     GFP_KERNEL);
+	if (!tmp)
+		return NULL;
+
+	pages->pages = tmp;
+	pages->pages[pages->num++] = page;
+
+	return no_free_ptr(page);
+}
 
 /* Initialize a thunk with the "jmp *reg; int3" instructions. */
 static void *its_init_thunk(void *thunk, int reg)
@@ -151,6 +169,21 @@ static void *its_init_thunk(void *thunk, int reg)
 	return thunk + offset;
 }
 
+static void its_pages_protect(struct its_array *pages)
+{
+	for (int i = 0; i < pages->num; i++) {
+		void *page = pages->pages[i];
+		execmem_restore_rox(page, PAGE_SIZE);
+	}
+}
+
+static void its_fini_core(void)
+{
+	if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX))
+		its_pages_protect(&its_pages);
+	kfree(its_pages.pages);
+}
+
 #ifdef CONFIG_MODULES
 void its_init_mod(struct module *mod)
 {
@@ -173,10 +206,8 @@ void its_fini_mod(struct module *mod)
 	its_page = NULL;
 	mutex_unlock(&text_mutex);
 
-	for (int i = 0; i < mod->arch.its_pages.num; i++) {
-		void *page = mod->arch.its_pages.pages[i];
-		execmem_restore_rox(page, PAGE_SIZE);
-	}
+	if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
+		its_pages_protect(&mod->arch.its_pages);
 }
 
 void its_free_mod(struct module *mod)
@@ -194,28 +225,23 @@ void its_free_mod(struct module *mod)
 
 static void *its_alloc(void)
 {
-	void *page __free(execmem) = execmem_alloc(EXECMEM_MODULE_TEXT, PAGE_SIZE);
+	struct its_array *pages = &its_pages;
+	void *page;
 
+#ifdef CONFIG_MODULE
+	if (its_mod)
+		pages = &its_mod->arch.its_pages;
+#endif
+
+	page = __its_alloc(pages);
 	if (!page)
 		return NULL;
 
-#ifdef CONFIG_MODULES
-	if (its_mod) {
-		struct its_array *pages = &its_mod->arch.its_pages;
-		void *tmp = krealloc(pages->pages,
-				     (pages->num+1) * sizeof(void *),
-				     GFP_KERNEL);
-		if (!tmp)
-			return NULL;
-
-		pages->pages = tmp;
-		pages->pages[pages->num++] = page;
+	execmem_make_temp_rw(page, PAGE_SIZE);
+	if (pages == &its_pages)
+		set_memory_x((unsigned long)page, 1);
 
-		execmem_make_temp_rw(page, PAGE_SIZE);
-	}
-#endif /* CONFIG_MODULES */
-
-	return no_free_ptr(page);
+	return page;
 }
 
 static void *its_allocate_thunk(int reg)
@@ -269,7 +295,9 @@ u8 *its_static_thunk(int reg)
 	return thunk;
 }
 
-#endif
+#else
+static inline void its_fini_core(void) {}
+#endif /* CONFIG_MITIGATION_ITS */
 
 /*
  * Nomenclature for variable names to simplify and clarify this code and ease
@@ -2339,6 +2367,8 @@ void __init alternative_instructions(void)
 	apply_retpolines(__retpoline_sites, __retpoline_sites_end);
 	apply_returns(__return_sites, __return_sites_end);
 
+	its_fini_core();
+
 	/*
 	 * Adjust all CALL instructions to point to func()-10, including
 	 * those in .altinstr_replacement.

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [tip: x86/urgent] x86/its: move its_pages array to struct mod_arch_specific
  2025-06-03 11:14 ` [PATCH 3/5] x86/its: move its_pages array to struct mod_arch_specific Mike Rapoport
@ 2025-06-11  9:30   ` tip-bot2 for Mike Rapoport (Microsoft)
  0 siblings, 0 replies; 16+ messages in thread
From: tip-bot2 for Mike Rapoport (Microsoft) @ 2025-06-11  9:30 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: Peter Zijlstra (Intel), Mike Rapoport (Microsoft), stable, x86,
	linux-kernel

The following commit has been merged into the x86/urgent branch of tip:

Commit-ID:     0b0cae7119a0ec9449d7261b5e672a5fed765068
Gitweb:        https://git.kernel.org/tip/0b0cae7119a0ec9449d7261b5e672a5fed765068
Author:        Mike Rapoport (Microsoft) <rppt@kernel.org>
AuthorDate:    Tue, 03 Jun 2025 14:14:43 +03:00
Committer:     Peter Zijlstra <peterz@infradead.org>
CommitterDate: Wed, 11 Jun 2025 11:20:51 +02:00

x86/its: move its_pages array to struct mod_arch_specific

The of pages with ITS thunks allocated for modules are tracked by an
array in 'struct module'.

Since this is very architecture specific data structure, move it to
'struct mod_arch_specific'.

No functional changes.

Fixes: 872df34d7c51 ("x86/its: Use dynamic thunks for indirect branches")
Suggested-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: stable@vger.kernel.org
Link: https://lkml.kernel.org/r/20250603111446.2609381-4-rppt@kernel.org
---
 arch/x86/include/asm/module.h |  8 ++++++++
 arch/x86/kernel/alternative.c | 19 ++++++++++---------
 include/linux/module.h        |  5 -----
 3 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/arch/x86/include/asm/module.h b/arch/x86/include/asm/module.h
index e988bac..3c2de4c 100644
--- a/arch/x86/include/asm/module.h
+++ b/arch/x86/include/asm/module.h
@@ -5,12 +5,20 @@
 #include <asm-generic/module.h>
 #include <asm/orc_types.h>
 
+struct its_array {
+#ifdef CONFIG_MITIGATION_ITS
+	void **pages;
+	int num;
+#endif
+};
+
 struct mod_arch_specific {
 #ifdef CONFIG_UNWINDER_ORC
 	unsigned int num_orcs;
 	int *orc_unwind_ip;
 	struct orc_entry *orc_unwind;
 #endif
+	struct its_array its_pages;
 };
 
 #endif /* _ASM_X86_MODULE_H */
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index ecfe7b4..b50fe6c 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -173,8 +173,8 @@ void its_fini_mod(struct module *mod)
 	its_page = NULL;
 	mutex_unlock(&text_mutex);
 
-	for (int i = 0; i < mod->its_num_pages; i++) {
-		void *page = mod->its_page_array[i];
+	for (int i = 0; i < mod->arch.its_pages.num; i++) {
+		void *page = mod->arch.its_pages.pages[i];
 		execmem_restore_rox(page, PAGE_SIZE);
 	}
 }
@@ -184,11 +184,11 @@ void its_free_mod(struct module *mod)
 	if (!cpu_feature_enabled(X86_FEATURE_INDIRECT_THUNK_ITS))
 		return;
 
-	for (int i = 0; i < mod->its_num_pages; i++) {
-		void *page = mod->its_page_array[i];
+	for (int i = 0; i < mod->arch.its_pages.num; i++) {
+		void *page = mod->arch.its_pages.pages[i];
 		execmem_free(page);
 	}
-	kfree(mod->its_page_array);
+	kfree(mod->arch.its_pages.pages);
 }
 #endif /* CONFIG_MODULES */
 
@@ -201,14 +201,15 @@ static void *its_alloc(void)
 
 #ifdef CONFIG_MODULES
 	if (its_mod) {
-		void *tmp = krealloc(its_mod->its_page_array,
-				     (its_mod->its_num_pages+1) * sizeof(void *),
+		struct its_array *pages = &its_mod->arch.its_pages;
+		void *tmp = krealloc(pages->pages,
+				     (pages->num+1) * sizeof(void *),
 				     GFP_KERNEL);
 		if (!tmp)
 			return NULL;
 
-		its_mod->its_page_array = tmp;
-		its_mod->its_page_array[its_mod->its_num_pages++] = page;
+		pages->pages = tmp;
+		pages->pages[pages->num++] = page;
 
 		execmem_make_temp_rw(page, PAGE_SIZE);
 	}
diff --git a/include/linux/module.h b/include/linux/module.h
index 92e1420..5faa1fb 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -586,11 +586,6 @@ struct module {
 	atomic_t refcnt;
 #endif
 
-#ifdef CONFIG_MITIGATION_ITS
-	int its_num_pages;
-	void **its_page_array;
-#endif
-
 #ifdef CONFIG_CONSTRUCTORS
 	/* Constructor functions. */
 	ctor_fn_t *ctors;

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [tip: x86/urgent] x86/Kconfig: only enable ROX cache in execmem when STRICT_MODULE_RWX is set
  2025-06-03 11:14 ` [PATCH 2/5] x86/Kconfig: only enable ROX cache in execmem when STRICT_MODULE_RWX is set Mike Rapoport
@ 2025-06-11  9:30   ` tip-bot2 for Mike Rapoport (Microsoft)
  0 siblings, 0 replies; 16+ messages in thread
From: tip-bot2 for Mike Rapoport (Microsoft) @ 2025-06-11  9:30 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: Mike Rapoport (Microsoft), Peter Zijlstra (Intel), stable, x86,
	linux-kernel

The following commit has been merged into the x86/urgent branch of tip:

Commit-ID:     47410d839fcda6890cb82828f874f97710982f24
Gitweb:        https://git.kernel.org/tip/47410d839fcda6890cb82828f874f97710982f24
Author:        Mike Rapoport (Microsoft) <rppt@kernel.org>
AuthorDate:    Tue, 03 Jun 2025 14:14:42 +03:00
Committer:     Peter Zijlstra <peterz@infradead.org>
CommitterDate: Wed, 11 Jun 2025 11:20:51 +02:00

x86/Kconfig: only enable ROX cache in execmem when STRICT_MODULE_RWX is set

Currently ROX cache in execmem is enabled regardless of
STRICT_MODULE_RWX setting. This breaks an assumption that module memory
is writable when STRICT_MODULE_RWX is disabled, for instance for kernel
debuggin.

Only enable ROX cache in execmem when STRICT_MODULE_RWX is set to
restore the original behaviour of module text permissions.

Fixes: 64f6a4e10c05 ("x86: re-enable EXECMEM_ROX support")
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: stable@vger.kernel.org
Link: https://lkml.kernel.org/r/20250603111446.2609381-3-rppt@kernel.org
---
 arch/x86/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 340e546..71019b3 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -89,7 +89,7 @@ config X86
 	select ARCH_HAS_DMA_OPS			if GART_IOMMU || XEN
 	select ARCH_HAS_EARLY_DEBUG		if KGDB
 	select ARCH_HAS_ELF_RANDOMIZE
-	select ARCH_HAS_EXECMEM_ROX		if X86_64
+	select ARCH_HAS_EXECMEM_ROX		if X86_64 && STRICT_MODULE_RWX
 	select ARCH_HAS_FAST_MULTIPLIER
 	select ARCH_HAS_FORTIFY_SOURCE
 	select ARCH_HAS_GCOV_PROFILE_ALL

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH 4/5] x86/its: explicitly manage permissions for ITS pages
  2025-06-03 14:36     ` Mike Rapoport
  2025-06-03 14:45       ` Peter Zijlstra
@ 2025-06-11 21:09       ` Chuck Zmudzinski
  1 sibling, 0 replies; 16+ messages in thread
From: Chuck Zmudzinski @ 2025-06-11 21:09 UTC (permalink / raw)
  To: Mike Rapoport, Peter Zijlstra
  Cc: Borislav Petkov, Dave Hansen, Ingo Molnar, J�rgen Gro,
	H. Peter Anvin, Thomas Gleixner, Xin Li, linux-kernel, stable,
	x86

On 6/3/25 10:36 AM, Mike Rapoport wrote:
> On Tue, Jun 03, 2025 at 03:58:45PM +0200, Peter Zijlstra wrote:
> > On Tue, Jun 03, 2025 at 02:14:44PM +0300, Mike Rapoport wrote:
> > > From: "Peter Zijlstra (Intel)" <peterz@infradead.org>
> > > 
> > > execmem_alloc() sets permissions differently depending on the kernel
> > > configuration, CPU support for PSE and whether a page is allocated
> > > before or after mark_rodata_ro().
> > > 
> > > Add tracking for pages allocated for ITS when patching the core kernel
> > > and make sure the permissions for ITS pages are explicitly managed for
> > > both kernel and module allocations.
> > > 
> > > Fixes: 872df34d7c51 ("x86/its: Use dynamic thunks for indirect branches")
> > > Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
> > > Co-developed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> > > Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> > > ---
> > 
> > How about something like this on top?
>
> Works for me :)
>
> > --- a/arch/x86/kernel/alternative.c
> > +++ b/arch/x86/kernel/alternative.c
> > @@ -121,7 +121,6 @@ struct its_array its_pages;
> >  static void *__its_alloc(struct its_array *pages)
> >  {
> >  	void *page __free(execmem) = execmem_alloc(EXECMEM_MODULE_TEXT, PAGE_SIZE);
> > -
> >  	if (!page)
> >  		return NULL;
> >  
> > @@ -172,6 +171,9 @@ static void *its_init_thunk(void *thunk,
> >  
> >  static void its_pages_protect(struct its_array *pages)
> >  {
> > +	if (!IS_ENABLED(CONFIG_STRICT_KERNEL_RWX))
> > +		return;
> > +
>
> But modules generally use STRICT_MODULE_RWX.
> Do you want to make the its pages stricter than normal module text?
>
> >  	for (int i = 0; i < pages->num; i++) {
> >  		void *page = pages->pages[i];
> >  		execmem_restore_rox(page, PAGE_SIZE);
> > @@ -180,8 +182,7 @@ static void its_pages_protect(struct its
> >  
> >  static void its_fini_core(void)
> >  {
> > -	if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX))
> > -		its_pages_protect(&its_pages);
> > +	its_pages_protect(&its_pages);
> >  	kfree(its_pages.pages);
> >  }
> >  
> > @@ -207,8 +208,7 @@ void its_fini_mod(struct module *mod)
> >  	its_page = NULL;
> >  	mutex_unlock(&text_mutex);
> >  
> > -	if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
> > -		its_pages_protect(&mod->arch.its_pages);
> > +	its_pages_protect(&mod->arch.its_pages);
> >  }
>

I tested the 5-patch series without this 6th patch on top of 6.15.2 released yesterday
and it fixes a crash I get in 6.15.2 in my Xen PV dom0 without this patch set.

I also  tried this 6th patch (including Mike's suggested removal of the three lines from
Peter's add-on 6th patch ) but I got a kernel panic in Xen PV dom0 with this extra patch.

Chuck Zmudzinski

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2025-06-11 21:19 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-03 11:14 [PATCH 0/5] Fixes for ITS mitigation and execmem Mike Rapoport
2025-06-03 11:14 ` [PATCH 1/5] x86/mm/pat: don't collapse pages without PSE set Mike Rapoport
2025-06-03 11:14 ` [PATCH 2/5] x86/Kconfig: only enable ROX cache in execmem when STRICT_MODULE_RWX is set Mike Rapoport
2025-06-11  9:30   ` [tip: x86/urgent] " tip-bot2 for Mike Rapoport (Microsoft)
2025-06-03 11:14 ` [PATCH 3/5] x86/its: move its_pages array to struct mod_arch_specific Mike Rapoport
2025-06-11  9:30   ` [tip: x86/urgent] " tip-bot2 for Mike Rapoport (Microsoft)
2025-06-03 11:14 ` [PATCH 4/5] x86/its: explicitly manage permissions for ITS pages Mike Rapoport
2025-06-03 13:58   ` Peter Zijlstra
2025-06-03 14:36     ` Mike Rapoport
2025-06-03 14:45       ` Peter Zijlstra
2025-06-11 21:09       ` Chuck Zmudzinski
2025-06-05  9:23   ` Nikolay Borisov
2025-06-11  9:30   ` [tip: x86/urgent] " tip-bot2 for Peter Zijlstra (Intel)
2025-06-03 11:14 ` [PATCH 5/5] Revert "mm/execmem: Unify early execmem_cache behaviour" Mike Rapoport
2025-06-11  9:30   ` [tip: x86/urgent] " tip-bot2 for Mike Rapoport (Microsoft)
2025-06-10  6:00 ` [PATCH 0/5] Fixes for ITS mitigation and execmem Jürgen Groß

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).