* [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
* 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
* [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 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
* 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
* [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
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