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 v2 20/29] bpf: Find a copy of an induction variable without scalar ids
Date: Wed, 11 Nov 2026 05:57:25 +0000	[thread overview]
Message-ID: <sashiko-outbox-208372@kernel.org> (raw)
In-Reply-To: <20261111051341.2800252-21-alexei.starovoitov@gmail.com>

Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [High] bpf: type confusion between pointer and scalar bounds in
  is_iv_at_header()
--

commit a899486291f489b60aa159499a2316c95dbc938e
Author: Alexei Starovoitov <ast@kernel.org>

bpf: Find a copy of an induction variable without scalar ids

This commit replaces COPY_SCEV and scalar ID checks for induction variable
copies with untyped expression comparisons via const_diff_at_header().

> diff --git a/kernel/bpf/scev.c b/kernel/bpf/scev.c
> index 98a05f97196a6..28fd06c16fe4d 100644
> --- a/kernel/bpf/scev.c
> +++ b/kernel/bpf/scev.c

[ ... ]

> @@ -4585,6 +4518,19 @@ static void linear_bounds(struct bpf_reg_state *reg, u32 max_header_count,
>  	out->r32 = r32;
>  }
>  
> +/*
> + * Is @r the induction variable that the latch tests, or congruent to it: equal to it at the header
> + * of the loop at @h in every iteration? Then the range of the one is the range of the other.
> + */
> +static bool is_iv_at_header(struct bpf_verifier_env *env, int h, int iv_reg, u32 r)
> +{
> +	s64 delta;
> +
> +	if (iv_reg < 0)
> +		return false;
> +	return r == iv_reg || (const_diff_at_header(env, h, iv_reg, r, &delta) && !delta);
> +}
> +
>  static void iv_bounds(struct bounds *bounds, struct cnum64 iv_range)
>  {
>  	struct cnum64 r64 = cnum64_intersect(bounds->r64, iv_range);

[ ... ]

> @@ -5128,7 +5074,7 @@ int bpf_widen_scev_regs(struct bpf_verifier_env *env, struct bpf_verifier_state
>  			if (err)
>  				return err;
>  			linear_bounds(reg, iters->max_header_count, &coefs, &bounds);
> -			if (coefs.base_reg == iters->iv_reg)
> +			if (is_iv_at_header(env, insn_idx, iters->iv_reg, coefs.base_reg))
>  				iv_bounds(&bounds, iters->iv_range);
>  			if (log->level & BPF_LOG_LEVEL2) {
>  				bpf_log(log, "loop header at %d, widening ", insn_idx);

[ ... ]

> @@ -5251,7 +5196,11 @@ int bpf_clamp_scev_regs(struct bpf_verifier_env *env, struct bpf_func_state *cur
>  			continue;
>  clamp:
>  		linear_bounds(entry_reg, max_header_count, &coefs, &bounds);
> -		if (coefs.base_reg == entry->iv_reg && !moved)
> +		/*
> +		 * iv_range is the range at the header. After the latch @r can be the zero extension
> +		 * of its header value. @reg went through that insn and has what holds of the range.
> +		 */
> +		if (!behind && is_iv_at_header(env, insn_idx, entry->iv_reg, coefs.base_reg))
>  			iv_bounds(&bounds, entry->iv_range);
>  		if (moved) {
>  			/* a sum that can wrap has another residue, see scalar_step_add() */

[Severity: High]
Can is_iv_at_header() apply a pointer induction variable's offset range
(iv_range) to a congruent SCALAR_VALUE register?

const_diff_at_header() compares untyped SCEV expressions without checking
that iv_reg and r have the same register type in the loop-entry state.  In
transfer(), a no-op 64-bit BPF_ALU | BPF_END (such as le64 on a
little-endian host) leaves reg2expr[dst] unchanged:

kernel/bpf/scev.c:transfer() {
    ...
			need_bswap = class == BPF_ALU64 || ((x_or_k == BPF_TO_LE) != little_endian);
			switch (insn->imm) {
			case 16: op = need_bswap ? BSWAP16 : ZEXT16; break;
			case 32: op = need_bswap ? BSWAP32 : ZEXT32; break;
			case 64: op = need_bswap ? BSWAP64 : 0; break;
    ...
			id = reg2expr[dst];
			if (op)
				id = expr1(scev, op, reg2expr[dst]);

			return replace_reg(scev, e, dst, id);
}

When env->allow_ptr_leaks is enabled, check_alu_op() degrades a pointer
register passed to that instruction to an unknown SCALAR_VALUE while the
instruction preserves the raw 64-bit pointer value at runtime.

If iv_reg is a pointer induction variable (for example PTR_TO_MAP_VALUE
with offset in [1, 10]) and r is copied from iv_reg and passed through a
64-bit no-op BPF_END both before the loop and on the backedge,
compute_header_scevs() and is_iv_at_header() treat r as congruent to
iv_reg.  bpf_widen_scev_regs() and bpf_clamp_scev_regs() then intersect
r's scalar bounds with iv_range, causing the verifier to bound a register
holding a raw 64-bit kernel pointer to the small scalar range [1, 10] and
allowing out-of-bounds memory access.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261111051341.2800252-1-alexei.starovoitov@gmail.com?part=20

  reply	other threads:[~2026-11-11  5:57 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-11  5:13 [PATCH bpf-next v2 00/29] bpf: Find linked registers by scalar evolution, remove scalar ids Alexei Starovoitov
2026-11-11  5:13 ` [PATCH bpf-next v2 01/29] bpf: Keep the 32-bit range across a no-op sign extension Alexei Starovoitov
2026-11-11  5:13 ` [PATCH bpf-next v2 02/29] bpf: Model 32-bit shifts and divisions exactly in scalar evolution Alexei Starovoitov
2026-11-11  5:13 ` [PATCH bpf-next v2 03/29] bpf: Construct scalar evolution expressions without allocations Alexei Starovoitov
2026-11-11  5:13 ` [PATCH bpf-next v2 04/29] bpf: Don't join dead registers in scalar evolution Alexei Starovoitov
2026-11-11  8:27   ` bot+bpf-ci
2026-11-11  5:13 ` [PATCH bpf-next v2 05/29] bpf: Simplify scalar evolution expressions at construction Alexei Starovoitov
2026-11-11  5:13 ` [PATCH bpf-next v2 06/29] bpf: Give SSA names to the values that scalar evolution does not track Alexei Starovoitov
2026-11-11  8:27   ` bot+bpf-ci
2026-11-11  5:13 ` [PATCH bpf-next v2 07/29] bpf: Compute scalar evolution expressions for whole subprogs Alexei Starovoitov
2026-11-11  5:13 ` [PATCH bpf-next v2 08/29] bpf: Mark the attr argument of bpf_sys_bpf() as MEM_WRITE Alexei Starovoitov
2026-11-11  5:13 ` [PATCH bpf-next v2 09/29] bpf: Include older frames in a fill through an imprecise stack pointer Alexei Starovoitov
2026-11-11  5:13 ` [PATCH bpf-next v2 10/29] bpf: Detect a dead branch when a range and var_off don't overlap Alexei Starovoitov
2026-11-11  8:27   ` bot+bpf-ci
2026-11-11  5:13 ` [PATCH bpf-next v2 11/29] bpf: Don't treat half of a 64-bit spill as a 32-bit spill on big endian Alexei Starovoitov
2026-11-11  5:13 ` [PATCH bpf-next v2 12/29] bpf: Refine registers linked by scalar evolution at conditional jumps Alexei Starovoitov
2026-11-11  5:13 ` [PATCH bpf-next v2 13/29] bpf: Value number the phis of scalar evolution Alexei Starovoitov
2026-11-11  8:27   ` bot+bpf-ci
2026-11-11  5:13 ` [PATCH bpf-next v2 14/29] selftests/bpf: Test registers linked by " Alexei Starovoitov
2026-11-11  5:13 ` [PATCH bpf-next v2 15/29] selftests/bpf: Test sign extensions of a range and of a linked register Alexei Starovoitov
2026-11-11  5:13 ` [PATCH bpf-next v2 16/29] bpf: Recompute a pointer after the jump that bounds its index Alexei Starovoitov
2026-11-11  5:48   ` sashiko-bot
2026-11-11  5:13 ` [PATCH bpf-next v2 17/29] selftests/bpf: Test a pointer computed before its index is bounded Alexei Starovoitov
2026-11-11  5:13 ` [PATCH bpf-next v2 18/29] bpf: Promote memory behind a pointer to SCEV registers Alexei Starovoitov
2026-11-11  5:13 ` [PATCH bpf-next v2 19/29] selftests/bpf: Test the memory of a caller that a jump tests Alexei Starovoitov
2026-11-11  5:13 ` [PATCH bpf-next v2 20/29] bpf: Find a copy of an induction variable without scalar ids Alexei Starovoitov
2026-11-11  5:57   ` sashiko-bot [this message]
2026-11-11  5:13 ` [PATCH bpf-next v2 21/29] bpf: Compute scalar evolution expressions in irreducible loops Alexei Starovoitov
2026-11-11  5:13 ` [PATCH bpf-next v2 22/29] bpf: Remove sync_linked_regs(), refine by scalar evolution only Alexei Starovoitov
2026-11-11  5:13 ` [PATCH bpf-next v2 23/29] bpf: Recognize copies of a scalar by their ranges in flow_join_makes_up() Alexei Starovoitov
2026-11-11  5:13 ` [PATCH bpf-next v2 24/29] bpf: Stop assigning ids to scalars Alexei Starovoitov
2026-11-11  5:13 ` [PATCH bpf-next v2 25/29] bpf: Remove scalar ids from regsafe() Alexei Starovoitov
2026-11-11  5:13 ` [PATCH bpf-next v2 26/29] bpf: Remove scalar ids from the join of states Alexei Starovoitov
2026-11-11  5:13 ` [PATCH bpf-next v2 27/29] bpf: Remove scalar ids from the log and from bpf_verifier.h Alexei Starovoitov
2026-11-11  5:13 ` [PATCH bpf-next v2 28/29] bpf: Support sign-extended 32-bit linear scalar evolution Alexei Starovoitov
2026-11-11  5:13 ` [PATCH bpf-next v2 29/29] selftests/bpf: Test loops with a sign-extended 32-bit induction variable 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-208372@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