From: Alexei Starovoitov Date: Fri, 3 Apr 2026 02:44:16 +0000 (-0700) Subject: bpf: Do register range validation early X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=503d21ef8eac1437d76919921115acf0aef328a0;p=thirdparty%2Fkernel%2Flinux.git bpf: Do register range validation early Instead of checking src/dst range multiple times during the main verifier pass do them once. Acked-by: Eduard Zingerman Link: https://lore.kernel.org/r/20260403024422.87231-2-alexei.starovoitov@gmail.com Signed-off-by: Alexei Starovoitov --- diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 5434b162c930..9de49d43c21d 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2256,13 +2256,6 @@ static void __mark_reg_const_zero(const struct bpf_verifier_env *env, struct bpf static void mark_reg_known_zero(struct bpf_verifier_env *env, struct bpf_reg_state *regs, u32 regno) { - if (WARN_ON(regno >= MAX_BPF_REG)) { - verbose(env, "mark_reg_known_zero(regs, %u)\n", regno); - /* Something bad happened, let's kill all regs */ - for (regno = 0; regno < MAX_BPF_REG; regno++) - __mark_reg_not_init(env, regs + regno); - return; - } __mark_reg_known_zero(regs + regno); } @@ -2936,13 +2929,6 @@ static void __mark_reg_unknown(const struct bpf_verifier_env *env, static void mark_reg_unknown(struct bpf_verifier_env *env, struct bpf_reg_state *regs, u32 regno) { - if (WARN_ON(regno >= MAX_BPF_REG)) { - verbose(env, "mark_reg_unknown(regs, %u)\n", regno); - /* Something bad happened, let's kill all regs except FP */ - for (regno = 0; regno < BPF_REG_FP; regno++) - __mark_reg_not_init(env, regs + regno); - return; - } __mark_reg_unknown(env, regs + regno); } @@ -2975,13 +2961,6 @@ static void __mark_reg_not_init(const struct bpf_verifier_env *env, static void mark_reg_not_init(struct bpf_verifier_env *env, struct bpf_reg_state *regs, u32 regno) { - if (WARN_ON(regno >= MAX_BPF_REG)) { - verbose(env, "mark_reg_not_init(regs, %u)\n", regno); - /* Something bad happened, let's kill all regs except FP */ - for (regno = 0; regno < BPF_REG_FP; regno++) - __mark_reg_not_init(env, regs + regno); - return; - } __mark_reg_not_init(env, regs + regno); } @@ -3986,11 +3965,6 @@ static int __check_reg_arg(struct bpf_verifier_env *env, struct bpf_reg_state *r struct bpf_reg_state *reg; bool rw64; - if (regno >= MAX_BPF_REG) { - verbose(env, "R%d is invalid\n", regno); - return -EINVAL; - } - mark_reg_scratched(env, regno); reg = ®s[regno]; @@ -21999,6 +21973,14 @@ static int resolve_pseudo_ldimm64(struct bpf_verifier_env *env) return err; for (i = 0; i < insn_cnt; i++, insn++) { + if (insn->dst_reg >= MAX_BPF_REG) { + verbose(env, "R%d is invalid\n", insn->dst_reg); + return -EINVAL; + } + if (insn->src_reg >= MAX_BPF_REG) { + verbose(env, "R%d is invalid\n", insn->src_reg); + return -EINVAL; + } if (BPF_CLASS(insn->code) == BPF_LDX && ((BPF_MODE(insn->code) != BPF_MEM && BPF_MODE(insn->code) != BPF_MEMSX) || insn->imm != 0)) { diff --git a/tools/testing/selftests/bpf/verifier/junk_insn.c b/tools/testing/selftests/bpf/verifier/junk_insn.c index 89d690f1992a..7d10b0a48f51 100644 --- a/tools/testing/selftests/bpf/verifier/junk_insn.c +++ b/tools/testing/selftests/bpf/verifier/junk_insn.c @@ -28,7 +28,7 @@ { "junk insn4", .insns = { - BPF_RAW_INSN(-1, -1, -1, -1, -1), + BPF_RAW_INSN(-1, 0, 0, -1, -1), BPF_EXIT_INSN(), }, .errstr = "unknown opcode ff", @@ -37,7 +37,7 @@ { "junk insn5", .insns = { - BPF_RAW_INSN(0x7f, -1, -1, -1, -1), + BPF_RAW_INSN(0x7f, 0, 0, -1, -1), BPF_EXIT_INSN(), }, .errstr = "BPF_ALU uses reserved fields",