When calling connect to change the CID of a vsock, the loopback
worker for the VIRTIO_VSOCK_OP_RST command is invoked.
During this process, vsock_stream_has_data() calls
vsk->transport->stream_has_data().
However, a null-ptr-deref occurs because vsk->transport was set
to NULL in vsock_deassign_transport().

                     cpu0                                                      
cpu1

                                                               socket(A)

                                                               bind(A, 
VMADDR_CID_LOCAL)
                                                                 vsock_bind()

                                                               listen(A)
                                                                 vsock_listen()
  socket(B)

  connect(B, VMADDR_CID_LOCAL)

  connect(B, VMADDR_CID_HYPERVISOR)
    vsock_connect(B)
      lock_sock(sk);
      vsock_assign_transport()
        virtio_transport_release()
          virtio_transport_close()
            virtio_transport_shutdown()
              virtio_transport_send_pkt_info()
                vsock_loopback_send_pkt(VIRTIO_VSOCK_OP_SHUTDOWN)
                  queue_work(vsock_loopback_work)
        vsock_deassign_transport()
          vsk->transport = NULL;
                                                               
vsock_loopback_work()
                                                                 
virtio_transport_recv_pkt(VIRTIO_VSOCK_OP_SHUTDOWN)
                                                                   
virtio_transport_recv_connected()
                                                                     
virtio_transport_reset()
                                                                       
virtio_transport_send_pkt_info()
                                                                         
vsock_loopback_send_pkt(VIRTIO_VSOCK_OP_RST)
                                                                           
queue_work(vsock_loopback_work)

                                                               
vsock_loopback_work()
                                                                 
virtio_transport_recv_pkt(VIRTIO_VSOCK_OP_RST)
                                                                   
virtio_transport_recv_disconnecting()
                                                                     
virtio_transport_do_close()
                                                                       
vsock_stream_has_data()
                                                                         
vsk->transport->stream_has_data(vsk);    // null-ptr-deref

To resolve this issue, add a check for vsk->transport, similar to
functions like vsock_send_shutdown().

Fixes: fe502c4a38d9 ("vsock: add 'transport' member in the struct vsock_sock")
Signed-off-by: Hyunwoo Kim <v4...@theori.io>
Signed-off-by: Wongi Lee <qwe...@theori.io>
---
 net/vmw_vsock/af_vsock.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
index 5cf8109f672a..a0c008626798 100644
--- a/net/vmw_vsock/af_vsock.c
+++ b/net/vmw_vsock/af_vsock.c
@@ -870,6 +870,9 @@ EXPORT_SYMBOL_GPL(vsock_create_connected);
 
 s64 vsock_stream_has_data(struct vsock_sock *vsk)
 {
+       if (!vsk->transport)
+               return 0;
+
        return vsk->transport->stream_has_data(vsk);
 }
 EXPORT_SYMBOL_GPL(vsock_stream_has_data);
-- 
2.34.1


Reply via email to