]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
selftests/bpf: Test 32-bit scalar spill pruning in stacksafe()
authorAlexei Starovoitov <ast@kernel.org>
Mon, 23 Mar 2026 02:24:10 +0000 (19:24 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Tue, 24 Mar 2026 19:10:38 +0000 (12:10 -0700)
Add a test verifying that stacksafe() correctly handles 32-bit scalar
spills when comparing stack states for equivalence during state pruning.

A 32-bit scalar spill creates slot[0-3] = STACK_INVALID and
slot[4-7] = STACK_SPILL. Without the im=4 check in stacksafe(), the
STACK_SPILL vs STACK_MISC mismatch at byte 4 causes pruning to fail,
forcing the verifier to re-explore a path that is provably safe.

Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20260323022410.75444-2-alexei.starovoitov@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
tools/testing/selftests/bpf/progs/verifier_spill_fill.c

index 893d3bb024a0bdc39843ecd13a44fb8003ee79c1..a2b6d99628da007f0f7f7c1b8be44ddf2ba589be 100644 (file)
@@ -1279,4 +1279,41 @@ __naked void stack_noperfmon_spill_32bit_onto_64bit_slot(void)
        : __clobber_all);
 }
 
+/*
+ * stacksafe(): check if 32-bit scalar spill in old state is considered
+ * equivalent to STACK_MISC in cur state.
+ * 32-bit scalar spill creates slot[0-3] = STACK_MISC, slot[4-7] = STACK_SPILL.
+ * Without 32-bit spill support in stacksafe(), the STACK_SPILL vs STACK_MISC
+ * mismatch at slot[4] causes pruning to fail.
+ */
+SEC("socket")
+__success __log_level(2)
+__msg("8: (79) r1 = *(u64 *)(r10 -8)")
+__msg("8: safe")
+__msg("processed 11 insns")
+__flag(BPF_F_TEST_STATE_FREQ)
+__naked void old_imprecise_scalar32_vs_cur_stack_misc(void)
+{
+       asm volatile(
+       /* get a random value for branching */
+       "call %[bpf_ktime_get_ns];"
+       "if r0 == 0 goto 1f;"
+       /* conjure 32-bit scalar spill at fp-8 */
+       "r0 = 42;"
+       "*(u32*)(r10 - 8) = r0;"
+       "goto 2f;"
+"1:"
+       /* conjure STACK_MISC at fp-8 */
+       "call %[bpf_ktime_get_ns];"
+       "*(u16*)(r10 - 8) = r0;"
+       "*(u16*)(r10 - 6) = r0;"
+"2:"
+       /* read fp-8, should be considered safe on second visit */
+       "r1 = *(u64*)(r10 - 8);"
+       "exit;"
+       :
+       : __imm(bpf_ktime_get_ns)
+       : __clobber_all);
+}
+
 char _license[] SEC("license") = "GPL";