• Daniel Borkmann's avatar
    bpf: Fix alu32 const subreg bound tracking on bitwise operations · 049c4e13
    Daniel Borkmann authored
    Fix a bug in the verifier's scalar32_min_max_*() functions which leads to
    incorrect tracking of 32 bit bounds for the simulation of and/or/xor bitops.
    When both the src & dst subreg is a known constant, then the assumption is
    that scalar_min_max_*() will take care to update bounds correctly. However,
    this is not the case, for example, consider a register R2 which has a tnum
    of 0xffffffff00000000, meaning, lower 32 bits are known constant and in this
    case of value 0x00000001. R2 is then and'ed with a register R3 which is a
    64 bit known constant, here, 0x100000002.
    
    What can be seen in line '10:' is that 32 bit bounds reach an invalid state
    where {u,s}32_min_value > {u,s}32_max_value. The reason is scalar32_min_max_*()
    delegates 32 bit bounds updates to scalar_min_max_*(), however, that really
    only takes place when both the 64 bit src & dst register is a known constant.
    Given scalar32_min_max_*() is intended to be designed as closely as possible
    to scalar_min_max_*(), update the 32 bit bounds in this situation through
    __mark_reg32_known() which will set all {u,s}32_{min,max}_value to the correct
    constant, which is 0x00000000 after the fix (given 0x00000001 & 0x00000002 in
    32 bit space). This is possible given var32_off already holds the final value
    as dst_reg->var_off is updated before calling scalar32_min_max_*().
    
    Before fix, invalid tracking of R2:
    
      [...]
      9: R0_w=inv1337 R1=ctx(id=0,off=0,imm=0) R2_w=inv(id=0,smin_value=-9223372036854775807 (0x8000000000000001),smax_value=9223372032559808513 (0x7fffffff00000001),umin_value=1,umax_value=0xffffffff00000001,var_off=(0x1; 0xffffffff00000000),s32_min_value=1,s32_max_value=1,u32_min_value=1,u32_max_value=1) R3_w=inv4294967298 R10=fp0
      9: (5f) r2 &= r3
      10: R0_w=inv1337 R1=ctx(id=0,off=0,imm=0) R2_w=inv(id=0,smin_value=0,smax_value=4294967296 (0x100000000),umin_value=0,umax_value=0x100000000,var_off=(0x0; 0x100000000),s32_min_value=1,s32_max_value=0,u32_min_value=1,u32_max_value=0) R3_w=inv4294967298 R10=fp0
      [...]
    
    After fix, correct tracking of R2:
    
      [...]
      9: R0_w=inv1337 R1=ctx(id=0,off=0,imm=0) R2_w=inv(id=0,smin_value=-9223372036854775807 (0x8000000000000001),smax_value=9223372032559808513 (0x7fffffff00000001),umin_value=1,umax_value=0xffffffff00000001,var_off=(0x1; 0xffffffff00000000),s32_min_value=1,s32_max_value=1,u32_min_value=1,u32_max_value=1) R3_w=inv4294967298 R10=fp0
      9: (5f) r2 &= r3
      10: R0_w=inv1337 R1=ctx(id=0,off=0,imm=0) R2_w=inv(id=0,smin_value=0,smax_value=4294967296 (0x100000000),umin_value=0,umax_value=0x100000000,var_off=(0x0; 0x100000000),s32_min_value=0,s32_max_value=0,u32_min_value=0,u32_max_value=0) R3_w=inv4294967298 R10=fp0
      [...]
    
    Fixes: 3f50f132 ("bpf: Verifier, do explicit ALU32 bounds tracking")
    Fixes: 2921c90d ("bpf: Fix a verifier failure with xor")
    Reported-by: Manfred Paul (@_manfp)
    Reported-by: default avatarThadeu Lima de Souza Cascardo <cascardo@canonical.com>
    Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
    Reviewed-by: default avatarJohn Fastabend <john.fastabend@gmail.com>
    Acked-by: default avatarAlexei Starovoitov <ast@kernel.org>
    049c4e13
verifier.c 384 KB