From: Vineet Gupta <vineet.gupta@linux.dev>
To: 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,
Vineet Gupta <vineet.gupta@linux.dev>
Subject: [PATCH bpf-next v2 10/13] selftests/bpf: cover the low-32 link for narrowing stack fills
Date: Thu, 10 Sep 2026 22:16:32 +0530 [thread overview]
Message-ID: <20260910164635.459558-11-vineet.gupta@linux.dev> (raw)
In-Reply-To: <20260910164635.459558-1-vineet.gupta@linux.dev>
Five programs, following the mov set:
- zext_fill_narrow_from_wide_spill: narrowing the spilled value reaches
the filled register
- sext_fill_narrow_from_wide_spill: the same for a sign-extending fill,
and the value that arrives is sign-extended
- zext_fill_full_width_keeps_full_link: a full-width fill is a plain
64-bit equality and must keep propagating as before
- zext_fill_byte_forms_no_link: a sub-word fill is below the low-32
model, so no link is formed
- fill_kinds_reach_different_values: the same, for the two fill kinds off
one slot
The first two are the ones that pin the new behaviour: disabling link
formation in the fill arm makes both fail. The other three are guards
against the feature applying where it should not, and hold either way.
Signed-off-by: Vineet Gupta <vineet.gupta@linux.dev>
---
v2: new, with 9/13.
.../bpf/progs/verifier_linked_scalars.c | 144 ++++++++++++++++++
1 file changed, 144 insertions(+)
diff --git a/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c b/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c
index 9d060d8b0c1f..e8a44e7579c8 100644
--- a/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c
+++ b/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c
@@ -966,6 +966,88 @@ __naked void zext_mov_breaks_add_const_src(void)
: __clobber_all);
}
+/*
+ * A narrowing fill keeps only the slot's low 32 bits, so a later narrowing of
+ * the spilled value must still reach the filled register. Same relation as a
+ * 32-bit mov from a wide source, with the stack slot as the base.
+ */
+SEC("socket")
+__success
+__naked void zext_fill_narrow_from_wide_spill(void)
+{
+ asm volatile (" \
+ call %[bpf_get_prandom_u32]; \
+ r6 = r0; \
+ call %[bpf_get_prandom_u32]; \
+ r0 <<= 32; \
+ r6 |= r0; /* r6 = full 64-bit unknown */ \
+ *(u64 *)(r10 - 8) = r6; /* slot linked to r6 */ \
+ r2 = *(u32 *)(r10 - 8); /* narrowing fill, forms the link */ \
+ if w6 != 0 goto 1f; /* narrows r6, propagates to r2 */ \
+ if r2 == 0 goto 1f; \
+ r0 /= 0; \
+1: \
+ r0 = 0; \
+ exit; \
+" :
+ : __imm(bpf_get_prandom_u32)
+ : __clobber_all);
+}
+
+/*
+ * A full-width fill of a wide slot is a plain 64-bit equality, not a low-32
+ * link, so it must keep propagating exactly as before.
+ */
+SEC("socket")
+__success
+__naked void zext_fill_full_width_keeps_full_link(void)
+{
+ asm volatile (" \
+ call %[bpf_get_prandom_u32]; \
+ r6 = r0; \
+ call %[bpf_get_prandom_u32]; \
+ r0 <<= 32; \
+ r6 |= r0; \
+ *(u64 *)(r10 - 8) = r6; \
+ r2 = *(u64 *)(r10 - 8); /* no narrowing */ \
+ if r6 != 0 goto 1f; \
+ if r2 == 0 goto 1f; \
+ r0 /= 0; \
+1: \
+ r0 = 0; \
+ exit; \
+" :
+ : __imm(bpf_get_prandom_u32)
+ : __clobber_all);
+}
+
+/*
+ * A sub-word fill is below the low-32 model, so no link is formed and the
+ * relation is dropped as before.
+ */
+SEC("socket")
+__failure __msg("div by zero")
+__naked void zext_fill_byte_forms_no_link(void)
+{
+ asm volatile (" \
+ call %[bpf_get_prandom_u32]; \
+ r6 = r0; \
+ call %[bpf_get_prandom_u32]; \
+ r0 <<= 32; \
+ r6 |= r0; \
+ *(u64 *)(r10 - 8) = r6; \
+ r2 = *(u8 *)(r10 - 8); /* 1-byte fill: no link */ \
+ if w6 != 0 goto 1f; \
+ if r2 == 0 goto 1f; /* not deduced */ \
+ r0 /= 0; \
+1: \
+ r0 = 0; \
+ exit; \
+" :
+ : __imm(bpf_get_prandom_u32)
+ : __clobber_all);
+}
+
#ifdef CAN_USE_MOVSX
/*
@@ -1129,6 +1211,68 @@ __naked void sext_kinds_reach_different_values(void)
: __clobber_all);
}
+/*
+ * The sign-extending counterpart: the filled register is the sign extension of
+ * the slot's low 32 bits, so a narrowing of those bits arrives sign-extended.
+ */
+SEC("socket")
+__success
+__naked void sext_fill_narrow_from_wide_spill(void)
+{
+ asm volatile (" \
+ call %[bpf_get_prandom_u32]; \
+ r6 = r0; \
+ call %[bpf_get_prandom_u32]; \
+ r0 <<= 32; \
+ r6 |= r0; /* r6 = full 64-bit unknown */ \
+ *(u64 *)(r10 - 8) = r6; /* slot linked to r6 */ \
+ r2 = *(s32 *)(r10 - 8); /* narrowing sx fill */ \
+ if w6 != -1 goto 1f; /* narrows r6, propagates to r2 */ \
+ if r2 == -1 goto 1f; /* sign-extended, not 0xffffffff */ \
+ r0 /= 0; \
+1: \
+ r0 = 0; \
+ exit; \
+" :
+ : __imm(bpf_get_prandom_u32)
+ : __clobber_all);
+}
+
+/*
+ * The same, for the two fill kinds off one slot.
+ */
+SEC("socket")
+__failure __msg("div by zero")
+__flag(BPF_F_TEST_STATE_FREQ)
+__naked void fill_kinds_reach_different_values(void)
+{
+ asm volatile (" \
+ call %[bpf_get_prandom_u32]; \
+ r6 = r0; \
+ r6 &= 1; \
+ call %[bpf_get_prandom_u32]; \
+ r8 = r0; \
+ call %[bpf_get_prandom_u32]; \
+ r0 <<= 32; \
+ r8 |= r0; \
+ *(u64 *)(r10 - 8) = r8; \
+ if r6 >= 1 goto 2f; \
+ r2 = *(s32 *)(r10 - 8); /* sign-extending fill */ \
+ goto 1f; \
+2: \
+ r2 = *(u32 *)(r10 - 8); /* zero-extending fill */ \
+1: \
+ if w8 != -1 goto 3f; \
+ if r2 == -1 goto 3f; /* only the sign-extending path */ \
+ r0 /= 0; \
+3: \
+ r0 = 0; \
+ exit; \
+" :
+ : __imm(bpf_get_prandom_u32)
+ : __clobber_all);
+}
+
#endif /* CAN_USE_MOVSX */
char _license[] SEC("license") = "GPL";
--
2.53.0-Meta
next prev parent reply other threads:[~2026-09-10 16:47 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
2026-09-11 6:43 ` Vineet Gupta
2026-09-10 16:46 ` Vineet Gupta [this message]
2026-09-10 17:00 ` [PATCH bpf-next v2 10/13] selftests/bpf: cover the low-32 link for " 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=20260910164635.459558-11-vineet.gupta@linux.dev \
--to=vineet.gupta@linux.dev \
--cc=andrii@kernel.org \
--cc=ast@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@linux.dev \
--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 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.