virtio_transport_recv_pkt() copies a packet's destination CID into the
local address of the socket it reaches, so that sockets follow a guest
CID change after a transport reset. But the bound-socket lookup also
delivers packets addressed to VMADDR_CID_ANY, and vsock_loopback can
carry them: a connect() to VMADDR_CID_ANY goes over loopback when the
guest->host transport has no CID (no virtio-vsock device, or hv_sock).
The socket bound to that port then ends up with VMADDR_CID_ANY as its
local CID: a listener on (VMADDR_CID_LOCAL, P) turns into a wildcard
listener, and a socket whose connect() was refused for its CID would
pass the check in virtio_transport_connect() on the next try.
Only take the destination CID if it differs from the socket's current
one, is not VMADDR_CID_ANY, and is the transport's own CID. The
VMADDR_CID_ANY test is still needed: get_local_cid() itself returns
VMADDR_CID_ANY while the virtio-vsock device is removed or frozen.
In a guest without a virtio-vsock device, after a loopback connect() to
(VMADDR_CID_ANY, P), getsockname() on a listener bound to
(VMADDR_CID_LOCAL, P) returns VMADDR_CID_ANY on unmodified kernels and
VMADDR_CID_LOCAL with this patch; vsock_test passes. Drafted with
Claude.
Fixes: 408624af4c89 ("vsock: use local transport when it is loaded")
Reported-by: Sashiko <[email protected]>
Closes: https://lore.kernel.org/all/[email protected]/
Signed-off-by: Yiran Qiu <[email protected]>
---
Since 36c5b48b91ac ("vsock: fix bind() behaviour taking care of CID")
the CID update no longer helps listeners, and connected sockets are
reset on a transport reset, so the update could be dropped instead;
would you prefer that? Refusing connect() to VMADDR_CID_ANY in
vsock_use_local_transport() would also work, but would stop guests
without a guest->host CID from reaching local listeners.
net/vmw_vsock/virtio_transport_common.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/net/vmw_vsock/virtio_transport_common.c
b/net/vmw_vsock/virtio_transport_common.c
index 4d0511629044..b276009efab9 100644
--- a/net/vmw_vsock/virtio_transport_common.c
+++ b/net/vmw_vsock/virtio_transport_common.c
@@ -1861,7 +1861,10 @@ void virtio_transport_recv_pkt(struct virtio_transport
*t,
space_available = virtio_transport_space_update(sk, skb);
/* Update CID in case it has changed after a transport reset event */
- if (vsk->local_addr.svm_cid != VMADDR_CID_ANY)
+ if (vsk->local_addr.svm_cid != VMADDR_CID_ANY &&
+ vsk->local_addr.svm_cid != dst.svm_cid &&
+ dst.svm_cid != VMADDR_CID_ANY &&
+ dst.svm_cid == t->transport.get_local_cid())
vsk->local_addr.svm_cid = dst.svm_cid;
if (space_available)
--
2.56.0