s390/bpf: Fix optimizing out zero-extensions
authorIlya Leoshkevich <iii@linux.ibm.com>
Mon, 6 Sep 2021 13:04:14 +0000 (15:04 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 22 Sep 2021 10:28:02 +0000 (12:28 +0200)
commit db7bee653859ef7179be933e7d1384644f795f26 upstream.

Currently the JIT completely removes things like `reg32 += 0`,
however, the BPF_ALU semantics requires the target register to be
zero-extended in such cases.

Fix by optimizing out only the arithmetic operation, but not the
subsequent zero-extension.

Reported-by: Johan Almbladh <johan.almbladh@anyfinetworks.com>
Fixes: 054623105728 ("s390/bpf: Add s390x eBPF JIT compiler backend")
Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/s390/net/bpf_jit_comp.c

index dee01d3..2847632 100644 (file)
@@ -761,10 +761,10 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
                EMIT4(0xb9080000, dst_reg, src_reg);
                break;
        case BPF_ALU | BPF_ADD | BPF_K: /* dst = (u32) dst + (u32) imm */
-               if (!imm)
-                       break;
-               /* alfi %dst,imm */
-               EMIT6_IMM(0xc20b0000, dst_reg, imm);
+               if (imm != 0) {
+                       /* alfi %dst,imm */
+                       EMIT6_IMM(0xc20b0000, dst_reg, imm);
+               }
                EMIT_ZERO(dst_reg);
                break;
        case BPF_ALU64 | BPF_ADD | BPF_K: /* dst = dst + imm */
@@ -786,10 +786,10 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
                EMIT4(0xb9090000, dst_reg, src_reg);
                break;
        case BPF_ALU | BPF_SUB | BPF_K: /* dst = (u32) dst - (u32) imm */
-               if (!imm)
-                       break;
-               /* alfi %dst,-imm */
-               EMIT6_IMM(0xc20b0000, dst_reg, -imm);
+               if (imm != 0) {
+                       /* alfi %dst,-imm */
+                       EMIT6_IMM(0xc20b0000, dst_reg, -imm);
+               }
                EMIT_ZERO(dst_reg);
                break;
        case BPF_ALU64 | BPF_SUB | BPF_K: /* dst = dst - imm */
@@ -811,10 +811,10 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
                EMIT4(0xb90c0000, dst_reg, src_reg);
                break;
        case BPF_ALU | BPF_MUL | BPF_K: /* dst = (u32) dst * (u32) imm */
-               if (imm == 1)
-                       break;
-               /* msfi %r5,imm */
-               EMIT6_IMM(0xc2010000, dst_reg, imm);
+               if (imm != 1) {
+                       /* msfi %r5,imm */
+                       EMIT6_IMM(0xc2010000, dst_reg, imm);
+               }
                EMIT_ZERO(dst_reg);
                break;
        case BPF_ALU64 | BPF_MUL | BPF_K: /* dst = dst * imm */
@@ -867,6 +867,8 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
                        if (BPF_OP(insn->code) == BPF_MOD)
                                /* lhgi %dst,0 */
                                EMIT4_IMM(0xa7090000, dst_reg, 0);
+                       else
+                               EMIT_ZERO(dst_reg);
                        break;
                }
                /* lhi %w0,0 */
@@ -999,10 +1001,10 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
                EMIT4(0xb9820000, dst_reg, src_reg);
                break;
        case BPF_ALU | BPF_XOR | BPF_K: /* dst = (u32) dst ^ (u32) imm */
-               if (!imm)
-                       break;
-               /* xilf %dst,imm */
-               EMIT6_IMM(0xc0070000, dst_reg, imm);
+               if (imm != 0) {
+                       /* xilf %dst,imm */
+                       EMIT6_IMM(0xc0070000, dst_reg, imm);
+               }
                EMIT_ZERO(dst_reg);
                break;
        case BPF_ALU64 | BPF_XOR | BPF_K: /* dst = dst ^ imm */
@@ -1033,10 +1035,10 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
                EMIT6_DISP_LH(0xeb000000, 0x000d, dst_reg, dst_reg, src_reg, 0);
                break;
        case BPF_ALU | BPF_LSH | BPF_K: /* dst = (u32) dst << (u32) imm */
-               if (imm == 0)
-                       break;
-               /* sll %dst,imm(%r0) */
-               EMIT4_DISP(0x89000000, dst_reg, REG_0, imm);
+               if (imm != 0) {
+                       /* sll %dst,imm(%r0) */
+                       EMIT4_DISP(0x89000000, dst_reg, REG_0, imm);
+               }
                EMIT_ZERO(dst_reg);
                break;
        case BPF_ALU64 | BPF_LSH | BPF_K: /* dst = dst << imm */
@@ -1058,10 +1060,10 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
                EMIT6_DISP_LH(0xeb000000, 0x000c, dst_reg, dst_reg, src_reg, 0);
                break;
        case BPF_ALU | BPF_RSH | BPF_K: /* dst = (u32) dst >> (u32) imm */
-               if (imm == 0)
-                       break;
-               /* srl %dst,imm(%r0) */
-               EMIT4_DISP(0x88000000, dst_reg, REG_0, imm);
+               if (imm != 0) {
+                       /* srl %dst,imm(%r0) */
+                       EMIT4_DISP(0x88000000, dst_reg, REG_0, imm);
+               }
                EMIT_ZERO(dst_reg);
                break;
        case BPF_ALU64 | BPF_RSH | BPF_K: /* dst = dst >> imm */
@@ -1083,10 +1085,10 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
                EMIT6_DISP_LH(0xeb000000, 0x000a, dst_reg, dst_reg, src_reg, 0);
                break;
        case BPF_ALU | BPF_ARSH | BPF_K: /* ((s32) dst >> imm */
-               if (imm == 0)
-                       break;
-               /* sra %dst,imm(%r0) */
-               EMIT4_DISP(0x8a000000, dst_reg, REG_0, imm);
+               if (imm != 0) {
+                       /* sra %dst,imm(%r0) */
+                       EMIT4_DISP(0x8a000000, dst_reg, REG_0, imm);
+               }
                EMIT_ZERO(dst_reg);
                break;
        case BPF_ALU64 | BPF_ARSH | BPF_K: /* ((s64) dst) >>= imm */