mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH bpf-next 0/2] bpf: Preserve pointer spill metadata during half-slot cleanup
@ 2026-06-15  8:09 Nuoqi Gui
  2026-06-15  8:09 ` [PATCH bpf-next 1/2] " Nuoqi Gui
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Nuoqi Gui @ 2026-06-15  8:09 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
	Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis, Shuah Khan
  Cc: bpf, linux-kernel, linux-kselftest, Nuoqi Gui

__clean_func_state() cleans stack liveness in 4-byte halves. When the high
half of a spilled register slot is dead but the low half remains live, it can
currently degrade the low half of any STACK_SPILL to raw stack bytes and clear
the saved spilled_ptr metadata.

That is safe for scalar spills, but not for non-scalar pointer spills. A later
partial 32-bit fill from the remaining live half can otherwise avoid the normal
non-scalar spill rejection.

Keep pointer spill provenance intact for that half-live case and add a verifier
regression test for the reported shape.

Validation:

- A raw `bpf(BPF_PROG_LOAD)` reproducer exercises the half-slot cleanup case by
  spilling `r1` as a pointer, executing `goto +0`, and then doing a 32-bit fill
  from `fp-4`.
- Unpatched `bpf-next` at 7bfb93e3475be9de894f1cecd3a727d3e1649b03:
  selftest FAIL as expected because the verifier accepts the partial
  pointer-spill fill.
- Patched with this series: PASS because the verifier rejects the same load at
  `r0 = *(u32 *)(r10 -4)` with `invalid size of register fill`.

---
Nuoqi Gui (2):
      bpf: Preserve pointer spill metadata during half-slot cleanup
      selftests/bpf: Cover half-slot cleanup of pointer spills

 kernel/bpf/states.c                                    | 13 +++++++------
 .../testing/selftests/bpf/progs/verifier_spill_fill.c  | 18 ++++++++++++++++++
 2 files changed, 25 insertions(+), 6 deletions(-)
---
base-commit: 7bfb93e3475be9de894f1cecd3a727d3e1649b03
change-id: 20260615-f01-06-half-slot-pointer-spill-e4bd2665c532

Best regards,
--  
Nuoqi Gui <gnq25@mails.tsinghua.edu.cn>


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH bpf-next 1/2] bpf: Preserve pointer spill metadata during half-slot cleanup
  2026-06-15  8:09 [PATCH bpf-next 0/2] bpf: Preserve pointer spill metadata during half-slot cleanup Nuoqi Gui
@ 2026-06-15  8:09 ` Nuoqi Gui
  2026-06-15  8:48   ` bot+bpf-ci
  2026-06-15 17:19   ` Eduard Zingerman
  2026-06-15  8:09 ` [PATCH bpf-next 2/2] selftests/bpf: Cover half-slot cleanup of pointer spills Nuoqi Gui
  2026-06-17 15:20 ` [PATCH bpf-next v2 0/2] bpf: Preserve pointer spill metadata during half-slot cleanup Nuoqi Gui
  2 siblings, 2 replies; 12+ messages in thread
From: Nuoqi Gui @ 2026-06-15  8:09 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
	Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis, Shuah Khan
  Cc: bpf, linux-kernel, linux-kselftest, Nuoqi Gui

__clean_func_state() cleans dead stack slots in 4-byte halves. When the
high half of a STACK_SPILL slot is dead and the low half remains live,
cleanup converts the live low half to STACK_MISC or STACK_ZERO and clears
the saved spilled_ptr metadata.

That conversion is safe only for scalar spills. For a pointer spill, this
metadata clear lets a later 32-bit fill from the still-live half avoid the
normal non-scalar register-fill check and be treated as an ordinary scalar
stack read.

Leave non-scalar spill slots intact in this half-live shape. This is
conservative for pruning and preserves the existing
check_stack_read_fixed_off() rejection path for partial fills from pointer
spills.

