Re: [PATCH stable 6.6.y v3 0/4] bpf: linked scalar precision fixes
From: Shung-Hsi Yu <hidden>
Date: 2026-06-16 05:22:18
Also in:
bpf, lkml, stable
On Tue, Jun 16, 2026 at 12:51:34AM +0200, Paul Chaignon wrote:
On Mon, Jun 15, 2026 at 12:58:37AM +0800, Zhenzhong Wu wrote:quoted
Hi, This v3 targets 6.6.y and changes the backport strategy based on review feedback on v2.[...]quoted
Relevant QEMU selftest results on 6.6.y with this backport: verifier_scalar_ids passed all 18 subtests, including the newly backported linked-scalar precision tests and the related check_ids_in_regsafe tests.The first patch in this backport series is actually breaking the "precise: test 1" selftest from test_verifier. You can see the full error at [1]. I haven't yet checked if it's the test or the backport that needs to be adjusted.
I had a quick look, and believe it was that test that needs to be
adjusted to include r9 into the precise register set.
So unless Sasha have other preference, I suggest Zhenzhong send a v4,
with changes to tools/testing/selftests/bpf/verifier/precise.c
(including "r9" the the expected verifier output) merged into "bpf:
Track equal scalars history on per-instruction level".
---
The program under test is:
00: BPF_MOV64_IMM(BPF_REG_0, 1),
01: BPF_LD_MAP_FD(BPF_REG_6, 0),
03: BPF_MOV64_REG(BPF_REG_1, BPF_REG_6),
04: BPF_MOV64_REG(BPF_REG_2, BPF_REG_FP),
05: BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
06: BPF_ST_MEM(BPF_DW, BPF_REG_FP, -8, 0),
07: BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
08: BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
09: BPF_EXIT_INSN(),
10: BPF_MOV64_REG(BPF_REG_9, BPF_REG_0),
11: BPF_MOV64_REG(BPF_REG_1, BPF_REG_6),
12: BPF_MOV64_REG(BPF_REG_2, BPF_REG_FP),
13: BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
14: BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
15: BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
16: BPF_EXIT_INSN(),
17: BPF_MOV64_REG(BPF_REG_8, BPF_REG_0),
18: BPF_ALU64_REG(BPF_SUB, BPF_REG_9, BPF_REG_8), /* map_value_ptr -= map_value_ptr */
19: BPF_MOV64_REG(BPF_REG_2, BPF_REG_9),
20: BPF_JMP_IMM(BPF_JLT, BPF_REG_2, 8, 1),
21: BPF_EXIT_INSN(),
22: BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, 1), /* R2=scalar(umin=1, umax=8) */
23: BPF_MOV64_REG(BPF_REG_1, BPF_REG_FP),
24: BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8),
25: BPF_MOV64_IMM(BPF_REG_3, 0),
26: BPF_EMIT_CALL(BPF_FUNC_probe_read_kernel),
27: BPF_EXIT_INSN(),
The test was expecting the following line in the verifier log that was
shown during the backtracking start at instruction 26 (call
bpf_probe_read_kernel#113)
mark_precise: frame0: regs=r2 stack= before 20: (a5) if r2 < 0x8 goto pc+1
mark_precise: frame0: parent state regs=r2 stack=: ...
mark_precise: frame0: last_idx 19 first_idx 10 ...
But after applying the patchset, we now got an additional register r9 in
the precise set:
mark_precise: frame0: regs=r2 stack= before 20: (a5) if r2 < 0x8 goto pc+1
mark_precise: frame0: parent state regs=r2,r9 stack=: ....
mark_precise: frame0: last_idx 19 first_idx 10 ...
The additional r9 in the precise set seems actually correct, this is
because r2 and r9 share the same scalar ID at instruction 20 (before the
link got broken in instruction 21), and hence at that point, both
register should be marked as precise.
---
In upstream the test already has the expected verifier log to include
r9, and hence no failure, but it simply comes from the fact that r2 and
r9 maintain a link even after instruction 22 (r2 += 1).
commit 98d7ca374ba4b39e7535613d40e159f09ca14da2
Author: Alexei Starovoitov [off-list ref]
Date: Wed Jun 12 18:38:13 2024 -0700
bpf: Track delta between "linked" registers.
...
--- a/tools/testing/selftests/bpf/verifier/precise.c
+++ b/tools/testing/selftests/bpf/verifier/precise.c
@@ -39,12 +39,12 @@
.result = VERBOSE_ACCEPT,
.errstr =
"mark_precise: frame0: last_idx 26 first_idx 20\
- mark_precise: frame0: regs=r2 stack= before 25\
- mark_precise: frame0: regs=r2 stack= before 24\
- mark_precise: frame0: regs=r2 stack= before 23\
- mark_precise: frame0: regs=r2 stack= before 22\
- mark_precise: frame0: regs=r2 stack= before 20\
- mark_precise: frame0: parent state regs=r2 stack=:\
+ mark_precise: frame0: regs=r2,r9 stack= before 25\
+ mark_precise: frame0: regs=r2,r9 stack= before 24\
+ mark_precise: frame0: regs=r2,r9 stack= before 23\
+ mark_precise: frame0: regs=r2,r9 stack= before 22\
+ mark_precise: frame0: regs=r2,r9 stack= before 20\
+ mark_precise: frame0: parent state regs=r2,r9 stack=:\
mark_precise: frame0: last_idx 19 first_idx 10\
mark_precise: frame0: regs=r2,r9 stack= before 19\
mark_precise: frame0: regs=r9 stack= before 18\
...
---
Full test log below
#492/p precise: test 1 FAIL
Unexpected verifier log!
EXP: mark_precise: frame0: parent state regs=r2 stack=:
RES:
func#0 @0
0: R1=ctx(off=0,imm=0) R10=fp0
0: (b7) r0 = 1 ; R0_w=1
1: (18) r6 = 0xffff9eb644619000 ; R6_w=map_ptr(off=0,ks=4,vs=48,imm=0)
3: (bf) r1 = r6 ; R1_w=map_ptr(off=0,ks=4,vs=48,imm=0) R6_w=map_ptr(off=0,ks=4,vs=48,imm=0)
4: (bf) r2 = r10 ; R2_w=fp0 R10=fp0
5: (07) r2 += -8 ; R2_w=fp-8
6: (7a) *(u64 *)(r10 -8) = 0 ; R10=fp0 fp-8_w=00000000
7: (85) call bpf_map_lookup_elem#1 ; R0_w=map_value_or_null(id=1,off=0,ks=4,vs=48,imm=0)
8: (55) if r0 != 0x0 goto pc+1 ; R0_w=0
9: (95) exit
from 8 to 10: R0=map_value(off=0,ks=4,vs=48,imm=0) R6=map_ptr(off=0,ks=4,vs=48,imm=0) R10=fp0 fp-8=0000mmmm
10: R0=map_value(off=0,ks=4,vs=48,imm=0) R6=map_ptr(off=0,ks=4,vs=48,imm=0) R10=fp0 fp-8=0000mmmm
10: (bf) r9 = r0 ; R0=map_value(off=0,ks=4,vs=48,imm=0) R9_w=map_value(off=0,ks=4,vs=48,imm=0)
11: (bf) r1 = r6 ; R1_w=map_ptr(off=0,ks=4,vs=48,imm=0) R6=map_ptr(off=0,ks=4,vs=48,imm=0)
12: (bf) r2 = r10 ; R2_w=fp0 R10=fp0
13: (07) r2 += -8 ; R2_w=fp-8
14: (85) call bpf_map_lookup_elem#1 ; R0_w=map_value_or_null(id=2,off=0,ks=4,vs=48,imm=0)
15: (55) if r0 != 0x0 goto pc+1 ; R0_w=0
16: (95) exit
from 15 to 17: R0_w=map_value(off=0,ks=4,vs=48,imm=0) R6=map_ptr(off=0,ks=4,vs=48,imm=0) R9_w=map_value(off=0,ks=4,vs=48,imm=0) R10=fp0 fp-8=0000mmmm
17: R0_w=map_value(off=0,ks=4,vs=48,imm=0) R6=map_ptr(off=0,ks=4,vs=48,imm=0) R9_w=map_value(off=0,ks=4,vs=48,imm=0) R10=fp0 fp-8=0000mmmm
17: (bf) r8 = r0 ; R0_w=map_value(off=0,ks=4,vs=48,imm=0) R8_w=map_value(off=0,ks=4,vs=48,imm=0)
18: (1f) r9 -= r8 ; R8_w=map_value(off=0,ks=4,vs=48,imm=0) R9_w=scalar()
19: (bf) r2 = r9 ; R2=scalar(id=3) R9=scalar(id=3)
20: (a5) if r2 < 0x8 goto pc+1 ; R2=scalar(id=3,umin=8)
21: (95) exit
from 20 to 22: R0=map_value(off=0,ks=4,vs=48,imm=0) R2=scalar(id=3,umax=7,var_off=(0x0; 0x7)) R6=map_ptr(off=0,ks=4,vs=48,imm=0) R8=map_value(off=0,ks=4,vs=48,imm=0) R9=scalar(id=3,umax=7,var_off=(0x0; 0x7)) R10=fp0 fp-8=0000mmmm
22: R0=map_value(off=0,ks=4,vs=48,imm=0) R2=scalar(id=3,umax=7,var_off=(0x0; 0x7)) R6=map_ptr(off=0,ks=4,vs=48,imm=0) R8=map_value(off=0,ks=4,vs=48,imm=0) R9=scalar(id=3,umax=7,var_off=(0x0; 0x7)) R10=fp0 fp-8=0000mmmm
22: (07) r2 += 1 ; R2_w=scalar(umin=1,umax=8,var_off=(0x0; 0xf))
23: (bf) r1 = r10 ; R1_w=fp0 R10=fp0
24: (07) r1 += -8 ; R1_w=fp-8
25: (b7) r3 = 0 ; R3_w=0
26: (85) call bpf_probe_read_kernel#113
mark_precise: frame0: last_idx 26 first_idx 20 subseq_idx -1
mark_precise: frame0: regs=r2 stack= before 25: (b7) r3 = 0
mark_precise: frame0: regs=r2 stack= before 24: (07) r1 += -8
mark_precise: frame0: regs=r2 stack= before 23: (bf) r1 = r10
mark_precise: frame0: regs=r2 stack= before 22: (07) r2 += 1
mark_precise: frame0: regs=r2 stack= before 20: (a5) if r2 < 0x8 goto pc+1
mark_precise: frame0: parent state regs=r2,r9 stack=: R0_rw=map_value(off=0,ks=4,vs=48,imm=0) R2_rw=Pscalar(id=3) R6=map_ptr(off=0,ks=4,vs=48,imm=0) R8_w=map_value(off=0,ks=4,vs=48,imm=0) R9_w=Pscalar(id=3) R10=fp0 fp-8_r=0000mmmm
mark_precise: frame0: last_idx 19 first_idx 10 subseq_idx 20
mark_precise: frame0: regs=r2,r9 stack= before 19: (bf) r2 = r9
mark_precise: frame0: regs=r9 stack= before 18: (1f) r9 -= r8
mark_precise: frame0: regs=r8,r9 stack= before 17: (bf) r8 = r0
mark_precise: frame0: regs=r0,r9 stack= before 15: (55) if r0 != 0x0 goto pc+1
mark_precise: frame0: regs=r0,r9 stack= before 14: (85) call bpf_map_lookup_elem#1
mark_precise: frame0: regs=r9 stack= before 13: (07) r2 += -8
mark_precise: frame0: regs=r9 stack= before 12: (bf) r2 = r10
mark_precise: frame0: regs=r9 stack= before 11: (bf) r1 = r6
mark_precise: frame0: regs=r9 stack= before 10: (bf) r9 = r0
mark_precise: frame0: parent state regs= stack=: R0_rw=map_value(off=0,ks=4,vs=48,imm=0) R6_rw=map_ptr(off=0,ks=4,vs=48,imm=0) R10=fp0 fp-8_rw=0000mmmm
27: R0_w=scalar()
27: (95) exit
processed 27 insns (limit 1000000) max_states_per_insn 0 total_states 2 peak_states 2 mark_read 1
[...]