]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
selftests/bpf: Add tests for maybe_fork_scalars() OR vs AND handling
authorDaniel Wade <danjwade95@gmail.com>
Sat, 14 Mar 2026 02:15:21 +0000 (13:15 +1100)
committerAlexei Starovoitov <ast@kernel.org>
Sat, 21 Mar 2026 20:14:28 +0000 (13:14 -0700)
Add three test cases to verifier_bounds.c to verify that
maybe_fork_scalars() correctly tracks register values for BPF_OR
operations with constant source operands:

1. or_scalar_fork_rejects_oob: After ARSH 63 + OR 8, the pushed
   path should have dst = 8. With value_size = 8, accessing
   map_value + 8 is out of bounds and must be rejected.

2. and_scalar_fork_still_works: Regression test ensuring AND
   forking continues to work. ARSH 63 + AND 4 produces pushed
   dst = 0 and current dst = 4, both within value_size = 8.

3. or_scalar_fork_allows_inbounds: After ARSH 63 + OR 4, the
   pushed path has dst = 4, which is within value_size = 8
   and should be accepted.

These tests exercise the fix in the previous patch, which makes the
pushed path re-execute the ALU instruction so it computes the correct
result for BPF_OR.

Signed-off-by: Daniel Wade <danjwade95@gmail.com>
Reviewed-by: Amery Hung <ameryhung@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20260314021521.128361-3-danjwade95@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
tools/testing/selftests/bpf/progs/verifier_bounds.c

index e526315c718ad7e7905d95cc9b52b229cb12af39..79a328276805de721a112f54eebdc0110fdc3e30 100644 (file)
@@ -2037,4 +2037,98 @@ __naked void signed_unsigned_intersection32_case2(void *ctx)
        : __clobber_all);
 }
 
+SEC("socket")
+__description("maybe_fork_scalars: OR with constant rejects OOB")
+__failure __msg("invalid access to map value")
+__naked void or_scalar_fork_rejects_oob(void)
+{
+       asm volatile ("                                 \
+       r1 = 0;                                         \
+       *(u64*)(r10 - 8) = r1;                          \
+       r2 = r10;                                       \
+       r2 += -8;                                       \
+       r1 = %[map_hash_8b] ll;                         \
+       call %[bpf_map_lookup_elem];                    \
+       if r0 == 0 goto l0_%=;                          \
+       r9 = r0;                                        \
+       r6 = *(u64*)(r9 + 0);                           \
+       r6 s>>= 63;                                     \
+       r6 |= 8;                                        \
+       /* r6 is -1 (current) or 8 (pushed) */          \
+       if r6 s< 0 goto l0_%=;                          \
+       /* pushed path: r6 = 8, OOB for value_size=8 */ \
+       r9 += r6;                                       \
+       r0 = *(u8*)(r9 + 0);                            \
+l0_%=: r0 = 0;                                         \
+       exit;                                           \
+"      :
+       : __imm(bpf_map_lookup_elem),
+         __imm_addr(map_hash_8b)
+       : __clobber_all);
+}
+
+SEC("socket")
+__description("maybe_fork_scalars: AND with constant still works")
+__success __retval(0)
+__naked void and_scalar_fork_still_works(void)
+{
+       asm volatile ("                                 \
+       r1 = 0;                                         \
+       *(u64*)(r10 - 8) = r1;                          \
+       r2 = r10;                                       \
+       r2 += -8;                                       \
+       r1 = %[map_hash_8b] ll;                         \
+       call %[bpf_map_lookup_elem];                    \
+       if r0 == 0 goto l0_%=;                          \
+       r9 = r0;                                        \
+       r6 = *(u64*)(r9 + 0);                           \
+       r6 s>>= 63;                                     \
+       r6 &= 4;                                        \
+       /*                                              \
+        * r6 is 0 (pushed, 0&4==0) or 4 (current)      \
+        * both within value_size=8                     \
+        */                                             \
+       if r6 s< 0 goto l0_%=;                          \
+       r9 += r6;                                       \
+       r0 = *(u8*)(r9 + 0);                            \
+l0_%=: r0 = 0;                                         \
+       exit;                                           \
+"      :
+       : __imm(bpf_map_lookup_elem),
+         __imm_addr(map_hash_8b)
+       : __clobber_all);
+}
+
+SEC("socket")
+__description("maybe_fork_scalars: OR with constant allows in-bounds")
+__success __retval(0)
+__naked void or_scalar_fork_allows_inbounds(void)
+{
+       asm volatile ("                                 \
+       r1 = 0;                                         \
+       *(u64*)(r10 - 8) = r1;                          \
+       r2 = r10;                                       \
+       r2 += -8;                                       \
+       r1 = %[map_hash_8b] ll;                         \
+       call %[bpf_map_lookup_elem];                    \
+       if r0 == 0 goto l0_%=;                          \
+       r9 = r0;                                        \
+       r6 = *(u64*)(r9 + 0);                           \
+       r6 s>>= 63;                                     \
+       r6 |= 4;                                        \
+       /*                                              \
+        * r6 is -1 (current) or 4 (pushed)             \
+        * pushed path: r6 = 4, within value_size=8     \
+        */                                             \
+       if r6 s< 0 goto l0_%=;                          \
+       r9 += r6;                                       \
+       r0 = *(u8*)(r9 + 0);                            \
+l0_%=: r0 = 0;                                         \
+       exit;                                           \
+"      :
+       : __imm(bpf_map_lookup_elem),
+         __imm_addr(map_hash_8b)
+       : __clobber_all);
+}
+
 char _license[] SEC("license") = "GPL";