]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
selftests/bpf: Add test for add_const base_id consistency
authorDaniel Borkmann <daniel@iogearbox.net>
Fri, 10 Apr 2026 23:26:51 +0000 (01:26 +0200)
committerAlexei Starovoitov <ast@kernel.org>
Sat, 11 Apr 2026 00:39:09 +0000 (17:39 -0700)
Add a test to verifier_linked_scalars that exercises the base_id
consistency check for BPF_ADD_CONST linked scalars during state
pruning.

With the fix, pruning fails and the verifier discovers the true
branch's R3 is too wide for the stack access.

  # LDLIBS=-static PKG_CONFIG='pkg-config --static' ./vmtest.sh -- ./test_progs -t verifier_linked_scalars
  [...]
  #613/22  verifier_linked_scalars/scalars_stale_delta_from_cleared_id:OK
  #613/23  verifier_linked_scalars/scalars_stale_delta_from_cleared_id_alu32:OK
  #613/24  verifier_linked_scalars/linked scalars: add_const base_id must be consistent for pruning:OK
  #613     verifier_linked_scalars:OK
  Summary: 1/24 PASSED, 0 SKIPPED, 0 FAILED

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/r/20260410232651.559778-2-daniel@iogearbox.net
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
tools/testing/selftests/bpf/progs/verifier_linked_scalars.c

index 60a6f246e2d173d23e41ae7f7c224c93691cfc53..d571fbfc86a3a39a134a45734f248fbe61c8641f 100644 (file)
@@ -647,4 +647,67 @@ l_exit_%=:                                                 \
        : __clobber_all);
 }
 
+/*
+ * Test that regsafe() verifies base_id consistency for BPF_ADD_CONST
+ * linked scalars during state pruning.
+ *
+ * The false branch (explored first) links R3 to R2 via ADD_CONST.
+ * The true branch (runtime path) links R3 to R4 (unrelated base_id).
+ * At the merge point, pruning must fail because the linkage topology
+ * differs.
+ */
+SEC("socket")
+__description("linked scalars: add_const base_id must be consistent for pruning")
+__failure __msg("invalid variable-offset")
+__flag(BPF_F_TEST_STATE_FREQ)
+__naked void add_const_base_id_pruning(void)
+{
+       asm volatile ("                                         \
+       r1 = 0;                                                 \
+       *(u64*)(r10 - 16) = r1;                                 \
+       call %[bpf_get_prandom_u32];                            \
+       r6 = r0;                                                \
+       r6 &= 1;                                                \
+       if r6 >= 1 goto l_true_%=;                              \
+                                                               \
+       /* False branch (explored first, old state) */          \
+       call %[bpf_get_prandom_u32];                            \
+       r2 = r0;                                                \
+       r2 &= 0xff;             /* R2 = scalar(id=A) [0,255] */ \
+       r3 = r2;                /* R3 linked to R2 (id=A) */    \
+       r3 += 10;               /* R3 id=A|ADD_CONST, delta=10 */\
+       r6 = 0;                                                 \
+       goto l_merge_%=;                                        \
+                                                               \
+l_true_%=:                                                     \
+       /* True branch (runtime path, cur state) */             \
+       call %[bpf_get_prandom_u32];                            \
+       r2 = r0;                                                \
+       r2 &= 0xff;             /* R2 = scalar [0,255], id=0 */ \
+       r4 = r0;                                                \
+       r4 &= 0xff;             /* R4 = scalar [0,255], id=0 */ \
+       r3 = r4;                /* R3 linked to R4 (new id=C) */\
+       r3 += 10;               /* R3 id=C|ADD_CONST, delta=10 */\
+       r6 = 0;                                                 \
+                                                               \
+l_merge_%=:                                                    \
+       /* At merge, old R3 linked to R2, cur R3 linked to R4. */\
+       /* Pruning must fail: base_ids A vs C inconsistent. */  \
+       if r2 >= 6 goto l_exit_%=;                              \
+       /* sync_linked_regs: R2<6 => R3<16 in old state. */     \
+       /* Without fix: R3 in [10,15] from incorrect pruning. */\
+       /* With fix: R3 in [10,265], not synced from R2. */     \
+       r3 -= 10;               /* [0,5] vs [0,255] */          \
+       r9 = r10;                                               \
+       r9 += -16;                                              \
+       r9 += r3;               /* fp-16+[0,5] vs fp-16+[0,255] */\
+       *(u8*)(r9 + 0) = r6;    /* within 16B vs past fp */     \
+l_exit_%=:                                                     \
+       r0 = 0;                                                 \
+       exit;                                                   \
+"      :
+       : __imm(bpf_get_prandom_u32)
+       : __clobber_all);
+}
+
 char _license[] SEC("license") = "GPL";