selftests/bpf: trigger verifier.c:maybe_exit_scc() for a speculative state

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>
This commit is contained in:
Eduard Zingerman 2025-09-16 14:22:51 -07:00 committed by Alexei Starovoitov
parent a3c73d629e
commit a24a2dda70

View 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";