| From cd39d9e6b7e4c58fa77783e7aedf7ada51d02ea3 Mon Sep 17 00:00:00 2001 |
| From: Haoran Jiang <jianghaoran@kylinos.cn> |
| Date: Tue, 5 Aug 2025 19:00:22 +0800 |
| Subject: LoongArch: BPF: Fix jump offset calculation in tailcall |
| |
| From: Haoran Jiang <jianghaoran@kylinos.cn> |
| |
| commit cd39d9e6b7e4c58fa77783e7aedf7ada51d02ea3 upstream. |
| |
| The extra pass of bpf_int_jit_compile() skips JIT context initialization |
| which essentially skips offset calculation leaving out_offset = -1, so |
| the jmp_offset in emit_bpf_tail_call is calculated by |
| |
| "#define jmp_offset (out_offset - (cur_offset))" |
| |
| is a negative number, which is wrong. The final generated assembly are |
| as follow. |
| |
| 54: bgeu $a2, $t1, -8 # 0x0000004c |
| 58: addi.d $a6, $s5, -1 |
| 5c: bltz $a6, -16 # 0x0000004c |
| 60: alsl.d $t2, $a2, $a1, 0x3 |
| 64: ld.d $t2, $t2, 264 |
| 68: beq $t2, $zero, -28 # 0x0000004c |
| |
| Before apply this patch, the follow test case will reveal soft lock issues. |
| |
| cd tools/testing/selftests/bpf/ |
| ./test_progs --allow=tailcalls/tailcall_bpf2bpf_1 |
| |
| dmesg: |
| watchdog: BUG: soft lockup - CPU#2 stuck for 26s! [test_progs:25056] |
| |
| Cc: stable@vger.kernel.org |
| Fixes: 5dc615520c4d ("LoongArch: Add BPF JIT support") |
| Reviewed-by: Hengqi Chen <hengqi.chen@gmail.com> |
| Signed-off-by: Haoran Jiang <jianghaoran@kylinos.cn> |
| Signed-off-by: Huacai Chen <chenhuacai@loongson.cn> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/loongarch/net/bpf_jit.c | 21 +++++---------------- |
| 1 file changed, 5 insertions(+), 16 deletions(-) |
| |
| --- a/arch/loongarch/net/bpf_jit.c |
| +++ b/arch/loongarch/net/bpf_jit.c |
| @@ -201,11 +201,9 @@ bool bpf_jit_supports_kfunc_call(void) |
| return true; |
| } |
| |
| -/* initialized on the first pass of build_body() */ |
| -static int out_offset = -1; |
| -static int emit_bpf_tail_call(struct jit_ctx *ctx) |
| +static int emit_bpf_tail_call(struct jit_ctx *ctx, int insn) |
| { |
| - int off; |
| + int off, tc_ninsn = 0; |
| u8 tcc = tail_call_reg(ctx); |
| u8 a1 = LOONGARCH_GPR_A1; |
| u8 a2 = LOONGARCH_GPR_A2; |
| @@ -215,7 +213,7 @@ static int emit_bpf_tail_call(struct jit |
| const int idx0 = ctx->idx; |
| |
| #define cur_offset (ctx->idx - idx0) |
| -#define jmp_offset (out_offset - (cur_offset)) |
| +#define jmp_offset (tc_ninsn - (cur_offset)) |
| |
| /* |
| * a0: &ctx |
| @@ -225,6 +223,7 @@ static int emit_bpf_tail_call(struct jit |
| * if (index >= array->map.max_entries) |
| * goto out; |
| */ |
| + tc_ninsn = insn ? ctx->offset[insn+1] - ctx->offset[insn] : ctx->offset[0]; |
| off = offsetof(struct bpf_array, map.max_entries); |
| emit_insn(ctx, ldwu, t1, a1, off); |
| /* bgeu $a2, $t1, jmp_offset */ |
| @@ -256,15 +255,6 @@ static int emit_bpf_tail_call(struct jit |
| emit_insn(ctx, ldd, t3, t2, off); |
| __build_epilogue(ctx, true); |
| |
| - /* out: */ |
| - if (out_offset == -1) |
| - out_offset = cur_offset; |
| - if (cur_offset != out_offset) { |
| - pr_err_once("tail_call out_offset = %d, expected %d!\n", |
| - cur_offset, out_offset); |
| - return -1; |
| - } |
| - |
| return 0; |
| |
| toofar: |
| @@ -789,7 +779,7 @@ static int build_insn(const struct bpf_i |
| /* tail call */ |
| case BPF_JMP | BPF_TAIL_CALL: |
| mark_tail_call(ctx); |
| - if (emit_bpf_tail_call(ctx) < 0) |
| + if (emit_bpf_tail_call(ctx, i) < 0) |
| return -EINVAL; |
| break; |
| |
| @@ -1170,7 +1160,6 @@ out: |
| if (tmp_blinded) |
| bpf_jit_prog_release_other(prog, prog == orig_prog ? tmp : orig_prog); |
| |
| - out_offset = -1; |
| |
| return prog; |
| } |