| From d9fd833798db839be187606e9949021b3ef4f0c6 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 30 Sep 2025 23:04:33 +0800 |
| Subject: bpf: Reject negative offsets for ALU ops |
| |
| From: Yazhou Tang <tangyazhou518@outlook.com> |
| |
| [ Upstream commit 55c0ced59fe17dee34e9dfd5f7be63cbab207758 ] |
| |
| 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: Shenghao Yuan <shenghaoyuan0928@163.com> |
| Signed-off-by: Shenghao Yuan <shenghaoyuan0928@163.com> |
| Co-developed-by: Tianci Cao <ziye@zju.edu.cn> |
| Signed-off-by: Tianci Cao <ziye@zju.edu.cn> |
| Signed-off-by: Yazhou Tang <tangyazhou518@outlook.com> |
| Acked-by: Yonghong Song <yonghong.song@linux.dev> |
| Fixes: ec0e2da95f72 ("bpf: Support new signed div/mod instructions.") |
| Link: https://lore.kernel.org/r/tencent_70D024BAE70A0A309A4781694C7B764B0608@qq.com |
| Signed-off-by: Alexei Starovoitov <ast@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| kernel/bpf/verifier.c | 4 ++-- |
| 1 file changed, 2 insertions(+), 2 deletions(-) |
| |
| diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c |
| index 299e43dac873e..ed1457c273409 100644 |
| --- a/kernel/bpf/verifier.c |
| +++ b/kernel/bpf/verifier.c |
| @@ -15755,7 +15755,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; |
| @@ -15765,7 +15765,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; |
| -- |
| 2.51.0 |
| |