Skip to content

Commit de5cb6e

Browse files
author
Martin Schwidefsky
committed
s390: use expoline thunks in the BPF JIT
The BPF JIT need safe guarding against spectre v2 in the sk_load_xxx assembler stubs and the indirect branches generated by the JIT itself need to be converted to expolines. Signed-off-by: Martin Schwidefsky <[email protected]>
1 parent 6deaa3b commit de5cb6e

File tree

2 files changed

+71
-8
lines changed

2 files changed

+71
-8
lines changed

arch/s390/net/bpf_jit.S

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*/
1010

1111
#include <linux/linkage.h>
12+
#include <asm/nospec-insn.h>
1213
#include "bpf_jit.h"
1314

1415
/*
@@ -54,7 +55,7 @@ ENTRY(sk_load_##NAME##_pos); \
5455
clg %r3,STK_OFF_HLEN(%r15); /* Offset + SIZE > hlen? */ \
5556
jh sk_load_##NAME##_slow; \
5657
LOAD %r14,-SIZE(%r3,%r12); /* Get data from skb */ \
57-
b OFF_OK(%r6); /* Return */ \
58+
B_EX OFF_OK,%r6; /* Return */ \
5859
\
5960
sk_load_##NAME##_slow:; \
6061
lgr %r2,%r7; /* Arg1 = skb pointer */ \
@@ -64,11 +65,14 @@ sk_load_##NAME##_slow:; \
6465
brasl %r14,skb_copy_bits; /* Get data from skb */ \
6566
LOAD %r14,STK_OFF_TMP(%r15); /* Load from temp bufffer */ \
6667
ltgr %r2,%r2; /* Set cc to (%r2 != 0) */ \
67-
br %r6; /* Return */
68+
BR_EX %r6; /* Return */
6869

6970
sk_load_common(word, 4, llgf) /* r14 = *(u32 *) (skb->data+offset) */
7071
sk_load_common(half, 2, llgh) /* r14 = *(u16 *) (skb->data+offset) */
7172

73+
GEN_BR_THUNK %r6
74+
GEN_B_THUNK OFF_OK,%r6
75+
7276
/*
7377
* Load 1 byte from SKB (optimized version)
7478
*/
@@ -80,7 +84,7 @@ ENTRY(sk_load_byte_pos)
8084
clg %r3,STK_OFF_HLEN(%r15) # Offset >= hlen?
8185
jnl sk_load_byte_slow
8286
llgc %r14,0(%r3,%r12) # Get byte from skb
83-
b OFF_OK(%r6) # Return OK
87+
B_EX OFF_OK,%r6 # Return OK
8488

8589
sk_load_byte_slow:
8690
lgr %r2,%r7 # Arg1 = skb pointer
@@ -90,7 +94,7 @@ sk_load_byte_slow:
9094
brasl %r14,skb_copy_bits # Get data from skb
9195
llgc %r14,STK_OFF_TMP(%r15) # Load result from temp buffer
9296
ltgr %r2,%r2 # Set cc to (%r2 != 0)
93-
br %r6 # Return cc
97+
BR_EX %r6 # Return cc
9498

9599
#define sk_negative_common(NAME, SIZE, LOAD) \
96100
sk_load_##NAME##_slow_neg:; \
@@ -104,7 +108,7 @@ sk_load_##NAME##_slow_neg:; \
104108
jz bpf_error; \
105109
LOAD %r14,0(%r2); /* Get data from pointer */ \
106110
xr %r3,%r3; /* Set cc to zero */ \
107-
br %r6; /* Return cc */
111+
BR_EX %r6; /* Return cc */
108112

109113
sk_negative_common(word, 4, llgf)
110114
sk_negative_common(half, 2, llgh)
@@ -113,4 +117,4 @@ sk_negative_common(byte, 1, llgc)
113117
bpf_error:
114118
# force a return 0 from jit handler
115119
ltgr %r15,%r15 # Set condition code
116-
br %r6
120+
BR_EX %r6

arch/s390/net/bpf_jit_comp.c

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#include <linux/bpf.h>
2626
#include <asm/cacheflush.h>
2727
#include <asm/dis.h>
28+
#include <asm/facility.h>
29+
#include <asm/nospec-branch.h>
2830
#include <asm/set_memory.h>
2931
#include "bpf_jit.h"
3032

