[PATCH bpf-next v2 2/2] selftests/bpf: Cover helper reads of invalid spill siblings

From: Yiyang Chen

Date: Fri Jul 17 2026 - 06:13:04 EST


Add a verifier_spill_fill case that passes an untouched byte next to a
one-byte scalar spill to bpf_map_update_elem(). The full-capability load
retains the existing uninitialized-stack behavior, while the CAP_BPF-only
load must reject the STACK_INVALID helper read.

Fixes: 354e8f1970f8 ("bpf: Support <8-byte scalar spill and refill")
Signed-off-by: Yiyang Chen <chenyy23@xxxxxxxxxxxxxxxxxxxxx>
---
.../selftests/bpf/progs/verifier_spill_fill.c | 34 +++++++++++++++++++
1 file changed, 34 insertions(+)

diff --git a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c
index 8b166c42c4e0e..2e62a7ddcbce2 100644
--- a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c
+++ b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c
@@ -11,6 +11,13 @@ struct {
__uint(max_entries, 4096);
} map_ringbuf SEC(".maps");

+struct {
+ __uint(type, BPF_MAP_TYPE_ARRAY);
+ __uint(max_entries, 1);
+ __type(key, __u32);
+ __type(value, __u8);
+} map_partial_spill SEC(".maps");
+
SEC("socket")
__description("check valid spill/fill")
__success __failure_unpriv __msg_unpriv("R0 leaks addr")
@@ -1307,6 +1314,33 @@ __naked void stack_noperfmon_spill_32bit_onto_64bit_slot(void)
: __clobber_all);
}

+SEC("socket")
+__description("helper read must reject an invalid sibling of a narrow spill")
+__success
+__caps_unpriv(CAP_BPF)
+__failure_unpriv __msg_unpriv("invalid read from stack R3 off -7+0 size 1")
+__naked void helper_read_invalid_partial_spill_sibling(void)
+{
+ asm volatile (" \
+ r5 = 1; \
+ *(u8 *)(r10 - 8) = r5; \
+ r2 = 0; \
+ *(u32 *)(r10 - 16) = r2; \
+ r1 = %[map_partial_spill] ll; \
+ r2 = r10; \
+ r2 += -16; \
+ r3 = r10; \
+ r3 += -7; \
+ r4 = 0; \
+ call %[bpf_map_update_elem]; \
+ r0 = 0; \
+ exit; \
+" :
+ : __imm(bpf_map_update_elem),
+ __imm_addr(map_partial_spill)
+ : __clobber_all);
+}
+
/*
* stacksafe(): check if 32-bit scalar spill in old state is considered
* equivalent to STACK_MISC in cur state.
--
2.34.1