Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: 5dc615520c4d ("LoongArch: Add BPF JIT support")
Signed-off-by: Hengqi Chen <hengqi.chen@gmail.com>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>

authored by

Hengqi Chen and committed by
Huacai Chen
3f5a238f 45cb47c6

+42
+16
arch/loongarch/net/bpf_jit.c
··· 950 950 emit_insn(ctx, ldd, REG_TCC, LOONGARCH_GPR_SP, tcc_ptr_off); 951 951 } 952 952 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 + 953 969 move_addr(ctx, t1, func_addr); 954 970 emit_insn(ctx, jirl, LOONGARCH_GPR_RA, t1, 0); 955 971
+26
arch/loongarch/net/bpf_jit.h
··· 88 88 emit_insn(ctx, addiw, reg, reg, 0); 89 89 } 90 90 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 + 91 117 static inline void move_addr(struct jit_ctx *ctx, enum loongarch_gpr rd, u64 addr) 92 118 { 93 119 u64 imm_11_0, imm_31_12, imm_51_32, imm_63_52;