@@ -41,6 +43,8 @@ struct bpf_jit {
4143
int base_ip; /* Base address for literal pool */
4244
int ret0_ip; /* Address of return 0 */
4345
int exit_ip; /* Address of exit */
46+
int r1_thunk_ip; /* Address of expoline thunk for 'br %r1' */
47+
int r14_thunk_ip; /* Address of expoline thunk for 'br %r14' */
4448
int tail_call_start; /* Tail call start offset */
4549
int labels[1]; /* Labels for local jumps */
4650
};
@@ -250,6 +254,19 @@ static inline void reg_set_seen(struct bpf_jit *jit, u32 b1)
250254
REG_SET_SEEN(b2); \
251255
})
252256

257+
#define EMIT6_PCREL_RILB(op, b, target) \
258+
({ \
259+
int rel = (target - jit->prg) / 2; \
260+
_EMIT6(op | reg_high(b) << 16 | rel >> 16, rel & 0xffff); \
261+
REG_SET_SEEN(b); \
262+
})
263+
264+
#define EMIT6_PCREL_RIL(op, target) \
265+
({ \
266+
int rel = (target - jit->prg) / 2; \
267+
_EMIT6(op | rel >> 16, rel & 0xffff); \
268+
})
269+
253270
#define _EMIT6_IMM(op, imm) \
254271
({ \
255272
unsigned int __imm = (imm); \
@@ -469,8 +486,45 @@ static void bpf_jit_epilogue(struct bpf_jit *jit, u32 stack_depth)
469486
EMIT4(0xb9040000, REG_2, BPF_REG_0);
470487
/* Restore registers */
471488
save_restore_regs(jit, REGS_RESTORE, stack_depth);
489+
if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable) {
490+
jit->r14_thunk_ip = jit->prg;
491+
/* Generate __s390_indirect_jump_r14 thunk */
492+
if (test_facility(35)) {
493+
/* exrl %r0,.+10 */
494+
EMIT6_PCREL_RIL(0xc6000000, jit->prg + 10);
495+
} else {
496+
/* larl %r1,.+14 */
497+
EMIT6_PCREL_RILB(0xc0000000, REG_1, jit->prg + 14);
498+
/* ex 0,0(%r1) */
499+
EMIT4_DISP(0x44000000, REG_0, REG_1, 0);
500+
}
501+
/* j . */
502+
EMIT4_PCREL(0xa7f40000, 0);
503+
}
472504
/* br %r14 */
473505
_EMIT2(0x07fe);
506+
507+
if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable &&
508+
(jit->seen & SEEN_FUNC)) {
509+
jit->r1_thunk_ip = jit->prg;
510+
/* Generate __s390_indirect_jump_r1 thunk */
511+
if (test_facility(35)) {
512+
/* exrl %r0,.+10 */
513+
EMIT6_PCREL_RIL(0xc6000000, jit->prg + 10);
514+
/* j . */
515+
EMIT4_PCREL(0xa7f40000, 0);
516+
/* br %r1 */
517+
_EMIT2(0x07f1);
518+
} else {
519+
/* larl %r1,.+14 */
520+
EMIT6_PCREL_RILB(0xc0000000, REG_1, jit->prg + 14);
521+
/* ex 0,S390_lowcore.br_r1_tampoline */
522+
EMIT4_DISP(0x44000000, REG_0, REG_0,
523+
offsetof(struct lowcore, br_r1_trampoline));
524+
/* j . */
525+
EMIT4_PCREL(0xa7f40000, 0);
526+
}
527+
}
474528
}
475529

476530
/*
@@ -966,8 +1020,13 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i
9661020
/* lg %w1,<d(imm)>(%l) */
9671021
EMIT6_DISP_LH(0xe3000000, 0x0004, REG_W1, REG_0, REG_L,
9681022
EMIT_CONST_U64(func));
969-
/* basr %r14,%w1 */
970-
EMIT2(0x0d00, REG_14, REG_W1);
1023+
if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable) {
1024+
/* brasl %r14,__s390_indirect_jump_r1 */
1025+
EMIT6_PCREL_RILB(0xc0050000, REG_14, jit->r1_thunk_ip);
1026+
} else {
1027+
/* basr %r14,%w1 */
1028+
EMIT2(0x0d00, REG_14, REG_W1);
1029+
}
9711030
/* lgr %b0,%r2: load return value into %b0 */
9721031
EMIT4(0xb9040000, BPF_REG_0, REG_2);
9731032
if ((jit->seen & SEEN_SKB) &&

0 commit comments

Comments
 (0)