Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vsock: each transport cycles only on its own sockets

When iterating over sockets using vsock_for_each_connected_socket, make
sure that a transport filters out sockets that don't belong to the
transport.

There actually was an issue caused by this; in a nested VM
configuration, destroying the nested VM (which often involves the
closing of /dev/vhost-vsock if there was h2g connections to the nested
VM) kills not only the h2g connections, but also all existing g2h
connections to the (outmost) host which are totally unrelated.

Tested: Executed the following steps on Cuttlefish (Android running on a
VM) [1]: (1) Enter into an `adb shell` session - to have a g2h
connection inside the VM, (2) open and then close /dev/vhost-vsock by
`exec 3< /dev/vhost-vsock && exec 3<&-`, (3) observe that the adb
session is not reset.

[1] https://android.googlesource.com/device/google/cuttlefish/

Fixes: c0cfa2d8a788 ("vsock: add multi-transports support")
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Jiyong Park <jiyong@google.com>
Link: https://lore.kernel.org/r/20220311020017.1509316-1-jiyong@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Jiyong Park and committed by
Jakub Kicinski
8e6ed963 46b348fd

+20 -7
+2 -1
drivers/vhost/vsock.c
··· 753 753 754 754 /* Iterating over all connections for all CIDs to find orphans is 755 755 * inefficient. Room for improvement here. */ 756 - vsock_for_each_connected_socket(vhost_vsock_reset_orphans); 756 + vsock_for_each_connected_socket(&vhost_transport.transport, 757 + vhost_vsock_reset_orphans); 757 758 758 759 /* Don't check the owner, because we are in the release path, so we 759 760 * need to stop the vsock device in any case.
+2 -1
include/net/af_vsock.h
··· 205 205 struct sock *vsock_find_connected_socket(struct sockaddr_vm *src, 206 206 struct sockaddr_vm *dst); 207 207 void vsock_remove_sock(struct vsock_sock *vsk); 208 - void vsock_for_each_connected_socket(void (*fn)(struct sock *sk)); 208 + void vsock_for_each_connected_socket(struct vsock_transport *transport, 209 + void (*fn)(struct sock *sk)); 209 210 int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk); 210 211 bool vsock_find_cid(unsigned int cid); 211 212
+7 -2
net/vmw_vsock/af_vsock.c
··· 334 334 } 335 335 EXPORT_SYMBOL_GPL(vsock_remove_sock); 336 336 337 - void vsock_for_each_connected_socket(void (*fn)(struct sock *sk)) 337 + void vsock_for_each_connected_socket(struct vsock_transport *transport, 338 + void (*fn)(struct sock *sk)) 338 339 { 339 340 int i; 340 341 ··· 344 343 for (i = 0; i < ARRAY_SIZE(vsock_connected_table); i++) { 345 344 struct vsock_sock *vsk; 346 345 list_for_each_entry(vsk, &vsock_connected_table[i], 347 - connected_table) 346 + connected_table) { 347 + if (vsk->transport != transport) 348 + continue; 349 + 348 350 fn(sk_vsock(vsk)); 351 + } 349 352 } 350 353 351 354 spin_unlock_bh(&vsock_table_lock);
+5 -2
net/vmw_vsock/virtio_transport.c
··· 24 24 static struct workqueue_struct *virtio_vsock_workqueue; 25 25 static struct virtio_vsock __rcu *the_virtio_vsock; 26 26 static DEFINE_MUTEX(the_virtio_vsock_mutex); /* protects the_virtio_vsock */ 27 + static struct virtio_transport virtio_transport; /* forward declaration */ 27 28 28 29 struct virtio_vsock { 29 30 struct virtio_device *vdev; ··· 385 384 switch (le32_to_cpu(event->id)) { 386 385 case VIRTIO_VSOCK_EVENT_TRANSPORT_RESET: 387 386 virtio_vsock_update_guest_cid(vsock); 388 - vsock_for_each_connected_socket(virtio_vsock_reset_sock); 387 + vsock_for_each_connected_socket(&virtio_transport.transport, 388 + virtio_vsock_reset_sock); 389 389 break; 390 390 } 391 391 } ··· 664 662 synchronize_rcu(); 665 663 666 664 /* Reset all connected sockets when the device disappear */ 667 - vsock_for_each_connected_socket(virtio_vsock_reset_sock); 665 + vsock_for_each_connected_socket(&virtio_transport.transport, 666 + virtio_vsock_reset_sock); 668 667 669 668 /* Stop all work handlers to make sure no one is accessing the device, 670 669 * so we can safely call virtio_reset_device().
+4 -1
net/vmw_vsock/vmci_transport.c
··· 75 75 76 76 static int PROTOCOL_OVERRIDE = -1; 77 77 78 + static struct vsock_transport vmci_transport; /* forward declaration */ 79 + 78 80 /* Helper function to convert from a VMCI error code to a VSock error code. */ 79 81 80 82 static s32 vmci_transport_error_to_vsock_error(s32 vmci_error) ··· 884 882 const struct vmci_event_data *e_data, 885 883 void *client_data) 886 884 { 887 - vsock_for_each_connected_socket(vmci_transport_handle_detach); 885 + vsock_for_each_connected_socket(&vmci_transport, 886 + vmci_transport_handle_detach); 888 887 } 889 888 890 889 static void vmci_transport_recv_pkt_work(struct work_struct *work)