]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
LoongArch: BPF: Zero-extend signed ALU32 div/mod results
authorNicholas Dudar <main.kalliope@gmail.com>
Thu, 23 Jul 2026 14:27:35 +0000 (22:27 +0800)
committerHuacai Chen <chenhuacai@loongson.cn>
Thu, 23 Jul 2026 14:27:35 +0000 (22:27 +0800)
ALU32 operations write a 32-bit result and leave the upper 32 bits of
the BPF register zero. The LoongArch JIT sign-extends the result of
signed ALU32 BPF_DIV and BPF_MOD (off=1), so a negative 32-bit quotient
or remainder leaves bits 63:32 set in JITted code while the verifier
and interpreter model those bits as zero.

Keep sign-extension on the operands, which signed divide needs, and
zero-extend the ALU32 result after the divide or modulo instruction,
matching the unsigned ALU32 div/mod paths and every other ALU32
operation in this JIT.

Fixes: 2425c9e002d2 ("LoongArch: BPF: Support signed div instructions")
Fixes: 7b6b13d32965 ("LoongArch: BPF: Support signed mod instructions")
Assisted-by: Claude:claude-opus-4-8
Acked-by: Tiezhu Yang <yangtiezhu@loongson.cn>
Tested-by: Tiezhu Yang <yangtiezhu@loongson.cn>
Signed-off-by: Nicholas Dudar <main.kalliope@gmail.com>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
arch/loongarch/net/bpf_jit.c

index 2738b4db11653367a51b3b63a16b55ede7db1a48..c91d474faba73b74d9bb2893cbad1747343b3f31 100644 (file)
@@ -835,7 +835,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
                        move_reg(ctx, t1, src);
                        emit_sext_32(ctx, t1, is32);
                        emit_insn(ctx, divd, dst, dst, t1);
-                       emit_sext_32(ctx, dst, is32);
+                       emit_zext_32(ctx, dst, is32);
                }
                break;
 
@@ -852,7 +852,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
                        emit_sext_32(ctx, t1, is32);
                        emit_sext_32(ctx, dst, is32);
                        emit_insn(ctx, divd, dst, dst, t1);
-                       emit_sext_32(ctx, dst, is32);
+                       emit_zext_32(ctx, dst, is32);
                }
                break;
 
@@ -870,7 +870,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
                        move_reg(ctx, t1, src);
                        emit_sext_32(ctx, t1, is32);
                        emit_insn(ctx, modd, dst, dst, t1);
-                       emit_sext_32(ctx, dst, is32);
+                       emit_zext_32(ctx, dst, is32);
                }
                break;
 
@@ -887,7 +887,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
                        emit_sext_32(ctx, t1, is32);
                        emit_sext_32(ctx, dst, is32);
                        emit_insn(ctx, modd, dst, dst, t1);
-                       emit_sext_32(ctx, dst, is32);
+                       emit_zext_32(ctx, dst, is32);
                }
                break;