mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-08-28 00:19:36 +00: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: 872df34d7c
("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
This commit is contained in:
parent
0b0cae7119
commit
a82b26451d
@ -116,6 +116,24 @@ static struct module *its_mod;
|
|||||||
#endif
|
#endif
|
||||||
static void *its_page;
|
static void *its_page;
|
||||||
static unsigned int its_offset;
|
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. */
|
/* Initialize a thunk with the "jmp *reg; int3" instructions. */
|
||||||
static void *its_init_thunk(void *thunk, int reg)
|
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;
|
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
|
#ifdef CONFIG_MODULES
|
||||||
void its_init_mod(struct module *mod)
|
void its_init_mod(struct module *mod)
|
||||||
{
|
{
|
||||||
@ -173,10 +206,8 @@ void its_fini_mod(struct module *mod)
|
|||||||
its_page = NULL;
|
its_page = NULL;
|
||||||
mutex_unlock(&text_mutex);
|
mutex_unlock(&text_mutex);
|
||||||
|
|
||||||
for (int i = 0; i < mod->arch.its_pages.num; i++) {
|
if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
|
||||||
void *page = mod->arch.its_pages.pages[i];
|
its_pages_protect(&mod->arch.its_pages);
|
||||||
execmem_restore_rox(page, PAGE_SIZE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void its_free_mod(struct module *mod)
|
void its_free_mod(struct module *mod)
|
||||||
@ -194,28 +225,23 @@ void its_free_mod(struct module *mod)
|
|||||||
|
|
||||||
static void *its_alloc(void)
|
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)
|
if (!page)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
#ifdef CONFIG_MODULES
|
execmem_make_temp_rw(page, PAGE_SIZE);
|
||||||
if (its_mod) {
|
if (pages == &its_pages)
|
||||||
struct its_array *pages = &its_mod->arch.its_pages;
|
set_memory_x((unsigned long)page, 1);
|
||||||
void *tmp = krealloc(pages->pages,
|
|
||||||
(pages->num+1) * sizeof(void *),
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!tmp)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
pages->pages = tmp;
|
return page;
|
||||||
pages->pages[pages->num++] = page;
|
|
||||||
|
|
||||||
execmem_make_temp_rw(page, PAGE_SIZE);
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_MODULES */
|
|
||||||
|
|
||||||
return no_free_ptr(page);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *its_allocate_thunk(int reg)
|
static void *its_allocate_thunk(int reg)
|
||||||
@ -269,7 +295,9 @@ u8 *its_static_thunk(int reg)
|
|||||||
return thunk;
|
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
|
* 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_retpolines(__retpoline_sites, __retpoline_sites_end);
|
||||||
apply_returns(__return_sites, __return_sites_end);
|
apply_returns(__return_sites, __return_sites_end);
|
||||||
|
|
||||||
|
its_fini_core();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Adjust all CALL instructions to point to func()-10, including
|
* Adjust all CALL instructions to point to func()-10, including
|
||||||
* those in .altinstr_replacement.
|
* those in .altinstr_replacement.
|
||||||
|
Loading…
Reference in New Issue
Block a user