From: Yazhou Tang check_alu_fields() currently validates insn->off together with the source-specific reserved fields. This duplicates the DIV and MOD variant rules between register and immediate forms and makes the valid instruction variants difficult to identify. Move the opcode-specific insn->off validation into is_valid_alu_variant(). The helper permits off == 1 for DIV and MOD and requires off == 0 for all other ALU operations. Validate the variant once, then separately check the reserved immediate field for register sources and src_reg for immediate sources. This is a pure refactoring and does not change which instruction encodings the verifier accepts. Signed-off-by: Yazhou Tang Co-developed-by: Tianci Cao Signed-off-by: Tianci Cao Co-developed-by: Shenghao Yuan Signed-off-by: Shenghao Yuan --- kernel/bpf/verifier.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 8f585ceb2cd5..92ab55ba349d 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -19108,6 +19108,18 @@ static int fd_array_get_map_idx(struct bpf_verifier_env *env, u32 idx) return -EPROTO; } +static bool is_valid_alu_variant(const struct bpf_insn *insn) +{ + switch (BPF_OP(insn->code)) { + case BPF_DIV: + case BPF_MOD: + /* off == 1 selects SDIV/SMOD. */ + return insn->off == 0 || insn->off == 1; + default: + return insn->off == 0; + } +} + static int check_alu_fields(struct bpf_verifier_env *env, struct bpf_insn *insn) { u8 class = BPF_CLASS(insn->code); @@ -19163,15 +19175,9 @@ static int check_alu_fields(struct bpf_verifier_env *env, struct bpf_insn *insn) case BPF_MUL: case BPF_DIV: case BPF_MOD: - if (BPF_SRC(insn->code) == BPF_X) { - if (insn->imm != 0 || (insn->off != 0 && insn->off != 1) || - (insn->off == 1 && opcode != BPF_MOD && opcode != BPF_DIV)) { - verbose(env, "BPF_ALU uses reserved fields\n"); - return -EINVAL; - } - } else if (insn->src_reg != BPF_REG_0 || - (insn->off != 0 && insn->off != 1) || - (insn->off == 1 && opcode != BPF_MOD && opcode != BPF_DIV)) { + if (!is_valid_alu_variant(insn) || + (BPF_SRC(insn->code) == BPF_X && insn->imm != 0) || + (BPF_SRC(insn->code) == BPF_K && insn->src_reg != BPF_REG_0)) { verbose(env, "BPF_ALU uses reserved fields\n"); return -EINVAL; } -- 2.43.0