Skip to content

Commit 5882764

Browse files
borkmanngregkh
authored andcommitted
bpf, x64: implement retpoline for tail call
[ upstream commit a493a87 ] Implement a retpoline [0] for the BPF tail call JIT'ing that converts the indirect jump via jmp %rax that is used to make the long jump into another JITed BPF image. Since this is subject to speculative execution, we need to control the transient instruction sequence here as well when CONFIG_RETPOLINE is set, and direct it into a pause + lfence loop. The latter aligns also with what gcc / clang emits (e.g. [1]). JIT dump after patch: # bpftool p d x i 1 0: (18) r2 = map[id:1] 2: (b7) r3 = 0 3: (85) call bpf_tail_call#12 4: (b7) r0 = 2 5: (95) exit With CONFIG_RETPOLINE: # bpftool p d j i 1 [...] 33: cmp %edx,0x24(%rsi) 36: jbe 0x0000000000000072 |* 38: mov 0x24(%rbp),%eax 3e: cmp $0x20,%eax 41: ja 0x0000000000000072 | 43: add $0x1,%eax 46: mov %eax,0x24(%rbp) 4c: mov 0x90(%rsi,%rdx,8),%rax 54: test %rax,%rax 57: je 0x0000000000000072 | 59: mov 0x28(%rax),%rax 5d: add $0x25,%rax 61: callq 0x000000000000006d |+ 66: pause | 68: lfence | 6b: jmp 0x0000000000000066 | 6d: mov %rax,(%rsp) | 71: retq | 72: mov $0x2,%eax [...] * relative fall-through jumps in error case + retpoline for indirect jump Without CONFIG_RETPOLINE: # bpftool p d j i 1 [...] 33: cmp %edx,0x24(%rsi) 36: jbe 0x0000000000000063 |* 38: mov 0x24(%rbp),%eax 3e: cmp $0x20,%eax 41: ja 0x0000000000000063 | 43: add $0x1,%eax 46: mov %eax,0x24(%rbp) 4c: mov 0x90(%rsi,%rdx,8),%rax 54: test %rax,%rax 57: je 0x0000000000000063 | 59: mov 0x28(%rax),%rax 5d: add $0x25,%rax 61: jmpq *%rax |- 63: mov $0x2,%eax [...] * relative fall-through jumps in error case - plain indirect jump as before [0] https://support.google.com/faqs/answer/7625886 [1] gcc-mirror/gcc@a31e654 Signed-off-by: Daniel Borkmann <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 519f40b commit 5882764

File tree

2 files changed

+42
-4
lines changed

2 files changed

+42
-4
lines changed

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,4 +177,41 @@ static inline void indirect_branch_prediction_barrier(void)
177177
}
178178

179179
#endif /* __ASSEMBLY__ */
180+
181+
/*
182+
* Below is used in the eBPF JIT compiler and emits the byte sequence
183+
* for the following assembly:
184+
*
185+
* With retpolines configured:
186+
*
187+
* callq do_rop
188+
* spec_trap:
189+
* pause
190+
* lfence
191+
* jmp spec_trap
192+
* do_rop:
193+
* mov %rax,(%rsp)
194+
* retq
195+
*
196+
* Without retpolines configured:
197+
*
198+
* jmp *%rax
199+
*/
200+
#ifdef CONFIG_RETPOLINE
201+
# define RETPOLINE_RAX_BPF_JIT_SIZE 17
202+
# define RETPOLINE_RAX_BPF_JIT() \
203+
EMIT1_off32(0xE8, 7); /* callq do_rop */ \
204+
/* spec_trap: */ \
205+
EMIT2(0xF3, 0x90); /* pause */ \
206+
EMIT3(0x0F, 0xAE, 0xE8); /* lfence */ \
207+
EMIT2(0xEB, 0xF9); /* jmp spec_trap */ \
208+
/* do_rop: */ \
209+
EMIT4(0x48, 0x89, 0x04, 0x24); /* mov %rax,(%rsp) */ \
210+
EMIT1(0xC3); /* retq */
211+
#else
212+
# define RETPOLINE_RAX_BPF_JIT_SIZE 2
213+
# define RETPOLINE_RAX_BPF_JIT() \
214+
EMIT2(0xFF, 0xE0); /* jmp *%rax */
215+
#endif
216+
180217
#endif /* _ASM_X86_NOSPEC_BRANCH_H_ */

arch/x86/net/bpf_jit_comp.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <linux/if_vlan.h>
1414
#include <asm/cacheflush.h>
1515
#include <asm/set_memory.h>
16+
#include <asm/nospec-branch.h>
1617
#include <linux/bpf.h>
1718

1819
int bpf_jit_enable __read_mostly;
@@ -287,7 +288,7 @@ static void emit_bpf_tail_call(u8 **pprog)
287288
EMIT2(0x89, 0xD2); /* mov edx, edx */
288289
EMIT3(0x39, 0x56, /* cmp dword ptr [rsi + 16], edx */
289290
offsetof(struct bpf_array, map.max_entries));
290-
#define OFFSET1 43 /* number of bytes to jump */
291+
#define OFFSET1 (41 + RETPOLINE_RAX_BPF_JIT_SIZE) /* number of bytes to jump */
291292
EMIT2(X86_JBE, OFFSET1); /* jbe out */
292293
label1 = cnt;
293294

@@ -296,7 +297,7 @@ static void emit_bpf_tail_call(u8 **pprog)
296297
*/
297298
EMIT2_off32(0x8B, 0x85, 36); /* mov eax, dword ptr [rbp + 36] */
298299
EMIT3(0x83, 0xF8, MAX_TAIL_CALL_CNT); /* cmp eax, MAX_TAIL_CALL_CNT */
299-
#define OFFSET2 32
300+
#define OFFSET2 (30 + RETPOLINE_RAX_BPF_JIT_SIZE)
300301
EMIT2(X86_JA, OFFSET2); /* ja out */
301302
label2 = cnt;
302303
EMIT3(0x83, 0xC0, 0x01); /* add eax, 1 */
@@ -310,7 +311,7 @@ static void emit_bpf_tail_call(u8 **pprog)
310311
* goto out;
311312
*/
312313
EMIT3(0x48, 0x85, 0xC0); /* test rax,rax */
313-
#define OFFSET3 10
314+
#define OFFSET3 (8 + RETPOLINE_RAX_BPF_JIT_SIZE)
314315
EMIT2(X86_JE, OFFSET3); /* je out */
315316
label3 = cnt;
316317

@@ -323,7 +324,7 @@ static void emit_bpf_tail_call(u8 **pprog)
323324
* rdi == ctx (1st arg)
324325
* rax == prog->bpf_func + prologue_size
325326
*/
326-
EMIT2(0xFF, 0xE0); /* jmp rax */
327+
RETPOLINE_RAX_BPF_JIT();
327328

328329
/* out: */
329330
BUILD_BUG_ON(cnt - label1 != OFFSET1);

0 commit comments

Comments
 (0)