Skip to content

Commit e1671f5

Browse files
borkmannshiloong
authored andcommitted
bpf: Introduce BPF nospec instruction for mitigating Spectre v4
OpenAnolis Bug Tracker: 0000429 commit f5e81d1 upstream. In case of JITs, each of the JIT backends compiles the BPF nospec instruction /either/ to a machine instruction which emits a speculation barrier /or/ to /no/ machine instruction in case the underlying architecture is not affected by Speculative Store Bypass or has different mitigations in place already. This covers both x86 and (implicitly) arm64: In case of x86, we use 'lfence' instruction for mitigation. In case of arm64, we rely on the firmware mitigation as controlled via the ssbd kernel parameter. Whenever the mitigation is enabled, it works for all of the kernel code with no need to provide any additional instructions here (hence only comment in arm64 JIT). Other archs can follow as needed. The BPF nospec instruction is specifically targeting Spectre v4 since i) we don't use a serialization barrier for the Spectre v1 case, and ii) mitigation instructions for v1 and v4 might be different on some archs. The BPF nospec is required for a future commit, where the BPF verifier does annotate intermediate BPF programs with speculation barriers. Co-developed-by: Piotr Krysiuk <[email protected]> Co-developed-by: Benedict Schlueter <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Signed-off-by: Piotr Krysiuk <[email protected]> Signed-off-by: Benedict Schlueter <[email protected]> Acked-by: Alexei Starovoitov <[email protected]> [OP: adjusted context for 4.19, drop riscv and ppc32 changes] Signed-off-by: Ovidiu Panait <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]> Fixes: CVE-2021-34556, CVE-2021-35477 Signed-off-by: Shile Zhang <[email protected]> Acked-by: Mao Wenan <[email protected]>
1 parent 3500a01 commit e1671f5

File tree

11 files changed

+87
-8
lines changed

11 files changed

+87
-8
lines changed

arch/arm/net/bpf_jit_32.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1562,6 +1562,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
15621562
rn = arm_bpf_get_reg32(src_lo, tmp2[1], ctx);
15631563
emit_ldx_r(dst, rn, off, ctx, BPF_SIZE(code));
15641564
break;
1565+
/* speculation barrier */
1566+
case BPF_ST | BPF_NOSPEC:
1567+
break;
15651568
/* ST: *(size *)(dst + off) = imm */
15661569
case BPF_ST | BPF_MEM | BPF_W:
15671570
case BPF_ST | BPF_MEM | BPF_H:

arch/arm64/net/bpf_jit_comp.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,19 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
685685
}
686686
break;
687687

688+
/* speculation barrier */
689+
case BPF_ST | BPF_NOSPEC:
690+
/*
691+
* Nothing required here.
692+
*
693+
* In case of arm64, we rely on the firmware mitigation of
694+
* Speculative Store Bypass as controlled via the ssbd kernel
695+
* parameter. Whenever the mitigation is enabled, it works
696+
* for all of the kernel code with no need to provide any
697+
* additional instructions.
698+
*/
699+
break;
700+
688701
/* ST: *(size *)(dst + off) = imm */
689702
case BPF_ST | BPF_MEM | BPF_W:
690703
case BPF_ST | BPF_MEM | BPF_H:

arch/mips/net/ebpf_jit.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,6 +1281,9 @@ static int build_one_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
12811281
}
12821282
break;
12831283

1284+
case BPF_ST | BPF_NOSPEC: /* speculation barrier */
1285+
break;
1286+
12841287
case BPF_ST | BPF_B | BPF_MEM:
12851288
case BPF_ST | BPF_H | BPF_MEM:
12861289
case BPF_ST | BPF_W | BPF_MEM:

arch/powerpc/net/bpf_jit_comp64.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,12 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image,
596596
}
597597
break;
598598

599+
/*
600+
* BPF_ST NOSPEC (speculation barrier)
601+
*/
602+
case BPF_ST | BPF_NOSPEC:
603+
break;
604+
599605
/*
600606
* BPF_ST(X)
601607
*/

arch/s390/net/bpf_jit_comp.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,11 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i
883883
break;
884884
}
885885
break;
886+
/*
887+
* BPF_NOSPEC (speculation barrier)
888+
*/
889+
case BPF_ST | BPF_NOSPEC:
890+
break;
886891
/*
887892
* BPF_ST(X)
888893
*/

