| From 0e4cddbd7409d13712149839c75e2b6ac930b9a5 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 17 Jul 2020 18:53:23 +0200 |
| Subject: s390/bpf: Fix sign extension in branch_ku |
| |
| From: Ilya Leoshkevich <iii@linux.ibm.com> |
| |
| [ Upstream commit 7477d43be5b1448bc0d4c85cb185a0144cc080e1 ] |
| |
| Both signed and unsigned variants of BPF_JMP | BPF_K require |
| sign-extending the immediate. JIT emits cgfi for the signed case, |
| which is correct, and clgfi for the unsigned case, which is not |
| correct: clgfi zero-extends the immediate. |
| |
| s390 does not provide an instruction that does sign-extension and |
| unsigned comparison at the same time. Therefore, fix by first loading |
| the sign-extended immediate into work register REG_1 and proceeding |
| as if it's BPF_X. |
| |
| Fixes: 4e9b4a6883dd ("s390/bpf: Use relative long branches") |
| Reported-by: Seth Forshee <seth.forshee@canonical.com> |
| Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> |
| Signed-off-by: Alexei Starovoitov <ast@kernel.org> |
| Tested-by: Seth Forshee <seth.forshee@canonical.com> |
| Link: https://lore.kernel.org/bpf/20200717165326.6786-3-iii@linux.ibm.com |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| arch/s390/net/bpf_jit_comp.c | 19 ++++--------------- |
| 1 file changed, 4 insertions(+), 15 deletions(-) |
| |
| diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c |
| index 0f37a1b635f85..ac227ea13cbe7 100644 |
| --- a/arch/s390/net/bpf_jit_comp.c |
| +++ b/arch/s390/net/bpf_jit_comp.c |
| @@ -1416,21 +1416,10 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, |
| } |
| break; |
| branch_ku: |
| - is_jmp32 = BPF_CLASS(insn->code) == BPF_JMP32; |
| - /* clfi or clgfi %dst,imm */ |
| - EMIT6_IMM(is_jmp32 ? 0xc20f0000 : 0xc20e0000, |
| - dst_reg, imm); |
| - if (!is_first_pass(jit) && |
| - can_use_rel(jit, addrs[i + off + 1])) { |
| - /* brc mask,off */ |
| - EMIT4_PCREL_RIC(0xa7040000, |
| - mask >> 12, addrs[i + off + 1]); |
| - } else { |
| - /* brcl mask,off */ |
| - EMIT6_PCREL_RILC(0xc0040000, |
| - mask >> 12, addrs[i + off + 1]); |
| - } |
| - break; |
| + /* lgfi %w1,imm (load sign extend imm) */ |
| + src_reg = REG_1; |
| + EMIT6_IMM(0xc0010000, src_reg, imm); |
| + goto branch_xu; |
| branch_xs: |
| is_jmp32 = BPF_CLASS(insn->code) == BPF_JMP32; |
| if (!is_first_pass(jit) && |
| -- |
| 2.25.1 |
| |