Commit 55c0ced5 authored by Yazhou Tang's avatar Yazhou Tang Committed by Alexei Starovoitov
Browse files

bpf: Reject negative offsets for ALU ops



When verifying BPF programs, the check_alu_op() function validates
instructions with ALU operations. The 'offset' field in these
instructions is a signed 16-bit integer.

The existing check 'insn->off > 1' was intended to ensure the offset is
either 0, or 1 for BPF_MOD/BPF_DIV. However, because 'insn->off' is
signed, this check incorrectly accepts all negative values (e.g., -1).

This commit tightens the validation by changing the condition to
'(insn->off != 0 && insn->off != 1)'. This ensures that any value
other than the explicitly permitted 0 and 1 is rejected, hardening the
verifier against malformed BPF programs.

Co-developed-by: default avatarShenghao Yuan <shenghaoyuan0928@163.com>
Signed-off-by: default avatarShenghao Yuan <shenghaoyuan0928@163.com>
Co-developed-by: default avatarTianci Cao <ziye@zju.edu.cn>
Signed-off-by: default avatarTianci Cao <ziye@zju.edu.cn>
Signed-off-by: default avatarYazhou Tang <tangyazhou518@outlook.com>
Acked-by: default avatarYonghong Song <yonghong.song@linux.dev>
Fixes: ec0e2da9 ("bpf: Support new signed div/mod instructions.")
Link: https://lore.kernel.org/r/tencent_70D024BAE70A0A309A4781694C7B764B0608@qq.com


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 1bd3773a
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -15804,7 +15804,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
	} else {	/* all other ALU ops: and, sub, xor, add, ... */
		if (BPF_SRC(insn->code) == BPF_X) {
			if (insn->imm != 0 || insn->off > 1 ||
			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;
@@ -15814,7 +15814,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
			if (err)
				return err;
		} else {
			if (insn->src_reg != BPF_REG_0 || insn->off > 1 ||
			if (insn->src_reg != BPF_REG_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;