]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
selftests/bpf: a test for proper cnums compare in is_state_visited()
authorEduard Zingerman <eddyz87@gmail.com>
Sat, 25 Apr 2026 22:48:24 +0000 (15:48 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Mon, 27 Apr 2026 16:56:39 +0000 (09:56 -0700)
Test case demonstrating a bug in cnum comparison logic fixed by
previous commit. A pruning point is reached with r6 in two states:
1. 32-bit range of [0x7FFFFFF0, U32_MAX] ∪ [0, 0x10]
2. 32-bit range of [0x100, 0x200]

At pruning point the buggy is_state_visited() logic would assume that
would assume range (2) to be a subset of (1) and fail to explore the
path performing division by zero.

Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20260425-cnum-range-within-v1-2-2fdca70cb09d@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
tools/testing/selftests/bpf/progs/verifier_bounds.c

index 5dd243e653c9ff86e768dbc4ef1b2d3240d158ba..a3e4c0945137320266f3e5b6249a3b3144f870cb 100644 (file)
@@ -2267,4 +2267,31 @@ __naked void deduce64_from_32_wrapping_32bit(void)
        : __clobber_all);
 }
 
+/* Check that range_within() compares cnum ranges, not min/max projections. */
+SEC("socket")
+__failure __msg("div by zero")
+__flag(BPF_F_TEST_STATE_FREQ)
+__naked void range_within_cnum_cross_both_boundaries(void)
+{
+       asm volatile ("                                                 \
+       call %[bpf_get_prandom_u32];                                    \
+       r1 = 0x80000020;                                                \
+       if r0 > r1 goto 1f;                                             \
+       r0 += 0x7FFFFFF0;                       /* PATH 1 */            \
+       goto 2f;                                                        \
+1:     call %[bpf_get_prandom_u32];            /* PATH 2 */            \
+       if r0 < 0x100 goto 3f;                                          \
+       if r0 > 0x200 goto 3f;                                          \
+2:     /* PATH 1: r0 ∈ [0x7FFFFFF0, U32_MAX] ∪ [0, 0x10] */                \
+       /* PATH 2: r0 ∈ [0x100, 0x200] */                             \
+       if r0 != 0x100 goto 3f; /* True only on PATH 2 */               \
+       r0 /= 0;                                                        \
+3:     exit;                                                           \
+       "
+       :: __imm(bpf_map_lookup_elem),
+          __imm_addr(map_hash_8b),
+          __imm(bpf_get_prandom_u32)
+       : __clobber_all);
+}
+
 char _license[] SEC("license") = "GPL";