BPF List
 help / color / mirror / Atom feed
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

  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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox