Skip to content

Commit 9afe652

Browse files
committed
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
2 parents 44a5ab7 + 7cd9a11 commit 9afe652

File tree

16 files changed

+207
-84
lines changed

16 files changed

+207
-84
lines changed

arch/x86/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ config X86
8989
select ARCH_HAS_DMA_OPS if GART_IOMMU || XEN
9090
select ARCH_HAS_EARLY_DEBUG if KGDB
9191
select ARCH_HAS_ELF_RANDOMIZE
92-
select ARCH_HAS_EXECMEM_ROX if X86_64
92+
select ARCH_HAS_EXECMEM_ROX if X86_64 && STRICT_MODULE_RWX
9393
select ARCH_HAS_FAST_MULTIPLIER
9494
select ARCH_HAS_FORTIFY_SOURCE
9595
select ARCH_HAS_GCOV_PROFILE_ALL

arch/x86/include/asm/module.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,20 @@
55
#include <asm-generic/module.h>
66
#include <asm/orc_types.h>
77

8+
struct its_array {
9+
#ifdef CONFIG_MITIGATION_ITS
10+
void **pages;
11+
int num;
12+
#endif
13+
};
14+
815
struct mod_arch_specific {
916
#ifdef CONFIG_UNWINDER_ORC
1017
unsigned int num_orcs;
1118
int *orc_unwind_ip;
1219
struct orc_entry *orc_unwind;
1320
#endif
21+
struct its_array its_pages;
1422
};
1523

1624
#endif /* _ASM_X86_MODULE_H */

arch/x86/include/asm/sighandling.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,26 @@ int ia32_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs);
2424
int x64_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs);
2525
int x32_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs);
2626

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

arch/x86/include/asm/tdx.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ void tdx_init(void);
106106

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

109-
static inline u64 sc_retry(sc_func_t func, u64 fn,
109+
static __always_inline u64 sc_retry(sc_func_t func, u64 fn,
110110
struct tdx_module_args *args)
111111
{
112112
int retry = RDRAND_RETRY_LOOPS;

arch/x86/kernel/alternative.c

Lines changed: 55 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,24 @@ static struct module *its_mod;
116116
#endif
117117
static void *its_page;
118118
static unsigned int its_offset;
119+
struct its_array its_pages;
120+
121+
static void *__its_alloc(struct its_array *pages)
122+
{
123+
void *page __free(execmem) = execmem_alloc(EXECMEM_MODULE_TEXT, PAGE_SIZE);
124+
if (!page)
125+
return NULL;
126+
127+
void *tmp = krealloc(pages->pages, (pages->num+1) * sizeof(void *),
128+
GFP_KERNEL);
129+
if (!tmp)
130+
return NULL;
131+
132+
pages->pages = tmp;
133+
pages->pages[pages->num++] = page;
134+
135+
return no_free_ptr(page);
136+
}
119137

120138
/* Initialize a thunk with the "jmp *reg; int3" instructions. */
121139
static void *its_init_thunk(void *thunk, int reg)
@@ -151,6 +169,21 @@ static void *its_init_thunk(void *thunk, int reg)
151169
return thunk + offset;
152170
}
153171

172+
static void its_pages_protect(struct its_array *pages)
173+
{
174+
for (int i = 0; i < pages->num; i++) {
175+
void *page = pages->pages[i];
176+
execmem_restore_rox(page, PAGE_SIZE);
177+
}
178+
}
179+
180+
static void its_fini_core(void)
181+
{
182+
if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX))
183+
its_pages_protect(&its_pages);
184+
kfree(its_pages.pages);
185+
}
186+
154187
#ifdef CONFIG_MODULES
155188
void its_init_mod(struct module *mod)
156189
{
@@ -173,48 +206,42 @@ void its_fini_mod(struct module *mod)
173206
its_page = NULL;
174207
mutex_unlock(&text_mutex);
175208

176-
for (int i = 0; i < mod->its_num_pages; i++) {
177-
void *page = mod->its_page_array[i];
178-
execmem_restore_rox(page, PAGE_SIZE);
179-
}
209+
if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
210+
its_pages_protect(&mod->arch.its_pages);
180211
}
181212

