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 <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20260403024422.87231-2-alexei.starovoitov@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Alexei Starovoitov
2026-04-02 19:44:16 -07:00
parent 891a05ccba
commit 503d21ef8e
2 changed files with 10 additions and 28 deletions

View File

@@ -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, static void mark_reg_known_zero(struct bpf_verifier_env *env,
struct bpf_reg_state *regs, u32 regno) 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); __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, static void mark_reg_unknown(struct bpf_verifier_env *env,
struct bpf_reg_state *regs, u32 regno) 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); __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, static void mark_reg_not_init(struct bpf_verifier_env *env,
struct bpf_reg_state *regs, u32 regno) 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); __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; struct bpf_reg_state *reg;
bool rw64; bool rw64;
if (regno >= MAX_BPF_REG) {
verbose(env, "R%d is invalid\n", regno);
return -EINVAL;
}
mark_reg_scratched(env, regno); mark_reg_scratched(env, regno);
reg = &regs[regno]; reg = &regs[regno];
@@ -21999,6 +21973,14 @@ static int resolve_pseudo_ldimm64(struct bpf_verifier_env *env)
return err; return err;
for (i = 0; i < insn_cnt; i++, insn++) { 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 && if (BPF_CLASS(insn->code) == BPF_LDX &&
((BPF_MODE(insn->code) != BPF_MEM && BPF_MODE(insn->code) != BPF_MEMSX) || ((BPF_MODE(insn->code) != BPF_MEM && BPF_MODE(insn->code) != BPF_MEMSX) ||
insn->imm != 0)) { insn->imm != 0)) {

View File

@@ -28,7 +28,7 @@
{ {
"junk insn4", "junk insn4",
.insns = { .insns = {
BPF_RAW_INSN(-1, -1, -1, -1, -1), BPF_RAW_INSN(-1, 0, 0, -1, -1),
BPF_EXIT_INSN(), BPF_EXIT_INSN(),
}, },
.errstr = "unknown opcode ff", .errstr = "unknown opcode ff",
@@ -37,7 +37,7 @@
{ {
"junk insn5", "junk insn5",
.insns = { .insns = {
BPF_RAW_INSN(0x7f, -1, -1, -1, -1), BPF_RAW_INSN(0x7f, 0, 0, -1, -1),
BPF_EXIT_INSN(), BPF_EXIT_INSN(),
}, },
.errstr = "BPF_ALU uses reserved fields", .errstr = "BPF_ALU uses reserved fields",