• D
    bpf: Fix out of bounds access from invalid *_or_null type verification · 026193f7
    Daniel Borkmann 提交于
    stable inclusion
    from stable-v5.10.92
    commit 35ab8c9085b0af847df7fac9571ccd26d9f0f513
    bugzilla: https://gitee.com/openeuler/kernel/issues/I4WRPV
    
    Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=35ab8c9085b0af847df7fac9571ccd26d9f0f513
    
    --------------------------------
    
    [ no upstream commit given implicitly fixed through the larger refactoring
      in c25b2ae1 ]
    
    While auditing some other code, I noticed missing checks inside the pointer
    arithmetic simulation, more specifically, adjust_ptr_min_max_vals(). Several
    *_OR_NULL types are not rejected whereas they are _required_ to be rejected
    given the expectation is that they get promoted into a 'real' pointer type
    for the success case, that is, after an explicit != NULL check.
    
    One case which stands out and is accessible from unprivileged (iff enabled
    given disabled by default) is BPF ring buffer. From crafting a PoC, the NULL
    check can be bypassed through an offset, and its id marking will then lead
    to promotion of mem_or_null to a mem type.
    
    bpf_ringbuf_reserve() helper can trigger this case through passing of reserved
    flags, for example.
    
      func#0 @0
      0: R1=ctx(id=0,off=0,imm=0) R10=fp0
      0: (7a) *(u64 *)(r10 -8) = 0
      1: R1=ctx(id=0,off=0,imm=0) R10=fp0 fp-8_w=mmmmmmmm
      1: (18) r1 = 0x0
      3: R1_w=map_ptr(id=0,off=0,ks=0,vs=0,imm=0) R10=fp0 fp-8_w=mmmmmmmm
      3: (b7) r2 = 8
      4: R1_w=map_ptr(id=0,off=0,ks=0,vs=0,imm=0) R2_w=invP8 R10=fp0 fp-8_w=mmmmmmmm
      4: (b7) r3 = 0
      5: R1_w=map_ptr(id=0,off=0,ks=0,vs=0,imm=0) R2_w=invP8 R3_w=invP0 R10=fp0 fp-8_w=mmmmmmmm
      5: (85) call bpf_ringbuf_reserve#131
      6: R0_w=mem_or_null(id=2,ref_obj_id=2,off=0,imm=0) R10=fp0 fp-8_w=mmmmmmmm refs=2
      6: (bf) r6 = r0
      7: R0_w=mem_or_null(id=2,ref_obj_id=2,off=0,imm=0) R6_w=mem_or_null(id=2,ref_obj_id=2,off=0,imm=0) R10=fp0 fp-8_w=mmmmmmmm refs=2
      7: (07) r0 += 1
      8: R0_w=mem_or_null(id=2,ref_obj_id=2,off=1,imm=0) R6_w=mem_or_null(id=2,ref_obj_id=2,off=0,imm=0) R10=fp0 fp-8_w=mmmmmmmm refs=2
      8: (15) if r0 == 0x0 goto pc+4
       R0_w=mem(id=0,ref_obj_id=0,off=0,imm=0) R6_w=mem(id=0,ref_obj_id=2,off=0,imm=0) R10=fp0 fp-8_w=mmmmmmmm refs=2
      9: R0_w=mem(id=0,ref_obj_id=0,off=0,imm=0) R6_w=mem(id=0,ref_obj_id=2,off=0,imm=0) R10=fp0 fp-8_w=mmmmmmmm refs=2
      9: (62) *(u32 *)(r6 +0) = 0
       R0_w=mem(id=0,ref_obj_id=0,off=0,imm=0) R6_w=mem(id=0,ref_obj_id=2,off=0,imm=0) R10=fp0 fp-8_w=mmmmmmmm refs=2
      10: R0_w=mem(id=0,ref_obj_id=0,off=0,imm=0) R6_w=mem(id=0,ref_obj_id=2,off=0,imm=0) R10=fp0 fp-8_w=mmmmmmmm refs=2
      10: (bf) r1 = r6
      11: R0_w=mem(id=0,ref_obj_id=0,off=0,imm=0) R1_w=mem(id=0,ref_obj_id=2,off=0,imm=0) R6_w=mem(id=0,ref_obj_id=2,off=0,imm=0) R10=fp0 fp-8_w=mmmmmmmm refs=2
      11: (b7) r2 = 0
      12: R0_w=mem(id=0,ref_obj_id=0,off=0,imm=0) R1_w=mem(id=0,ref_obj_id=2,off=0,imm=0) R2_w=invP0 R6_w=mem(id=0,ref_obj_id=2,off=0,imm=0) R10=fp0 fp-8_w=mmmmmmmm refs=2
      12: (85) call bpf_ringbuf_submit#132
      13: R6=invP(id=0) R10=fp0 fp-8=mmmmmmmm
      13: (b7) r0 = 0
      14: R0_w=invP0 R6=invP(id=0) R10=fp0 fp-8=mmmmmmmm
      14: (95) exit
    
      from 8 to 13: safe
      processed 15 insns (limit 1000000) max_states_per_insn 0 total_states 1 peak_states 1 mark_read 0
      OK
    
    All three commits, that is b121b341 ("bpf: Add PTR_TO_BTF_ID_OR_NULL support"),
    457f4436 ("bpf: Implement BPF ring buffer and verifier support for it"), and the
    afbf21dc ("bpf: Support readonly/readwrite buffers in verifier") suffer the same
    cause and their *_OR_NULL type pendants must be rejected in adjust_ptr_min_max_vals().
    
    Make the test more robust by reusing reg_type_may_be_null() helper such that we catch
    all *_OR_NULL types we have today and in future.
    
    Note that pointer arithmetic on PTR_TO_BTF_ID, PTR_TO_RDONLY_BUF, and PTR_TO_RDWR_BUF
    is generally allowed.
    
    Fixes: b121b341 ("bpf: Add PTR_TO_BTF_ID_OR_NULL support")
    Fixes: 457f4436 ("bpf: Implement BPF ring buffer and verifier support for it")
    Fixes: afbf21dc ("bpf: Support readonly/readwrite buffers in verifier")
    Signed-off-by: NDaniel Borkmann <daniel@iogearbox.net>
    Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    Signed-off-by: NPu Lehui <pulehui@huawei.com>
    Reviewed-by: NKuohai Xu <xukuohai@huawei.com>
    Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
    026193f7
verifier.c 358.6 KB