Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

socket, bpf: fix possible use after free

Starting from linux-4.4, 3WHS no longer takes the listener lock.

Since this time, we might hit a use-after-free in sk_filter_charge(),
if the filter we got in the memcpy() of the listener content
just happened to be replaced by a thread changing listener BPF filter.

To fix this, we need to make sure the filter refcount is not already
zero before incrementing it again.

Fixes: e994b2f0fb92 ("tcp: do not lock listener to process SYN packets")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Eric Dumazet and committed by
David S. Miller
eefca20e 4ee4553e

+12 -5
+8 -4
net/core/filter.c
··· 989 989 990 990 bool sk_filter_charge(struct sock *sk, struct sk_filter *fp) 991 991 { 992 - bool ret = __sk_filter_charge(sk, fp); 993 - if (ret) 994 - refcount_inc(&fp->refcnt); 995 - return ret; 992 + if (!refcount_inc_not_zero(&fp->refcnt)) 993 + return false; 994 + 995 + if (!__sk_filter_charge(sk, fp)) { 996 + sk_filter_release(fp); 997 + return false; 998 + } 999 + return true; 996 1000 } 997 1001 998 1002 static struct bpf_prog *bpf_migrate_filter(struct bpf_prog *fp)
+4 -1
net/core/sock.c
··· 1684 1684 1685 1685 sock_reset_flag(newsk, SOCK_DONE); 1686 1686 1687 - filter = rcu_dereference_protected(newsk->sk_filter, 1); 1687 + rcu_read_lock(); 1688 + filter = rcu_dereference(sk->sk_filter); 1688 1689 if (filter != NULL) 1689 1690 /* though it's an empty new sock, the charging may fail 1690 1691 * if sysctl_optmem_max was changed between creation of 1691 1692 * original socket and cloning 1692 1693 */ 1693 1694 is_charged = sk_filter_charge(newsk, filter); 1695 + RCU_INIT_POINTER(newsk->sk_filter, filter); 1696 + rcu_read_unlock(); 1694 1697 1695 1698 if (unlikely(!is_charged || xfrm_sk_clone_policy(newsk, sk))) { 1696 1699 /* We need to make sure that we don't uncharge the new