Re: [PATCH v2] LoongArch: BPF: Fix incorrect return pointer value in the eBPF program

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 2025/8/15 下午4:29, Haoran Jiang wrote:
In some eBPF programs, the return value is a pointer.
When the kernel call an eBPF program (such as struct_ops),
it expects a 64-bit address to be returned, but instead a 32-bit value.

With this v2 patch and the v1 patch:

$ sudo modprobe test_bpf
modprobe: ERROR: could not insert 'test_bpf': Invalid argument
$ dmesg -t | grep Summary
test_bpf: Summary: 1039 PASSED, 14 FAILED, [1041/1041 JIT'ed]

Without the patches, all of the tests passed.
This is related with the previous fix:
LoongArch: BPF: Sign-extend return values
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=73c359d1d356

diff --git a/arch/loongarch/include/asm/inst.h b/arch/loongarch/include/asm/inst.h
index 277d2140676b..20f4fc745bea 100644
--- a/arch/loongarch/include/asm/inst.h
+++ b/arch/loongarch/include/asm/inst.h
@@ -92,6 +92,8 @@ enum reg2i6_op {
  };
enum reg2i12_op {
+	slti_op         = 0x08,
+	sltui_op        = 0x09,
  	addiw_op	= 0x0a,
  	addid_op	= 0x0b,
  	lu52id_op	= 0x0c,
@@ -148,6 +150,8 @@ enum reg3_op {
  	addd_op		= 0x21,
  	subw_op		= 0x22,
  	subd_op		= 0x23,
+	slt_op          = 0x24,
+	sltu_op         = 0x25,

Only slt is used in bpf_jit.c,
slti, sltui and sltu can be removed
because they are not used in this patch.

diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c
index abfdb6bb5c38..50067be79c4f 100644
--- a/arch/loongarch/net/bpf_jit.c
+++ b/arch/loongarch/net/bpf_jit.c
@@ -229,8 +229,21 @@ static void __build_epilogue(struct jit_ctx *ctx, bool is_tail_call)
  	emit_insn(ctx, addid, LOONGARCH_GPR_SP, LOONGARCH_GPR_SP, stack_adjust);
if (!is_tail_call) {
-		/* Set return value */
-		emit_insn(ctx, addiw, LOONGARCH_GPR_A0, regmap[BPF_REG_0], 0);
+		/*
+		 *  Set return value

It is better to update the comment:

The return value is either a unsigned 32-bit value or a unsigned 64-bit address.

+		 *  Check if the 64th bit in regmap[BPF_REG_0] is 1. If it is,
+		 *  the value in regmap[BPF_REG_0] is a kernel-space address.
+
+		 *  long long val = regmap[BPF_REG_0];
+		 *  int shift = 0 < val ? 32 : 0;
+		 *  return (val << shift) >> shift;
+		 */
+		move_reg(ctx, LOONGARCH_GPR_A0, regmap[BPF_REG_0]);
+		emit_insn(ctx, slt, LOONGARCH_GPR_T0, LOONGARCH_GPR_ZERO, LOONGARCH_GPR_A0);

LOONGARCH_GPR_T0 may be not the expected value 1 if the return value
is a unsigned 32-bit value.

A quick way to verify this issue:

Add "move_imm(ctx, LOONGARCH_GPR_T0, 1, true)" after "slt" to force
LOONGARCH_GPR_T0 as 1 can fix the above failed tests.

The initial conclusion is that if the 64th bit in regmap[BPF_REG_0]
is 1, it can not recognize the value in regmap[BPF_REG_0] must be a
kernel-space address, it may be a unsigned 32-bit return value, for
this case just use addi.w to extend bit 31 into bits 63 through 32
of a5 to a0.

Thanks,
Tiezhu





[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux