__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 <[email protected]>