diff options
| author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2018-04-23 08:31:36 -0400 |
|---|---|---|
| committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2018-05-07 15:12:43 -0400 |
| commit | de5cb6eb514ebe241e3edeb290cb41deb380b81d (patch) | |
| tree | 67d7c8cfa87e8ea7cfcd35e43efa325815f27106 | |
| parent | 6deaa3bbca804b2a3627fd685f75de64da7be535 (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.S | 16 | ||||
| -rw-r--r-- | arch/s390/net/bpf_jit_comp.c | 63 |
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 | \ |
| 59 | sk_load_##NAME##_slow:; \ | 60 | sk_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 | ||
| 69 | sk_load_common(word, 4, llgf) /* r14 = *(u32 *) (skb->data+offset) */ | 70 | sk_load_common(word, 4, llgf) /* r14 = *(u32 *) (skb->data+offset) */ |
| 70 | sk_load_common(half, 2, llgh) /* r14 = *(u16 *) (skb->data+offset) */ | 71 | sk_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 | ||
| 85 | sk_load_byte_slow: | 89 | sk_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) \ |
| 96 | sk_load_##NAME##_slow_neg:; \ | 100 | sk_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 | ||
| 109 | sk_negative_common(word, 4, llgf) | 113 | sk_negative_common(word, 4, llgf) |
| 110 | sk_negative_common(half, 2, llgh) | 114 | sk_negative_common(half, 2, llgh) |
| @@ -113,4 +117,4 @@ sk_negative_common(byte, 1, llgc) | |||
| 113 | bpf_error: | 117 | bpf_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) && |
