aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/nospec-branch.h78
-rw-r--r--arch/x86/kvm/svm.c4
-rw-r--r--arch/x86/kvm/vmx.c4
3 files changed, 85 insertions, 1 deletions
diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h
index ea034fa6e261..402a11c803c3 100644
--- a/arch/x86/include/asm/nospec-branch.h
+++ b/arch/x86/include/asm/nospec-branch.h
@@ -7,6 +7,48 @@
7#include <asm/alternative-asm.h> 7#include <asm/alternative-asm.h>
8#include <asm/cpufeatures.h> 8#include <asm/cpufeatures.h>
9 9
10/*
11 * Fill the CPU return stack buffer.
12 *
13 * Each entry in the RSB, if used for a speculative 'ret', contains an
14 * infinite 'pause; jmp' loop to capture speculative execution.
15 *
16 * This is required in various cases for retpoline and IBRS-based
17 * mitigations for the Spectre variant 2 vulnerability. Sometimes to
18 * eliminate potentially bogus entries from the RSB, and sometimes
19 * purely to ensure that it doesn't get empty, which on some CPUs would
20 * allow predictions from other (unwanted!) sources to be used.
21 *
22 * We define a CPP macro such that it can be used from both .S files and
23 * inline assembly. It's possible to do a .macro and then include that
24 * from C via asm(".include <asm/nospec-branch.h>") but let's not go there.
25 */
26
27#define RSB_CLEAR_LOOPS 32 /* To forcibly overwrite all entries */
28#define RSB_FILL_LOOPS 16 /* To avoid underflow */
29
30/*
31 * Google experimented with loop-unrolling and this turned out to be
32 * the optimal version — two calls, each with their own speculation
33 * trap should their return address end up getting used, in a loop.
34 */
35#define __FILL_RETURN_BUFFER(reg, nr, sp) \
36 mov $(nr/2), reg; \
37771: \
38 call 772f; \
39773: /* speculation trap */ \
40 pause; \
41 jmp 773b; \
42772: \
43 call 774f; \
44775: /* speculation trap */ \
45 pause; \
46 jmp 775b; \
47774: \
48 dec reg; \
49 jnz 771b; \
50 add $(BITS_PER_LONG/8) * nr, sp;
51
10#ifdef __ASSEMBLY__ 52#ifdef __ASSEMBLY__
11 53
12/* 54/*
@@ -76,6 +118,20 @@
76#endif 118#endif
77.endm 119.endm
78 120
121 /*
122 * A simpler FILL_RETURN_BUFFER macro. Don't make people use the CPP
123 * monstrosity above, manually.
124 */
125.macro FILL_RETURN_BUFFER reg:req nr:req ftr:req
126#ifdef CONFIG_RETPOLINE
127 ANNOTATE_NOSPEC_ALTERNATIVE
128 ALTERNATIVE "jmp .Lskip_rsb_\@", \
129 __stringify(__FILL_RETURN_BUFFER(\reg,\nr,%_ASM_SP)) \
130 \ftr
131.Lskip_rsb_\@:
132#endif
133.endm
134
79#else /* __ASSEMBLY__ */ 135#else /* __ASSEMBLY__ */
80 136
81#define ANNOTATE_NOSPEC_ALTERNATIVE \ 137#define ANNOTATE_NOSPEC_ALTERNATIVE \
@@ -119,7 +175,7 @@
119 X86_FEATURE_RETPOLINE) 175 X86_FEATURE_RETPOLINE)
120 176
121# define THUNK_TARGET(addr) [thunk_target] "rm" (addr) 177# define THUNK_TARGET(addr) [thunk_target] "rm" (addr)
122#else /* No retpoline */ 178#else /* No retpoline for C / inline asm */
123# define CALL_NOSPEC "call *%[thunk_target]\n" 179# define CALL_NOSPEC "call *%[thunk_target]\n"
124# define THUNK_TARGET(addr) [thunk_target] "rm" (addr) 180# define THUNK_TARGET(addr) [thunk_target] "rm" (addr)
125#endif 181#endif
@@ -134,5 +190,25 @@ enum spectre_v2_mitigation {
134 SPECTRE_V2_IBRS, 190 SPECTRE_V2_IBRS,
135}; 191};
136 192
193/*
194 * On VMEXIT we must ensure that no RSB predictions learned in the guest
195 * can be followed in the host, by overwriting the RSB completely. Both
196 * retpoline and IBRS mitigations for Spectre v2 need this; only on future
197 * CPUs with IBRS_ATT *might* it be avoided.
198 */
199static inline void vmexit_fill_RSB(void)
200{
201#ifdef CONFIG_RETPOLINE
202 unsigned long loops = RSB_CLEAR_LOOPS / 2;
203
204 asm volatile (ANNOTATE_NOSPEC_ALTERNATIVE
205 ALTERNATIVE("jmp 910f",
206 __stringify(__FILL_RETURN_BUFFER(%0, RSB_CLEAR_LOOPS, %1)),
207 X86_FEATURE_RETPOLINE)
208 "910:"
209 : "=&r" (loops), ASM_CALL_CONSTRAINT
210 : "r" (loops) : "memory" );
211#endif
212}
137#endif /* __ASSEMBLY__ */ 213#endif /* __ASSEMBLY__ */
138#endif /* __NOSPEC_BRANCH_H__ */ 214#endif /* __NOSPEC_BRANCH_H__ */
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 0e68f0b3cbf7..2744b97345b8 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -45,6 +45,7 @@
45#include <asm/debugreg.h> 45#include <asm/debugreg.h>
46#include <asm/kvm_para.h> 46#include <asm/kvm_para.h>
47#include <asm/irq_remapping.h> 47#include <asm/irq_remapping.h>
48#include <asm/nospec-branch.h>
48 49
49#include <asm/virtext.h> 50#include <asm/virtext.h>
50#include "trace.h" 51#include "trace.h"
@@ -4985,6 +4986,9 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
4985#endif 4986#endif
4986 ); 4987 );
4987 4988
4989 /* Eliminate branch target predictions from guest mode */
4990 vmexit_fill_RSB();
4991
4988#ifdef CONFIG_X86_64 4992#ifdef CONFIG_X86_64
4989 wrmsrl(MSR_GS_BASE, svm->host.gs_base); 4993 wrmsrl(MSR_GS_BASE, svm->host.gs_base);
4990#else 4994#else
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 62ee4362e1c1..d1e25dba3112 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -50,6 +50,7 @@
50#include <asm/apic.h> 50#include <asm/apic.h>
51#include <asm/irq_remapping.h> 51#include <asm/irq_remapping.h>
52#include <asm/mmu_context.h> 52#include <asm/mmu_context.h>
53#include <asm/nospec-branch.h>
53 54
54#include "trace.h" 55#include "trace.h"
55#include "pmu.h" 56#include "pmu.h"
@@ -9403,6 +9404,9 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
9403#endif 9404#endif
9404 ); 9405 );
9405 9406
9407 /* Eliminate branch target predictions from guest mode */
9408 vmexit_fill_RSB();
9409
9406 /* MSR_IA32_DEBUGCTLMSR is zeroed on vmexit. Restore it if needed */ 9410 /* MSR_IA32_DEBUGCTLMSR is zeroed on vmexit. Restore it if needed */
9407 if (debugctlmsr) 9411 if (debugctlmsr)
9408 update_debugctlmsr(debugctlmsr); 9412 update_debugctlmsr(debugctlmsr);