• Daniel Borkmann's avatar
    bpf, verifier: fix alu ops against map_value{, _adj} register types · fce366a9
    Daniel Borkmann authored
    While looking into map_value_adj, I noticed that alu operations
    directly on the map_value() resp. map_value_adj() register (any
    alu operation on a map_value() register will turn it into a
    map_value_adj() typed register) are not sufficiently protected
    against some of the operations. Two non-exhaustive examples are
    provided that the verifier needs to reject:
    
     i) BPF_AND on r0 (map_value_adj):
    
      0: (bf) r2 = r10
      1: (07) r2 += -8
      2: (7a) *(u64 *)(r2 +0) = 0
      3: (18) r1 = 0xbf842a00
      5: (85) call bpf_map_lookup_elem#1
      6: (15) if r0 == 0x0 goto pc+2
       R0=map_value(ks=8,vs=48,id=0),min_value=0,max_value=0 R10=fp
      7: (57) r0 &= 8
      8: (7a) *(u64 *)(r0 +0) = 22
       R0=map_value_adj(ks=8,vs=48,id=0),min_value=0,max_value=8 R10=fp
      9: (95) exit
    
      from 6 to 9: R0=inv,min_value=0,max_value=0 R10=fp
      9: (95) exit
      processed 10 insns
    
    ii) BPF_ADD in 32 bit mode on r0 (map_value_adj):
    
      0: (bf) r2 = r10
      1: (07) r2 += -8
      2: (7a) *(u64 *)(r2 +0) = 0
      3: (18) r1 = 0xc24eee00
      5: (85) call bpf_map_lookup_elem#1
      6: (15) if r0 == 0x0 goto pc+2
       R0=map_value(ks=8,vs=48,id=0),min_value=0,max_value=0 R10=fp
      7: (04) (u32) r0 += (u32) 0
      8: (7a) *(u64 *)(r0 +0) = 22
       R0=map_value_adj(ks=8,vs=48,id=0),min_value=0,max_value=0 R10=fp
      9: (95) exit
    
      from 6 to 9: R0=inv,min_value=0,max_value=0 R10=fp
      9: (95) exit
      processed 10 insns
    
    Issue is, while min_value / max_value boundaries for the access
    are adjusted appropriately, we change the pointer value in a way
    that cannot be sufficiently tracked anymore from its origin.
    Operations like BPF_{AND,OR,DIV,MUL,etc} on a destination register
    that is PTR_TO_MAP_VALUE{,_ADJ} was probably unintended, in fact,
    all the test cases coming with 48461135 ("bpf: allow access
    into map value arrays") perform BPF_ADD only on the destination
    register that is PTR_TO_MAP_VALUE_ADJ.
    
    Only for UNKNOWN_VALUE register types such operations make sense,
    f.e. with unknown memory content fetched initially from a constant
    offset from the map value memory into a register. That register is
    then later tested against lower / upper bounds, so that the verifier
    can then do the tracking of min_value / max_value, and properly
    check once that UNKNOWN_VALUE register is added to the destination
    register with type PTR_TO_MAP_VALUE{,_ADJ}. This is also what the
    original use-case is solving. Note, tracking on what is being
    added is done through adjust_reg_min_max_vals() and later access
    to the map value enforced with these boundaries and the given offset
    from the insn through check_map_access_adj().
    
    Tests will fail for non-root environment due to prohibited pointer
    arithmetic, in particular in check_alu_op(), we bail out on the
    is_pointer_value() check on the dst_reg (which is false in root
    case as we allow for pointer arithmetic via env->allow_ptr_leaks).
    
    Similarly to PTR_TO_PACKET, one way to fix it is to restrict the
    allowed operations on PTR_TO_MAP_VALUE{,_ADJ} registers to 64 bit
    mode BPF_ADD. The test_verifier suite runs fine after the patch
    and it also rejects mentioned test cases.
    
    Fixes: 48461135 ("bpf: allow access into map value arrays")
    Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
    Reviewed-by: default avatarJosef Bacik <jbacik@fb.com>
    Acked-by: default avatarAlexei Starovoitov <ast@kernel.org>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    fce366a9
verifier.c 96.6 KB