Skip to content

Commit 1dde741

Browse files
bp3tk0vKAGA-KOKO
authored andcommitted
x86/retpoline: Simplify vmexit_fill_RSB()
Simplify it to call an asm-function instead of pasting 41 insn bytes at every call site. Also, add alignment to the macro as suggested here: https://support.google.com/faqs/answer/7625886 [dwmw2: Clean up comments, let it clobber %ebx and just tell the compiler] Signed-off-by: Borislav Petkov <[email protected]> Signed-off-by: David Woodhouse <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Link: https://lkml.kernel.org/r/[email protected]
1 parent 2961298 commit 1dde741

File tree

6 files changed

+71
-65
lines changed

6 files changed

+71
-65
lines changed

arch/x86/entry/entry_32.S

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,8 @@ ENTRY(__switch_to_asm)
252252
* exist, overwrite the RSB with entries which capture
253253
* speculative execution to prevent attack.
254254
*/
255-
FILL_RETURN_BUFFER %ebx, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW
255+
/* Clobbers %ebx */
256+
FILL_RETURN_BUFFER RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW
256257
#endif
257258

258259
/* restore callee-saved registers */

arch/x86/entry/entry_64.S

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,8 @@ ENTRY(__switch_to_asm)
495495
* exist, overwrite the RSB with entries which capture
496496
* speculative execution to prevent attack.
497497
*/
498-
FILL_RETURN_BUFFER %r12, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW
498+
/* Clobbers %rbx */
499+
FILL_RETURN_BUFFER RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW
499500
#endif
500501

501502
/* restore callee-saved registers */

arch/x86/include/asm/asm-prototypes.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,7 @@ INDIRECT_THUNK(dx)
3838
INDIRECT_THUNK(si)
3939
INDIRECT_THUNK(di)
4040
INDIRECT_THUNK(bp)
41+
asmlinkage void __fill_rsb(void);
42+
asmlinkage void __clear_rsb(void);
43+
4144
#endif /* CONFIG_RETPOLINE */

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

Lines changed: 7 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -7,50 +7,6 @@
77
#include <asm/alternative-asm.h>
88
#include <asm/cpufeatures.h>
99

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; lfence; 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; \
37-
771: \
38-
call 772f; \
39-
773: /* speculation trap */ \
40-
pause; \
41-
lfence; \
42-
jmp 773b; \
43-
772: \
44-
call 774f; \
45-
775: /* speculation trap */ \
46-
pause; \
47-
lfence; \
48-
jmp 775b; \
49-
774: \
50-
dec reg; \
51-
jnz 771b; \
52-
add $(BITS_PER_LONG/8) * nr, sp;
53-
5410
#ifdef __ASSEMBLY__
5511

5612
/*
@@ -121,17 +77,10 @@
12177
#endif
12278
.endm
12379

124-
/*
125-
* A simpler FILL_RETURN_BUFFER macro. Don't make people use the CPP
126-
* monstrosity above, manually.
127-
*/
128-
.macro FILL_RETURN_BUFFER reg:req nr:req ftr:req
80+
/* This clobbers the BX register */
81+
.macro FILL_RETURN_BUFFER nr:req ftr:req
12982
#ifdef CONFIG_RETPOLINE
130-
ANNOTATE_NOSPEC_ALTERNATIVE
131-
ALTERNATIVE "jmp .Lskip_rsb_\@", \
132-
__stringify(__FILL_RETURN_BUFFER(\reg,\nr,%_ASM_SP)) \
133-
\ftr
134-
.Lskip_rsb_\@:
83+
ALTERNATIVE "", "call __clear_rsb", \ftr
13584
#endif
13685
.endm
13786

@@ -206,15 +155,10 @@ extern char __indirect_thunk_end[];
206155
static inline void vmexit_fill_RSB(void)
207156
{
208157
#ifdef CONFIG_RETPOLINE
209-
unsigned long loops;
210-
211-
asm volatile (ANNOTATE_NOSPEC_ALTERNATIVE
212-
ALTERNATIVE("jmp 910f",
213-
__stringify(__FILL_RETURN_BUFFER(%0, RSB_CLEAR_LOOPS, %1)),
214-
X86_FEATURE_RETPOLINE)
215-
"910:"
216-
: "=r" (loops), ASM_CALL_CONSTRAINT
217-
: : "memory" );
158+
alternative_input("",
159+
"call __fill_rsb",
160+
X86_FEATURE_RETPOLINE,
161+
ASM_NO_INPUT_CLOBBER(_ASM_BX, "memory"));
218162
#endif
219163
}
220164

arch/x86/lib/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
2727
lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o
2828
lib-$(CONFIG_RANDOMIZE_BASE) += kaslr.o
2929
lib-$(CONFIG_RETPOLINE) += retpoline.o
30+
OBJECT_FILES_NON_STANDARD_retpoline.o :=y
3031

3132
obj-y += msr.o msr-reg.o msr-reg-export.o hweight.o
3233

arch/x86/lib/retpoline.S

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <asm/alternative-asm.h>
88
#include <asm/export.h>
99
#include <asm/nospec-branch.h>
10+
#include <asm/bitsperlong.h>
1011

1112
.macro THUNK reg
1213
.section .text.__x86.indirect_thunk
@@ -46,3 +47,58 @@ GENERATE_THUNK(r13)
4647
GENERATE_THUNK(r14)
4748
GENERATE_THUNK(r15)
4849
#endif
50+
51+
/*
52+
* Fill the CPU return stack buffer.
53+
*
54+
* Each entry in the RSB, if used for a speculative 'ret', contains an
55+
* infinite 'pause; lfence; jmp' loop to capture speculative execution.
56+
*
57+
* This is required in various cases for retpoline and IBRS-based
58+
* mitigations for the Spectre variant 2 vulnerability. Sometimes to
59+
* eliminate potentially bogus entries from the RSB, and sometimes
60+
* purely to ensure that it doesn't get empty, which on some CPUs would
61+
* allow predictions from other (unwanted!) sources to be used.
62+
*
63+
* Google experimented with loop-unrolling and this turned out to be
64+
* the optimal version - two calls, each with their own speculation
65+
* trap should their return address end up getting used, in a loop.
66+
*/
67+
.macro STUFF_RSB nr:req sp:req
68+
mov $(\nr / 2), %_ASM_BX
69+
.align 16
70+
771:
71+
call 772f
72+
773: /* speculation trap */
73+
pause
74+
lfence
75+
jmp 773b
76+
.align 16
77+
772:
78+
call 774f
79+
775: /* speculation trap */
80+
pause
81+
lfence
82+
jmp 775b
83+
.align 16
84+
774:
85+
dec %_ASM_BX
86+
jnz 771b
87+
add $((BITS_PER_LONG/8) * \nr), \sp
88+
.endm
89+
90+
#define RSB_FILL_LOOPS 16 /* To avoid underflow */
91+
92+
ENTRY(__fill_rsb)
93+
STUFF_RSB RSB_FILL_LOOPS, %_ASM_SP
94+
ret
95+
END(__fill_rsb)
96+
EXPORT_SYMBOL_GPL(__fill_rsb)
97+
98+
#define RSB_CLEAR_LOOPS 32 /* To forcibly overwrite all entries */
99+
100+
ENTRY(__clear_rsb)
101+
STUFF_RSB RSB_CLEAR_LOOPS, %_ASM_SP
102+
ret
103+
END(__clear_rsb)
104+
EXPORT_SYMBOL_GPL(__clear_rsb)

0 commit comments

Comments
 (0)