Skip to content

Commit 2dbb887

Browse files
Peter Zijlstrasuryasaimadhu
authored andcommitted
x86/entry: Add kernel IBRS implementation
Implement Kernel IBRS - currently the only known option to mitigate RSB underflow speculation issues on Skylake hardware. Note: since IBRS_ENTER requires fuller context established than UNTRAIN_RET, it must be placed after it. However, since UNTRAIN_RET itself implies a RET, it must come after IBRS_ENTER. This means IBRS_ENTER needs to also move UNTRAIN_RET. Note 2: KERNEL_IBRS is sub-optimal for XenPV. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Borislav Petkov <bp@suse.de> Reviewed-by: Josh Poimboeuf <jpoimboe@kernel.org> Signed-off-by: Borislav Petkov <bp@suse.de>
1 parent caa0ff2 commit 2dbb887

4 files changed

Lines changed: 111 additions & 10 deletions

File tree

arch/x86/entry/calling.h

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#include <asm/asm-offsets.h>
88
#include <asm/processor-flags.h>
99
#include <asm/ptrace-abi.h>
10+
#include <asm/msr.h>
11+
#include <asm/nospec-branch.h>
1012

1113
/*
1214
@@ -282,6 +284,62 @@ For 32-bit we have the following conventions - kernel is built with
282284

283285
#endif
284286

287+
/*
288+
* IBRS kernel mitigation for Spectre_v2.
289+
*
290+
* Assumes full context is established (PUSH_REGS, CR3 and GS) and it clobbers
291+
* the regs it uses (AX, CX, DX). Must be called before the first RET
292+
* instruction (NOTE! UNTRAIN_RET includes a RET instruction)
293+
*
294+
* The optional argument is used to save/restore the current value,
295+
* which is used on the paranoid paths.
296+
*
297+
* Assumes x86_spec_ctrl_{base,current} to have SPEC_CTRL_IBRS set.
298+
*/
299+
.macro IBRS_ENTER save_reg
300+
ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_KERNEL_IBRS
301+
movl $MSR_IA32_SPEC_CTRL, %ecx
302+
303+
.ifnb \save_reg
304+
rdmsr
305+
shl $32, %rdx
306+
or %rdx, %rax
307+
mov %rax, \save_reg
308+
test $SPEC_CTRL_IBRS, %eax
309+
jz .Ldo_wrmsr_\@
310+
lfence
311+
jmp .Lend_\@
312+
.Ldo_wrmsr_\@:
313+
.endif
314+
315+
movq PER_CPU_VAR(x86_spec_ctrl_current), %rdx
316+
movl %edx, %eax
317+
shr $32, %rdx
318+
wrmsr
319+
.Lend_\@:
320+
.endm
321+
322+
/*
323+
* Similar to IBRS_ENTER, requires KERNEL GS,CR3 and clobbers (AX, CX, DX)
324+
* regs. Must be called after the last RET.
325+
*/
326+
.macro IBRS_EXIT save_reg
327+
ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_KERNEL_IBRS
328+
movl $MSR_IA32_SPEC_CTRL, %ecx
329+
330+
.ifnb \save_reg
331+
mov \save_reg, %rdx
332+
.else
333+
movq PER_CPU_VAR(x86_spec_ctrl_current), %rdx
334+
andl $(~SPEC_CTRL_IBRS), %edx
335+
.endif
336+
337+
movl %edx, %eax
338+
shr $32, %rdx
339+
wrmsr
340+
.Lend_\@:
341+
.endm
342+
285343
/*
286344
* Mitigate Spectre v1 for conditional swapgs code paths.
287345
*

arch/x86/entry/entry_64.S

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ SYM_CODE_START(entry_SYSCALL_64)
9696

9797
SYM_INNER_LABEL(entry_SYSCALL_64_safe_stack, SYM_L_GLOBAL)
9898
ANNOTATE_NOENDBR
99-
UNTRAIN_RET
10099

101100
/* Construct struct pt_regs on stack */
102101
pushq $__USER_DS /* pt_regs->ss */
@@ -113,6 +112,11 @@ SYM_INNER_LABEL(entry_SYSCALL_64_after_hwframe, SYM_L_GLOBAL)
113112
movq %rsp, %rdi
114113
/* Sign extend the lower 32bit as syscall numbers are treated as int */
115114
movslq %eax, %rsi
115+
116+
/* clobbers %rax, make sure it is after saving the syscall nr */
117+
IBRS_ENTER
118+
UNTRAIN_RET
119+
116120
call do_syscall_64 /* returns with IRQs disabled */
117121

118122
/*
@@ -192,6 +196,7 @@ SYM_INNER_LABEL(entry_SYSCALL_64_after_hwframe, SYM_L_GLOBAL)
192196
* perf profiles. Nothing jumps here.
193197
*/
194198
syscall_return_via_sysret:
199+
IBRS_EXIT
195200
POP_REGS pop_rdi=0
196201

197202
/*
@@ -605,6 +610,7 @@ __irqentry_text_end:
605610

606611
SYM_CODE_START_LOCAL(common_interrupt_return)
607612
SYM_INNER_LABEL(swapgs_restore_regs_and_return_to_usermode, SYM_L_GLOBAL)
613+
IBRS_EXIT
608614
#ifdef CONFIG_DEBUG_ENTRY
609615
/* Assert that pt_regs indicates user mode. */
610616
testb $3, CS(%rsp)
@@ -891,6 +897,9 @@ SYM_CODE_END(xen_failsafe_callback)
891897
* 1 -> no SWAPGS on exit
892898
*
893899
* Y GSBASE value at entry, must be restored in paranoid_exit
900+
*
901+
* R14 - old CR3
902+
* R15 - old SPEC_CTRL
894903
*/
895904
SYM_CODE_START_LOCAL(paranoid_entry)
896905
UNWIND_HINT_FUNC
@@ -913,7 +922,6 @@ SYM_CODE_START_LOCAL(paranoid_entry)
913922
* be retrieved from a kernel internal table.
914923
*/
915924
SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg=%rax save_reg=%r14
916-
UNTRAIN_RET
917925

918926
/*
919927
* Handling GSBASE depends on the availability of FSGSBASE.
@@ -935,7 +943,7 @@ SYM_CODE_START_LOCAL(paranoid_entry)
935943
* is needed here.
936944
*/
937945
SAVE_AND_SET_GSBASE scratch_reg=%rax save_reg=%rbx
938-
RET
946+
jmp .Lparanoid_gsbase_done
939947

940948
.Lparanoid_entry_checkgs:
941949
/* EBX = 1 -> kernel GSBASE active, no restore required */
@@ -954,8 +962,16 @@ SYM_CODE_START_LOCAL(paranoid_entry)
954962
xorl %ebx, %ebx
955963
swapgs
956964
.Lparanoid_kernel_gsbase:
957-
958965
FENCE_SWAPGS_KERNEL_ENTRY
966+
.Lparanoid_gsbase_done:
967+
968+
/*
969+
* Once we have CR3 and %GS setup save and set SPEC_CTRL. Just like
970+
* CR3 above, keep the old value in a callee saved register.
971+
*/
972+
IBRS_ENTER save_reg=%r15
973+
UNTRAIN_RET
974+
959975
RET
960976
SYM_CODE_END(paranoid_entry)
961977

@@ -977,9 +993,19 @@ SYM_CODE_END(paranoid_entry)
977993
* 1 -> no SWAPGS on exit
978994
*
979995
* Y User space GSBASE, must be restored unconditionally
996+
*
997+
* R14 - old CR3
998+
* R15 - old SPEC_CTRL
980999
*/
9811000
SYM_CODE_START_LOCAL(paranoid_exit)
9821001
UNWIND_HINT_REGS
1002+
1003+
/*
1004+
* Must restore IBRS state before both CR3 and %GS since we need access
1005+
* to the per-CPU x86_spec_ctrl_shadow variable.
1006+
*/
1007+
IBRS_EXIT save_reg=%r15
1008+
9831009
/*
9841010
* The order of operations is important. RESTORE_CR3 requires
9851011
* kernel GSBASE.
@@ -1023,10 +1049,12 @@ SYM_CODE_START_LOCAL(error_entry)
10231049
FENCE_SWAPGS_USER_ENTRY
10241050
/* We have user CR3. Change to kernel CR3. */
10251051
SWITCH_TO_KERNEL_CR3 scratch_reg=%rax
1052+
IBRS_ENTER
10261053
UNTRAIN_RET
10271054

10281055
leaq 8(%rsp), %rdi /* arg0 = pt_regs pointer */
10291056
.Lerror_entry_from_usermode_after_swapgs:
1057+
10301058
/* Put us onto the real thread stack. */
10311059
call sync_regs
10321060
RET
@@ -1076,6 +1104,7 @@ SYM_CODE_START_LOCAL(error_entry)
10761104
swapgs
10771105
FENCE_SWAPGS_USER_ENTRY
10781106
SWITCH_TO_KERNEL_CR3 scratch_reg=%rax
1107+
IBRS_ENTER
10791108
UNTRAIN_RET
10801109

10811110
/*
@@ -1172,7 +1201,6 @@ SYM_CODE_START(asm_exc_nmi)
11721201
movq %rsp, %rdx
11731202
movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
11741203
UNWIND_HINT_IRET_REGS base=%rdx offset=8
1175-
UNTRAIN_RET
11761204
pushq 5*8(%rdx) /* pt_regs->ss */
11771205
pushq 4*8(%rdx) /* pt_regs->rsp */
11781206
pushq 3*8(%rdx) /* pt_regs->flags */
@@ -1183,6 +1211,9 @@ SYM_CODE_START(asm_exc_nmi)
11831211
PUSH_AND_CLEAR_REGS rdx=(%rdx)
11841212
ENCODE_FRAME_POINTER
11851213

1214+
IBRS_ENTER
1215+
UNTRAIN_RET
1216+
11861217
/*
11871218
* At this point we no longer need to worry about stack damage
11881219
* due to nesting -- we're on the normal thread stack and we're
@@ -1407,6 +1438,9 @@ end_repeat_nmi:
14071438
movq $-1, %rsi
14081439
call exc_nmi
14091440

1441+
/* Always restore stashed SPEC_CTRL value (see paranoid_entry) */
1442+
IBRS_EXIT save_reg=%r15
1443+
14101444
/* Always restore stashed CR3 value (see paranoid_entry) */
14111445
RESTORE_CR3 scratch_reg=%r15 save_reg=%r14
14121446

arch/x86/entry/entry_64_compat.S

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
*
55
* Copyright 2000-2002 Andi Kleen, SuSE Labs.
66
*/
7-
#include "calling.h"
87
#include <asm/asm-offsets.h>
98
#include <asm/current.h>
109
#include <asm/errno.h>
@@ -18,6 +17,8 @@
1817
#include <linux/linkage.h>
1918
#include <linux/err.h>
2019

20+
#include "calling.h"
21+
2122
.section .entry.text, "ax"
2223

2324
/*
@@ -73,7 +74,6 @@ SYM_CODE_START(entry_SYSENTER_compat)
7374
pushq $__USER32_CS /* pt_regs->cs */
7475
pushq $0 /* pt_regs->ip = 0 (placeholder) */
7576
SYM_INNER_LABEL(entry_SYSENTER_compat_after_hwframe, SYM_L_GLOBAL)
76-
UNTRAIN_RET
7777

7878
/*
7979
* User tracing code (ptrace or signal handlers) might assume that
@@ -90,6 +90,9 @@ SYM_INNER_LABEL(entry_SYSENTER_compat_after_hwframe, SYM_L_GLOBAL)
9090

9191
cld
9292

93+
IBRS_ENTER
94+
UNTRAIN_RET
95+
9396
/*
9497
* SYSENTER doesn't filter flags, so we need to clear NT and AC
9598
* ourselves. To save a few cycles, we can check whether
@@ -192,7 +195,6 @@ SYM_CODE_START(entry_SYSCALL_compat)
192195

193196
SYM_INNER_LABEL(entry_SYSCALL_compat_safe_stack, SYM_L_GLOBAL)
194197
ANNOTATE_NOENDBR
195-
UNTRAIN_RET
196198

197199
/* Construct struct pt_regs on stack */
198200
pushq $__USER32_DS /* pt_regs->ss */
@@ -206,6 +208,9 @@ SYM_INNER_LABEL(entry_SYSCALL_compat_after_hwframe, SYM_L_GLOBAL)
206208
PUSH_AND_CLEAR_REGS rcx=%rbp rax=$-ENOSYS
207209
UNWIND_HINT_REGS
208210

211+
IBRS_ENTER
212+
UNTRAIN_RET
213+
209214
movq %rsp, %rdi
210215
call do_fast_syscall_32
211216
/* XEN PV guests always use IRET path */
@@ -220,6 +225,8 @@ sysret32_from_system_call:
220225
*/
221226
STACKLEAK_ERASE
222227

228+
IBRS_EXIT
229+
223230
movq RBX(%rsp), %rbx /* pt_regs->rbx */
224231
movq RBP(%rsp), %rbp /* pt_regs->rbp */
225232
movq EFLAGS(%rsp), %r11 /* pt_regs->flags (in r11) */
@@ -335,12 +342,14 @@ SYM_CODE_START(entry_INT80_compat)
335342
pushq 0*8(%rax) /* regs->orig_ax */
336343
.Lint80_keep_stack:
337344

338-
UNTRAIN_RET
339345
PUSH_AND_CLEAR_REGS rax=$-ENOSYS
340346
UNWIND_HINT_REGS
341347

342348
cld
343349

350+
IBRS_ENTER
351+
UNTRAIN_RET
352+
344353
movq %rsp, %rdi
345354
call do_int80_syscall_32
346355
jmp swapgs_restore_regs_and_return_to_usermode

arch/x86/include/asm/cpufeatures.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@
203203
#define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */
204204
#define X86_FEATURE_XCOMPACTED ( 7*32+10) /* "" Use compacted XSTATE (XSAVES or XSAVEC) */
205205
#define X86_FEATURE_PTI ( 7*32+11) /* Kernel Page Table Isolation enabled */
206-
/* FREE! ( 7*32+12) */
206+
#define X86_FEATURE_KERNEL_IBRS ( 7*32+12) /* "" Set/clear IBRS on kernel entry/exit */
207207
/* FREE! ( 7*32+13) */
208208
#define X86_FEATURE_INTEL_PPIN ( 7*32+14) /* Intel Processor Inventory Number */
209209
#define X86_FEATURE_CDP_L2 ( 7*32+15) /* Code and Data Prioritization L2 */

0 commit comments

Comments
 (0)