From 35724bccae7926557ebffd1f41f878616f5dff03 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Wed, 1 Mar 2017 13:29:48 -0800 Subject: [PATCH] BACKPORT: tcp: fix potential double free issue for fastopen_req commit 7db92362d2fee5887f6b0c41653b8c9f8f5d6020 upstream. tp->fastopen_req could potentially be double freed if a malicious user does the following: 1. Enable TCP_FASTOPEN_CONNECT sockopt and do a connect() on the socket. 2. Call connect() with AF_UNSPEC to disconnect the socket. 3. Make this socket a listening socket by calling listen(). 4. Accept incoming connections and generate child sockets. All child sockets will get a copy of the pointer of fastopen_req. 5. Call close() on all sockets. fastopen_req will get freed multiple times. Fixes: 19f6d3f3c842 ("net/tcp-fastopen: Add new API support") Reported-by: Andrey Konovalov Signed-off-by: Wei Wang Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Change-Id: I6bb174d6997470643df5ba34e1f9858e16f4989d Fixes: Change-Id: Icc181febd74e3117c2fc835d7ed935e107b5815e ("BACKPORT: net/tcp-fastopen: Add new API support") Signed-off-by: Amit Pundir --- net/ipv4/tcp.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 7f701b16e068..ee3dde5ff32f 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1115,9 +1115,14 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, flags = (msg->msg_flags & MSG_DONTWAIT) ? O_NONBLOCK : 0; err = __inet_stream_connect(sk->sk_socket, uaddr, msg->msg_namelen, flags); - inet->defer_connect = 0; - *copied = tp->fastopen_req->copied; - tcp_free_fastopen_req(tp); + /* fastopen_req could already be freed in __inet_stream_connect + * if the connection times out or gets rst + */ + if (tp->fastopen_req) { + *copied = tp->fastopen_req->copied; + tcp_free_fastopen_req(tp); + inet->defer_connect = 0; + } return err; } @@ -2331,6 +2336,10 @@ int tcp_disconnect(struct sock *sk, int flags) sk->sk_rx_dst = NULL; tcp_saved_syn_free(tp); + /* Clean up fastopen related fields */ + tcp_free_fastopen_req(tp); + inet->defer_connect = 0; + WARN_ON(inet->inet_num && !icsk->icsk_bind_hash); if (sk->sk_frag.page) {