• Daniel Borkmann's avatar
    bpf, sockmap: fix sock_map_ctx_update_elem race with exist/noexist · 585f5a62
    Daniel Borkmann authored
    The current code in sock_map_ctx_update_elem() allows for BPF_EXIST
    and BPF_NOEXIST map update flags. While on array-like maps this approach
    is rather uncommon, e.g. bpf_fd_array_map_update_elem() and others
    enforce map update flags to be BPF_ANY such that xchg() can be used
    directly, the current implementation in sock map does not guarantee
    that such operation with BPF_EXIST / BPF_NOEXIST is atomic.
    
    The initial test does a READ_ONCE(stab->sock_map[i]) to fetch the
    socket from the slot which is then tested for NULL / non-NULL. However
    later after __sock_map_ctx_update_elem(), the actual update is done
    through osock = xchg(&stab->sock_map[i], sock). Problem is that in
    the meantime a different CPU could have updated / deleted a socket
    on that specific slot and thus flag contraints won't hold anymore.
    
    I've been thinking whether best would be to just break UAPI and do
    an enforcement of BPF_ANY to check if someone actually complains,
    however trouble is that already in BPF kselftest we use BPF_NOEXIST
    for the map update, and therefore it might have been copied into
    applications already. The fix to keep the current behavior intact
    would be to add a map lock similar to the sock hash bucket lock only
    for covering the whole map.
    
    Fixes: 174a79ff ("bpf: sockmap with sk redirect support")
    Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
    Acked-by: default avatarJohn Fastabend <john.fastabend@gmail.com>
    Acked-by: default avatarSong Liu <songliubraving@fb.com>
    Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
    585f5a62
sockmap.c 59.7 KB