Fixes: 2cb27158adb3 ("bpf: poison dead stack slots")
Signed-off-by: Nuoqi Gui <gnq25@mails.tsinghua.edu.cn>
---
 kernel/bpf/states.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/kernel/bpf/states.c b/kernel/bpf/states.c
index 32f346ce3ffc..ea2153cf28d0 100644
--- a/kernel/bpf/states.c
+++ b/kernel/bpf/states.c
@@ -436,12 +436,10 @@ static void __clean_func_state(struct bpf_verifier_env *env,
 				continue;
 
 			/*
-			 * Only destroy spilled_ptr when hi half is dead.
-			 * If hi half is still live with STACK_SPILL, the
-			 * spilled_ptr metadata is needed for correct state
-			 * comparison in stacksafe().
-			 * is_spilled_reg() is using slot_type[7], but
-			 * is_spilled_scalar_after() check either slot_type[0] or [4]
+			 * Only scalar spills can be degraded to raw stack bytes
+			 * when their high half is dead. Pointer spills need the
+			 * saved spilled_ptr metadata so partial fills keep
+			 * rejecting as non-scalar register fills.
 			 */
 			if (!hi_live) {
 				struct bpf_reg_state *spill = &st->stack[i].spilled_ptr;
@@ -449,6 +447,9 @@ static void __clean_func_state(struct bpf_verifier_env *env,
 				if (lo_live && stype == STACK_SPILL) {
 					u8 val = STACK_MISC;
 
+					if (spill->type != SCALAR_VALUE)
+						continue;
+
 					/*
 					 * 8 byte spill of scalar 0 where half slot is dead
 					 * should become STACK_ZERO in lo 4 bytes.

-- 
2.34.1


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH bpf-next 2/2] selftests/bpf: Cover half-slot cleanup of pointer spills
  2026-06-15  8:09 [PATCH bpf-next 0/2] bpf: Preserve pointer spill metadata during half-slot cleanup Nuoqi Gui
  2026-06-15  8:09 ` [PATCH bpf-next 1/2] " Nuoqi Gui
@ 2026-06-15  8:09 ` Nuoqi Gui
  2026-06-15 17:19   ` Eduard Zingerman
  2026-06-17 15:20 ` [PATCH bpf-next v2 0/2] bpf: Preserve pointer spill metadata during half-slot cleanup Nuoqi Gui
  2 siblings, 1 reply; 12+ messages in thread
From: Nuoqi Gui @ 2026-06-15  8:09 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
	Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis, Shuah Khan
  Cc: bpf, linux-kernel, linux-kselftest, Nuoqi Gui

Add a verifier regression test for a pointer spill whose high half is
cleaned dead while the low half remains live. Force checkpoint creation
with BPF_F_TEST_STATE_FREQ and assert the verifier log reaches the
checkpoint and the subsequent 32-bit fill before rejecting the partial fill
from a non-scalar spill.

Signed-off-by: Nuoqi Gui <gnq25@mails.tsinghua.edu.cn>
---
 .../testing/selftests/bpf/progs/verifier_spill_fill.c  | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c
index 6bc721accbae..0174887e28f5 100644
--- a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c
+++ b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c
@@ -1359,4 +1359,22 @@ __naked void var_off_write_over_scalar_spill(void)
 	: __clobber_all);
 }
 
+SEC("socket")
+__description("partial fill from cleaned pointer spill")
+__failure
+__log_level(2)
+__msg("1: (05) goto pc+0")
+__msg("2: (61) r0 = *(u32 *)(r10 -4)")
+__msg("invalid size of register fill")
+__flag(BPF_F_TEST_STATE_FREQ)
+__naked void partial_fill_from_cleaned_pointer_spill(void)
+{
+	/* Spill R1(ctx), then force a checkpoint and half-slot cleanup. */
+	asm volatile ("*(u64 *)(r10 - 8) = r1;"
+		      "goto +0;"
+		      "r0 = *(u32 *)(r10 - 4);"
+		      "exit;"
+		      ::: __clobber_all);
+}
+
 char _license[] SEC("license") = "GPL";

-- 
2.34.1


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH bpf-next 1/2] bpf: Preserve pointer spill metadata during half-slot cleanup
  2026-06-15  8:09 ` [PATCH bpf-next 1/2] " Nuoqi Gui
@ 2026-06-15  8:48   ` bot+bpf-ci
  2026-06-15  9:17     ` Nuoqi Gui
  2026-06-15 17:19   ` Eduard Zingerman
  1 sibling, 1 reply; 12+ messages in thread
From: bot+bpf-ci @ 2026-06-15  8:48 UTC (permalink / raw)
  To: gnq25, ast, daniel, andrii, eddyz87, memxor, martin.lau, song,
	yonghong.song, jolsa, emil, shuah
  Cc: bpf, linux-kernel, linux-kselftest, gnq25, ast, andrii, daniel,
	martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 1991 bytes --]

>     bpf: Preserve pointer spill metadata during half-slot cleanup
>
>     __clean_func_state() cleans dead stack slots in 4-byte halves. When the
>     high half of a STACK_SPILL slot is dead and the low half remains live,
>     cleanup converts the live low half to STACK_MISC or STACK_ZERO and clears
>     the saved spilled_ptr metadata.
>
>     That conversion is safe only for scalar spills. For a pointer spill, this
>     metadata clear lets a later 32-bit fill from the still-live half avoid the
>     normal non-scalar register-fill check and be treated as an ordinary scalar
>     stack read.
>
>     Leave non-scalar spill slots intact in this half-live shape. This is
>     conservative for pruning and preserves the existing
>     check_stack_read_fixed_off() rejection path for partial fills from pointer
>     spills.
>
>     Fixes: 2cb27158adb3 ("bpf: poison dead stack slots")
>     Signed-off-by: Nuoqi Gui <gnq25@mails.tsinghua.edu.cn>

Is the Fixes: tag pointing at the right commit?

The commit referenced, 2cb27158adb3 ("bpf: poison dead stack slots"), adds
STACK_POISON handling in kernel/bpf/verifier.c and does not contain the
half-slot cleanup logic being corrected here.

The 4-byte half-slot cleanup in __clean_func_state() that downgrades a
still-live STACK_SPILL low half to STACK_MISC/STACK_ZERO and clears the
saved spilled_ptr metadata without checking for SCALAR_VALUE was introduced
by be23266b4a08 ("bpf: 4-byte precise clean_verifier_state"). That commit
added the lo_live/hi_live model and the exact block this patch corrects:

	if (lo_live && stype == STACK_SPILL) {

be23266b4a08 predates both 2cb27158adb3 and this fix. Should the tag be:

  Fixes: be23266b4a08 ("bpf: 4-byte precise clean_verifier_state")


---
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/27533304560

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Re: [PATCH bpf-next 1/2] bpf: Preserve pointer spill metadata during half-slot cleanup
  2026-06-15  8:48   ` bot+bpf-ci
@ 2026-06-15  9:17     ` Nuoqi Gui
  0 siblings, 0 replies; 12+ messages in thread
From: Nuoqi Gui @ 2026-06-15  9:17 UTC (permalink / raw)
  To: bot+bpf-ci
  Cc: ast, daniel, andrii, eddyz87, memxor, martin.lau, song,
	yonghong.song, jolsa, emil, shuah, bpf, linux-kernel,
	linux-kselftest, martin.lau, clm, ihor.solodrai




> -----Original Messages-----
> From: bot+bpf-ci@kernel.org
> Send time:Monday, 15/06/2026 16:48:49
> To: gnq25@mails.tsinghua.edu.cn, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, eddyz87@gmail.com, memxor@gmail.com, martin.lau@linux.dev, song@kernel.org, yonghong.song@linux.dev, jolsa@kernel.org, emil@etsalapatis.com, shuah@kernel.org
> Cc: bpf@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, gnq25@mails.tsinghua.edu.cn, ast@kernel.org, andrii@kernel.org, daniel@iogearbox.net, martin.lau@kernel.org, eddyz87@gmail.com, yonghong.song@linux.dev, clm@meta.com, ihor.solodrai@linux.dev
> Subject: Re: [PATCH bpf-next 1/2] bpf: Preserve pointer spill metadata during half-slot cleanup
> 
> >     bpf: Preserve pointer spill metadata during half-slot cleanup
> >
> >     __clean_func_state() cleans dead stack slots in 4-byte halves. When the
> >     high half of a STACK_SPILL slot is dead and the low half remains live,
> >     cleanup converts the live low half to STACK_MISC or STACK_ZERO and clears
> >     the saved spilled_ptr metadata.
> >
> >     That conversion is safe only for scalar spills. For a pointer spill, this
> >     metadata clear lets a later 32-bit fill from the still-live half avoid the
> >     normal non-scalar register-fill check and be treated as an ordinary scalar
> >     stack read.
> >
> >     Leave non-scalar spill slots intact in this half-live shape. This is
> >     conservative for pruning and preserves the existing
> >     check_stack_read_fixed_off() rejection path for partial fills from pointer
> >     spills.
> >
> >     Fixes: 2cb27158adb3 ("bpf: poison dead stack slots")
> >     Signed-off-by: Nuoqi Gui <gnq25@mails.tsinghua.edu.cn>
> 
> Is the Fixes: tag pointing at the right commit?
> 
> The commit referenced, 2cb27158adb3 ("bpf: poison dead stack slots"), adds
> STACK_POISON handling in kernel/bpf/verifier.c and does not contain the
> half-slot cleanup logic being corrected here.
> 
> The 4-byte half-slot cleanup in __clean_func_state() that downgrades a
> still-live STACK_SPILL low half to STACK_MISC/STACK_ZERO and clears the
> saved spilled_ptr metadata without checking for SCALAR_VALUE was introduced
> by be23266b4a08 ("bpf: 4-byte precise clean_verifier_state"). That commit
> added the lo_live/hi_live model and the exact block this patch corrects:
> 
> 	if (lo_live && stype == STACK_SPILL) {
> 
> be23266b4a08 predates both 2cb27158adb3 and this fix. Should the tag be:
> 
>   Fixes: be23266b4a08 ("bpf: 4-byte precise clean_verifier_state")
> 
> 
> ---
> 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/27533304560

Yes, be23266b4a08 is the right Fixes target.


The bug is in the half-slot cleanup logic introduced by that commit:
when the high half is dead and the low half remains live, it can downgrade
the still-live STACK_SPILL bytes to STACK_MISC/STACK_ZERO and clear the
spilled_ptr metadata.

2cb27158adb3 only changed the dead-slot marker to STACK_POISON and did not
introduce that half-slot spill cleanup behavior.

I will update the tag to:
Fixes: be23266b4a08 ("bpf: 4-byte precise clean_verifier_state")

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH bpf-next 1/2] bpf: Preserve pointer spill metadata during half-slot cleanup
  2026-06-15  8:09 ` [PATCH bpf-next 1/2] " Nuoqi Gui
  2026-06-15  8:48   ` bot+bpf-ci
@ 2026-06-15 17:19   ` Eduard Zingerman
  1 sibling, 0 replies; 12+ messages in thread
From: Eduard Zingerman @ 2026-06-15 17:19 UTC (permalink / raw)
  To: Nuoqi Gui, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Kumar Kartikeya Dwivedi, Martin KaFai Lau, Song Liu,
	Yonghong Song, Jiri Olsa, Emil Tsalapatis, Shuah Khan
  Cc: bpf, linux-kernel, linux-kselftest

On Mon, 2026-06-15 at 16:09 +0800, Nuoqi Gui wrote:
> __clean_func_state() cleans dead stack slots in 4-byte halves. When the
> high half of a STACK_SPILL slot is dead and the low half remains live,
> cleanup converts the live low half to STACK_MISC or STACK_ZERO and clears
> the saved spilled_ptr metadata.
> 
> That conversion is safe only for scalar spills. For a pointer spill, this
> metadata clear lets a later 32-bit fill from the still-live half avoid the
> normal non-scalar register-fill check and be treated as an ordinary scalar
> stack read.
> 
> Leave non-scalar spill slots intact in this half-live shape. This is
> conservative for pruning and preserves the existing
> check_stack_read_fixed_off() rejection path for partial fills from pointer
> spills.
> 
> Fixes: 2cb27158adb3 ("bpf: poison dead stack slots")
> Signed-off-by: Nuoqi Gui <gnq25@mails.tsinghua.edu.cn>
> ---

Acked-by: Eduard Zingerman <eddyz87@gmail.com>

[...]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH bpf-next 2/2] selftests/bpf: Cover half-slot cleanup of pointer spills
  2026-06-15  8:09 ` [PATCH bpf-next 2/2] selftests/bpf: Cover half-slot cleanup of pointer spills Nuoqi Gui
@ 2026-06-15 17:19   ` Eduard Zingerman
  0 siblings, 0 replies; 12+ messages in thread
From: Eduard Zingerman @ 2026-06-15 17:19 UTC (permalink / raw)
  To: Nuoqi Gui, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Kumar Kartikeya Dwivedi, Martin KaFai Lau, Song Liu,
	Yonghong Song, Jiri Olsa, Emil Tsalapatis, Shuah Khan
  Cc: bpf, linux-kernel, linux-kselftest

On Mon, 2026-06-15 at 16:09 +0800, Nuoqi Gui wrote:
> Add a verifier regression test for a pointer spill whose high half is
> cleaned dead while the low half remains live. Force checkpoint creation
> with BPF_F_TEST_STATE_FREQ and assert the verifier log reaches the
> checkpoint and the subsequent 32-bit fill before rejecting the partial fill
> from a non-scalar spill.
> 
> Signed-off-by: Nuoqi Gui <gnq25@mails.tsinghua.edu.cn>
> ---

Acked-by: Eduard Zingerman <eddyz87@gmail.com>

[...]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH bpf-next v2 0/2] bpf: Preserve pointer spill metadata during half-slot cleanup
  2026-06-15  8:09 [PATCH bpf-next 0/2] bpf: Preserve pointer spill metadata during half-slot cleanup Nuoqi Gui
  2026-06-15  8:09 ` [PATCH bpf-next 1/2] " Nuoqi Gui
  2026-06-15  8:09 ` [PATCH bpf-next 2/2] selftests/bpf: Cover half-slot cleanup of pointer spills Nuoqi Gui
@ 2026-06-17 15:20 ` Nuoqi Gui
  2026-06-17 15:20   ` [PATCH bpf-next v2 1/2] " Nuoqi Gui
  2026-06-17 15:20   ` [PATCH bpf-next v2 2/2] selftests/bpf: Cover half-slot cleanup of pointer spills Nuoqi Gui
  2 siblings, 2 replies; 12+ messages in thread
From: Nuoqi Gui @ 2026-06-17 15:20 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
	Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis, Shuah Khan
  Cc: bpf, linux-kernel, linux-kselftest, Nuoqi Gui

__clean_func_state() cleans stack liveness in 4-byte halves. When the high
half of a spilled register slot is dead but the low half remains live, it can
currently degrade the low half of any STACK_SPILL to raw stack bytes and clear
the saved spilled_ptr metadata.

That is safe for scalar spills, but not for non-scalar pointer spills. A later
partial 32-bit fill from the remaining live half can otherwise avoid the normal
non-scalar spill rejection.

Keep pointer spill provenance intact for that half-live case and add a verifier
regression test for the reported shape.

Validation:

- A raw `bpf(BPF_PROG_LOAD)` reproducer exercises the half-slot cleanup case by
  spilling `r1` as a pointer, executing `goto +0`, and then doing a 32-bit fill
  from `fp-4`.
- Unpatched `bpf-next` at 7bfb93e3475be9de894f1cecd3a727d3e1649b03:
  selftest FAIL as expected because the verifier accepts the partial
  pointer-spill fill.
- Patched with this series: PASS because the verifier rejects the same load at
  `r0 = *(u32 *)(r10 -4)` with `invalid size of register fill`.

v1->v2:
  - Correct the Fixes tag to be23266b4a08 ("bpf: 4-byte precise
    clean_verifier_state")

Link to v1: https://patch.msgid.link/20260615-f01-06-half-slot-pointer-spill-v1-0-47f1c18a8965@mails.tsinghua.edu.cn

---
Nuoqi Gui (2):
      bpf: Preserve pointer spill metadata during half-slot cleanup
      selftests/bpf: Cover half-slot cleanup of pointer spills

 kernel/bpf/states.c                                    | 13 +++++++------
 .../testing/selftests/bpf/progs/verifier_spill_fill.c  | 18 ++++++++++++++++++
 2 files changed, 25 insertions(+), 6 deletions(-)
---
base-commit: 7bfb93e3475be9de894f1cecd3a727d3e1649b03
change-id: 20260617-f01-06-half-slot-pointer-spill-a4a81eeab2cb

Best regards,
--  
Nuoqi Gui <gnq25@mails.tsinghua.edu.cn>


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH bpf-next v2 1/2] bpf: Preserve pointer spill metadata during half-slot cleanup
  2026-06-17 15:20 ` [PATCH bpf-next v2 0/2] bpf: Preserve pointer spill metadata during half-slot cleanup Nuoqi Gui
@ 2026-06-17 15:20   ` Nuoqi Gui
  2026-06-22 21:10     ` patchwork-bot+netdevbpf
  2026-06-17 15:20   ` [PATCH bpf-next v2 2/2] selftests/bpf: Cover half-slot cleanup of pointer spills Nuoqi Gui
  1 sibling, 1 reply; 12+ messages in thread
From: Nuoqi Gui @ 2026-06-17 15:20 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
	Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis, Shuah Khan
  Cc: bpf, linux-kernel, linux-kselftest, Nuoqi Gui

__clean_func_state() cleans dead stack slots in 4-byte halves. When the
high half of a STACK_SPILL slot is dead and the low half remains live,
cleanup converts the live low half to STACK_MISC or STACK_ZERO and clears
the saved spilled_ptr metadata.

That conversion is safe only for scalar spills. For a pointer spill, this
metadata clear lets a later 32-bit fill from the still-live half avoid the
normal non-scalar register-fill check and be treated as an ordinary scalar
stack read.

Leave non-scalar spill slots intact in this half-live shape. This is
conservative for pruning and preserves the existing
check_stack_read_fixed_off() rejection path for partial fills from pointer
spills.

Fixes: be23266b4a08 ("bpf: 4-byte precise clean_verifier_state")
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Nuoqi Gui <gnq25@mails.tsinghua.edu.cn>
---
 kernel/bpf/states.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/kernel/bpf/states.c b/kernel/bpf/states.c
index 32f346ce3ffc..ea2153cf28d0 100644
--- a/kernel/bpf/states.c
+++ b/kernel/bpf/states.c
@@ -436,12 +436,10 @@ static void __clean_func_state(struct bpf_verifier_env *env,
 				continue;
 
 			/*
-			 * Only destroy spilled_ptr when hi half is dead.
-			 * If hi half is still live with STACK_SPILL, the
-			 * spilled_ptr metadata is needed for correct state
-			 * comparison in stacksafe().
-			 * is_spilled_reg() is using slot_type[7], but
-			 * is_spilled_scalar_after() check either slot_type[0] or [4]
+			 * Only scalar spills can be degraded to raw stack bytes
+			 * when their high half is dead. Pointer spills need the
+			 * saved spilled_ptr metadata so partial fills keep
+			 * rejecting as non-scalar register fills.
 			 */
 			if (!hi_live) {
 				struct bpf_reg_state *spill = &st->stack[i].spilled_ptr;
@@ -449,6 +447,9 @@ static void __clean_func_state(struct bpf_verifier_env *env,
 				if (lo_live && stype == STACK_SPILL) {
 					u8 val = STACK_MISC;
 
+					if (spill->type != SCALAR_VALUE)
+						continue;
+
 					/*
 					 * 8 byte spill of scalar 0 where half slot is dead
 					 * should become STACK_ZERO in lo 4 bytes.

-- 
2.34.1


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH bpf-next v2 2/2] selftests/bpf: Cover half-slot cleanup of pointer spills
  2026-06-17 15:20 ` [PATCH bpf-next v2 0/2] bpf: Preserve pointer spill metadata during half-slot cleanup Nuoqi Gui
  2026-06-17 15:20   ` [PATCH bpf-next v2 1/2] " Nuoqi Gui
@ 2026-06-17 15:20   ` Nuoqi Gui
  2026-06-17 16:02     ` bot+bpf-ci
  1 sibling, 1 reply; 12+ messages in thread
From: Nuoqi Gui @ 2026-06-17 15:20 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
	Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis, Shuah Khan
  Cc: bpf, linux-kernel, linux-kselftest, Nuoqi Gui

Add a verifier regression test for a pointer spill whose high half is
cleaned dead while the low half remains live. Force checkpoint creation
with BPF_F_TEST_STATE_FREQ and assert the verifier log reaches the
checkpoint and the subsequent 32-bit fill before rejecting the partial fill
from a non-scalar spill.

Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Nuoqi Gui <gnq25@mails.tsinghua.edu.cn>
---
 .../testing/selftests/bpf/progs/verifier_spill_fill.c  | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c
index 6bc721accbae..0174887e28f5 100644
--- a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c
+++ b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c
@@ -1359,4 +1359,22 @@ __naked void var_off_write_over_scalar_spill(void)
 	: __clobber_all);
 }
 
+SEC("socket")
+__description("partial fill from cleaned pointer spill")
+__failure
+__log_level(2)
+__msg("1: (05) goto pc+0")
+__msg("2: (61) r0 = *(u32 *)(r10 -4)")
+__msg("invalid size of register fill")
+__flag(BPF_F_TEST_STATE_FREQ)
+__naked void partial_fill_from_cleaned_pointer_spill(void)
+{
+	/* Spill R1(ctx), then force a checkpoint and half-slot cleanup. */
+	asm volatile ("*(u64 *)(r10 - 8) = r1;"
+		      "goto +0;"
+		      "r0 = *(u32 *)(r10 - 4);"
+		      "exit;"
+		      ::: __clobber_all);
+}
+
 char _license[] SEC("license") = "GPL";

-- 
2.34.1


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH bpf-next v2 2/2] selftests/bpf: Cover half-slot cleanup of pointer spills
  2026-06-17 15:20   ` [PATCH bpf-next v2 2/2] selftests/bpf: Cover half-slot cleanup of pointer spills Nuoqi Gui
@ 2026-06-17 16:02     ` bot+bpf-ci
  0 siblings, 0 replies; 12+ messages in thread
From: bot+bpf-ci @ 2026-06-17 16:02 UTC (permalink / raw)
  To: gnq25, ast, daniel, andrii, eddyz87, memxor, martin.lau, song,
	yonghong.song, jolsa, emil, shuah
  Cc: bpf, linux-kernel, linux-kselftest, gnq25, ast, andrii, daniel,
	martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 1307 bytes --]

>     selftests/bpf: Cover half-slot cleanup of pointer spills
>
>     Add a verifier regression test for a pointer spill whose high half is
>     cleaned dead while the low half remains live. Force checkpoint creation
>     with BPF_F_TEST_STATE_FREQ and assert the verifier log reaches the
>     checkpoint and the subsequent 32-bit fill before rejecting the partial fill
>     from a non-scalar spill.
>
>     Acked-by: Eduard Zingerman <eddyz87@gmail.com>
>     Signed-off-by: Nuoqi Gui <gnq25@mails.tsinghua.edu.cn>

This is a regression test for a verifier bug where a partial 32-bit fill
from a pointer spill whose high half was cleaned dead could read a
non-scalar stack slot past the register-fill check.

The half-slot cleanup that destroys the spilled_ptr metadata when the hi
half is dead was introduced in __clean_func_state() by:

  be23266b4a08 ("bpf: 4-byte precise clean_verifier_state")

Should this test carry a Fixes: tag pointing at that commit, matching the
accompanying fix?

  Fixes: be23266b4a08 ("bpf: 4-byte precise clean_verifier_state")


---
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/27700639579

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH bpf-next v2 1/2] bpf: Preserve pointer spill metadata during half-slot cleanup
  2026-06-17 15:20   ` [PATCH bpf-next v2 1/2] " Nuoqi Gui
@ 2026-06-22 21:10     ` patchwork-bot+netdevbpf
  0 siblings, 0 replies; 12+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-06-22 21:10 UTC (permalink / raw)
  To: Nuoqi Gui
  Cc: ast, daniel, andrii, eddyz87, memxor, martin.lau, song,
	yonghong.song, jolsa, emil, shuah, bpf, linux-kernel,
	linux-kselftest

Hello:

This series was applied to bpf/bpf.git (master)
by Alexei Starovoitov <ast@kernel.org>:

On Wed, 17 Jun 2026 23:20:20 +0800 you wrote:
> __clean_func_state() cleans dead stack slots in 4-byte halves. When the
> high half of a STACK_SPILL slot is dead and the low half remains live,
> cleanup converts the live low half to STACK_MISC or STACK_ZERO and clears
> the saved spilled_ptr metadata.
> 
> That conversion is safe only for scalar spills. For a pointer spill, this
> metadata clear lets a later 32-bit fill from the still-live half avoid the
> normal non-scalar register-fill check and be treated as an ordinary scalar
> stack read.
> 
> [...]

Here is the summary with links:
  - [bpf-next,v2,1/2] bpf: Preserve pointer spill metadata during half-slot cleanup
    https://git.kernel.org/bpf/bpf/c/3a354149bcea
  - [bpf-next,v2,2/2] selftests/bpf: Cover half-slot cleanup of pointer spills
    https://git.kernel.org/bpf/bpf/c/8816d94303f0

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2026-06-22 21:10 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-15  8:09 [PATCH bpf-next 0/2] bpf: Preserve pointer spill metadata during half-slot cleanup Nuoqi Gui
2026-06-15  8:09 ` [PATCH bpf-next 1/2] " Nuoqi Gui
2026-06-15  8:48   ` bot+bpf-ci
2026-06-15  9:17     ` Nuoqi Gui
2026-06-15 17:19   ` Eduard Zingerman
2026-06-15  8:09 ` [PATCH bpf-next 2/2] selftests/bpf: Cover half-slot cleanup of pointer spills Nuoqi Gui
2026-06-15 17:19   ` Eduard Zingerman
2026-06-17 15:20 ` [PATCH bpf-next v2 0/2] bpf: Preserve pointer spill metadata during half-slot cleanup Nuoqi Gui
2026-06-17 15:20   ` [PATCH bpf-next v2 1/2] " Nuoqi Gui
2026-06-22 21:10     ` patchwork-bot+netdevbpf
2026-06-17 15:20   ` [PATCH bpf-next v2 2/2] selftests/bpf: Cover half-slot cleanup of pointer spills Nuoqi Gui
2026-06-17 16:02     ` bot+bpf-ci

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox