Commit 7db92362 authored by Wei Wang's avatar Wei Wang Committed by David S. Miller

tcp: fix potential double free issue for fastopen_req

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: 19f6d3f3 ("net/tcp-fastopen: Add new API support")
Reported-by: default avatarAndrey Konovalov <andreyknvl@google.com>
Signed-off-by: default avatarWei Wang <weiwan@google.com>
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 94352d45
...@@ -1110,9 +1110,14 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, ...@@ -1110,9 +1110,14 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg,
flags = (msg->msg_flags & MSG_DONTWAIT) ? O_NONBLOCK : 0; flags = (msg->msg_flags & MSG_DONTWAIT) ? O_NONBLOCK : 0;
err = __inet_stream_connect(sk->sk_socket, msg->msg_name, err = __inet_stream_connect(sk->sk_socket, msg->msg_name,
msg->msg_namelen, flags, 1); msg->msg_namelen, flags, 1);
inet->defer_connect = 0; /* fastopen_req could already be freed in __inet_stream_connect
*copied = tp->fastopen_req->copied; * if the connection times out or gets rst
tcp_free_fastopen_req(tp); */
if (tp->fastopen_req) {
*copied = tp->fastopen_req->copied;
tcp_free_fastopen_req(tp);
inet->defer_connect = 0;
}
return err; return err;
} }
...@@ -2318,6 +2323,10 @@ int tcp_disconnect(struct sock *sk, int flags) ...@@ -2318,6 +2323,10 @@ int tcp_disconnect(struct sock *sk, int flags)
memset(&tp->rx_opt, 0, sizeof(tp->rx_opt)); memset(&tp->rx_opt, 0, sizeof(tp->rx_opt));
__sk_dst_reset(sk); __sk_dst_reset(sk);
/* Clean up fastopen related fields */
tcp_free_fastopen_req(tp);
inet->defer_connect = 0;
WARN_ON(inet->inet_num && !icsk->icsk_bind_hash); WARN_ON(inet->inet_num && !icsk->icsk_bind_hash);
sk->sk_error_report(sk); sk->sk_error_report(sk);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment