]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
selftests/bpf: new cases handled by 32->64 range refinements
authorEduard Zingerman <eddyz87@gmail.com>
Fri, 24 Apr 2026 22:52:45 +0000 (15:52 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Sat, 25 Apr 2026 01:14:18 +0000 (18:14 -0700)
1. 32-bit range starts before 64-bit range's low bits in each block,
   causing intersection to skip entire blocks.
2. 32-bit range crosses the U32_MAX/0 boundary, represented as s32
   range crossing sign boundary.

Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20260424-cnums-everywhere-rfc-v1-v3-4-ca434b39a486@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
tools/testing/selftests/bpf/progs/verifier_bounds.c

index f0b3fbbbb62787504c881bc161dc1a95503b92eb..5dd243e653c9ff86e768dbc4ef1b2d3240d158ba 100644 (file)
@@ -2187,4 +2187,84 @@ __naked void tnums_equal_impossible_constant(void *ctx)
        : __clobber_all);
 }
 
+/*
+ * 32-bit range starts before 64-bit range low bits in each 2^32 block.
+ *
+ * N*2^32                   (N+1)*2^32                (N+2)*2^32                (N+3)*2^32
+ * ||----|=====|--|----------||----|=====|-------------||--|-|=====|-------------||
+ *       |< b >|  |                |< b >|                 | |< b >|
+ *                |                |     |                 |
+ *                |<---------------+- a -+---------------->|
+ *                                 |     |
+ *                                 |< t >| refined r0 range
+ *
+ * a = u64 [0x1'00000008, 0x3'00000001]
+ * b = u32 [2, 5]
+ * t = u64 [0x2'00000002, 0x2'00000005]
+ */
+SEC("socket")
+__success
+__flag(BPF_F_TEST_REG_INVARIANTS)
+__naked void deduce64_from_32_before_block_start(void)
+{
+       asm volatile ("                                                 \
+       call %[bpf_get_prandom_u32];                                    \
+       r1 = 0x100000008 ll;                                            \
+       if r0 < r1 goto 2f;                                             \
+       r1 = 0x300000001 ll;                                            \
+       if r0 > r1 goto 2f;     /* u64: [0x1'00000008, 0x3'00000001] */ \
+       if w0 < 2 goto 2f;                                              \
+       if w0 > 5 goto 2f;      /* u32: [2, 5] */                       \
+       r2 = 0x200000002 ll;                                            \
+       r3 = 0x200000005 ll;                                            \
+       if r0 >= r2 goto 1f;    /* should be always true */             \
+       r10 = 0;                /* dead code */                         \
+1:     if r0 <= r3 goto 2f;    /* should be always true */             \
+       r10 = 0;                /* dead code */                         \
+2:     exit;                                                           \
+       "
+       :: __imm(bpf_get_prandom_u32)
+       : __clobber_all);
+}
+
+/*
+ * 32-bit range crossing U32_MAX / 0 boundary.
+ *
+ * N*2^32                   (N+1)*2^32                (N+2)*2^32                (N+3)*2^32
+ * ||===|---------|------|===||===|----------------|===||===|---------|------|===||
+ *  |b >|         |      |< b||b >|                |< b||b >|         |      |< b|
+ *                |      |                                  |         |
+ *                |<-----+----------------- a --------------+-------->|
+ *                       |                                  |
+ *                       |<---------------- t ------------->| refined r0 range
+ *
+ * a = u64 [0x1'00000006, 0x2'FFFFFFEF]
+ * b = s32 [-16, 5] (u32 wrapping [0xFFFFFFF0, 0x00000005])
+ * t = u64 [0x1'FFFFFFF0, 0x2'00000005]
+ */
+SEC("socket")
+__success
+__flag(BPF_F_TEST_REG_INVARIANTS)
+__naked void deduce64_from_32_wrapping_32bit(void)
+{
+       asm volatile ("                                                 \
+       call %[bpf_get_prandom_u32];                                    \
+       r1 = 0x100000006 ll;                                            \
+       if r0 < r1 goto 2f;                                             \
+       r1 = 0x2ffffffef ll;                                            \
+       if r0 > r1 goto 2f;     /* u64: [0x1'00000006, 0x2'FFFFFFEF] */ \
+       if w0 s< -16 goto 2f;                                           \
+       if w0 s> 5 goto 2f;     /* s32: [-16, 5] */                     \
+       r1 = 0x1fffffff0 ll;                                            \
+       r2 = 0x200000005 ll;                                            \
+       if r0 >= r1 goto 1f;    /* should be always true */             \
+       r10 = 0;                /* dead code */                         \
+1:     if r0 <= r2 goto 2f;    /* should be always true */             \
+       r10 = 0;                /* dead code */                         \
+2:     exit;                                                           \
+       "
+       :: __imm(bpf_get_prandom_u32)
+       : __clobber_all);
+}
+
 char _license[] SEC("license") = "GPL";