From: sashiko-bot@kernel.org
To: "Alexei Starovoitov" <alexei.starovoitov@gmail.com>, bpf@vger.kernel.org
Subject: Re: [PATCH bpf-next 12/26] bpf: Refine registers linked by scalar evolution at conditional jumps
Date: Mon, 09 Nov 2026 07:41:24 +0000 [thread overview]
Message-ID: <sashiko-outbox-204548@kernel.org> (raw)
In-Reply-To: <20261109064715.2382452-13-alexei.starovoitov@gmail.com>
Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [Medium] bpf: false verifier_bug_if() in check_special_kfunc() for
slice_slots
- [Medium] bpf: missing tnum_overlap() check in refine_linked_regs()
--
commit 99b81d82029ad28c10234130c05d5b0dee306874
Author: Alexei Starovoitov <ast@kernel.org>
bpf: Refine registers linked by scalar evolution at conditional jumps
This commit uses scalar evolution to find live registers and stack slots
that hold a tested register plus a constant offset on every path to a
conditional jump, and refines their bounds in the main verifier pass.
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 83249ecbdfb1d..d980e2c608050 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
[ ... ]
> @@ -16054,6 +16060,12 @@ static int check_special_kfunc(struct bpf_verifier_env *env, struct bpf_call_arg
> regs[BPF_REG_0].buf = meta->slice_buf;
> if (meta->slice_buf.size)
> env->seen_stack_slice = true;
> + if (verifier_bug_if(meta->slice_buf.size &&
> + !type_is_rdonly_mem(regs[BPF_REG_0].type) &&
> + !bpf_scev_in_slice_slots(env, meta->slice_buf.off,
> + meta->slice_buf.size),
> + env, "slice buffer is not in scev slice_slots"))
> + return -EFAULT;
> } else {
> return 0;
> }
[Severity: Medium]
Can bpf_scev_in_slice_slots() return false here and trigger a false
verifier_bug_if() when bpf_dynptr_slice_rdwr() is called with a
variable-offset PTR_TO_STACK buffer?
bpf_scev_in_slice_slots() requires every slot in
[meta->slice_buf.off, meta->slice_buf.off + meta->slice_buf.size) to be
set in env->scev->slice_slots, which find_slice_slots() populates from
bpf_may_write_mask():
kernel/bpf/verifier.c:check_kfunc_call() {
...
if (buf->type == PTR_TO_STACK) {
meta.slice_buf.frameno = buf->frameno;
meta.slice_buf.off = reg_smin(buf);
meta.slice_buf.size = reg_smax(buf) - reg_smin(buf) +
meta.arg_constant.value;
...
}
When arg_track tracks discrete stack offsets (such as fp-128 and fp-96)
that merge into a range in the main pass, record_stack_access() only sets
may_write_mask for those discrete slots, leaving the intermediate gap
slots (fp-120..fp-104) unset; unlike check_may_write_mask() with
fixed_off == false, bpf_scev_in_slice_slots() rejects the gap slots and
fails verification with -EFAULT.
Similarly, if buffer__szk (meta.arg_constant.value) is 0 and buf has
reg_smax(buf) > reg_smin(buf), record_arg_access() returns early on
!info.size without setting any bits in may_write_mask, while
meta.slice_buf.size is still non-zero.
> @@ -19730,6 +19742,82 @@ static void sync_linked_regs(struct bpf_verifier_env *env, struct bpf_verifier_s
[ ... ]
> +static void refine_linked_regs(struct bpf_verifier_env *env, struct bpf_verifier_state *vstate,
> + int idx, u32 regno)
> +{
> + struct bpf_func_state *frame = vstate->frame[vstate->curframe];
> + struct bpf_reg_state *reg, implied, saved;
> + u32 pos, linked_regno, fill_off, bits;
> + s64 delta;
> +
> + if (frame->regs[regno].type != SCALAR_VALUE)
> + return;
> + for (pos = 0;
> + bpf_scev_next_linked_reg(env, idx, regno, &pos, &linked_regno, &fill_off, &delta,
> + &bits);
> + pos++) {
> + reg = scev_reg_for_fill(frame, linked_regno, fill_off, bits);
> + if (!reg || reg->type != SCALAR_VALUE)
> + continue;
> +
> + implied = frame->regs[regno];
> + add_scalar_to_reg(&implied, delta);
> + if (regs_fit_in_bits(reg, &implied, bits))
> + bits = 64;
> + if (bits < 32)
> + continue;
> + saved = *reg;
> + regs_refine_cond_op(reg, &implied, BPF_JEQ, bits == 32);
> + reg_bounds_sync(reg);
> + if (reg_is_empty(reg) || const_tnum_range_mismatch(reg) ||
> + const_tnum_range_mismatch_32(reg)) {
> + *reg = saved;
> + continue;
> + }
[Severity: Medium]
Does refine_linked_regs() need to check tnum_overlap() before calling
regs_refine_cond_op(reg, &implied, BPF_JEQ, bits == 32)?
tnum_intersect() assumes its operands overlap and ORs conflicting known 0
and known 1 bits into known 1 bits rather than producing an empty state.
On an infeasible branch where reg and implied have overlapping cnum
ranges but disjoint var_off tnums (for instance, r1 = (u8)r0 refined to
even values in [0, 4] while r0 is refined to odd values in [1, 5] on the
taken branch of 'if r0 & 1'), regs_refine_cond_op() turns r1 into odd
values in [1, 3] without triggering reg_is_empty() or
const_tnum_range_mismatch*(), corrupting reg instead of restoring saved.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261109064715.2382452-1-alexei.starovoitov@gmail.com?part=12
next prev parent reply other threads:[~2026-11-09 7:41 UTC|newest]
Thread overview: 37+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-09 6:46 [PATCH bpf-next 00/26] bpf: Find linked registers by scalar evolution, remove scalar ids Alexei Starovoitov
2026-11-09 6:46 ` [PATCH bpf-next 01/26] bpf: Keep the 32-bit range across a no-op sign extension Alexei Starovoitov
2026-11-09 6:46 ` [PATCH bpf-next 02/26] bpf: Model 32-bit shifts and divisions exactly in scalar evolution Alexei Starovoitov
2026-11-09 6:46 ` [PATCH bpf-next 03/26] bpf: Construct scalar evolution expressions without allocations Alexei Starovoitov
2026-11-09 6:46 ` [PATCH bpf-next 04/26] bpf: Don't join dead registers in scalar evolution Alexei Starovoitov
2026-11-09 6:46 ` [PATCH bpf-next 05/26] bpf: Simplify scalar evolution expressions at construction Alexei Starovoitov
2026-11-09 6:46 ` [PATCH bpf-next 06/26] bpf: Give SSA names to the values that scalar evolution does not track Alexei Starovoitov
2026-11-09 7:45 ` bot+bpf-ci
2026-11-09 6:46 ` [PATCH bpf-next 07/26] bpf: Compute scalar evolution expressions for whole subprogs Alexei Starovoitov
2026-11-09 6:46 ` [PATCH bpf-next 08/26] bpf: Mark the attr argument of bpf_sys_bpf() as MEM_WRITE Alexei Starovoitov
2026-11-09 7:17 ` bot+bpf-ci
2026-11-09 6:46 ` [PATCH bpf-next 09/26] bpf: Check writes to the stack against bpf_may_write_mask() Alexei Starovoitov
2026-11-09 7:42 ` sashiko-bot
2026-11-09 6:46 ` [PATCH bpf-next 10/26] bpf: Detect a dead branch when a range and var_off don't overlap Alexei Starovoitov
2026-11-09 6:46 ` [PATCH bpf-next 11/26] bpf: Don't treat half of a 64-bit spill as a 32-bit spill on big endian Alexei Starovoitov
2026-11-09 6:46 ` [PATCH bpf-next 12/26] bpf: Refine registers linked by scalar evolution at conditional jumps Alexei Starovoitov
2026-11-09 7:41 ` sashiko-bot [this message]
2026-11-09 7:45 ` bot+bpf-ci
2026-11-09 6:46 ` [PATCH bpf-next 13/26] selftests/bpf: Test registers linked by scalar evolution Alexei Starovoitov
2026-11-09 6:46 ` [PATCH bpf-next 14/26] selftests/bpf: Test sign extensions of a range and of a linked register Alexei Starovoitov
2026-11-09 6:46 ` [PATCH bpf-next 15/26] bpf: Recompute a pointer after the jump that bounds its index Alexei Starovoitov
2026-11-09 7:32 ` sashiko-bot
2026-11-09 6:47 ` [PATCH bpf-next 16/26] selftests/bpf: Test a pointer computed before its index is bounded Alexei Starovoitov
2026-11-09 6:47 ` [PATCH bpf-next 17/26] bpf: Find a copy of an induction variable without scalar ids Alexei Starovoitov
2026-11-09 7:30 ` bot+bpf-ci
2026-11-09 6:47 ` [PATCH bpf-next 18/26] bpf: Find linked registers in the basic blocks of irreducible loops Alexei Starovoitov
2026-11-09 6:47 ` [PATCH bpf-next 19/26] bpf: Remove sync_linked_regs(), refine by scalar evolution only Alexei Starovoitov
2026-11-09 6:47 ` [PATCH bpf-next 20/26] bpf: Recognize copies of a scalar by their ranges in flow_join_makes_up() Alexei Starovoitov
2026-11-09 6:47 ` [PATCH bpf-next 21/26] bpf: Stop assigning ids to scalars Alexei Starovoitov
2026-11-09 7:08 ` sashiko-bot
2026-11-09 6:47 ` [PATCH bpf-next 22/26] bpf: Remove scalar ids from regsafe() Alexei Starovoitov
2026-11-09 7:06 ` sashiko-bot
2026-11-09 6:47 ` [PATCH bpf-next 23/26] bpf: Remove scalar ids from the join of states Alexei Starovoitov
2026-11-09 6:47 ` [PATCH bpf-next 24/26] bpf: Remove scalar ids from the log and from bpf_verifier.h Alexei Starovoitov
2026-11-09 6:47 ` [PATCH bpf-next 25/26] bpf: Support sign-extended 32-bit linear scalar evolution Alexei Starovoitov
2026-11-09 6:47 ` [PATCH bpf-next 26/26] selftests/bpf: Test loops with a sign-extended 32-bit induction variable Alexei Starovoitov
2026-11-09 18:16 ` [PATCH bpf-next 00/26] bpf: Find linked registers by scalar evolution, remove scalar ids Alexei Starovoitov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-204548@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=alexei.starovoitov@gmail.com \
--cc=bpf@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.