Commit 9afe6529 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'x86_urgent_for_6.16-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 fixes from Dave Hansen:
 "This is a pretty scattered set of fixes. The majority of them are
  further fixups around the recent ITS mitigations.

  The rest don't really have a coherent story:

   - Some flavors of Xen PV guests don't support large pages, but the
     set_memory.c code assumes all CPUs support them.

     Avoid problems with a quick CPU feature check.

   - The TDX code has some wrappers to help retry calls to the TDX
     module. They use function pointers to assembly functions and the
     compiler usually generates direct CALLs. But some new compilers,
     plus -Os turned them in to indirect CALLs and the assembly code was
     not annotated for indirect calls.

     Force inlining of the helper to fix it up.

   - Last, a FRED issue showed up when single-stepping. It's fine when
     using an external debugger, but was getting stuck returning from a
     SIGTRAP handler otherwise.

     Clear the FRED 'swevent' bit to ensure that forward progress is
     made"

* tag 'x86_urgent_for_6.16-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  Revert "mm/execmem: Unify early execmem_cache behaviour"
  x86/its: explicitly manage permissions for ITS pages
  x86/its: move its_pages array to struct mod_arch_specific
  x86/Kconfig: only enable ROX cache in execmem when STRICT_MODULE_RWX is set
  x86/mm/pat: don't collapse pages without PSE set
  x86/virt/tdx: Avoid indirect calls to TDX assembly functions
  selftests/x86: Add a test to detect infinite SIGTRAP handler loop
  x86/fred/signal: Prevent immediate repeat of single step trap on return from SIGTRAP handler
parents 44a5ab7a 7cd9a11d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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
+8 −0
Original line number Diff line number Diff line
@@ -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 */
+22 −0
Original line number Diff line number Diff line
@@ -24,4 +24,26 @@ int ia32_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs);
int x64_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs);
int x32_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs);

/*
 * To prevent immediate repeat of single step trap on return from SIGTRAP
 * handler if the trap flag (TF) is set without an external debugger attached,
 * clear the software event flag in the augmented SS, ensuring no single-step
 * trap is pending upon ERETU completion.
 *
 * Note, this function should be called in sigreturn() before the original
 * state is restored to make sure the TF is read from the entry frame.
 */
static __always_inline void prevent_single_step_upon_eretu(struct pt_regs *regs)
{
	/*
	 * If the trap flag (TF) is set, i.e., the sigreturn() SYSCALL instruction
	 * is being single-stepped, do not clear the software event flag in the
	 * augmented SS, thus a debugger won't skip over the following instruction.
	 */
#ifdef CONFIG_X86_FRED
	if (!(regs->flags & X86_EFLAGS_TF))
		regs->fred_ss.swevent = 0;
#endif
}

#endif /* _ASM_X86_SIGHANDLING_H */
+1 −1
Original line number Diff line number Diff line
@@ -106,7 +106,7 @@ void tdx_init(void);

typedef u64 (*sc_func_t)(u64 fn, struct tdx_module_args *args);

static inline u64 sc_retry(sc_func_t func, u64 fn,
static __always_inline u64 sc_retry(sc_func_t func, u64 fn,
			   struct tdx_module_args *args)
{
	int retry = RDRAND_RETRY_LOOPS;
+55 −24
Original line number Diff line number Diff line
@@ -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->its_num_pages; i++) {
		void *page = mod->its_page_array[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)
@@ -184,37 +215,33 @@ 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 */

static void *its_alloc(void)
{
	void *page __free(execmem) = execmem_alloc(EXECMEM_MODULE_TEXT, PAGE_SIZE);
	struct its_array *pages = &its_pages;
	void *page;

	if (!page)
		return NULL;
#ifdef CONFIG_MODULE
	if (its_mod)
		pages = &its_mod->arch.its_pages;
#endif

#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)
	page = __its_alloc(pages);
	if (!page)
		return NULL;

		its_mod->its_page_array = tmp;
		its_mod->its_page_array[its_mod->its_num_pages++] = page;

	execmem_make_temp_rw(page, PAGE_SIZE);
	}
#endif /* CONFIG_MODULES */
	if (pages == &its_pages)
		set_memory_x((unsigned long)page, 1);

	return no_free_ptr(page);
	return page;
}

static void *its_allocate_thunk(int reg)
@@ -268,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
@@ -2338,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.
Loading