• Andrii Nakryiko's avatar
    bpf: fix calculation of subseq_idx during precision backtracking · d84b1a67
    Andrii Nakryiko authored
    Subsequent instruction index (subseq_idx) is an index of an instruction
    that was verified/executed by verifier after the currently processed
    instruction. It is maintained during precision backtracking processing
    and is used to detect various subprog calling conditions.
    
    This patch fixes the bug with incorrectly resetting subseq_idx to -1
    when going from child state to parent state during backtracking. If we
    don't maintain correct subseq_idx we can misidentify subprog calls
    leading to precision tracking bugs.
    
    One such case was triggered by test_global_funcs/global_func9 test where
    global subprog call happened to be the very last instruction in parent
    state, leading to subseq_idx==-1, triggering WARN_ONCE:
    
      [   36.045754] verifier backtracking bug
      [   36.045764] WARNING: CPU: 13 PID: 2073 at kernel/bpf/verifier.c:3503 __mark_chain_precision+0xcc6/0xde0
      [   36.046819] Modules linked in: aesni_intel(E) crypto_simd(E) cryptd(E) kvm_intel(E) kvm(E) irqbypass(E) i2c_piix4(E) serio_raw(E) i2c_core(E) crc32c_intel)
      [   36.048040] CPU: 13 PID: 2073 Comm: test_progs Tainted: G        W  OE      6.3.0-07976-g4d585f48-dirty #972
      [   36.048783] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.0-59-gc9ba5276e321-prebuilt.qemu.org 04/01/2014
      [   36.049648] RIP: 0010:__mark_chain_precision+0xcc6/0xde0
      [   36.050038] Code: 3d 82 c6 05 bb 35 32 02 01 e8 66 21 ec ff 0f 0b b8 f2 ff ff ff e9 30 f5 ff ff 48 c7 c7 f3 61 3d 82 4c 89 0c 24 e8 4a 21 ec ff <0f> 0b 4c0
    
    With the fix precision tracking across multiple states works correctly now:
    
    mark_precise: frame0: last_idx 45 first_idx 38 subseq_idx -1
    mark_precise: frame0: regs=r8 stack= before 44: (61) r7 = *(u32 *)(r10 -4)
    mark_precise: frame0: regs=r8 stack= before 43: (85) call pc+41
    mark_precise: frame0: regs=r8 stack= before 42: (07) r1 += -48
    mark_precise: frame0: regs=r8 stack= before 41: (bf) r1 = r10
    mark_precise: frame0: regs=r8 stack= before 40: (63) *(u32 *)(r10 -48) = r1
    mark_precise: frame0: regs=r8 stack= before 39: (b4) w1 = 0
    mark_precise: frame0: regs=r8 stack= before 38: (85) call pc+38
    mark_precise: frame0: parent state regs=r8 stack=:  R0_w=scalar() R1_w=map_value(off=4,ks=4,vs=8,imm=0) R6=1 R7_w=scalar() R8_r=P0 R10=fpm
    mark_precise: frame0: last_idx 36 first_idx 28 subseq_idx 38
    mark_precise: frame0: regs=r8 stack= before 36: (18) r1 = 0xffff888104f2ed14
    mark_precise: frame0: regs=r8 stack= before 35: (85) call pc+33
    mark_precise: frame0: regs=r8 stack= before 33: (18) r1 = 0xffff888104f2ed10
    mark_precise: frame0: regs=r8 stack= before 32: (85) call pc+36
    mark_precise: frame0: regs=r8 stack= before 31: (07) r1 += -4
    mark_precise: frame0: regs=r8 stack= before 30: (bf) r1 = r10
    mark_precise: frame0: regs=r8 stack= before 29: (63) *(u32 *)(r10 -4) = r7
    mark_precise: frame0: regs=r8 stack= before 28: (4c) w7 |= w0
    mark_precise: frame0: parent state regs=r8 stack=:  R0_rw=scalar() R6=1 R7_rw=scalar() R8_rw=P0 R10=fp0 fp-48_r=mmmmmmmm
    mark_precise: frame0: last_idx 27 first_idx 16 subseq_idx 28
    mark_precise: frame0: regs=r8 stack= before 27: (85) call pc+31
    mark_precise: frame0: regs=r8 stack= before 26: (b7) r1 = 0
    mark_precise: frame0: regs=r8 stack= before 25: (b7) r8 = 0
    
    Note how subseq_idx starts out as -1, then is preserved as 38 and then 28 as we
    go up the parent state chain.
    Reported-by: default avatarAlexei Starovoitov <ast@kernel.org>
    Fixes: fde2a388 ("bpf: support precision propagation in the presence of subprogs")
    Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
    Link: https://lore.kernel.org/r/20230515180710.1535018-1-andrii@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
    d84b1a67
verifier.c 567 KB