1 From foo@baz Fri Mar 9 14:18:36 PST 2018
2 From: Daniel Borkmann <daniel@iogearbox.net>
3 Date: Thu, 8 Mar 2018 13:14:43 +0100
4 Subject: bpf, x64: implement retpoline for tail call
5 To: gregkh@linuxfoundation.org
6 Cc: ast@kernel.org, daniel@iogearbox.net, stable@vger.kernel.org
7 Message-ID: <f3349163f9a6f32c6e845e9a9e1a82d0d69110fe.1520504748.git.daniel@iogearbox.net>
9 From: Daniel Borkmann <daniel@iogearbox.net>
11 [ upstream commit a493a87f38cfa48caaa95c9347be2d914c6fdf29 ]
13 Implement a retpoline [0] for the BPF tail call JIT'ing that converts
14 the indirect jump via jmp %rax that is used to make the long jump into
15 another JITed BPF image. Since this is subject to speculative execution,
16 we need to control the transient instruction sequence here as well
17 when CONFIG_RETPOLINE is set, and direct it into a pause + lfence loop.
18 The latter aligns also with what gcc / clang emits (e.g. [1]).
23 0: (18) r2 = map[id:1]
25 3: (85) call bpf_tail_call#12
29 With CONFIG_RETPOLINE:
33 33: cmp %edx,0x24(%rsi)
34 36: jbe 0x0000000000000072 |*
35 38: mov 0x24(%rbp),%eax
37 41: ja 0x0000000000000072 |
39 46: mov %eax,0x24(%rbp)
40 4c: mov 0x90(%rsi,%rdx,8),%rax
42 57: je 0x0000000000000072 |
43 59: mov 0x28(%rax),%rax
45 61: callq 0x000000000000006d |+
48 6b: jmp 0x0000000000000066 |
54 * relative fall-through jumps in error case
55 + retpoline for indirect jump
57 Without CONFIG_RETPOLINE:
61 33: cmp %edx,0x24(%rsi)
62 36: jbe 0x0000000000000063 |*
63 38: mov 0x24(%rbp),%eax
65 41: ja 0x0000000000000063 |
67 46: mov %eax,0x24(%rbp)
68 4c: mov 0x90(%rsi,%rdx,8),%rax
70 57: je 0x0000000000000063 |
71 59: mov 0x28(%rax),%rax
77 * relative fall-through jumps in error case
78 - plain indirect jump as before
80 [0] https://support.google.com/faqs/answer/7625886
81 [1] https://github.com/gcc-mirror/gcc/commit/a31e654fa107be968b802786d747e962c2fcdb2b
83 Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
84 Signed-off-by: Alexei Starovoitov <ast@kernel.org>
85 Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
86 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
88 arch/x86/include/asm/nospec-branch.h | 37 +++++++++++++++++++++++++++++++++++
89 arch/x86/net/bpf_jit_comp.c | 9 ++++----
90 2 files changed, 42 insertions(+), 4 deletions(-)
92 --- a/arch/x86/include/asm/nospec-branch.h
93 +++ b/arch/x86/include/asm/nospec-branch.h
94 @@ -177,4 +177,41 @@ static inline void indirect_branch_predi
97 #endif /* __ASSEMBLY__ */
100 + * Below is used in the eBPF JIT compiler and emits the byte sequence
101 + * for the following assembly:
103 + * With retpolines configured:
114 + * Without retpolines configured:
118 +#ifdef CONFIG_RETPOLINE
119 +# define RETPOLINE_RAX_BPF_JIT_SIZE 17
120 +# define RETPOLINE_RAX_BPF_JIT() \
121 + EMIT1_off32(0xE8, 7); /* callq do_rop */ \
123 + EMIT2(0xF3, 0x90); /* pause */ \
124 + EMIT3(0x0F, 0xAE, 0xE8); /* lfence */ \
125 + EMIT2(0xEB, 0xF9); /* jmp spec_trap */ \
127 + EMIT4(0x48, 0x89, 0x04, 0x24); /* mov %rax,(%rsp) */ \
128 + EMIT1(0xC3); /* retq */
130 +# define RETPOLINE_RAX_BPF_JIT_SIZE 2
131 +# define RETPOLINE_RAX_BPF_JIT() \
132 + EMIT2(0xFF, 0xE0); /* jmp *%rax */
135 #endif /* _ASM_X86_NOSPEC_BRANCH_H_ */
136 --- a/arch/x86/net/bpf_jit_comp.c
137 +++ b/arch/x86/net/bpf_jit_comp.c
139 #include <linux/if_vlan.h>
140 #include <asm/cacheflush.h>
141 #include <asm/set_memory.h>
142 +#include <asm/nospec-branch.h>
143 #include <linux/bpf.h>
145 int bpf_jit_enable __read_mostly;
146 @@ -287,7 +288,7 @@ static void emit_bpf_tail_call(u8 **ppro
147 EMIT2(0x89, 0xD2); /* mov edx, edx */
148 EMIT3(0x39, 0x56, /* cmp dword ptr [rsi + 16], edx */
149 offsetof(struct bpf_array, map.max_entries));
150 -#define OFFSET1 43 /* number of bytes to jump */
151 +#define OFFSET1 (41 + RETPOLINE_RAX_BPF_JIT_SIZE) /* number of bytes to jump */
152 EMIT2(X86_JBE, OFFSET1); /* jbe out */
155 @@ -296,7 +297,7 @@ static void emit_bpf_tail_call(u8 **ppro
157 EMIT2_off32(0x8B, 0x85, 36); /* mov eax, dword ptr [rbp + 36] */
158 EMIT3(0x83, 0xF8, MAX_TAIL_CALL_CNT); /* cmp eax, MAX_TAIL_CALL_CNT */
160 +#define OFFSET2 (30 + RETPOLINE_RAX_BPF_JIT_SIZE)
161 EMIT2(X86_JA, OFFSET2); /* ja out */
163 EMIT3(0x83, 0xC0, 0x01); /* add eax, 1 */
164 @@ -310,7 +311,7 @@ static void emit_bpf_tail_call(u8 **ppro
167 EMIT3(0x48, 0x85, 0xC0); /* test rax,rax */
169 +#define OFFSET3 (8 + RETPOLINE_RAX_BPF_JIT_SIZE)
170 EMIT2(X86_JE, OFFSET3); /* je out */
173 @@ -323,7 +324,7 @@ static void emit_bpf_tail_call(u8 **ppro
174 * rdi == ctx (1st arg)
175 * rax == prog->bpf_func + prologue_size
177 - EMIT2(0xFF, 0xE0); /* jmp rax */
178 + RETPOLINE_RAX_BPF_JIT();
181 BUILD_BUG_ON(cnt - label1 != OFFSET1);