[PATCH bpf-next v2 5/8] bpf: Reject UHMUL/SHMUL in unsupported backends
tangyazhou at zju.edu.cn
tangyazhou at zju.edu.cn
Wed Oct 21 01:23:44 PDT 2026
From: Yazhou Tang <tangyazhou518 at outlook.com>
CPU JIT backends without explicit UHMUL/SHMUL support currently lower
BPF_MUL based on the opcode without examining insn->off. Once the verifier
accepts UHMUL and SHMUL, a backend without explicit support would therefore
lower either variant as the existing low-half multiplication and silently
produce the wrong result.
Reject UHMUL and SHMUL in each affected CPU JIT without native support,
using its existing unsupported-instruction path. This makes JIT compilation
fail cleanly instead of emitting an incorrect low-half multiply, and allows
the normal interpreter fallback when available.
The NFP hardware offload compiler has the same opcode-only dispatch:
BPF_ALU64 MUL instructions are routed to mul_reg64() or mul_imm64()
without considering insn->off. Reject UHMUL and SHMUL in the NFP offload
verifier as well, before they can reach the ordinary multiplication lowering.
Signed-off-by: Yazhou Tang <tangyazhou518 at outlook.com>
Co-developed-by: Tianci Cao <ziye at zju.edu.cn>
Signed-off-by: Tianci Cao <ziye at zju.edu.cn>
Co-developed-by: Shenghao Yuan <shenghaoyuan0928 at 163.com>
Signed-off-by: Shenghao Yuan <shenghaoyuan0928 at 163.com>
---
arch/arc/net/bpf_jit_core.c | 3 +++
arch/arm/net/bpf_jit_32.c | 3 +++
arch/loongarch/net/bpf_jit.c | 3 +++
arch/mips/net/bpf_jit_comp32.c | 3 +++
arch/mips/net/bpf_jit_comp64.c | 3 +++
arch/parisc/net/bpf_jit_comp32.c | 3 +++
arch/parisc/net/bpf_jit_comp64.c | 3 +++
arch/powerpc/net/bpf_jit_comp32.c | 3 +++
arch/powerpc/net/bpf_jit_comp64.c | 3 +++
arch/riscv/net/bpf_jit_comp32.c | 3 +++
arch/s390/net/bpf_jit_comp.c | 3 +++
arch/sparc/net/bpf_jit_comp_64.c | 3 +++
arch/x86/net/bpf_jit_comp32.c | 3 +++
drivers/net/ethernet/netronome/nfp/bpf/verifier.c | 6 ++++++
14 files changed, 45 insertions(+)
diff --git a/arch/arc/net/bpf_jit_core.c b/arch/arc/net/bpf_jit_core.c
index 639a2736f029..78b1819cee5a 100644
--- a/arch/arc/net/bpf_jit_core.c
+++ b/arch/arc/net/bpf_jit_core.c
@@ -734,6 +734,9 @@ static int handle_insn(struct jit_context *ctx, u32 idx)
u8 len = 0;
int ret = 0;
+ if (bpf_insn_is_hmul(insn))
+ return -EOPNOTSUPP;
+
switch (code) {
/* dst += src (32-bit) */
case BPF_ALU | BPF_ADD | BPF_X:
diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 9ede81afbc50..aa466fc79d96 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -1611,6 +1611,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
} while (0)
#define check_imm24(imm) check_imm(24, imm)
+ if (bpf_insn_is_hmul(insn))
+ goto notyet;
+
switch (code) {
/* ALU operations */
diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c
index 9393e4b0db8e..71bd518ceaf3 100644
--- a/arch/loongarch/net/bpf_jit.c
+++ b/arch/loongarch/net/bpf_jit.c
@@ -709,6 +709,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
const s32 imm = insn->imm;
const bool is32 = BPF_CLASS(insn->code) == BPF_ALU || BPF_CLASS(insn->code) == BPF_JMP32;
+ if (bpf_insn_is_hmul(insn))
+ return -EOPNOTSUPP;
+
switch (code) {
/* dst = src */
case BPF_ALU | BPF_MOV | BPF_X:
diff --git a/arch/mips/net/bpf_jit_comp32.c b/arch/mips/net/bpf_jit_comp32.c
index 84d9c7036e4f..4a8bedddf61b 100644
--- a/arch/mips/net/bpf_jit_comp32.c
+++ b/arch/mips/net/bpf_jit_comp32.c
@@ -1544,6 +1544,9 @@ int build_insn(const struct bpf_insn *insn, struct jit_context *ctx)
s32 val, rel;
u8 alu, jmp;
+ if (bpf_insn_is_hmul(insn))
+ goto notyet;
+
switch (code) {
/* ALU operations */
/* dst = imm */
diff --git a/arch/mips/net/bpf_jit_comp64.c b/arch/mips/net/bpf_jit_comp64.c
index 994589c3de46..75202cac31f4 100644
--- a/arch/mips/net/bpf_jit_comp64.c
+++ b/arch/mips/net/bpf_jit_comp64.c
@@ -719,6 +719,9 @@ int build_insn(const struct bpf_insn *insn, struct jit_context *ctx)
s32 val, rel;
u8 alu, jmp;
+ if (bpf_insn_is_hmul(insn))
+ goto notyet;
+
switch (code) {
/* ALU operations */
/* dst = imm */
diff --git a/arch/parisc/net/bpf_jit_comp32.c b/arch/parisc/net/bpf_jit_comp32.c
index eea0a34a3bfe..294eee24f2d9 100644
--- a/arch/parisc/net/bpf_jit_comp32.c
+++ b/arch/parisc/net/bpf_jit_comp32.c
@@ -1142,6 +1142,9 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct hppa_jit_context *ctx,
BPF_CLASS(code), code, (code & BPF_ALU64) ? 1:0, BPF_SIZE(code),
BPF_OP(code), insn->src_reg, insn->dst_reg);
+ if (bpf_insn_is_hmul(insn))
+ return -EOPNOTSUPP;
+
switch (code) {
/* dst = src */
case BPF_ALU64 | BPF_MOV | BPF_X:
diff --git a/arch/parisc/net/bpf_jit_comp64.c b/arch/parisc/net/bpf_jit_comp64.c
index c326fa737ec8..319bd28f1e5b 100644
--- a/arch/parisc/net/bpf_jit_comp64.c
+++ b/arch/parisc/net/bpf_jit_comp64.c
@@ -610,6 +610,9 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct hppa_jit_context *ctx,
init_regs(&rd, &rs, insn, ctx);
+ if (bpf_insn_is_hmul(insn))
+ return -EOPNOTSUPP;
+
switch (code) {
/* dst = src */
case BPF_ALU | BPF_MOV | BPF_X:
diff --git a/arch/powerpc/net/bpf_jit_comp32.c b/arch/powerpc/net/bpf_jit_comp32.c
index bfdc50740da8..6bfc97a029d7 100644
--- a/arch/powerpc/net/bpf_jit_comp32.c
+++ b/arch/powerpc/net/bpf_jit_comp32.c
@@ -349,6 +349,9 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct code
u32 true_cond;
u32 tmp_idx;
+ if (bpf_insn_is_hmul(&insn[i]))
+ return -EOPNOTSUPP;
+
if (i && (BPF_CLASS(code) == BPF_ALU64 || BPF_CLASS(code) == BPF_ALU) &&
(BPF_CLASS(prevcode) == BPF_ALU64 || BPF_CLASS(prevcode) == BPF_ALU) &&
BPF_OP(prevcode) == BPF_MOV && BPF_SRC(prevcode) == BPF_X &&
diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c
index fc9db691e820..192c96e0ed34 100644
--- a/arch/powerpc/net/bpf_jit_comp64.c
+++ b/arch/powerpc/net/bpf_jit_comp64.c
@@ -992,6 +992,9 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct code
u32 tmp_idx;
u32 jmp_off;
+ if (bpf_insn_is_hmul(&insn[i]))
+ return -EOPNOTSUPP;
+
/*
* addrs[] maps a BPF bytecode address into a real offset from
* the start of the body code.
diff --git a/arch/riscv/net/bpf_jit_comp32.c b/arch/riscv/net/bpf_jit_comp32.c
index a9e0bd5cc81d..64bc6779d25c 100644
--- a/arch/riscv/net/bpf_jit_comp32.c
+++ b/arch/riscv/net/bpf_jit_comp32.c
@@ -1014,6 +1014,9 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
const s8 *tmp1 = bpf2rv32[TMP_REG_1];
const s8 *tmp2 = bpf2rv32[TMP_REG_2];
+ if (bpf_insn_is_hmul(insn))
+ goto notsupported;
+
switch (code) {
case BPF_ALU64 | BPF_MOV | BPF_X:
if (insn->off != 0) {
diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
index 8eaaac7028a1..35af9a32294a 100644
--- a/arch/s390/net/bpf_jit_comp.c
+++ b/arch/s390/net/bpf_jit_comp.c
@@ -993,6 +993,9 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
bpf_jit_probe_init(&probe);
+ if (bpf_insn_is_hmul(insn))
+ return -EOPNOTSUPP;
+
switch (insn->code) {
/*
* BPF_MOV
diff --git a/arch/sparc/net/bpf_jit_comp_64.c b/arch/sparc/net/bpf_jit_comp_64.c
index 2fa0e9375127..1154ddc515b0 100644
--- a/arch/sparc/net/bpf_jit_comp_64.c
+++ b/arch/sparc/net/bpf_jit_comp_64.c
@@ -901,6 +901,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
const s16 off = insn->off;
const s32 imm = insn->imm;
+ if (bpf_insn_is_hmul(insn))
+ return -EOPNOTSUPP;
+
if (insn->src_reg == BPF_REG_FP)
ctx->saw_frame_pointer = true;
diff --git a/arch/x86/net/bpf_jit_comp32.c b/arch/x86/net/bpf_jit_comp32.c
index 852baf2e4db4..11ed65130d1e 100644
--- a/arch/x86/net/bpf_jit_comp32.c
+++ b/arch/x86/net/bpf_jit_comp32.c
@@ -1683,6 +1683,9 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
int ilen;
u8 *func;
+ if (bpf_insn_is_hmul(insn))
+ goto notyet;
+
switch (code) {
/* ALU operations */
/* dst = src */
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c
index 9ddbfe9d6019..4481c8d84d28 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c
@@ -3,6 +3,7 @@
#include <linux/bpf.h>
#include <linux/bpf_verifier.h>
+#include <linux/filter.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/pkt_cls.h>
@@ -561,6 +562,11 @@ nfp_bpf_check_alu(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
const struct bpf_reg_state *dreg =
cur_regs(env) + meta->insn.dst_reg;
+ if (bpf_insn_is_hmul(&meta->insn)) {
+ pr_vlog(env, "UHMUL/SHMUL are not supported\n");
+ return -EOPNOTSUPP;
+ }
+
meta->umin_src = min(meta->umin_src, reg_umin(sreg));
meta->umax_src = max(meta->umax_src, reg_umax(sreg));
meta->umin_dst = min(meta->umin_dst, reg_umin(dreg));
--
2.56.0
More information about the linux-riscv
mailing list