Skip to content

Commit bf98bae

Browse files
committed
Merge tag 'x86_urgent_for_v6.5_rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 fixes from Borislav Petkov: "Extraordinary embargoed times call for extraordinary measures. That's why this week's x86/urgent branch is larger than usual, containing all the known fallout fixes after the SRSO mitigation got merged. I know, it is a bit late in the game but everyone who has reported a bug stemming from the SRSO pile, has tested that branch and has confirmed that it fixes their bug. Also, I've run it on every possible hardware I have and it is looking good. It is running on this very machine while I'm typing, for 2 days now without an issue. Famous last words... - Use LEA ...%rsp instead of ADD %rsp in the Zen1/2 SRSO return sequence as latter clobbers flags which interferes with fastop emulation in KVM, leading to guests freezing during boot - A fix for the DIV(0) quotient data leak on Zen1 to clear the divider buffers at the right time - Disable the SRSO mitigation on unaffected configurations as it got enabled there unnecessarily - Change .text section name to fix CONFIG_LTO_CLANG builds - Improve the optprobe indirect jmp check so that certain configurations can still be able to use optprobes at all - A serious and good scrubbing of the untraining routines by PeterZ: - Add proper speculation stopping traps so that objtool is happy - Adjust objtool to handle the new thunks - Make the thunk pointer assignable to the different untraining sequences at runtime, thus avoiding the alternative at the return thunk. It simplifies the code a bit too. - Add a entry_untrain_ret() main entry point which selects the respective untraining sequence - Rename things so that they're more clear - Fix stack validation with FRAME_POINTER=y builds - Fix static call patching to handle when a JMP to the return thunk is the last insn on the very last module memory page - Add more documentation about what each untraining routine does and why" * tag 'x86_urgent_for_v6.5_rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/srso: Correct the mitigation status when SMT is disabled x86/static_call: Fix __static_call_fixup() objtool/x86: Fixup frame-pointer vs rethunk x86/srso: Explain the untraining sequences a bit more x86/cpu/kvm: Provide UNTRAIN_RET_VM x86/cpu: Cleanup the untrain mess x86/cpu: Rename srso_(.*)_alias to srso_alias_\1 x86/cpu: Rename original retbleed methods x86/cpu: Clean up SRSO return thunk mess x86/alternative: Make custom return thunk unconditional objtool/x86: Fix SRSO mess x86/cpu: Fix up srso_safe_ret() and __x86_return_thunk() x86/cpu: Fix __x86_return_thunk symbol type x86/retpoline,kprobes: Skip optprobe check for indirect jumps with retpolines and IBT x86/retpoline,kprobes: Fix position of thunk sections with CONFIG_LTO_CLANG x86/srso: Disable the mitigation on unaffected configurations x86/CPU/AMD: Fix the DIV(0) initial fix attempt x86/retpoline: Don't clobber RFLAGS during srso_safe_ret()
2 parents 4e7ffde + 6405b72 commit bf98bae

File tree

18 files changed

+236
-133
lines changed

18 files changed

+236
-133
lines changed

Documentation/admin-guide/hw-vuln/srso.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,8 @@ sequence.
141141
To ensure the safety of this mitigation, the kernel must ensure that the
142142
safe return sequence is itself free from attacker interference. In Zen3
143143
and Zen4, this is accomplished by creating a BTB alias between the
144-
untraining function srso_untrain_ret_alias() and the safe return
145-
function srso_safe_ret_alias() which results in evicting a potentially
144+
untraining function srso_alias_untrain_ret() and the safe return
145+
function srso_alias_safe_ret() which results in evicting a potentially
146146
poisoned BTB entry and using that safe one for all function returns.
147147

148148
In older Zen1 and Zen2, this is accomplished using a reinterpretation

arch/x86/include/asm/entry-common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs,
9292
static __always_inline void arch_exit_to_user_mode(void)
9393
{
9494
mds_user_clear_cpu_buffers();
95+
amd_clear_divider();
9596
}
9697
#define arch_exit_to_user_mode arch_exit_to_user_mode
9798

arch/x86/include/asm/nospec-branch.h

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -272,17 +272,17 @@
272272
.endm
273273

274274
#ifdef CONFIG_CPU_UNRET_ENTRY
275-
#define CALL_ZEN_UNTRAIN_RET "call zen_untrain_ret"
275+
#define CALL_UNTRAIN_RET "call entry_untrain_ret"
276276
#else
277-
#define CALL_ZEN_UNTRAIN_RET ""
277+
#define CALL_UNTRAIN_RET ""
278278
#endif
279279

