Re: [PATCH v3] vsock/virtio: initialize the_virtio_vsock before using VQs

From: Stefano Garzarella
Date: Tue Oct 24 2023 - 03:23:34 EST


On Mon, Oct 23, 2023 at 10:22:07PM +0300, Alexandru Matei wrote:
Once VQs are filled with empty buffers and we kick the host, it can send
connection requests. If the_virtio_vsock is not initialized before,
replies are silently dropped and do not reach the host.

virtio_transport_send_pkt() can queue packets once the_virtio_vsock is
set, but they won't be processed until vsock->tx_run is set to true. We
queue vsock->send_pkt_work when initialization finishes to send those
packets queued earlier.

Fixes: 0deab087b16a ("vsock/virtio: use RCU to avoid use-after-free on the_virtio_vsock")
Signed-off-by: Alexandru Matei <alexandru.matei@xxxxxxxxxx>
---
v3:
- renamed vqs_fill to vqs_start and moved tx_run initialization to it
- queued send_pkt_work at the end of initialization to send packets queued earlier
v2:
- split virtio_vsock_vqs_init in vqs_init and vqs_fill and moved
the_virtio_vsock initialization after vqs_init

net/vmw_vsock/virtio_transport.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
index e95df847176b..c0333f9a8002 100644
--- a/net/vmw_vsock/virtio_transport.c
+++ b/net/vmw_vsock/virtio_transport.c
@@ -555,6 +555,11 @@ static int virtio_vsock_vqs_init(struct virtio_vsock *vsock)

virtio_device_ready(vdev);

+ return 0;
+}
+
+static void virtio_vsock_vqs_start(struct virtio_vsock *vsock)
+{
mutex_lock(&vsock->tx_lock);
vsock->tx_run = true;
mutex_unlock(&vsock->tx_lock);
@@ -568,8 +573,6 @@ static int virtio_vsock_vqs_init(struct virtio_vsock *vsock)
virtio_vsock_event_fill(vsock);
vsock->event_run = true;
mutex_unlock(&vsock->event_lock);
-
- return 0;
}

static void virtio_vsock_vqs_del(struct virtio_vsock *vsock)
@@ -664,6 +667,9 @@ static int virtio_vsock_probe(struct virtio_device *vdev)
goto out;

rcu_assign_pointer(the_virtio_vsock, vsock);
+ virtio_vsock_vqs_start(vsock);
+
+ queue_work(virtio_vsock_workqueue, &vsock->send_pkt_work);

I would move this call in virtio_vsock_vqs_start() adding also a comment on top, bringing back what you wrote in the commit. Something like this:

/* virtio_transport_send_pkt() can queue packets once
* the_virtio_vsock is set, but they won't be processed until
* vsock->tx_run is set to true. We queue vsock->send_pkt_work
* when initialization finishes to send those packets queued
* earlier.
*/

Just as a consideration, we don't need to queue the other workers (rx, event) because as long as we don't fill the queues with empty buffers, the host can't send us any notification. (We could add it in the comment if you want).

The rest LGTM!

Thanks,
Stefano


mutex_unlock(&the_virtio_vsock_mutex);

@@ -736,6 +742,9 @@ static int virtio_vsock_restore(struct virtio_device *vdev)
goto out;

rcu_assign_pointer(the_virtio_vsock, vsock);
+ virtio_vsock_vqs_start(vsock);
+
+ queue_work(virtio_vsock_workqueue, &vsock->send_pkt_work);

out:
mutex_unlock(&the_virtio_vsock_mutex);
--
2.25.1