Skip to content

Commit 26f7df5

Browse files
Haoran JiangKernel Patches Daemon
authored andcommitted
LoongArch: BPF: Fix incorrect return pointer value in the eBPF program
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. Before applying this patch: ./test_progs -a ns_bpf_qdisc CPU 7 Unable to handle kernel paging request at virtual address 0000000010440158. As shown in the following test case, bpf_fifo_dequeue return value is a pointer. progs/bpf_qdisc_fifo.c SEC("struct_ops/bpf_fifo_dequeue") struct sk_buff *BPF_PROG(bpf_fifo_dequeue, struct Qdisc *sch) { struct sk_buff *skb = NULL; ........ skb = bpf_kptr_xchg(&skbn->skb, skb); ........ return skb; } kernel call bpf_fifo_dequeue: net/sched/sch_generic.c static struct sk_buff *dequeue_skb(struct Qdisc *q, bool *validate, int *packets) { struct sk_buff *skb = NULL; ........ skb = q->dequeue(q); ......... } When accessing the skb, an address exception error will occur. because the value returned by q->dequeue at this point is a 32-bit address rather than a 64-bit address. After applying the patch: ./test_progs -a ns_bpf_qdisc Warning: sch_htb: quantum of class 10001 is small. Consider r2q change. 213/1 ns_bpf_qdisc/fifo:OK 213/2 ns_bpf_qdisc/fq:OK 213/3 ns_bpf_qdisc/attach to mq:OK 213/4 ns_bpf_qdisc/attach to non root:OK 213/5 ns_bpf_qdisc/incompl_ops:OK 213 ns_bpf_qdisc:OK Summary: 1/5 PASSED, 0 SKIPPED, 0 FAILED Fixes: 73c359d ("LoongArch: BPF: Sign-extend return values") Signed-off-by: Jinyang He <[email protected]> Signed-off-by: Haoran Jiang <[email protected]> ---------- v2: 1,add emit_slt* helpers 2,Use slt/slld/srad instructions to avoid branch
1 parent 5e1a4c1 commit 26f7df5

File tree

2 files changed

+23
-2
lines changed

2 files changed

+23
-2
lines changed

arch/loongarch/include/asm/inst.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ enum reg2i6_op {
9292
};
9393

9494
enum reg2i12_op {
95+
slti_op = 0x08,
96+
sltui_op = 0x09,
9597
addiw_op = 0x0a,
9698
addid_op = 0x0b,
9799
lu52id_op = 0x0c,
@@ -148,6 +150,8 @@ enum reg3_op {
148150
addd_op = 0x21,
149151
subw_op = 0x22,
150152
subd_op = 0x23,
153+
slt_op = 0x24,
154+
sltu_op = 0x25,
151155
nor_op = 0x28,
152156
and_op = 0x29,
153157
or_op = 0x2a,
@@ -629,6 +633,8 @@ static inline void emit_##NAME(union loongarch_instruction *insn, \
629633
insn->reg2i12_format.rj = rj; \
630634
}
631635

636+
DEF_EMIT_REG2I12_FORMAT(slti, slti_op)
637+
DEF_EMIT_REG2I12_FORMAT(sltui, sltui_op)
632638
DEF_EMIT_REG2I12_FORMAT(addiw, addiw_op)
633639
DEF_EMIT_REG2I12_FORMAT(addid, addid_op)
634640
DEF_EMIT_REG2I12_FORMAT(lu52id, lu52id_op)
@@ -729,6 +735,8 @@ static inline void emit_##NAME(union loongarch_instruction *insn, \
729735
DEF_EMIT_REG3_FORMAT(addw, addw_op)
730736
DEF_EMIT_REG3_FORMAT(addd, addd_op)
731737
DEF_EMIT_REG3_FORMAT(subd, subd_op)
738+
DEF_EMIT_REG3_FORMAT(slt, slt_op)
739+
DEF_EMIT_REG3_FORMAT(sltu, sltu_op)
732740
DEF_EMIT_REG3_FORMAT(muld, muld_op)
733741
DEF_EMIT_REG3_FORMAT(divd, divd_op)
734742
DEF_EMIT_REG3_FORMAT(modd, modd_op)

arch/loongarch/net/bpf_jit.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,8 +229,21 @@ static void __build_epilogue(struct jit_ctx *ctx, bool is_tail_call)
229229
emit_insn(ctx, addid, LOONGARCH_GPR_SP, LOONGARCH_GPR_SP, stack_adjust);
230230

231231
if (!is_tail_call) {
232-
/* Set return value */
233-
emit_insn(ctx, addiw, LOONGARCH_GPR_A0, regmap[BPF_REG_0], 0);
232+
/*
233+
* Set return value
234+
* Check if the 64th bit in regmap[BPF_REG_0] is 1. If it is,
235+
* the value in regmap[BPF_REG_0] is a kernel-space address.
236+
237+
* long long val = regmap[BPF_REG_0];
238+
* int shift = 0 < val ? 32 : 0;
239+
* return (val << shift) >> shift;
240+
*/
241+
move_reg(ctx, LOONGARCH_GPR_A0, regmap[BPF_REG_0]);
242+
emit_insn(ctx, slt, LOONGARCH_GPR_T0, LOONGARCH_GPR_ZERO, LOONGARCH_GPR_A0);
243+
emit_insn(ctx, sllid, LOONGARCH_GPR_T0, LOONGARCH_GPR_T0, 5);
244+
emit_insn(ctx, slld, LOONGARCH_GPR_A0, LOONGARCH_GPR_A0, LOONGARCH_GPR_T0);
245+
emit_insn(ctx, srad, LOONGARCH_GPR_A0, LOONGARCH_GPR_A0, LOONGARCH_GPR_T0);
246+
234247
/* Return to the caller */
235248
emit_insn(ctx, jirl, LOONGARCH_GPR_ZERO, LOONGARCH_GPR_RA, 0);
236249
} else {

0 commit comments

Comments
 (0)