280280
/*
281281
* Mitigate RETBleed for AMD/Hygon Zen uarch. Requires KERNEL CR3 because the
282282
* return thunk isn't mapped into the userspace tables (then again, AMD
283283
* typically has NO_MELTDOWN).
284284
*
285-
* While zen_untrain_ret() doesn't clobber anything but requires stack,
285+
* While retbleed_untrain_ret() doesn't clobber anything but requires stack,
286286
* entry_ibpb() will clobber AX, CX, DX.
287287
*
288288
* As such, this must be placed after every *SWITCH_TO_KERNEL_CR3 at a point
@@ -293,14 +293,20 @@
293293
defined(CONFIG_CALL_DEPTH_TRACKING) || defined(CONFIG_CPU_SRSO)
294294
VALIDATE_UNRET_END
295295
ALTERNATIVE_3 "", \
296-
CALL_ZEN_UNTRAIN_RET, X86_FEATURE_UNRET, \
296+
CALL_UNTRAIN_RET, X86_FEATURE_UNRET, \
297297
"call entry_ibpb", X86_FEATURE_ENTRY_IBPB, \
298298
__stringify(RESET_CALL_DEPTH), X86_FEATURE_CALL_DEPTH
299299
#endif
300+
.endm
300301

301-
#ifdef CONFIG_CPU_SRSO
302-
ALTERNATIVE_2 "", "call srso_untrain_ret", X86_FEATURE_SRSO, \
303-
"call srso_untrain_ret_alias", X86_FEATURE_SRSO_ALIAS
302+
.macro UNTRAIN_RET_VM
303+
#if defined(CONFIG_CPU_UNRET_ENTRY) || defined(CONFIG_CPU_IBPB_ENTRY) || \
304+
defined(CONFIG_CALL_DEPTH_TRACKING) || defined(CONFIG_CPU_SRSO)
305+
VALIDATE_UNRET_END
306+
ALTERNATIVE_3 "", \
307+
CALL_UNTRAIN_RET, X86_FEATURE_UNRET, \
308+
"call entry_ibpb", X86_FEATURE_IBPB_ON_VMEXIT, \
309+
__stringify(RESET_CALL_DEPTH), X86_FEATURE_CALL_DEPTH
304310
#endif
305311
.endm
306312

@@ -309,15 +315,10 @@
309315
defined(CONFIG_CALL_DEPTH_TRACKING)
310316
VALIDATE_UNRET_END
311317
ALTERNATIVE_3 "", \
312-
CALL_ZEN_UNTRAIN_RET, X86_FEATURE_UNRET, \
318+
CALL_UNTRAIN_RET, X86_FEATURE_UNRET, \
313319
"call entry_ibpb", X86_FEATURE_ENTRY_IBPB, \
314320
__stringify(RESET_CALL_DEPTH_FROM_CALL), X86_FEATURE_CALL_DEPTH
315321
#endif
316-
317-
#ifdef CONFIG_CPU_SRSO
318-
ALTERNATIVE_2 "", "call srso_untrain_ret", X86_FEATURE_SRSO, \
319-
"call srso_untrain_ret_alias", X86_FEATURE_SRSO_ALIAS
320-
#endif
321322
.endm
322323

323324

@@ -341,17 +342,24 @@ extern retpoline_thunk_t __x86_indirect_thunk_array[];
341342
extern retpoline_thunk_t __x86_indirect_call_thunk_array[];
342343
extern retpoline_thunk_t __x86_indirect_jump_thunk_array[];
343344

345+
#ifdef CONFIG_RETHUNK
344346
extern void __x86_return_thunk(void);
345-
extern void zen_untrain_ret(void);
347+
#else
348+
static inline void __x86_return_thunk(void) {}
349+
#endif
350+
351+
extern void retbleed_return_thunk(void);
352+
extern void srso_return_thunk(void);
353+
extern void srso_alias_return_thunk(void);
354+
355+
extern void retbleed_untrain_ret(void);
346356
extern void srso_untrain_ret(void);
347-
extern void srso_untrain_ret_alias(void);
357+
extern void srso_alias_untrain_ret(void);
358+
359+
extern void entry_untrain_ret(void);
348360
extern void entry_ibpb(void);
349361

350-
#ifdef CONFIG_CALL_THUNKS
351362
extern void (*x86_return_thunk)(void);
352-
#else
353-
#define x86_return_thunk (&__x86_return_thunk)
354-
#endif
355363

356364
#ifdef CONFIG_CALL_DEPTH_TRACKING
357365
extern void __x86_return_skl(void);
@@ -478,9 +486,6 @@ enum ssb_mitigation {
478486
SPEC_STORE_BYPASS_SECCOMP,
479487
};
480488

481-
extern char __indirect_thunk_start[];
482-
extern char __indirect_thunk_end[];
483-
484489
static __always_inline
485490
void alternative_msr_write(unsigned int msr, u64 val, unsigned int feature)
486491
{

arch/x86/kernel/alternative.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -687,10 +687,6 @@ void __init_or_module noinline apply_retpolines(s32 *start, s32 *end)
687687

688688
#ifdef CONFIG_RETHUNK
689689

690-
#ifdef CONFIG_CALL_THUNKS
691-
void (*x86_return_thunk)(void) __ro_after_init = &__x86_return_thunk;
692-
#endif
693-
694690
/*
695691
* Rewrite the compiler generated return thunk tail-calls.
696692
*

arch/x86/kernel/cpu/amd.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,3 +1329,4 @@ void noinstr amd_clear_divider(void)
13291329
asm volatile(ALTERNATIVE("", "div %2\n\t", X86_BUG_DIV0)
13301330
:: "a" (0), "d" (0), "r" (1));
13311331
}
1332+
EXPORT_SYMBOL_GPL(amd_clear_divider);

arch/x86/kernel/cpu/bugs.c

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ EXPORT_SYMBOL_GPL(x86_pred_cmd);
6363

6464
static DEFINE_MUTEX(spec_ctrl_mutex);
6565

66+
void (*x86_return_thunk)(void) __ro_after_init = &__x86_return_thunk;
67+
6668
/* Update SPEC_CTRL MSR and its cached copy unconditionally */
6769
static void update_spec_ctrl(u64 val)
6870
{
@@ -165,6 +167,11 @@ void __init cpu_select_mitigations(void)
165167
md_clear_select_mitigation();
166168
srbds_select_mitigation();
167169
l1d_flush_select_mitigation();
170+
171+
/*
172+
* srso_select_mitigation() depends and must run after
173+
* retbleed_select_mitigation().
174+
*/
168175
srso_select_mitigation();
169176
gds_select_mitigation();
170177
}
@@ -1035,6 +1042,9 @@ static void __init retbleed_select_mitigation(void)
10351042
setup_force_cpu_cap(X86_FEATURE_RETHUNK);
10361043
setup_force_cpu_cap(X86_FEATURE_UNRET);
10371044

1045+
if (IS_ENABLED(CONFIG_RETHUNK))
1046+
x86_return_thunk = retbleed_return_thunk;
1047+
10381048
if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
10391049
boot_cpu_data.x86_vendor != X86_VENDOR_HYGON)
10401050
pr_err(RETBLEED_UNTRAIN_MSG);
@@ -1044,6 +1054,7 @@ static void __init retbleed_select_mitigation(void)
10441054

10451055
case RETBLEED_MITIGATION_IBPB:
10461056
setup_force_cpu_cap(X86_FEATURE_ENTRY_IBPB);
1057+
setup_force_cpu_cap(X86_FEATURE_IBPB_ON_VMEXIT);
10471058
mitigate_smt = true;
10481059
break;
10491060

@@ -2417,9 +2428,10 @@ static void __init srso_select_mitigation(void)
24172428
* Zen1/2 with SMT off aren't vulnerable after the right
24182429
* IBPB microcode has been applied.
24192430
*/
2420-
if ((boot_cpu_data.x86 < 0x19) &&
2421-
(!cpu_smt_possible() || (cpu_smt_control == CPU_SMT_DISABLED)))
2431+
if (boot_cpu_data.x86 < 0x19 && !cpu_smt_possible()) {
24222432
setup_force_cpu_cap(X86_FEATURE_SRSO_NO);
2433+
return;
2434+
}
24232435
}
24242436

