selftests/bpf: add edge case backtracking logic test
authorAndrii Nakryiko <andrii@kernel.org>
Fri, 10 Nov 2023 00:26:38 +0000 (16:26 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Fri, 10 Nov 2023 04:11:20 +0000 (20:11 -0800)
Add a dedicated selftests to try to set up conditions to have a state
with same first and last instruction index, but it actually is a loop
3->4->1->2->3. This confuses mark_chain_precision() if verifier doesn't
take into account jump history.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/r/20231110002638.4168352-4-andrii@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
tools/testing/selftests/bpf/progs/verifier_precision.c

index 193c0f8..6b564d4 100644 (file)
@@ -91,3 +91,43 @@ __naked int bpf_end_bswap(void)
 }
 
 #endif /* v4 instruction */
+
+SEC("?raw_tp")
+__success __log_level(2)
+/*
+ * Without the bug fix there will be no history between "last_idx 3 first_idx 3"
+ * and "parent state regs=" lines. "R0_w=6" parts are here to help anchor
+ * expected log messages to the one specific mark_chain_precision operation.
+ *
+ * This is quite fragile: if verifier checkpointing heuristic changes, this
+ * might need adjusting.
+ */
+__msg("2: (07) r0 += 1                       ; R0_w=6")
+__msg("3: (35) if r0 >= 0xa goto pc+1")
+__msg("mark_precise: frame0: last_idx 3 first_idx 3 subseq_idx -1")
+__msg("mark_precise: frame0: regs=r0 stack= before 2: (07) r0 += 1")
+__msg("mark_precise: frame0: regs=r0 stack= before 1: (07) r0 += 1")
+__msg("mark_precise: frame0: regs=r0 stack= before 4: (05) goto pc-4")
+__msg("mark_precise: frame0: regs=r0 stack= before 3: (35) if r0 >= 0xa goto pc+1")
+__msg("mark_precise: frame0: parent state regs= stack=:  R0_rw=P4")
+__msg("3: R0_w=6")
+__naked int state_loop_first_last_equal(void)
+{
+       asm volatile (
+               "r0 = 0;"
+       "l0_%=:"
+               "r0 += 1;"
+               "r0 += 1;"
+               /* every few iterations we'll have a checkpoint here with
+                * first_idx == last_idx, potentially confusing precision
+                * backtracking logic
+                */
+               "if r0 >= 10 goto l1_%=;"       /* checkpoint + mark_precise */
+               "goto l0_%=;"
+       "l1_%=:"
+               "exit;"
+               ::: __clobber_common
+       );
+}
+
+char _license[] SEC("license") = "GPL";