]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
selftests/bpf: trigger verifier.c:maybe_exit_scc() for a speculative state
authorEduard Zingerman <eddyz87@gmail.com>
Tue, 16 Sep 2025 21:22:51 +0000 (14:22 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Wed, 17 Sep 2025 18:19:58 +0000 (11:19 -0700)
This is a test case minimized from a syzbot reproducer from [1].
The test case triggers verifier.c:maybe_exit_scc() w/o
preceding call to verifier.c:maybe_enter_scc() on a speculative
symbolic execution path.

Here is verifier log for the test case:

  Live regs before insn:
        0: .......... (b7) r0 = 100
    1   1: 0......... (7b) *(u64 *)(r10 -512) = r0
    1   2: 0......... (b5) if r0 <= 0x0 goto pc-2
        3: 0......... (95) exit
  0: R1=ctx() R10=fp0
  0: (b7) r0 = 100                      ; R0_w=100
  1: (7b) *(u64 *)(r10 -512) = r0       ; R0_w=100 R10=fp0 fp-512_w=100
  2: (b5) if r0 <= 0x0 goto pc-2
  mark_precise: ...
  2: R0_w=100
  3: (95) exit

  from 2 to 1 (speculative execution): R0_w=scalar() R1=ctx() R10=fp0 fp-512_w=100
  1: R0_w=scalar() R1=ctx() R10=fp0 fp-512_w=100
  1: (7b) *(u64 *)(r10 -512) = r0
  processed 5 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0

- Non-speculative execution path 0-3 does not allocate any checkpoints
  (and hence does not call maybe_enter_scc()), and schedules a
  speculative jump from 2 to 1.
- Speculative execution path stops immediately because of an infinite
  loop detection and triggers verifier.c:update_branch_counts() ->
  maybe_exit_scc() calls.

[1] https://lore.kernel.org/bpf/68c85acd.050a0220.2ff435.03a4.GAE@google.com/

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

index e07b43b78fd21071f3386ab8d3a481f534c99749..fbdde80e7b9055e622c61474c4b0578332fcb646 100644 (file)
@@ -283,4 +283,25 @@ exit_%=:                                           \
        : __clobber_all);
 }
 
+/*
+ * This test case triggered a bug in verifier.c:maybe_exit_scc().
+ * Speculative execution path reaches stack access instruction,
+ * stops and triggers maybe_exit_scc() w/o accompanying maybe_enter_scc() call.
+ */
+SEC("socket")
+__arch_x86_64
+__caps_unpriv(CAP_BPF)
+__naked void maybe_exit_scc_bug1(void)
+{
+       asm volatile (
+       "r0 = 100;"
+"1:"
+       /* Speculative execution path reaches and stops here. */
+       "*(u64 *)(r10 - 512) = r0;"
+       /* Condition is always false, but verifier speculatively executes the true branch. */
+       "if r0 <= 0x0 goto 1b;"
+       "exit;"
+       ::: __clobber_all);
+}
+
 char _license[] SEC("license") = "GPL";