arch/sparc/net/bpf_jit_comp_64.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,6 +1261,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
12611261
emit(opcode | RS1(src) | rs2 | RD(dst), ctx);
12621262
break;
12631263
}
1264+
/* speculation barrier */
1265+
case BPF_ST | BPF_NOSPEC:
1266+
break;
12641267
/* ST: *(size *)(dst + off) = imm */
12651268
case BPF_ST | BPF_MEM | BPF_W:
12661269
case BPF_ST | BPF_MEM | BPF_H:

arch/x86/net/bpf_jit_comp.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,13 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
718718
}
719719
break;
720720

721+
/* speculation barrier */
722+
case BPF_ST | BPF_NOSPEC:
723+
if (boot_cpu_has(X86_FEATURE_XMM2))
724+
/* Emit 'lfence' */
725+
EMIT3(0x0F, 0xAE, 0xE8);
726+
break;
727+
721728
/* ST: *(u8*)(dst_reg + off) = imm */
722729
case BPF_ST | BPF_MEM | BPF_B:
723730
if (is_ereg(dst_reg))

arch/x86/net/bpf_jit_comp32.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1683,6 +1683,12 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
16831683
i++;
16841684
break;
16851685
}
1686+
/* speculation barrier */
1687+
case BPF_ST | BPF_NOSPEC:
1688+
if (boot_cpu_has(X86_FEATURE_XMM2))
1689+
/* Emit 'lfence' */
1690+
EMIT3(0x0F, 0xAE, 0xE8);
1691+
break;
16861692
/* ST: *(u8*)(dst_reg + off) = imm */
16871693
case BPF_ST | BPF_MEM | BPF_H:
16881694
case BPF_ST | BPF_MEM | BPF_B:

include/linux/filter.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ struct sock_reuseport;
6464
/* unused opcode to mark call to interpreter with arguments */
6565
#define BPF_CALL_ARGS 0xe0
6666

67+
/* unused opcode to mark speculation barrier for mitigating
68+
* Speculative Store Bypass
69+
*/
70+
#define BPF_NOSPEC 0xc0
71+
6772
/* As per nm, we expose JITed images as text (code) section for
6873
* kallsyms. That way, tools like perf can find it to match
6974
* addresses.
@@ -354,6 +359,16 @@ struct sock_reuseport;
354359
.off = 0, \
355360
.imm = 0 })
356361

362+
/* Speculation barrier */
363+
364+
#define BPF_ST_NOSPEC() \
365+
((struct bpf_insn) { \
366+
.code = BPF_ST | BPF_NOSPEC, \
367+
.dst_reg = 0, \
368+
.src_reg = 0, \
369+
.off = 0, \
370+
.imm = 0 })
371+
357372
/* Internal classic blocks for direct assignment */
358373

359374
#define __BPF_STMT(CODE, K) \

kernel/bpf/core.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <linux/rcupdate.h>
3434
#include <linux/perf_event.h>
3535

36+
#include <asm/barrier.h>
3637
#include <asm/unaligned.h>
3738

3839
/* Registers */
@@ -1050,6 +1051,7 @@ static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, u64 *stack)
10501051
/* Non-UAPI available opcodes. */
10511052
[BPF_JMP | BPF_CALL_ARGS] = &&JMP_CALL_ARGS,
10521053
[BPF_JMP | BPF_TAIL_CALL] = &&JMP_TAIL_CALL,
1054+
[BPF_ST | BPF_NOSPEC] = &&ST_NOSPEC,
10531055
};
10541056
#undef BPF_INSN_3_LBL
10551057
#undef BPF_INSN_2_LBL
@@ -1356,7 +1358,21 @@ static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, u64 *stack)
13561358
JMP_EXIT:
13571359
return BPF_R0;
13581360

1359-
/* STX and ST and LDX*/
1361+
/* ST, STX and LDX*/
1362+
ST_NOSPEC:
1363+
/* Speculation barrier for mitigating Speculative Store Bypass.
1364+
* In case of arm64, we rely on the firmware mitigation as
1365+
* controlled via the ssbd kernel parameter. Whenever the
1366+
* mitigation is enabled, it works for all of the kernel code
1367+
* with no need to provide any additional instructions here.
1368+
* In case of x86, we use 'lfence' insn for mitigation. We
1369+
* reuse preexisting logic from Spectre v1 mitigation that
1370+
* happens to produce the required code on x86 for v4 as well.
1371+
*/
1372+
#ifdef CONFIG_X86
1373+
barrier_nospec();
1374+
#endif
1375+
CONT;
13601376
#define LDST(SIZEOP, SIZE) \
13611377
STX_MEM_##SIZEOP: \
13621378
*(SIZE *)(unsigned long) (DST + insn->off) = SRC; \

0 commit comments

Comments
 (0)