mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Vineet Gupta <vineet.gupta@linux.dev>
To: bot+bpf-ci@kernel.org, ast@kernel.org, daniel@iogearbox.net,
	andrii@kernel.org, eddyz87@gmail.com, memxor@gmail.com
Cc: martin.lau@linux.dev, song@kernel.org, yonghong.song@linux.dev,
	jolsa@kernel.org, emil@etsalapatis.com, ihor.solodrai@linux.dev,
	john.fastabend@gmail.com, shuah@kernel.org, bpf@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org,
	martin.lau@kernel.org, mason@kernel.org
Subject: Re: [PATCH bpf-next v2 03/13] bpf: track low-32 scalar equality across zero-extending movs
Date: Fri, 11 Sep 2026 14:59:57 +0530	[thread overview]
Message-ID: <c0a15bf9-0922-42a7-b2a9-d7eff50669a5@linux.dev> (raw)
In-Reply-To: <ad011852b5532901853fbc1c16d5a27d50231065dad9b1e4bbfee1c02b4735e5@mail.kernel.org>

On 9/10/26 11:22 PM, bot+bpf-ci@kernel.org wrote:
>> @@ -17115,6 +17126,23 @@ static void collect_linked_regs(struct bpf_verifier_env *env,
>>   	}
>>   }
>>
>> +/*
>> + * Set @reg to the zero-extension of @known_reg's low 32 bits: it shares those
>> + * bits and its high half is zero. Copy the base to keep its precise low-32
>> + * tnum, then re-apply the zext_32_to_64() the 32-bit mov itself used.
>> + * @reg->id and ->delta already equal @known_reg's; only ->subreg is its own.
>> + */
>> +static void reconstruct_zext32(struct bpf_reg_state *reg,
>> +			       struct bpf_reg_state *known_reg)
>> +{
>> +	enum bpf_subreg subreg = reg->subreg;
>> +
>> +	*reg = *known_reg;
>> +	reg->subreg = subreg;
>> +	zext_32_to_64(reg);
>> +	reg_bounds_sync(reg);
>> +}
>> +
>>   /* For all R in linked_regs, copy known_reg range into R
>>    * if R->id == known_reg->id.
>>    */
>> @@ -17134,6 +17162,27 @@ static void sync_linked_regs(struct bpf_verifier_env *env, struct bpf_verifier_s
>>   			continue;
>>   		if (reg->id != known_reg->id)
>>   			continue;
>> +		/*
>> +		 * A ->subreg register shares only the base's low 32 bits, so it
>> +		 * is rebuilt rather than copied. Not modelled together with a
>> +		 * delta, so skip if either side has one (sound, less precise).
>> +		 */
>> +		if (reg->subreg) {
>> +			if (reg->add_const || known_reg->add_const)
>> +				continue;
>> +			reconstruct_zext32(reg, known_reg);
>> +			if (e->is_reg)
>> +				mark_reg_scratched(env, e->regno);
>> +			else
>> +				mark_stack_slot_scratched(env, e->spi);
>> +			continue;
>> +		}
>> +		/*
>> +		 * The reverse: known_reg knows only its low 32 bits, which say
>> +		 * nothing about reg's high half.
>> +		 */
>> +		if (known_reg->subreg)
>> +			continue;
>>   		/*
>>   		 * Skip mixed 32/64-bit links: the delta relationship doesn't
>>   		 * hold across different ALU widths.
> Can reconstruct_zext32() lose bounds that reg already learned on its own?
>
> Looking at the code, reconstruct_zext32() does:
>
>      *reg = *known_reg;
>      reg->subreg = subreg;
>      zext_32_to_64(reg);
>
> This overwrites reg's state wholesale without intersecting it with what reg
> already knew.
>
> For pre-existing full-64-bit links, sync_linked_regs() propagates changes
> in both directions, so the base is always at least as narrow as every
> member and the overwrite can only narrow. But the new low-32 link skips
> the member->base direction:
>
>      if (known_reg->subreg)
>          continue;
>
> so the base can end up strictly wider than the ->subreg member.
>
> Consider this sequence:
>
>    call bpf_get_prandom_u32;    /* r0 -> 64-bit unknown */
>    r6 = r0;                     /* r6 is 64-bit unknown */
>    w7 = w6;                     /* r7->id = r6->id, r7->subreg = SUBREG_ZEXT */
>    if w7 > 7 goto out;          /* fall-through: r7 u32 range [0,7]
>                                  * sync_linked_regs(known_reg=r7) skips r6 due
>                                  * to `if (known_reg->subreg) continue;`
>                                  * so r6 stays fully unknown */
>    if r6 > 100 goto out;        /* fall-through: r6 narrows to [0,100]
>                                  * sync_linked_regs(known_reg=r6) reaches r7
>                                  * via reconstruct_zext32(r7, r6) which does
>                                  * *r7 = *r6 then zext_32_to_64() */
>
> After the second jump, does r7 become [0,100] instead of staying [0,7]?

Yes it does and that's a problem.

> If so, a jump on an unrelated wide register would widen the bounds of a
> narrow copy that the verifier had already proved tighter, on a
> straight-line path. That would reject programs that narrowed the 32-bit
> copy first and the wide original second, then relied on the copy's
> narrower bound for a memory access or helper argument.

Right, sound, but loss of precision.

> The changelog acknowledges the other precision loss this patch introduces
> ("forming one costs the source its delta ... That loses tracking a wide
> source used to keep") and the follow-up selftest commit 36b84852a200 pins
> it down with zext_mov_breaks_add_const_src. But neither the changelog nor
> reconstruct_zext32()'s comment ("Copy the base to keep its precise low-32
> tnum"), nor any of the 10 new tests in 36b84852a200, mentions or covers
> this path. The only test that checks the member's fate is
> zext_narrow_dst_keeps_base, which verifies the base is not narrowed but
> does not check what happens to the member afterwards.

Ok. zext_sync_keeps_narrower_member() added and same for sext variant as 
reconstruct_sext32 gets similar fix.

> Would intersecting the rebuilt state with the member's existing one,

This one.

+       cnum64_intersect_with(&reg->r64, prev.r64);
+       cnum32_intersect_with(&reg->r32, prev.r32);
+       reg->var_off = tnum_intersect(reg->var_off, prev.var_off);

> narrowing the base's low half on the member->base direction instead of
> skipping it, prevent the member from ever being wider than what it already
> proved?

This is a new propagation path, trying to be conservative here.

Thx,
-Vineet

> ---
> AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
> See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
>
> CI run summary: https://github.com/kernel-patches/bpf/actions/runs/34506184282


  reply	other threads:[~2026-09-11  9:30 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-10 16:46 [PATCH bpf-next v2 00/13] bpf: track scalar equality across the low 32 bits Vineet Gupta
2026-09-10 16:46 ` [PATCH bpf-next v2 01/13] bpf: move linked-scalar flags out of bpf_reg_state->id [NFC] Vineet Gupta
2026-09-10 17:52   ` bot+bpf-ci
2026-09-10 16:46 ` [PATCH bpf-next v2 02/13] bpf: compare linked-scalar kinds in regs_exact() Vineet Gupta
2026-09-10 16:46 ` [PATCH bpf-next v2 03/13] bpf: track low-32 scalar equality across zero-extending movs Vineet Gupta
2026-09-10 17:52   ` bot+bpf-ci
2026-09-11  9:29     ` Vineet Gupta [this message]
2026-09-10 16:46 ` [PATCH bpf-next v2 04/13] selftests/bpf: cover the low-32 link for " Vineet Gupta
2026-09-10 16:46 ` [PATCH bpf-next v2 05/13] bpf: keep the range across a sign extension that cannot change it Vineet Gupta
2026-09-10 17:52   ` bot+bpf-ci
2026-09-11 10:37     ` Vineet Gupta
2026-09-10 16:46 ` [PATCH bpf-next v2 06/13] selftests/bpf: cover sign extensions that cannot change the range Vineet Gupta
2026-09-10 16:46 ` [PATCH bpf-next v2 07/13] bpf: track low-32 scalar equality across sign-extending movs Vineet Gupta
2026-09-10 17:52   ` bot+bpf-ci
2026-09-11 10:00     ` Vineet Gupta
2026-09-10 16:46 ` [PATCH bpf-next v2 08/13] selftests/bpf: cover the low-32 link for " Vineet Gupta
2026-09-10 17:52   ` bot+bpf-ci
2026-09-11  8:00     ` Vineet Gupta
2026-09-10 16:46 ` [PATCH bpf-next v2 09/13] bpf: track low-32 scalar equality across narrowing stack fills Vineet Gupta
2026-09-10 16:46 ` [PATCH bpf-next v2 10/13] selftests/bpf: cover the low-32 link for " Vineet Gupta
2026-09-10 17:31   ` bot+bpf-ci
2026-09-11  5:07     ` Vineet Gupta
2026-09-10 16:46 ` [PATCH bpf-next v2 11/13] bpf: record what a narrowing spill actually stores Vineet Gupta
2026-09-10 16:46 ` [PATCH bpf-next v2 12/13] bpf: track low-32 scalar equality across narrowing stack spills Vineet Gupta
2026-09-10 16:46 ` [PATCH bpf-next v2 13/13] selftests/bpf: cover the low-32 link for " Vineet Gupta

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=c0a15bf9-0922-42a7-b2a9-d7eff50669a5@linux.dev \
    --to=vineet.gupta@linux.dev \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bot+bpf-ci@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=eddyz87@gmail.com \
    --cc=emil@etsalapatis.com \
    --cc=ihor.solodrai@linux.dev \
    --cc=john.fastabend@gmail.com \
    --cc=jolsa@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=martin.lau@kernel.org \
    --cc=martin.lau@linux.dev \
    --cc=mason@kernel.org \
    --cc=memxor@gmail.com \
    --cc=shuah@kernel.org \
    --cc=song@kernel.org \
    --cc=yonghong.song@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

all inboxes | Powered by JetHome®