182213
void its_free_mod(struct module *mod)
183214
{
184215
if (!cpu_feature_enabled(X86_FEATURE_INDIRECT_THUNK_ITS))
185216
return;
186217

187-
for (int i = 0; i < mod->its_num_pages; i++) {
188-
void *page = mod->its_page_array[i];
218+
for (int i = 0; i < mod->arch.its_pages.num; i++) {
219+
void *page = mod->arch.its_pages.pages[i];
189220
execmem_free(page);
190221
}
191-
kfree(mod->its_page_array);
222+
kfree(mod->arch.its_pages.pages);
192223
}
193224
#endif /* CONFIG_MODULES */
194225

195226
static void *its_alloc(void)
196227
{
197-
void *page __free(execmem) = execmem_alloc(EXECMEM_MODULE_TEXT, PAGE_SIZE);
228+
struct its_array *pages = &its_pages;
229+
void *page;
198230

231+
#ifdef CONFIG_MODULE
232+
if (its_mod)
233+
pages = &its_mod->arch.its_pages;
234+
#endif
235+
236+
page = __its_alloc(pages);
199237
if (!page)
200238
return NULL;
201239

202-
#ifdef CONFIG_MODULES
203-
if (its_mod) {
204-
void *tmp = krealloc(its_mod->its_page_array,
205-
(its_mod->its_num_pages+1) * sizeof(void *),
206-
GFP_KERNEL);
207-
if (!tmp)
208-
return NULL;
209-
210-
its_mod->its_page_array = tmp;
211-
its_mod->its_page_array[its_mod->its_num_pages++] = page;
240+
execmem_make_temp_rw(page, PAGE_SIZE);
241+
if (pages == &its_pages)
242+
set_memory_x((unsigned long)page, 1);
212243

213-
execmem_make_temp_rw(page, PAGE_SIZE);
214-
}
215-
#endif /* CONFIG_MODULES */
216-
217-
return no_free_ptr(page);
244+
return page;
218245
}
219246

220247
static void *its_allocate_thunk(int reg)
@@ -268,7 +295,9 @@ u8 *its_static_thunk(int reg)
268295
return thunk;
269296
}
270297

271-
#endif
298+
#else
299+
static inline void its_fini_core(void) {}
300+
#endif /* CONFIG_MITIGATION_ITS */
272301

273302
/*
274303
* Nomenclature for variable names to simplify and clarify this code and ease
@@ -2338,6 +2367,8 @@ void __init alternative_instructions(void)
23382367
apply_retpolines(__retpoline_sites, __retpoline_sites_end);
23392368
apply_returns(__return_sites, __return_sites_end);
23402369

2370+
its_fini_core();
2371+
23412372
/*
23422373
* Adjust all CALL instructions to point to func()-10, including
23432374
* those in .altinstr_replacement.

arch/x86/kernel/signal_32.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ SYSCALL32_DEFINE0(sigreturn)
152152
struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
153153
sigset_t set;
154154

155+
prevent_single_step_upon_eretu(regs);
156+
155157
if (!access_ok(frame, sizeof(*frame)))
156158
goto badframe;
157159
if (__get_user(set.sig[0], &frame->sc.oldmask)
@@ -175,6 +177,8 @@ SYSCALL32_DEFINE0(rt_sigreturn)
175177
struct rt_sigframe_ia32 __user *frame;
176178
sigset_t set;
177179

180+
prevent_single_step_upon_eretu(regs);
181+
178182
frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
179183

180184
if (!access_ok(frame, sizeof(*frame)))

arch/x86/kernel/signal_64.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,8 @@ SYSCALL_DEFINE0(rt_sigreturn)
250250
sigset_t set;
251251
unsigned long uc_flags;
252252

253+
prevent_single_step_upon_eretu(regs);
254+
253255
frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long));
254256
if (!access_ok(frame, sizeof(*frame)))
255257
goto badframe;
@@ -366,6 +368,8 @@ COMPAT_SYSCALL_DEFINE0(x32_rt_sigreturn)
366368
sigset_t set;
367369
unsigned long uc_flags;
368370

371+
prevent_single_step_upon_eretu(regs);
372+
369373
frame = (struct rt_sigframe_x32 __user *)(regs->sp - 8);
370374

371375
if (!access_ok(frame, sizeof(*frame)))

arch/x86/mm/init_32.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
#include <linux/initrd.h>
3131
#include <linux/cpumask.h>
3232
#include <linux/gfp.h>
33-
#include <linux/execmem.h>
3433

3534
#include <asm/asm.h>
3635
#include <asm/bios_ebda.h>
@@ -749,8 +748,6 @@ void mark_rodata_ro(void)
749748
pr_info("Write protecting kernel text and read-only data: %luk\n",
750749
size >> 10);
751750

752-
execmem_cache_make_ro();
753-
754751
kernel_set_to_readonly = 1;
755752

756753
#ifdef CONFIG_CPA_DEBUG

arch/x86/mm/init_64.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
#include <linux/gfp.h>
3535
#include <linux/kcore.h>
3636
#include <linux/bootmem_info.h>
37-
#include <linux/execmem.h>
3837

3938
#include <asm/processor.h>
4039
#include <asm/bios_ebda.h>
@@ -1392,8 +1391,6 @@ void mark_rodata_ro(void)
13921391
(end - start) >> 10);
13931392
set_memory_ro(start, (end - start) >> PAGE_SHIFT);
13941393

1395-
execmem_cache_make_ro();
1396-
13971394
kernel_set_to_readonly = 1;
13981395

13991396
/*

arch/x86/mm/pat/set_memory.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,6 +1257,9 @@ static int collapse_pmd_page(pmd_t *pmd, unsigned long addr,
12571257
pgprot_t pgprot;
12581258
int i = 0;
12591259

1260+
if (!cpu_feature_enabled(X86_FEATURE_PSE))
1261+
return 0;
1262+
12601263
addr &= PMD_MASK;
12611264
pte = pte_offset_kernel(pmd, addr);
12621265
first = *pte;

arch/x86/virt/vmx/tdx/tdx.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,9 @@ static inline void seamcall_err_ret(u64 fn, u64 err,
7575
args->r9, args->r10, args->r11);
7676
}
7777

78-
static inline int sc_retry_prerr(sc_func_t func, sc_err_func_t err_func,
79-
u64 fn, struct tdx_module_args *args)
78+
static __always_inline int sc_retry_prerr(sc_func_t func,
79+
sc_err_func_t err_func,
80+
u64 fn, struct tdx_module_args *args)
8081
{
8182
u64 sret = sc_retry(func, fn, args);
8283

include/linux/execmem.h

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ enum execmem_range_flags {
5454
EXECMEM_ROX_CACHE = (1 << 1),
5555
};
5656

57-
#if defined(CONFIG_ARCH_HAS_EXECMEM_ROX) && defined(CONFIG_EXECMEM)
57+
#ifdef CONFIG_ARCH_HAS_EXECMEM_ROX
5858
/**
5959
* execmem_fill_trapping_insns - set memory to contain instructions that
6060
* will trap
@@ -94,15 +94,9 @@ int execmem_make_temp_rw(void *ptr, size_t size);
9494
* Return: 0 on success or negative error code on failure.
9595
*/
9696
int execmem_restore_rox(void *ptr, size_t size);
97-
98-
/*
99-
* Called from mark_readonly(), where the system transitions to ROX.
100-
*/
101-
void execmem_cache_make_ro(void);
10297
#else
10398
static inline int execmem_make_temp_rw(void *ptr, size_t size) { return 0; }
10499
static inline int execmem_restore_rox(void *ptr, size_t size) { return 0; }
105-
static inline void execmem_cache_make_ro(void) { }
106100
#endif
107101

