BPF List
 help / color / mirror / Atom feed
From: Vineet Gupta <vineet.gupta@linux.dev>
To: sashiko-reviews@lists.linux.dev
Cc: bpf@vger.kernel.org
Subject: Re: [PATCH bpf-next v2 09/13] bpf: track low-32 scalar equality across narrowing stack fills
Date: Fri, 11 Sep 2026 11:37:52 +0530	[thread overview]
Message-ID: <3f3e5658-4393-4530-8b3b-987fe20ddc95@linux.dev> (raw)
In-Reply-To: <20260910170419.4C8601F000FF@smtp.kernel.org>

On 9/10/26 10:34 PM, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [Critical] Sign-extending loads incorrectly preserve conflicting SUBREG_ZEXT metadata.
> --
>
> commit f939550a777ae3d2a7392dec744bffdc9fabcdda
> Author: Vineet Gupta <vineet.gupta@linux.dev>
>
> bpf: track low-32 scalar equality across narrowing stack fills
>
> This commit records a low-32 link for stack fills narrower than the wider
> source, allowing the verifier to deduce relations between 32-bit narrows
> and their wider origins. It also adjusts check_mem_access() to not clear
> the id of a ->subreg register on a sign-extending load.
>
>> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
>> index 308ff53232f06..89be1240c99ae 100644
>> --- a/kernel/bpf/verifier.c
>> +++ b/kernel/bpf/verifier.c
> [ ... ]
>
>> @@ -3968,18 +3969,34 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env,
>>   
>>   			if (size <= spill_size &&
>>   			    bpf_stack_narrow_access_ok(off, size, spill_size)) {
>> -				if (env->bpf_capable && size == 4 && spill_size == 4 &&
>> -				    get_reg_width(reg) <= 32)
>> +				bool narrowing = get_reg_width(reg) > size * BITS_PER_BYTE;
>> +				/*
>> +				 * A narrowing fill keeps only the slot's low 32 bits,
>> +				 * so record a low-32 link rather than dropping the
>> +				 * relation, as a 32-bit mov from a wide source does.
>> +				 * Which kind depends on how the load fills the high
>> +				 * half, hence is_ldsx.
>> +				 */
>> +				bool subreg_link = narrowing && size == 4;
>> +
>> +				if (env->bpf_capable && size == 4 &&
>> +				    (subreg_link || (spill_size == 4 && !narrowing)))
>>   					/* Ensure stack slot has an ID to build a relation
>>   					 * with the destination register on fill.
>>   					 */
>>   					assign_scalar_id_before_mov(env, reg);
>>   				state->regs[dst_regno] = *reg;
>>   
>> -				/* Break the relation on a narrowing fill.
>> -				 * coerce_reg_to_size will adjust the boundaries.
>> -				 */
>> -				if (get_reg_width(reg) > size * BITS_PER_BYTE)
>> +				if (subreg_link && reg->id)
>> +					state->regs[dst_regno].subreg =
>> +						is_ldsx ? SUBREG_SEXT : SUBREG_ZEXT;
>> +				else if (narrowing)
>> +					/*
>> +					 * Nothing to relate: either the slot has
>> +					 * no id to share, or the fill is narrower
>> +					 * than the 32 bits a link can describe.
>> +					 * coerce_reg_to_size adjusts the bounds.
>> +					 */
>>   					clear_scalar_id(&state->regs[dst_regno]);
> [Severity: Critical]
> When narrowing is false, does this preserve a stale SUBREG_ZEXT property for
> a sign-extending load?
>
> If a register with SUBREG_ZEXT is spilled to the stack and then read back
> via a 4-byte sign-extending load, narrowing evaluates to false. This allows
> the destination register to inherit the SUBREG_ZEXT property directly from
> the stack slot, even though it is being sign-extended.
>
> [ ... ]

Indeed if narrowing is false, wrong metadata can potentially be 
introduced, a comment to that effect is added here.

    /*
      * A fill that is not narrowing copies the slot's
      * kind verbatim, which a sign-extending load can
      * contradict. check_mem_access() runs after this
      * and drops any kind but SUBREG_SEXT once it knows
      * the extension was not a no-op.
      */


See the second site below for actual fix...

>> @@ -6736,13 +6753,15 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, struct b
>>   			 * Sign-extension can change the register value relative
>>   			 * to a scalar it is linked with by id (e.g. a zero-
>>   			 * extending fill of the same spilled stack slot), thus
>> -			 * drop the shared id in that case.
>> +			 * drop the shared id in that case. A ->subreg link is
>> +			 * the exception: it already records that only the low
>> +			 * 32 bits are shared, and how the high half follows.
>>   			 */
>>   			bool no_sext = reg_umax(&regs[value_regno]) <
>>   					(1ULL << (size * BITS_PER_BYTE - 1));
>>   
>>   			coerce_reg_to_size_sx(&regs[value_regno], size);
>> -			if (!no_sext)
>> +			if (!no_sext && !regs[value_regno].subreg)
>>   				clear_scalar_id(&regs[value_regno]);
> [Severity: Critical]
> Does this check wrongly preserve the ID for SUBREG_ZEXT registers that
> have just been sign-extended?
>
> Because SUBREG_ZEXT is non-zero, !regs[value_regno].subreg evaluates to
> false, skipping the clear_scalar_id() call for a register that might hold
> a sign-extended negative value.
>
> Later, if a conditional branch triggers sync_linked_regs(), it will see
> SUBREG_ZEXT and invoke reconstruct_zext32(). This would forcefully set the
> bounds to a zero-extended positive value.
>
> At runtime, the discrepancy between the verifier's zero-extended positive
> bounds and the actual sign-extended negative value could bypass bounds checks,
> potentially leading to out-of-bounds memory reads or writes.
>
> Should this explicitly check for SUBREG_SEXT rather than just allowing any
> non-zero ->subreg value?
Exactly that. And the first path leads here so the comment above suffices.

Thx,
-Vineet

  reply	other threads:[~2026-09-11  6:07 UTC|newest]

Thread overview: 39+ 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:00   ` sashiko-bot
2026-09-11  6:56     ` Vineet Gupta
2026-09-10 17:52   ` bot+bpf-ci
2026-09-12 18:50   ` Alexei Starovoitov
2026-09-10 16:46 ` [PATCH bpf-next v2 02/13] bpf: compare linked-scalar kinds in regs_exact() Vineet Gupta
2026-09-12 18:51   ` Alexei Starovoitov
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
2026-09-12 18:59   ` Alexei Starovoitov
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:08   ` sashiko-bot
2026-09-10 17:52   ` bot+bpf-ci
2026-09-11 10:37     ` Vineet Gupta
2026-09-12 19:02   ` Alexei Starovoitov
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-12 19:09   ` Alexei Starovoitov
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 17:04   ` sashiko-bot
2026-09-11  6:07     ` Vineet Gupta [this message]
2026-09-11  6:43       ` 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:00   ` sashiko-bot
2026-09-11  5:34     ` 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 17:05   ` sashiko-bot
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=3f3e5658-4393-4530-8b3b-987fe20ddc95@linux.dev \
    --to=vineet.gupta@linux.dev \
    --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