History

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.

Peter Zijlstra committed 4 years ago

Commit 2dbb8871 parent caa0ff24 files · +111 −10Browse files

Unified · Split

4 files
  1. arch/x86/entry/calling.h +58 −0
  2. arch/x86/entry/entry_64.S +39 −5
  3. arch/x86/entry/entry_64_compat.S +13 −4
  4. arch/x86/include/asm/cpufeatures.h +1 −1
arch/x86/entry/calling.h+58−0
@@ -7,6 +7,8 @@ · 6 unmodified lines
7#include <asm/asm-offsets.h>7#include <asm/asm-offsets.h>
8#include <asm/processor-flags.h>8#include <asm/processor-flags.h>
9#include <asm/ptrace-abi.h>9#include <asm/ptrace-abi.h>
10#include <asm/msr.h>
11#include <asm/nospec-branch.h>
10 12
11/*13/*
12 14
@@ -282,6 +284,62 @@ For 32-bit we have the following conventions - kernel is built with · 269 unmodified lines
282 284
283#endif285#endif
284 286
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
285/*343/*
286 * Mitigate Spectre v1 for conditional swapgs code paths.344 * Mitigate Spectre v1 for conditional swapgs code paths.
287 *345 *
arch/x86/entry/entry_64.S+39−5
@@ -96,7 +96,6 @@ SYM_CODE_START(entry_SYSCALL_64) · 95 unmodified lines
96 96
97SYM_INNER_LABEL(entry_SYSCALL_64_safe_stack, SYM_L_GLOBAL)97SYM_INNER_LABEL(entry_SYSCALL_64_safe_stack, SYM_L_GLOBAL)
98 ANNOTATE_NOENDBR98 ANNOTATE_NOENDBR
99 UNTRAIN_RET
100 99
101 /* Construct struct pt_regs on stack */100 /* Construct struct pt_regs on stack */
102 pushq $__USER_DS /* pt_regs->ss */101 pushq $__USER_DS /* pt_regs->ss */
@@ -113,6 +112,11 @@ SYM_INNER_LABEL(entry_SYSCALL_64_after_hwframe, SYM_L_GLOBAL) · 10 unmodified lines
113 movq %rsp, %rdi112 movq %rsp, %rdi
114 /* Sign extend the lower 32bit as syscall numbers are treated as int */113 /* Sign extend the lower 32bit as syscall numbers are treated as int */
115 movslq %eax, %rsi114 movslq %eax, %rsi
115
116 /* clobbers %rax, make sure it is after saving the syscall nr */
117 IBRS_ENTER
118 UNTRAIN_RET
119
116 call do_syscall_64 /* returns with IRQs disabled */120 call do_syscall_64 /* returns with IRQs disabled */
117 121
118 /*122 /*
@@ -192,6 +196,7 @@ SYM_INNER_LABEL(entry_SYSCALL_64_after_hwframe, SYM_L_GLOBAL) · 73 unmodified lines
192 * perf profiles. Nothing jumps here.196 * perf profiles. Nothing jumps here.
193 */197 */
194syscall_return_via_sysret:198syscall_return_via_sysret:
199 IBRS_EXIT
195 POP_REGS pop_rdi=0200 POP_REGS pop_rdi=0
196 201
197 /*202 /*
@@ -605,6 +610,7 @@ __irqentry_text_end: · 407 unmodified lines
605 610
606SYM_CODE_START_LOCAL(common_interrupt_return)611SYM_CODE_START_LOCAL(common_interrupt_return)
607SYM_INNER_LABEL(swapgs_restore_regs_and_return_to_usermode, SYM_L_GLOBAL)612SYM_INNER_LABEL(swapgs_restore_regs_and_return_to_usermode, SYM_L_GLOBAL)
613 IBRS_EXIT
608#ifdef CONFIG_DEBUG_ENTRY614#ifdef CONFIG_DEBUG_ENTRY
609 /* Assert that pt_regs indicates user mode. */615 /* Assert that pt_regs indicates user mode. */
610 testb $3, CS(%rsp)616 testb $3, CS(%rsp)
@@ -891,6 +897,9 @@ SYM_CODE_END(xen_failsafe_callback) · 280 unmodified lines
891 * 1 -> no SWAPGS on exit897 * 1 -> no SWAPGS on exit
892 *898 *
893 * Y GSBASE value at entry, must be restored in paranoid_exit899 * Y GSBASE value at entry, must be restored in paranoid_exit
900 *
901 * R14 - old CR3
902 * R15 - old SPEC_CTRL
894 */903 */
895SYM_CODE_START_LOCAL(paranoid_entry)904SYM_CODE_START_LOCAL(paranoid_entry)
896 UNWIND_HINT_FUNC905 UNWIND_HINT_FUNC
@@ -913,7 +922,6 @@ SYM_CODE_START_LOCAL(paranoid_entry) · 16 unmodified lines
913 * be retrieved from a kernel internal table.922 * be retrieved from a kernel internal table.
914 */923 */
915 SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg=%rax save_reg=%r14924 SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg=%rax save_reg=%r14
916 UNTRAIN_RET
917 925
918 /*926 /*
919 * Handling GSBASE depends on the availability of FSGSBASE.927 * Handling GSBASE depends on the availability of FSGSBASE.
@@ -935,7 +943,7 @@ SYM_CODE_START_LOCAL(paranoid_entry) · 15 unmodified lines
935 * is needed here.943 * is needed here.
936 */944 */
937 SAVE_AND_SET_GSBASE scratch_reg=%rax save_reg=%rbx945 SAVE_AND_SET_GSBASE scratch_reg=%rax save_reg=%rbx
938 RET946 jmp .Lparanoid_gsbase_done
939 947
940.Lparanoid_entry_checkgs:948.Lparanoid_entry_checkgs:
941 /* EBX = 1 -> kernel GSBASE active, no restore required */949 /* EBX = 1 -> kernel GSBASE active, no restore required */
@@ -954,8 +962,16 @@ SYM_CODE_START_LOCAL(paranoid_entry) · 12 unmodified lines
954 xorl %ebx, %ebx962 xorl %ebx, %ebx
955 swapgs963 swapgs
956.Lparanoid_kernel_gsbase:964.Lparanoid_kernel_gsbase:
957
958 FENCE_SWAPGS_KERNEL_ENTRY965 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
959 RET975 RET
960SYM_CODE_END(paranoid_entry)976SYM_CODE_END(paranoid_entry)
961 977
@@ -977,9 +993,19 @@ SYM_CODE_END(paranoid_entry) · 15 unmodified lines
977 * 1 -> no SWAPGS on exit993 * 1 -> no SWAPGS on exit
978 *994 *
979 * Y User space GSBASE, must be restored unconditionally995 * Y User space GSBASE, must be restored unconditionally
996 *
997 * R14 - old CR3
998 * R15 - old SPEC_CTRL
980 */999 */
981SYM_CODE_START_LOCAL(paranoid_exit)1000SYM_CODE_START_LOCAL(paranoid_exit)
982 UNWIND_HINT_REGS1001 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
983 /*1009 /*
984 * The order of operations is important. RESTORE_CR3 requires1010 * The order of operations is important. RESTORE_CR3 requires
985 * kernel GSBASE.1011 * kernel GSBASE.
@@ -1023,10 +1049,12 @@ SYM_CODE_START_LOCAL(error_entry) · 37 unmodified lines
1023 FENCE_SWAPGS_USER_ENTRY1049 FENCE_SWAPGS_USER_ENTRY
1024 /* We have user CR3. Change to kernel CR3. */1050 /* We have user CR3. Change to kernel CR3. */
1025 SWITCH_TO_KERNEL_CR3 scratch_reg=%rax1051 SWITCH_TO_KERNEL_CR3 scratch_reg=%rax
1052 IBRS_ENTER
1026 UNTRAIN_RET1053 UNTRAIN_RET
1027 1054
1028 leaq 8(%rsp), %rdi /* arg0 = pt_regs pointer */1055 leaq 8(%rsp), %rdi /* arg0 = pt_regs pointer */
1029.Lerror_entry_from_usermode_after_swapgs:1056.Lerror_entry_from_usermode_after_swapgs:
1057
1030 /* Put us onto the real thread stack. */1058 /* Put us onto the real thread stack. */
1031 call sync_regs1059 call sync_regs
1032 RET1060 RET
@@ -1076,6 +1104,7 @@ SYM_CODE_START_LOCAL(error_entry) · 43 unmodified lines
1076 swapgs1104 swapgs
1077 FENCE_SWAPGS_USER_ENTRY1105 FENCE_SWAPGS_USER_ENTRY
1078 SWITCH_TO_KERNEL_CR3 scratch_reg=%rax1106 SWITCH_TO_KERNEL_CR3 scratch_reg=%rax
1107 IBRS_ENTER
1079 UNTRAIN_RET1108 UNTRAIN_RET
1080 1109
1081 /*1110 /*
@@ -1172,7 +1201,6 @@ SYM_CODE_START(asm_exc_nmi) · 90 unmodified lines
1172 movq %rsp, %rdx1201 movq %rsp, %rdx
1173 movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp1202 movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
1174 UNWIND_HINT_IRET_REGS base=%rdx offset=81203 UNWIND_HINT_IRET_REGS base=%rdx offset=8
1175 UNTRAIN_RET
1176 pushq 5*8(%rdx) /* pt_regs->ss */1204 pushq 5*8(%rdx) /* pt_regs->ss */
1177 pushq 4*8(%rdx) /* pt_regs->rsp */1205 pushq 4*8(%rdx) /* pt_regs->rsp */
1178 pushq 3*8(%rdx) /* pt_regs->flags */1206 pushq 3*8(%rdx) /* pt_regs->flags */
@@ -1183,6 +1211,9 @@ SYM_CODE_START(asm_exc_nmi) · 4 unmodified lines
1183 PUSH_AND_CLEAR_REGS rdx=(%rdx)1211 PUSH_AND_CLEAR_REGS rdx=(%rdx)
1184 ENCODE_FRAME_POINTER1212 ENCODE_FRAME_POINTER
1185 1213
1214 IBRS_ENTER
1215 UNTRAIN_RET
1216
1186 /*1217 /*
1187 * At this point we no longer need to worry about stack damage1218 * At this point we no longer need to worry about stack damage
1188 * due to nesting -- we're on the normal thread stack and we're1219 * due to nesting -- we're on the normal thread stack and we're
@@ -1407,6 +1438,9 @@ end_repeat_nmi: · 218 unmodified lines
1407 movq $-1, %rsi1438 movq $-1, %rsi
1408 call exc_nmi1439 call exc_nmi
1409 1440
1441 /* Always restore stashed SPEC_CTRL value (see paranoid_entry) */
1442 IBRS_EXIT save_reg=%r15
1443
1410 /* Always restore stashed CR3 value (see paranoid_entry) */1444 /* Always restore stashed CR3 value (see paranoid_entry) */
1411 RESTORE_CR3 scratch_reg=%r15 save_reg=%r141445 RESTORE_CR3 scratch_reg=%r15 save_reg=%r14
1412 1446
arch/x86/entry/entry_64_compat.S+13−4
@@ -4,7 +4,6 @@ · 3 unmodified lines
4 *4 *
5 * Copyright 2000-2002 Andi Kleen, SuSE Labs.5 * Copyright 2000-2002 Andi Kleen, SuSE Labs.
6 */6 */
7#include "calling.h"
8#include <asm/asm-offsets.h>7#include <asm/asm-offsets.h>
9#include <asm/current.h>8#include <asm/current.h>
10#include <asm/errno.h>9#include <asm/errno.h>
@@ -18,6 +17,8 @@ · 7 unmodified lines
18#include <linux/linkage.h>17#include <linux/linkage.h>
19#include <linux/err.h>18#include <linux/err.h>
20 19
20#include "calling.h"
21
21 .section .entry.text, "ax"22 .section .entry.text, "ax"
22 23
23/*24/*
@@ -73,7 +74,6 @@ SYM_CODE_START(entry_SYSENTER_compat) · 49 unmodified lines
73 pushq $__USER32_CS /* pt_regs->cs */74 pushq $__USER32_CS /* pt_regs->cs */
74 pushq $0 /* pt_regs->ip = 0 (placeholder) */75 pushq $0 /* pt_regs->ip = 0 (placeholder) */
75SYM_INNER_LABEL(entry_SYSENTER_compat_after_hwframe, SYM_L_GLOBAL)76SYM_INNER_LABEL(entry_SYSENTER_compat_after_hwframe, SYM_L_GLOBAL)
76 UNTRAIN_RET
77 77
78 /*78 /*
79 * User tracing code (ptrace or signal handlers) might assume that79 * 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) · 10 unmodified lines
90 90
91 cld91 cld
92 92
93 IBRS_ENTER
94 UNTRAIN_RET
95
93 /*96 /*
94 * SYSENTER doesn't filter flags, so we need to clear NT and AC97 * SYSENTER doesn't filter flags, so we need to clear NT and AC
95 * ourselves. To save a few cycles, we can check whether98 * ourselves. To save a few cycles, we can check whether
@@ -192,7 +195,6 @@ SYM_CODE_START(entry_SYSCALL_compat) · 96 unmodified lines
192 195
193SYM_INNER_LABEL(entry_SYSCALL_compat_safe_stack, SYM_L_GLOBAL)196SYM_INNER_LABEL(entry_SYSCALL_compat_safe_stack, SYM_L_GLOBAL)
194 ANNOTATE_NOENDBR197 ANNOTATE_NOENDBR
195 UNTRAIN_RET
196 198
197 /* Construct struct pt_regs on stack */199 /* Construct struct pt_regs on stack */
198 pushq $__USER32_DS /* pt_regs->ss */200 pushq $__USER32_DS /* pt_regs->ss */
@@ -206,6 +208,9 @@ SYM_INNER_LABEL(entry_SYSCALL_compat_after_hwframe, SYM_L_GLOBAL) · 7 unmodified lines
206 PUSH_AND_CLEAR_REGS rcx=%rbp rax=$-ENOSYS208 PUSH_AND_CLEAR_REGS rcx=%rbp rax=$-ENOSYS
207 UNWIND_HINT_REGS209 UNWIND_HINT_REGS
208 210
211 IBRS_ENTER
212 UNTRAIN_RET
213
209 movq %rsp, %rdi214 movq %rsp, %rdi
210 call do_fast_syscall_32215 call do_fast_syscall_32
211 /* XEN PV guests always use IRET path */216 /* XEN PV guests always use IRET path */
@@ -220,6 +225,8 @@ sysret32_from_system_call: · 8 unmodified lines
220 */225 */
221 STACKLEAK_ERASE226 STACKLEAK_ERASE
222 227
228 IBRS_EXIT
229
223 movq RBX(%rsp), %rbx /* pt_regs->rbx */230 movq RBX(%rsp), %rbx /* pt_regs->rbx */
224 movq RBP(%rsp), %rbp /* pt_regs->rbp */231 movq RBP(%rsp), %rbp /* pt_regs->rbp */
225 movq EFLAGS(%rsp), %r11 /* pt_regs->flags (in r11) */232 movq EFLAGS(%rsp), %r11 /* pt_regs->flags (in r11) */
@@ -335,12 +342,14 @@ SYM_CODE_START(entry_INT80_compat) · 109 unmodified lines
335 pushq 0*8(%rax) /* regs->orig_ax */342 pushq 0*8(%rax) /* regs->orig_ax */
336.Lint80_keep_stack:343.Lint80_keep_stack:
337 344
338 UNTRAIN_RET
339 PUSH_AND_CLEAR_REGS rax=$-ENOSYS345 PUSH_AND_CLEAR_REGS rax=$-ENOSYS
340 UNWIND_HINT_REGS346 UNWIND_HINT_REGS
341 347
342 cld348 cld
343 349
350 IBRS_ENTER
351 UNTRAIN_RET
352
344 movq %rsp, %rdi353 movq %rsp, %rdi
345 call do_int80_syscall_32354 call do_int80_syscall_32
346 jmp swapgs_restore_regs_and_return_to_usermode355 jmp swapgs_restore_regs_and_return_to_usermode
arch/x86/include/asm/cpufeatures.h+1−1
@@ -203,7 +203,7 @@ · 202 unmodified lines
203#define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */203#define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */
204#define X86_FEATURE_XCOMPACTED ( 7*32+10) /* "" Use compacted XSTATE (XSAVES or XSAVEC) */204#define X86_FEATURE_XCOMPACTED ( 7*32+10) /* "" Use compacted XSTATE (XSAVES or XSAVEC) */
205#define X86_FEATURE_PTI ( 7*32+11) /* Kernel Page Table Isolation enabled */205#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 */
207/* FREE! ( 7*32+13) */207/* FREE! ( 7*32+13) */
208#define X86_FEATURE_INTEL_PPIN ( 7*32+14) /* Intel Processor Inventory Number */208#define X86_FEATURE_INTEL_PPIN ( 7*32+14) /* Intel Processor Inventory Number */
209#define X86_FEATURE_CDP_L2 ( 7*32+15) /* Code and Data Prioritization L2 */209#define X86_FEATURE_CDP_L2 ( 7*32+15) /* Code and Data Prioritization L2 */