On Wed, May 28, 2025 at 05:58:21PM +0200, Peter Zijlstra wrote:
On Wed, May 28, 2025 at 03:30:33PM +0200, Jürgen Groß wrote:
Have a look at its_fini_mod().
Oh, that's what you mean. But this still isn't very nice, you now have restore_rox() without make_temp_rw(), which was the intended usage pattern.
Bah, I hate how execmem works different for !PSE, Mike, you see a sane way to fix this?
Anyway, if we have to do something like this, then I would prefer it shaped something like so:
Missing file:
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 ecfe7b497cad..33d4d139cb50 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -111,9 +111,8 @@ static bool cfi_paranoid __ro_after_init; #ifdef CONFIG_MITIGATION_ITS -#ifdef CONFIG_MODULES static struct module *its_mod; -#endif +static struct its_array its_pages; static void *its_page; static unsigned int its_offset; @@ -151,68 +150,78 @@ static void *its_init_thunk(void *thunk, int reg) return thunk + offset; } -#ifdef CONFIG_MODULES void its_init_mod(struct module *mod) { if (!cpu_feature_enabled(X86_FEATURE_INDIRECT_THUNK_ITS)) return;
- mutex_lock(&text_mutex);
- its_mod = mod;
- its_page = NULL;
- if (mod) {
mutex_lock(&text_mutex);
its_mod = mod;
its_page = NULL;
- }
} void its_fini_mod(struct module *mod) {
- struct its_array *pages = &its_pages;
- if (!cpu_feature_enabled(X86_FEATURE_INDIRECT_THUNK_ITS)) return;
WARN_ON_ONCE(its_mod != mod);
- its_mod = NULL;
- its_page = NULL;
- mutex_unlock(&text_mutex);
- if (mod) {
pages = &mod->arch.its_pages;
its_mod = NULL;
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 < pages->num; i++) {
execmem_restore_rox(page, PAGE_SIZE); }void *page = pages->pages[i];
- if (!mod)
kfree(pages->pages);
} void its_free_mod(struct module *mod) {
- struct its_array *pages = &its_pages;
- 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];
- if (mod)
pages = &mod->arch.its_pages;
- for (int i = 0; i < pages->num; i++) {
execmem_free(page); }void *page = pages->pages[i];
- kfree(mod->its_page_array);
- kfree(pages->pages);
} -#endif /* CONFIG_MODULES */ static void *its_alloc(void) {
- void *page __free(execmem) = execmem_alloc(EXECMEM_MODULE_TEXT, PAGE_SIZE);
- struct its_array *pages = &its_pages;
- void *tmp;
- void *page __free(execmem) = execmem_alloc(EXECMEM_MODULE_TEXT, PAGE_SIZE); if (!page) return NULL;
-#ifdef CONFIG_MODULES
- if (its_mod) {
void *tmp = krealloc(its_mod->its_page_array,
(its_mod->its_num_pages+1) * sizeof(void *),
GFP_KERNEL);
if (!tmp)
return NULL;
- 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;
- if (its_mod) execmem_make_temp_rw(page, PAGE_SIZE);
- }
-#endif /* CONFIG_MODULES */ return no_free_ptr(page); } @@ -2338,6 +2347,8 @@ void __init alternative_instructions(void) apply_retpolines(__retpoline_sites, __retpoline_sites_end); apply_returns(__return_sites, __return_sites_end);
- its_fini_mod(NULL);
- /*
- Adjust all CALL instructions to point to func()-10, including
- those in .altinstr_replacement.