Skip to content

Commit 3f5a238

Browse files
chenhengqichenhuacai
authored andcommitted
LoongArch: BPF: Sign extend kfunc call arguments
The kfunc calls are native calls so they should follow LoongArch calling conventions. Sign extend its arguments properly to avoid kernel panic. This is done by adding a new emit_abi_ext() helper. The emit_abi_ext() helper performs extension in place meaning a value already store in the target register (Note: this is different from the existing sign_extend() helper and thus we can't reuse it). Cc: stable@vger.kernel.org Fixes: 5dc6155 ("LoongArch: Add BPF JIT support") Signed-off-by: Hengqi Chen <hengqi.chen@gmail.com> Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
1 parent 45cb47c commit 3f5a238

2 files changed

Lines changed: 42 additions & 0 deletions

File tree

arch/loongarch/net/bpf_jit.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -950,6 +950,22 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
950950
emit_insn(ctx, ldd, REG_TCC, LOONGARCH_GPR_SP, tcc_ptr_off);
951951
}
952952

953+
if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) {
954+
const struct btf_func_model *m;
955+
int i;
956+
957+
m = bpf_jit_find_kfunc_model(ctx->prog, insn);
958+
if (!m)
959+
return -EINVAL;
960+
961+
for (i = 0; i < m->nr_args; i++) {
962+
u8 reg = regmap[BPF_REG_1 + i];
963+
bool sign = m->arg_flags[i] & BTF_FMODEL_SIGNED_ARG;
964+
965+
emit_abi_ext(ctx, reg, m->arg_size[i], sign);
966+
}
967+
}
968+
953969
move_addr(ctx, t1, func_addr);
954970
emit_insn(ctx, jirl, LOONGARCH_GPR_RA, t1, 0);
955971

arch/loongarch/net/bpf_jit.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,32 @@ static inline void emit_sext_32(struct jit_ctx *ctx, enum loongarch_gpr reg, boo
8888
emit_insn(ctx, addiw, reg, reg, 0);
8989
}
9090

91+
/* Emit proper extension according to ABI requirements.
92+
* Note that it requires a value of size `size` already resides in register `reg`.
93+
*/
94+
static inline void emit_abi_ext(struct jit_ctx *ctx, int reg, u8 size, bool sign)
95+
{
96+
/* ABI requires unsigned char/short to be zero-extended */
97+
if (!sign && (size == 1 || size == 2))
98+
return;
99+
100+
switch (size) {
101+
case 1:
102+
emit_insn(ctx, extwb, reg, reg);
103+
break;
104+
case 2:
105+
emit_insn(ctx, extwh, reg, reg);
106+
break;
107+
case 4:
108+
emit_insn(ctx, addiw, reg, reg, 0);
109+
break;
110+
case 8:
111+
break;
112+
default:
113+
pr_warn("bpf_jit: invalid size %d for extension\n", size);
114+
}
115+
}
116+
91117
static inline void move_addr(struct jit_ctx *ctx, enum loongarch_gpr rd, u64 addr)
92118
{
93119
u64 imm_11_0, imm_31_12, imm_51_32, imm_63_52;

0 commit comments

Comments
 (0)