[PATCH bpf-next 4/5] selftests/bpf: Cover a nospec jump that becomes a nop

From: Qiliang Yuan

Date: Mon Nov 02 2026 - 07:42:13 EST


A conditional jump that is unsafe on a mispredicted path gets a barrier,
even when it later becomes a 'goto' over dead code only.

No test has such a jump, so nothing checks that bpf_opt_remove_nops()
keeps it with its barrier.

Compare a pointer on the mispredicted path at a jump that always goes
over dead code, and check that the barrier and the jump stay for a prog
loaded without CAP_PERFMON.

Reported-by: Alexei Starovoitov <ast@xxxxxxxxxx>
Closes: https://lore.kernel.org/bpf/DMKHZS5B5CNO.186F6YH1T6YU4@xxxxxxxxx/
Signed-off-by: Qiliang Yuan <odys.yuan@xxxxxxxxx>
---
.../testing/selftests/bpf/progs/verifier_unpriv.c | 35 ++++++++++++++++++++++
1 file changed, 35 insertions(+)

diff --git a/tools/testing/selftests/bpf/progs/verifier_unpriv.c b/tools/testing/selftests/bpf/progs/verifier_unpriv.c
index a54b5a58b945b..b9d96366e656d 100644
--- a/tools/testing/selftests/bpf/progs/verifier_unpriv.c
+++ b/tools/testing/selftests/bpf/progs/verifier_unpriv.c
@@ -1072,4 +1072,39 @@ __naked void nospec_backward_call(void)
" ::: __clobber_all);
}

+/*
+ * Compare a pointer at l0 on the mispredicted path, so that the jump gets a
+ * barrier. On the real path r1 is 0, and the jump only goes over dead code and
+ * becomes a nop. Keep it with its barrier.
+ */
+SEC("socket")
+__description("unpriv: nospec on a jump that becomes a nop")
+__success __success_unpriv
+__caps_unpriv(CAP_BPF)
+__retval(0)
+#ifdef SPEC_V1
+__xlated_unpriv("r1 = 0")
+__xlated_unpriv("nospec")
+__xlated_unpriv("goto pc+0")
+__xlated_unpriv("r0 = 0")
+__xlated_unpriv("exit")
+#endif
+__naked void nospec_jump_becomes_nop(void)
+{
+ asm volatile (" \
+ call %[bpf_get_prandom_u32]; \
+ r0 &= 0xff; \
+ r1 = 0; \
+ if r0 < 0x100 goto l0_%=; \
+ /* executed only speculatively */ \
+ r1 = r10; \
+l0_%=: if r1 == 0 goto l1_%=; \
+ r0 = 1; \
+l1_%=: r0 = 0; \
+ exit; \
+" :
+ : __imm(bpf_get_prandom_u32)
+ : __clobber_all);
+}
+
char _license[] SEC("license") = "GPL";

--
2.43.0