108102
/**

include/linux/module.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -586,11 +586,6 @@ struct module {
586586
atomic_t refcnt;
587587
#endif
588588

589-
#ifdef CONFIG_MITIGATION_ITS
590-
int its_num_pages;
591-
void **its_page_array;
592-
#endif
593-
594589
#ifdef CONFIG_CONSTRUCTORS
595590
/* Constructor functions. */
596591
ctor_fn_t *ctors;

mm/execmem.c

Lines changed: 3 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -254,34 +254,6 @@ static void *__execmem_cache_alloc(struct execmem_range *range, size_t size)
254254
return ptr;
255255
}
256256

257-
static bool execmem_cache_rox = false;
258-
259-
void execmem_cache_make_ro(void)
260-
{
261-
struct maple_tree *free_areas = &execmem_cache.free_areas;
262-
struct maple_tree *busy_areas = &execmem_cache.busy_areas;
263-
MA_STATE(mas_free, free_areas, 0, ULONG_MAX);
264-
MA_STATE(mas_busy, busy_areas, 0, ULONG_MAX);
265-
struct mutex *mutex = &execmem_cache.mutex;
266-
void *area;
267-
268-
execmem_cache_rox = true;
269-
270-
mutex_lock(mutex);
271-
272-
mas_for_each(&mas_free, area, ULONG_MAX) {
273-
unsigned long pages = mas_range_len(&mas_free) >> PAGE_SHIFT;
274-
set_memory_ro(mas_free.index, pages);
275-
}
276-
277-
mas_for_each(&mas_busy, area, ULONG_MAX) {
278-
unsigned long pages = mas_range_len(&mas_busy) >> PAGE_SHIFT;
279-
set_memory_ro(mas_busy.index, pages);
280-
}
281-
282-
mutex_unlock(mutex);
283-
}
284-
285257
static int execmem_cache_populate(struct execmem_range *range, size_t size)
286258
{
287259
unsigned long vm_flags = VM_ALLOW_HUGE_VMAP;
@@ -302,15 +274,9 @@ static int execmem_cache_populate(struct execmem_range *range, size_t size)
302274
/* fill memory with instructions that will trap */
303275
execmem_fill_trapping_insns(p, alloc_size, /* writable = */ true);
304276

305-
if (execmem_cache_rox) {
306-
err = set_memory_rox((unsigned long)p, vm->nr_pages);
307-
if (err)
308-
goto err_free_mem;
309-
} else {
310-
err = set_memory_x((unsigned long)p, vm->nr_pages);
311-
if (err)
312-
goto err_free_mem;
313-
}
277+
err = set_memory_rox((unsigned long)p, vm->nr_pages);
278+
if (err)
279+
goto err_free_mem;
314280

315281
err = execmem_cache_add(p, alloc_size);
316282
if (err)

tools/testing/selftests/x86/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ CAN_BUILD_WITH_NOPIE := $(shell ./check_cc.sh "$(CC)" trivial_program.c -no-pie)
1212

1313
TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt test_mremap_vdso \
1414
check_initial_reg_state sigreturn iopl ioperm \
15-
test_vsyscall mov_ss_trap \
15+
test_vsyscall mov_ss_trap sigtrap_loop \
1616
syscall_arg_fault fsgsbase_restore sigaltstack
1717
TARGETS_C_BOTHBITS += nx_stack
1818
TARGETS_C_32BIT_ONLY := entry_from_vm86 test_syscall_vdso unwind_vdso \

0 commit comments

Comments
 (0)