24252437
if (retbleed_mitigation == RETBLEED_MITIGATION_IBPB) {
@@ -2448,11 +2460,15 @@ static void __init srso_select_mitigation(void)
24482460
* like ftrace, static_call, etc.
24492461
*/
24502462
setup_force_cpu_cap(X86_FEATURE_RETHUNK);
2463+
setup_force_cpu_cap(X86_FEATURE_UNRET);
24512464

2452-
if (boot_cpu_data.x86 == 0x19)
2465+
if (boot_cpu_data.x86 == 0x19) {
24532466
setup_force_cpu_cap(X86_FEATURE_SRSO_ALIAS);
2454-
else
2467+
x86_return_thunk = srso_alias_return_thunk;
2468+
} else {
24552469
setup_force_cpu_cap(X86_FEATURE_SRSO);
2470+
x86_return_thunk = srso_return_thunk;
2471+
}
24562472
srso_mitigation = SRSO_MITIGATION_SAFE_RET;
24572473
} else {
24582474
pr_err("WARNING: kernel not compiled with CPU_SRSO.\n");
@@ -2696,6 +2712,9 @@ static ssize_t retbleed_show_state(char *buf)
26962712

26972713
static ssize_t srso_show_state(char *buf)
26982714
{
2715+
if (boot_cpu_has(X86_FEATURE_SRSO_NO))
2716+
return sysfs_emit(buf, "Mitigation: SMT disabled\n");
2717+
26992718
return sysfs_emit(buf, "%s%s\n",
27002719
srso_strings[srso_mitigation],
27012720
(cpu_has_ibpb_brtype_microcode() ? "" : ", no microcode"));

arch/x86/kernel/kprobes/opt.c

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ static int copy_optimized_instructions(u8 *dest, u8 *src, u8 *real)
226226
}
227227

228228
/* Check whether insn is indirect jump */
229-
static int __insn_is_indirect_jump(struct insn *insn)
229+
static int insn_is_indirect_jump(struct insn *insn)
230230
{
231231
return ((insn->opcode.bytes[0] == 0xff &&
232232
(X86_MODRM_REG(insn->modrm.value) & 6) == 4) || /* Jump */
@@ -260,26 +260,6 @@ static int insn_jump_into_range(struct insn *insn, unsigned long start, int len)
260260
return (start <= target && target <= start + len);
261261
}
262262

263-
static int insn_is_indirect_jump(struct insn *insn)
264-
{
265-
int ret = __insn_is_indirect_jump(insn);
266-
267-
#ifdef CONFIG_RETPOLINE
268-
/*
269-
* Jump to x86_indirect_thunk_* is treated as an indirect jump.
270-
* Note that even with CONFIG_RETPOLINE=y, the kernel compiled with
271-
* older gcc may use indirect jump. So we add this check instead of
272-
* replace indirect-jump check.
273-
*/
274-
if (!ret)
275-
ret = insn_jump_into_range(insn,
276-
(unsigned long)__indirect_thunk_start,
277-
(unsigned long)__indirect_thunk_end -
278-
(unsigned long)__indirect_thunk_start);
279-
#endif
280-
return ret;
281-
}
282-
283263
/* Decode whole function to ensure any instructions don't jump into target */
284264
static int can_optimize(unsigned long paddr)
285265
{
@@ -334,9 +314,21 @@ static int can_optimize(unsigned long paddr)
334314
/* Recover address */
335315
insn.kaddr = (void *)addr;
336316
insn.next_byte = (void *)(addr + insn.length);
337-
/* Check any instructions don't jump into target */
338-
if (insn_is_indirect_jump(&insn) ||
339-
insn_jump_into_range(&insn, paddr + INT3_INSN_SIZE,
317+
/*
318+
* Check any instructions don't jump into target, indirectly or
319+
* directly.
320+
*
321+
* The indirect case is present to handle a code with jump
322+
* tables. When the kernel uses retpolines, the check should in
323+
* theory additionally look for jumps to indirect thunks.
324+
* However, the kernel built with retpolines or IBT has jump
325+
* tables disabled so the check can be skipped altogether.
326+
*/
327+
if (!IS_ENABLED(CONFIG_RETPOLINE) &&
328+
!IS_ENABLED(CONFIG_X86_KERNEL_IBT) &&
329+
insn_is_indirect_jump(&insn))
330+
return 0;
331+
if (insn_jump_into_range(&insn, paddr + INT3_INSN_SIZE,
340332
DISP32_SIZE))
341333
return 0;
342334
addr += insn.length;

arch/x86/kernel/static_call.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,19 @@ EXPORT_SYMBOL_GPL(arch_static_call_transform);
186186
*/
187187
bool __static_call_fixup(void *tramp, u8 op, void *dest)
188188
{
189+
unsigned long addr = (unsigned long)tramp;
190+
/*
191+
* Not all .return_sites are a static_call trampoline (most are not).
192+
* Check if the 3 bytes after the return are still kernel text, if not,
193+
* then this definitely is not a trampoline and we need not worry
194+
* further.
195+
*
196+
* This avoids the memcmp() below tripping over pagefaults etc..
197+
*/
198+
if (((addr >> PAGE_SHIFT) != ((addr + 7) >> PAGE_SHIFT)) &&
199+
!kernel_text_address(addr + 7))
200+
return false;
201+
189202
if (memcmp(tramp+5, tramp_ud, 3)) {
190203
/* Not a trampoline site, not our problem. */
191204
return false;

arch/x86/kernel/traps.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,6 @@ DEFINE_IDTENTRY(exc_divide_error)
206206
{
207207
do_error_trap(regs, 0, "divide error", X86_TRAP_DE, SIGFPE,
208208
FPE_INTDIV, error_get_trap_addr(regs));
209-
210-
amd_clear_divider();
211209
}
212210

213211
DEFINE_IDTENTRY(exc_overflow)

arch/x86/kernel/vmlinux.lds.S

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -133,27 +133,25 @@ SECTIONS
133133
KPROBES_TEXT
134134
SOFTIRQENTRY_TEXT
135135
#ifdef CONFIG_RETPOLINE
136-
__indirect_thunk_start = .;
137-
*(.text.__x86.indirect_thunk)
138-
*(.text.__x86.return_thunk)
139-
__indirect_thunk_end = .;
136+
*(.text..__x86.indirect_thunk)
137+
*(.text..__x86.return_thunk)
140138
#endif
141139
STATIC_CALL_TEXT
142140

143141
ALIGN_ENTRY_TEXT_BEGIN
144142
#ifdef CONFIG_CPU_SRSO
145-
*(.text.__x86.rethunk_untrain)
143+
*(.text..__x86.rethunk_untrain)
146144
#endif
147145

148146
ENTRY_TEXT
149147

150148
#ifdef CONFIG_CPU_SRSO
151149
/*
152-
* See the comment above srso_untrain_ret_alias()'s
150+
* See the comment above srso_alias_untrain_ret()'s
153151
* definition.
154152
*/
155-
. = srso_untrain_ret_alias | (1 << 2) | (1 << 8) | (1 << 14) | (1 << 20);
156-
*(.text.__x86.rethunk_safe)
153+
. = srso_alias_untrain_ret | (1 << 2) | (1 << 8) | (1 << 14) | (1 << 20);
154+
*(.text..__x86.rethunk_safe)
157155
#endif
158156
ALIGN_ENTRY_TEXT_END
159157
*(.gnu.warning)
@@ -523,7 +521,7 @@ INIT_PER_CPU(irq_stack_backing_store);
523521
#endif
524522

525523
#ifdef CONFIG_RETHUNK
526-
. = ASSERT((__ret & 0x3f) == 0, "__ret not cacheline-aligned");
524+
. = ASSERT((retbleed_return_thunk & 0x3f) == 0, "retbleed_return_thunk not cacheline-aligned");
527525
. = ASSERT((srso_safe_ret & 0x3f) == 0, "srso_safe_ret not cacheline-aligned");
528526
#endif
529527

@@ -538,8 +536,8 @@ INIT_PER_CPU(irq_stack_backing_store);
538536
* Instead do: (A | B) - (A & B) in order to compute the XOR
539537
* of the two function addresses:
540538
*/
541-
. = ASSERT(((ABSOLUTE(srso_untrain_ret_alias) | srso_safe_ret_alias) -
542-
(ABSOLUTE(srso_untrain_ret_alias) & srso_safe_ret_alias)) == ((1 << 2) | (1 << 8) | (1 << 14) | (1 << 20)),
539+
. = ASSERT(((ABSOLUTE(srso_alias_untrain_ret) | srso_alias_safe_ret) -
540+
(ABSOLUTE(srso_alias_untrain_ret) & srso_alias_safe_ret)) == ((1 << 2) | (1 << 8) | (1 << 14) | (1 << 20)),
543541
"SRSO function pair won't alias");
544542
#endif
545543

0 commit comments

Comments
 (0)