Socket can flip to TCP_LISTEN when connect() schedules out. Respect
listen() winning the race: let connect() time out, but don't reset the
socket.

sk is CLOSE UNCONNECTED
non-blocking connect():
  sk := SYN_SENT CONNECTING
  enqueue vsock_connect_timeout()
                                   blocking connect():
                                     release_sock()
                                     schedule_timeout()
vsock_connect_timeout():
  sk := CLOSE UNCONNECTED
listen():
  sk := LISTEN UNCONNECTED
                                     lock_sock()
                                     sk is TCP_LISTEN UNCONNECTED

Signed-off-by: Michal Luczaj <[email protected]>
---
 net/vmw_vsock/af_vsock.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
index 5a2d7e10ecb8..56c595942456 100644
--- a/net/vmw_vsock/af_vsock.c
+++ b/net/vmw_vsock/af_vsock.c
@@ -1663,6 +1663,13 @@ static void vsock_unconnected_reset(struct sock *sk)
 
        sock_owned_by_me(sk);
 
+       /*
+        * listen() can race connect() on schedule_timeout().
+        * Don't reset TCP_LISTEN.
+        */
+       if (sk->sk_state == TCP_LISTEN)
+               return;
+
        /*
         * Transport events are serviced by resetting each connected socket to
         * TCP_CLOSE. The reset is done under vsock_table_lock but without

-- 
2.55.0


Reply via email to