Transport events are serviced by resetting each connected socket. The reset is done under vsock_table_lock but without taking lock_sock(), so from the point of view of vsock_connect() - locklessly. The same pattern is present in virtio_vsock_reset_sock(), vmci_transport_handle_detach() and vhost_vsock_reset_orphans(). While connect() waits for TCP_SYN_SENT -> TCP_ESTABLISHED, other transitions can also occur: TCP_SYN_SENT -> TCP_CLOSE on connection failure, timeout or signal TCP_SYN_SENT -> TCP_ESTABLISHED -> TCP_CLOSING on VIRTIO_VSOCK_OP_RST TCP_SYN_SENT -> TCP_ESTABLISHED -> [TCP_CLOSING ->] TCP_CLOSE on event But transport events leave SS_CONNECTED state unchanged. So take a note of that, rather than a) making every event handler drop the socket from connected_table, or b) adapting connect() to handle more transitions (while missing proper locking). Fixes: d021c344051a ("VSOCK: Introduce VM Sockets") Signed-off-by: Michal Luczaj --- net/vmw_vsock/af_vsock.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index ff4140aaf1f3..5a2d7e10ecb8 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -1663,6 +1663,19 @@ static void vsock_unconnected_reset(struct sock *sk) sock_owned_by_me(sk); + /* + * Transport events are serviced by resetting each connected socket to + * TCP_CLOSE. The reset is done under vsock_table_lock but without + * taking lock_sock(), so it is effectively lockless from the + * perspective of connect(). + * + * Preserve socket's bricked status. Also check SS_DISCONNECTING, since + * shutdown() may race us. + */ + if (sk->sk_socket->state == SS_CONNECTED || + sk->sk_socket->state == SS_DISCONNECTING) + return; + /* * Only connected socks may have peer_shutdown or SOCK_DONE set. * -- 2.55.0