aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2018-04-23 08:31:36 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2018-05-07 15:12:43 -0400
commitde5cb6eb514ebe241e3edeb290cb41deb380b81d (patch)
tree67d7c8cfa87e8ea7cfcd35e43efa325815f27106
parent6deaa3bbca804b2a3627fd685f75de64da7be535 (diff)
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 <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/net/bpf_jit.S16
-rw-r--r--arch/s390/net/bpf_jit_comp.c63
2 files changed, 71 insertions, 8 deletions
diff --git a/arch/s390/net/bpf_jit.S b/arch/s390/net/bpf_jit.S
index 25bb4643c4f4..9f794869c1b0 100644
--- a/arch/s390/net/bpf_jit.S
+++ b/arch/s390/net/bpf_jit.S
@@ -9,6 +9,7 @@
9 */ 9 */
10 10
11#include <linux/linkage.h> 11#include <linux/linkage.h>
12#include <asm/nospec-insn.h>
12#include "bpf_jit.h" 13#include "bpf_jit.h"
13 14
14/* 15/*
@@ -54,7 +55,7 @@ ENTRY(sk_load_##NAME##_pos); \
54 clg %r3,STK_OFF_HLEN(%r15); /* Offset + SIZE > hlen? */ \ 55 clg %r3,STK_OFF_HLEN(%r15); /* Offset + SIZE > hlen? */ \
55 jh sk_load_##NAME##_slow; \ 56 jh sk_load_##NAME##_slow; \
56 LOAD %r14,-SIZE(%r3,%r12); /* Get data from skb */ \ 57 LOAD %r14,-SIZE(%r3,%r12); /* Get data from skb */ \
57 b OFF_OK(%r6); /* Return */ \ 58 B_EX OFF_OK,%r6; /* Return */ \
58 \ 59 \
59sk_load_##NAME##_slow:; \ 60sk_load_##NAME##_slow:; \
60 lgr %r2,%r7; /* Arg1 = skb pointer */ \ 61 lgr %r2,%r7; /* Arg1 = skb pointer */ \
@@ -64,11 +65,14 @@ sk_load_##NAME##_slow:; \
64 brasl %r14,skb_copy_bits; /* Get data from skb */ \ 65 brasl %r14,skb_copy_bits; /* Get data from skb */ \
65 LOAD %r14,STK_OFF_TMP(%r15); /* Load from temp bufffer */ \ 66 LOAD %r14,STK_OFF_TMP(%r15); /* Load from temp bufffer */ \
66 ltgr %r2,%r2; /* Set cc to (%r2 != 0) */ \ 67 ltgr %r2,%r2; /* Set cc to (%r2 != 0) */ \
67 br %r6; /* Return */ 68 BR_EX %r6; /* Return */
68 69
69sk_load_common(word, 4, llgf) /* r14 = *(u32 *) (skb->data+offset) */ 70sk_load_common(word, 4, llgf) /* r14 = *(u32 *) (skb->data+offset) */
70sk_load_common(half, 2, llgh) /* r14 = *(u16 *) (skb->data+offset) */ 71sk_load_common(half, 2, llgh) /* r14 = *(u16 *) (skb->data+offset) */
71 72
73 GEN_BR_THUNK %r6
74 GEN_B_THUNK OFF_OK,%r6
75
72/* 76/*
73 * Load 1 byte from SKB (optimized version) 77 * Load 1 byte from SKB (optimized version)
74 */ 78 */
@@ -80,7 +84,7 @@ ENTRY(sk_load_byte_pos)
80 clg %r3,STK_OFF_HLEN(%r15) # Offset >= hlen? 84 clg %r3,STK_OFF_HLEN(%r15) # Offset >= hlen?
81 jnl sk_load_byte_slow 85 jnl sk_load_byte_slow
82 llgc %r14,0(%r3,%r12) # Get byte from skb 86 llgc %r14,0(%r3,%r12) # Get byte from skb
83 b OFF_OK(%r6) # Return OK 87 B_EX OFF_OK,%r6 # Return OK
84 88
85sk_load_byte_slow: 89sk_load_byte_slow:
86 lgr %r2,%r7 # Arg1 = skb pointer 90 lgr %r2,%r7 # Arg1 = skb pointer
@@ -90,7 +94,7 @@ sk_load_byte_slow:
90 brasl %r14,skb_copy_bits # Get data from skb 94 brasl %r14,skb_copy_bits # Get data from skb
91 llgc %r14,STK_OFF_TMP(%r15) # Load result from temp buffer 95 llgc %r14,STK_OFF_TMP(%r15) # Load result from temp buffer
92 ltgr %r2,%r2 # Set cc to (%r2 != 0) 96 ltgr %r2,%r2 # Set cc to (%r2 != 0)
93 br %r6 # Return cc 97 BR_EX %r6 # Return cc
94 98
95#define sk_negative_common(NAME, SIZE, LOAD) \ 99#define sk_negative_common(NAME, SIZE, LOAD) \
96sk_load_##NAME##_slow_neg:; \ 100sk_load_##NAME##_slow_neg:; \
@@ -104,7 +108,7 @@ sk_load_##NAME##_slow_neg:; \
104 jz bpf_error; \ 108 jz bpf_error; \
105 LOAD %r14,0(%r2); /* Get data from pointer */ \ 109 LOAD %r14,0(%r2); /* Get data from pointer */ \
106 xr %r3,%r3; /* Set cc to zero */ \ 110 xr %r3,%r3; /* Set cc to zero */ \
107 br %r6; /* Return cc */ 111 BR_EX %r6; /* Return cc */
108 112
109sk_negative_common(word, 4, llgf) 113sk_negative_common(word, 4, llgf)
110sk_negative_common(half, 2, llgh) 114sk_negative_common(half, 2, llgh)
@@ -113,4 +117,4 @@ sk_negative_common(byte, 1, llgc)
113bpf_error: 117bpf_error:
114# force a return 0 from jit handler 118# force a return 0 from jit handler
115 ltgr %r15,%r15 # Set condition code 119 ltgr %r15,%r15 # Set condition code
116 br %r6 120 BR_EX %r6
diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
index 78a19c93b380..dd2bcf0e7d00 100644
--- a/arch/s390/net/bpf_jit_comp.c
+++ b/arch/s390/net/bpf_jit_comp.c
@@ -25,6 +25,8 @@
25#include <linux/bpf.h> 25#include <linux/bpf.h>
26#include <asm/cacheflush.h> 26#include <asm/cacheflush.h>
27#include <asm/dis.h> 27#include <asm/dis.h>
28#include <asm/facility.h>
29#include <asm/nospec-branch.h>
28#include <asm/set_memory.h> 30#include <asm/set_memory.h>
29#include "bpf_jit.h" 31#include "bpf_jit.h"
30 32
@@ -41,6 +43,8 @@ struct bpf_jit {
41 int base_ip; /* Base address for literal pool */ 43 int base_ip; /* Base address for literal pool */
42 int ret0_ip; /* Address of return 0 */ 44 int ret0_ip; /* Address of return 0 */
43 int exit_ip; /* Address of exit */ 45 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' */
44 int tail_call_start; /* Tail call start offset */ 48 int tail_call_start; /* Tail call start offset */
45 int labels[1]; /* Labels for local jumps */ 49 int labels[1]; /* Labels for local jumps */
46}; 50};
@@ -250,6 +254,19 @@ static inline void reg_set_seen(struct bpf_jit *jit, u32 b1)
250 REG_SET_SEEN(b2); \ 254 REG_SET_SEEN(b2); \
251}) 255})
252 256
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
253#define _EMIT6_IMM(op, imm) \ 270#define _EMIT6_IMM(op, imm) \
254({ \ 271({ \
255 unsigned int __imm = (imm); \ 272 unsigned int __imm = (imm); \
@@ -469,8 +486,45 @@ static void bpf_jit_epilogue(struct bpf_jit *jit, u32 stack_depth)
469 EMIT4(0xb9040000, REG_2, BPF_REG_0); 486 EMIT4(0xb9040000, REG_2, BPF_REG_0);
470 /* Restore registers */ 487 /* Restore registers */
471 save_restore_regs(jit, REGS_RESTORE, stack_depth); 488 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 }
472 /* br %r14 */ 504 /* br %r14 */
473 _EMIT2(0x07fe); 505 _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 }
474} 528}
475 529
476/* 530/*
@@ -966,8 +1020,13 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i
966 /* lg %w1,<d(imm)>(%l) */ 1020 /* lg %w1,<d(imm)>(%l) */
967 EMIT6_DISP_LH(0xe3000000, 0x0004, REG_W1, REG_0, REG_L, 1021 EMIT6_DISP_LH(0xe3000000, 0x0004, REG_W1, REG_0, REG_L,
968 EMIT_CONST_U64(func)); 1022 EMIT_CONST_U64(func));
969 /* basr %r14,%w1 */ 1023 if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable) {
970 EMIT2(0x0d00, REG_14, REG_W1); 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 }
971 /* lgr %b0,%r2: load return value into %b0 */ 1030 /* lgr %b0,%r2: load return value into %b0 */
972 EMIT4(0xb9040000, BPF_REG_0, REG_2); 1031 EMIT4(0xb9040000, BPF_REG_0, REG_2);
973 if ((jit->seen & SEEN_SKB) && 1032 if ((jit->seen & SEEN_SKB) &&