summaryrefslogtreecommitdiff
path: root/net/core
diff options
context:
space:
mode:
authorCong Wang <cong.wang@bytedance.com>2021-04-08 06:05:56 +0300
committerDaniel Borkmann <daniel@iogearbox.net>2021-04-12 18:35:26 +0300
commitaadb2bb83ff789de63b48b4edeab7329423a50d3 (patch)
tree07700d24aae0e305a821a073a1662967172377df /net/core
parent51e0158a54321a48d260e95998393934bb0de52c (diff)
downloadlinux-aadb2bb83ff789de63b48b4edeab7329423a50d3.tar.xz
sock_map: Fix a potential use-after-free in sock_map_close()
The last refcnt of the psock can be gone right after sock_map_remove_links(), so sk_psock_stop() could trigger a UAF. The reason why I placed sk_psock_stop() there is to avoid RCU read critical section, and more importantly, some callee of sock_map_remove_links() is supposed to be called with RCU read lock, we can not simply get rid of RCU read lock here. Therefore, the only choice we have is to grab an additional refcnt with sk_psock_get() and put it back after sk_psock_stop(). Fixes: 799aa7f98d53 ("skmsg: Avoid lock_sock() in sk_psock_backlog()") Reported-by: syzbot+7b6548ae483d6f4c64ae@syzkaller.appspotmail.com Signed-off-by: Cong Wang <cong.wang@bytedance.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: John Fastabend <john.fastabend@gmail.com> Acked-by: Jakub Sitnicki <jakub@cloudflare.com> Link: https://lore.kernel.org/bpf/20210408030556.45134-1-xiyou.wangcong@gmail.com
Diffstat (limited to 'net/core')
-rw-r--r--net/core/sock_map.c3
1 files changed, 2 insertions, 1 deletions
diff --git a/net/core/sock_map.c b/net/core/sock_map.c
index f473c51cbc4b..6f1b82b8ad49 100644
--- a/net/core/sock_map.c
+++ b/net/core/sock_map.c
@@ -1521,7 +1521,7 @@ void sock_map_close(struct sock *sk, long timeout)
lock_sock(sk);
rcu_read_lock();
- psock = sk_psock(sk);
+ psock = sk_psock_get(sk);
if (unlikely(!psock)) {
rcu_read_unlock();
release_sock(sk);
@@ -1532,6 +1532,7 @@ void sock_map_close(struct sock *sk, long timeout)
sock_map_remove_links(sk, psock);
rcu_read_unlock();
sk_psock_stop(psock, true);
+ sk_psock_put(sk, psock);
release_sock(sk);
saved_close(sk, timeout);
}