All of lore.kernel.org
 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 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.