diff options
Diffstat (limited to 'arch/x86/include/asm/nospec-branch.h')
-rw-r--r-- | arch/x86/include/asm/nospec-branch.h | 143 |
1 files changed, 122 insertions, 21 deletions
diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index 81a1be326571..f928ad9b143f 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h | |||
@@ -8,6 +8,50 @@ | |||
8 | #include <asm/cpufeatures.h> | 8 | #include <asm/cpufeatures.h> |
9 | #include <asm/msr-index.h> | 9 | #include <asm/msr-index.h> |
10 | 10 | ||
11 | /* | ||
12 | * Fill the CPU return stack buffer. | ||
13 | * | ||
14 | * Each entry in the RSB, if used for a speculative 'ret', contains an | ||
15 | * infinite 'pause; lfence; jmp' loop to capture speculative execution. | ||
16 | * | ||
17 | * This is required in various cases for retpoline and IBRS-based | ||
18 | * mitigations for the Spectre variant 2 vulnerability. Sometimes to | ||
19 | * eliminate potentially bogus entries from the RSB, and sometimes | ||
20 | * purely to ensure that it doesn't get empty, which on some CPUs would | ||
21 | * allow predictions from other (unwanted!) sources to be used. | ||
22 | * | ||
23 | * We define a CPP macro such that it can be used from both .S files and | ||
24 | * inline assembly. It's possible to do a .macro and then include that | ||
25 | * from C via asm(".include <asm/nospec-branch.h>") but let's not go there. | ||
26 | */ | ||
27 | |||
28 | #define RSB_CLEAR_LOOPS 32 /* To forcibly overwrite all entries */ | ||
29 | #define RSB_FILL_LOOPS 16 /* To avoid underflow */ | ||
30 | |||
31 | /* | ||
32 | * Google experimented with loop-unrolling and this turned out to be | ||
33 | * the optimal version — two calls, each with their own speculation | ||
34 | * trap should their return address end up getting used, in a loop. | ||
35 | */ | ||
36 | #define __FILL_RETURN_BUFFER(reg, nr, sp) \ | ||
37 | mov $(nr/2), reg; \ | ||
38 | 771: \ | ||
39 | call 772f; \ | ||
40 | 773: /* speculation trap */ \ | ||
41 | pause; \ | ||
42 | lfence; \ | ||
43 | jmp 773b; \ | ||
44 | 772: \ | ||
45 | call 774f; \ | ||
46 | 775: /* speculation trap */ \ | ||
47 | pause; \ | ||
48 | lfence; \ | ||
49 | jmp 775b; \ | ||
50 | 774: \ | ||
51 | dec reg; \ | ||
52 | jnz 771b; \ | ||
53 | add $(BITS_PER_LONG/8) * nr, sp; | ||
54 | |||
11 | #ifdef __ASSEMBLY__ | 55 | #ifdef __ASSEMBLY__ |
12 | 56 | ||
13 | /* | 57 | /* |
@@ -24,6 +68,18 @@ | |||
24 | .endm | 68 | .endm |
25 | 69 | ||
26 | /* | 70 | /* |
71 | * This should be used immediately before an indirect jump/call. It tells | ||
72 | * objtool the subsequent indirect jump/call is vouched safe for retpoline | ||
73 | * builds. | ||
74 | */ | ||
75 | .macro ANNOTATE_RETPOLINE_SAFE | ||
76 | .Lannotate_\@: | ||
77 | .pushsection .discard.retpoline_safe | ||
78 | _ASM_PTR .Lannotate_\@ | ||
79 | .popsection | ||
80 | .endm | ||
81 | |||
82 | /* | ||
27 | * These are the bare retpoline primitives for indirect jmp and call. | 83 | * These are the bare retpoline primitives for indirect jmp and call. |
28 | * Do not use these directly; they only exist to make the ALTERNATIVE | 84 | * Do not use these directly; they only exist to make the ALTERNATIVE |
29 | * invocation below less ugly. | 85 | * invocation below less ugly. |
@@ -59,9 +115,9 @@ | |||
59 | .macro JMP_NOSPEC reg:req | 115 | .macro JMP_NOSPEC reg:req |
60 | #ifdef CONFIG_RETPOLINE | 116 | #ifdef CONFIG_RETPOLINE |
61 | ANNOTATE_NOSPEC_ALTERNATIVE | 117 | ANNOTATE_NOSPEC_ALTERNATIVE |
62 | ALTERNATIVE_2 __stringify(jmp *\reg), \ | 118 | ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; jmp *\reg), \ |
63 | __stringify(RETPOLINE_JMP \reg), X86_FEATURE_RETPOLINE, \ | 119 | __stringify(RETPOLINE_JMP \reg), X86_FEATURE_RETPOLINE, \ |
64 | __stringify(lfence; jmp *\reg), X86_FEATURE_RETPOLINE_AMD | 120 | __stringify(lfence; ANNOTATE_RETPOLINE_SAFE; jmp *\reg), X86_FEATURE_RETPOLINE_AMD |
65 | #else | 121 | #else |
66 | jmp *\reg | 122 | jmp *\reg |
67 | #endif | 123 | #endif |
@@ -70,18 +126,25 @@ | |||
70 | .macro CALL_NOSPEC reg:req | 126 | .macro CALL_NOSPEC reg:req |
71 | #ifdef CONFIG_RETPOLINE | 127 | #ifdef CONFIG_RETPOLINE |
72 | ANNOTATE_NOSPEC_ALTERNATIVE | 128 | ANNOTATE_NOSPEC_ALTERNATIVE |
73 | ALTERNATIVE_2 __stringify(call *\reg), \ | 129 | ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; call *\reg), \ |
74 | __stringify(RETPOLINE_CALL \reg), X86_FEATURE_RETPOLINE,\ | 130 | __stringify(RETPOLINE_CALL \reg), X86_FEATURE_RETPOLINE,\ |
75 | __stringify(lfence; call *\reg), X86_FEATURE_RETPOLINE_AMD | 131 | __stringify(lfence; ANNOTATE_RETPOLINE_SAFE; call *\reg), X86_FEATURE_RETPOLINE_AMD |
76 | #else | 132 | #else |
77 | call *\reg | 133 | call *\reg |
78 | #endif | 134 | #endif |
79 | .endm | 135 | .endm |
80 | 136 | ||
81 | /* This clobbers the BX register */ | 137 | /* |
82 | .macro FILL_RETURN_BUFFER nr:req ftr:req | 138 | * A simpler FILL_RETURN_BUFFER macro. Don't make people use the CPP |
139 | * monstrosity above, manually. | ||
140 | */ | ||
141 | .macro FILL_RETURN_BUFFER reg:req nr:req ftr:req | ||
83 | #ifdef CONFIG_RETPOLINE | 142 | #ifdef CONFIG_RETPOLINE |
84 | ALTERNATIVE "", "call __clear_rsb", \ftr | 143 | ANNOTATE_NOSPEC_ALTERNATIVE |
144 | ALTERNATIVE "jmp .Lskip_rsb_\@", \ | ||
145 | __stringify(__FILL_RETURN_BUFFER(\reg,\nr,%_ASM_SP)) \ | ||
146 | \ftr | ||
147 | .Lskip_rsb_\@: | ||
85 | #endif | 148 | #endif |
86 | .endm | 149 | .endm |
87 | 150 | ||
@@ -93,6 +156,12 @@ | |||
93 | ".long 999b - .\n\t" \ | 156 | ".long 999b - .\n\t" \ |
94 | ".popsection\n\t" | 157 | ".popsection\n\t" |
95 | 158 | ||
159 | #define ANNOTATE_RETPOLINE_SAFE \ | ||
160 | "999:\n\t" \ | ||
161 | ".pushsection .discard.retpoline_safe\n\t" \ | ||
162 | _ASM_PTR " 999b\n\t" \ | ||
163 | ".popsection\n\t" | ||
164 | |||
96 | #if defined(CONFIG_X86_64) && defined(RETPOLINE) | 165 | #if defined(CONFIG_X86_64) && defined(RETPOLINE) |
97 | 166 | ||
98 | /* | 167 | /* |
@@ -102,6 +171,7 @@ | |||
102 | # define CALL_NOSPEC \ | 171 | # define CALL_NOSPEC \ |
103 | ANNOTATE_NOSPEC_ALTERNATIVE \ | 172 | ANNOTATE_NOSPEC_ALTERNATIVE \ |
104 | ALTERNATIVE( \ | 173 | ALTERNATIVE( \ |
174 | ANNOTATE_RETPOLINE_SAFE \ | ||
105 | "call *%[thunk_target]\n", \ | 175 | "call *%[thunk_target]\n", \ |
106 | "call __x86_indirect_thunk_%V[thunk_target]\n", \ | 176 | "call __x86_indirect_thunk_%V[thunk_target]\n", \ |
107 | X86_FEATURE_RETPOLINE) | 177 | X86_FEATURE_RETPOLINE) |
@@ -113,7 +183,10 @@ | |||
113 | * otherwise we'll run out of registers. We don't care about CET | 183 | * otherwise we'll run out of registers. We don't care about CET |
114 | * here, anyway. | 184 | * here, anyway. |
115 | */ | 185 | */ |
116 | # define CALL_NOSPEC ALTERNATIVE("call *%[thunk_target]\n", \ | 186 | # define CALL_NOSPEC \ |
187 | ALTERNATIVE( \ | ||
188 | ANNOTATE_RETPOLINE_SAFE \ | ||
189 | "call *%[thunk_target]\n", \ | ||
117 | " jmp 904f;\n" \ | 190 | " jmp 904f;\n" \ |
118 | " .align 16\n" \ | 191 | " .align 16\n" \ |
119 | "901: call 903f;\n" \ | 192 | "901: call 903f;\n" \ |
@@ -156,26 +229,54 @@ extern char __indirect_thunk_end[]; | |||
156 | static inline void vmexit_fill_RSB(void) | 229 | static inline void vmexit_fill_RSB(void) |
157 | { | 230 | { |
158 | #ifdef CONFIG_RETPOLINE | 231 | #ifdef CONFIG_RETPOLINE |
159 | alternative_input("", | 232 | unsigned long loops; |
160 | "call __fill_rsb", | 233 | |
161 | X86_FEATURE_RETPOLINE, | 234 | asm volatile (ANNOTATE_NOSPEC_ALTERNATIVE |
162 | ASM_NO_INPUT_CLOBBER(_ASM_BX, "memory")); | 235 | ALTERNATIVE("jmp 910f", |
236 | __stringify(__FILL_RETURN_BUFFER(%0, RSB_CLEAR_LOOPS, %1)), | ||
237 | X86_FEATURE_RETPOLINE) | ||
238 | "910:" | ||
239 | : "=r" (loops), ASM_CALL_CONSTRAINT | ||
240 | : : "memory" ); | ||
163 | #endif | 241 | #endif |
164 | } | 242 | } |
165 | 243 | ||
244 | #define alternative_msr_write(_msr, _val, _feature) \ | ||
245 | asm volatile(ALTERNATIVE("", \ | ||
246 | "movl %[msr], %%ecx\n\t" \ | ||
247 | "movl %[val], %%eax\n\t" \ | ||
248 | "movl $0, %%edx\n\t" \ | ||
249 | "wrmsr", \ | ||
250 | _feature) \ | ||
251 | : : [msr] "i" (_msr), [val] "i" (_val) \ | ||
252 | : "eax", "ecx", "edx", "memory") | ||
253 | |||
166 | static inline void indirect_branch_prediction_barrier(void) | 254 | static inline void indirect_branch_prediction_barrier(void) |
167 | { | 255 | { |
168 | asm volatile(ALTERNATIVE("", | 256 | alternative_msr_write(MSR_IA32_PRED_CMD, PRED_CMD_IBPB, |
169 | "movl %[msr], %%ecx\n\t" | 257 | X86_FEATURE_USE_IBPB); |
170 | "movl %[val], %%eax\n\t" | ||
171 | "movl $0, %%edx\n\t" | ||
172 | "wrmsr", | ||
173 | X86_FEATURE_USE_IBPB) | ||
174 | : : [msr] "i" (MSR_IA32_PRED_CMD), | ||
175 | [val] "i" (PRED_CMD_IBPB) | ||
176 | : "eax", "ecx", "edx", "memory"); | ||
177 | } | 258 | } |
178 | 259 | ||
260 | /* | ||
261 | * With retpoline, we must use IBRS to restrict branch prediction | ||
262 | * before calling into firmware. | ||
263 | * | ||
264 | * (Implemented as CPP macros due to header hell.) | ||
265 | */ | ||
266 | #define firmware_restrict_branch_speculation_start() \ | ||
267 | do { \ | ||
268 | preempt_disable(); \ | ||
269 | alternative_msr_write(MSR_IA32_SPEC_CTRL, SPEC_CTRL_IBRS, \ | ||
270 | X86_FEATURE_USE_IBRS_FW); \ | ||
271 | } while (0) | ||
272 | |||
273 | #define firmware_restrict_branch_speculation_end() \ | ||
274 | do { \ | ||
275 | alternative_msr_write(MSR_IA32_SPEC_CTRL, 0, \ | ||
276 | X86_FEATURE_USE_IBRS_FW); \ | ||
277 | preempt_enable(); \ | ||
278 | } while (0) | ||
279 | |||
179 | #endif /* __ASSEMBLY__ */ | 280 | #endif /* __ASSEMBLY__ */ |
180 | 281 | ||
181 | /* | 282 | /* |