• Daniel Borkmann's avatar
    bpf: Fix incorrect verifier simulation around jmp32's jeq/jne · a12ca627
    Daniel Borkmann authored
    Kuee reported a quirk in the jmp32's jeq/jne simulation, namely that the
    register value does not match expectations for the fall-through path. For
    example:
    
    Before fix:
    
      0: R1=ctx(off=0,imm=0) R10=fp0
      0: (b7) r2 = 0                        ; R2_w=P0
      1: (b7) r6 = 563                      ; R6_w=P563
      2: (87) r2 = -r2                      ; R2_w=Pscalar()
      3: (87) r2 = -r2                      ; R2_w=Pscalar()
      4: (4c) w2 |= w6                      ; R2_w=Pscalar(umin=563,umax=4294967295,var_off=(0x233; 0xfffffdcc),s32_min=-2147483085) R6_w=P563
      5: (56) if w2 != 0x8 goto pc+1        ; R2_w=P571  <--- [*]
      6: (95) exit
      R0 !read_ok
    
    After fix:
    
      0: R1=ctx(off=0,imm=0) R10=fp0
      0: (b7) r2 = 0                        ; R2_w=P0
      1: (b7) r6 = 563                      ; R6_w=P563
      2: (87) r2 = -r2                      ; R2_w=Pscalar()
      3: (87) r2 = -r2                      ; R2_w=Pscalar()
      4: (4c) w2 |= w6                      ; R2_w=Pscalar(umin=563,umax=4294967295,var_off=(0x233; 0xfffffdcc),s32_min=-2147483085) R6_w=P563
      5: (56) if w2 != 0x8 goto pc+1        ; R2_w=P8  <--- [*]
      6: (95) exit
      R0 !read_ok
    
    As can be seen on line 5 for the branch fall-through path in R2 [*] is that
    given condition w2 != 0x8 is false, verifier should conclude that r2 = 8 as
    upper 32 bit are known to be zero. However, verifier incorrectly concludes
    that r2 = 571 which is far off.
    
    The problem is it only marks false{true}_reg as known in the switch for JE/NE
    case, but at the end of the function, it uses {false,true}_{64,32}off to
    update {false,true}_reg->var_off and they still hold the prior value of
    {false,true}_reg->var_off before it got marked as known. The subsequent
    __reg_combine_32_into_64() then propagates this old var_off and derives new
    bounds. The information between min/max bounds on {false,true}_reg from
    setting the register to known const combined with the {false,true}_reg->var_off
    based on the old information then derives wrong register data.
    
    Fix it by detangling the BPF_JEQ/BPF_JNE cases and updating relevant
    {false,true}_{64,32}off tnums along with the register marking to known
    constant.
    
    Fixes: 3f50f132 ("bpf: Verifier, do explicit ALU32 bounds tracking")
    Reported-by: default avatarKuee K1r0a <liulin063@gmail.com>
    Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
    Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
    Acked-by: default avatarJohn Fastabend <john.fastabend@gmail.com>
    Link: https://lore.kernel.org/bpf/20220701124727.11153-1-daniel@iogearbox.net
    a12ca627
verifier.c 431 KB