* [PATCH net v3 0/2] vsock: validate packet sources after bound lookup fallback @ 2026-08-23 17:58 Daehyeon Ko 2026-08-23 17:58 ` [PATCH net v3 1/2] vsock/virtio: validate packet source for connected sockets Daehyeon Ko 2026-08-23 17:58 ` [PATCH net v3 2/2] vsock/vmci: " Daehyeon Ko 0 siblings, 2 replies; 6+ messages in thread From: Daehyeon Ko @ 2026-08-23 17:58 UTC (permalink / raw) To: netdev Cc: sgarzare, stefanha, bobbyeshleman, davem, edumazet, kuba, pabeni, horms, mst, jasowangio, xuanzhuo, eperezma, bryan-bt.tan, vishnu.dasa, bcm-kernel-feedback-list, virtualization, kvm, linux-kernel Both virtio and VMCI look up connected sockets by the full tuple before falling back to a destination-only bound lookup. The fallback can select a non-listening socket without validating the packet source. V2 covered only the virtio path. Following Stefano's review, this series moves the source and transport validation into a documented AF_VSOCK helper and uses it for both virtio and VMCI. The VMCI patch checks both its bottom-half and deferred workqueue receive paths. The combined series was tested on x86_64 KASAN kernels. The original cross-UID virtio injection remained blocked in three boots, CID_LOCAL and CID_HOST loopback aliases passed, selected VSOCK selftests passed, and VMCI accepted a matched RST while rejecting a mismatched-context RST in three boots. All changed objects built without warnings under allmodconfig and allyesconfig with W=1. The current-tree guest-CID vhost probe could not be rerun because the test user lacks access to /dev/vhost-vsock. Changes in v3: - Move transport and source validation into vsock_check_source(). - Trust the internally generated source CID for the local transport. - Add VMCI validation in the bottom-half and workqueue receive paths. - Send the related virtio and VMCI fixes in one series. - Do not carry Bobby's v2 Reviewed-by because the helper and loopback logic changed; renewed review is requested. v2: https://lore.kernel.org/netdev/20260820001517.2148196-1-4ncienth@gmail.com/ v1: https://lore.kernel.org/netdev/20260813121236.2328599-1-4ncienth@gmail.com/ Daehyeon Ko (2): vsock/virtio: validate packet source for connected sockets vsock/vmci: validate packet source for connected sockets include/net/af_vsock.h | 3 +++ net/vmw_vsock/af_vsock.c | 32 +++++++++++++++++++++++++ net/vmw_vsock/virtio_transport_common.c | 3 ++- net/vmw_vsock/vmci_transport.c | 29 +++++++++++++++++----- 4 files changed, 60 insertions(+), 7 deletions(-) base-commit: 7cbfb180945ce529608e4d4e24a6d483699fab1e -- 2.54.0 ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH net v3 1/2] vsock/virtio: validate packet source for connected sockets 2026-08-23 17:58 [PATCH net v3 0/2] vsock: validate packet sources after bound lookup fallback Daehyeon Ko @ 2026-08-23 17:58 ` Daehyeon Ko 2026-08-25 22:32 ` Bobby Eshleman 2026-08-23 17:58 ` [PATCH net v3 2/2] vsock/vmci: " Daehyeon Ko 1 sibling, 1 reply; 6+ messages in thread From: Daehyeon Ko @ 2026-08-23 17:58 UTC (permalink / raw) To: netdev Cc: sgarzare, stefanha, bobbyeshleman, davem, edumazet, kuba, pabeni, horms, mst, jasowangio, xuanzhuo, eperezma, bryan-bt.tan, vishnu.dasa, bcm-kernel-feedback-list, virtualization, kvm, linux-kernel virtio_transport_recv_pkt() looks up sockets first by the full source and destination tuple, then by destination only in the bound table. The fallback is needed for listening and connecting sockets, but sockets remain in the bound table after connect(), so it can also return a non-listening socket. The fallback does not validate the source address. In TCP_SYN_SENT, a RESPONSE from an unrelated source can transition the victim socket to TCP_ESTABLISHED while its stored remote address remains unchanged. Subsequent RW packets from that source are delivered through the same destination-only fallback. This was reproduced with capability-empty processes under different UIDs. The attacker discovered the target tuple through unprivileged AF_VSOCK sock_diag and caused the victim socket to read 16 attacker-chosen bytes; the intended peer-side socket read 0 of those 16 bytes. Add vsock_check_source() to validate the transport, source port and source CID against the peer stored in a non-listening socket. The local transport is the CID exception because its packets are generated internally with VMADDR_CID_LOCAL as their source, including connections using CID aliases. Use the helper after lock_sock() in the virtio receive path. Fixes: 06a8fc78367d ("VSOCK: Introduce virtio_vsock_common.ko") Closes: https://lore.kernel.org/netdev/20260813121236.2328599-1-4ncienth@gmail.com/ Cc: stable@vger.kernel.org Suggested-by: Stefano Garzarella <sgarzare@redhat.com> Assisted-by: Codex:gpt-5.6-sol Signed-off-by: Daehyeon Ko <4ncienth@gmail.com> --- include/net/af_vsock.h | 3 +++ net/vmw_vsock/af_vsock.c | 32 +++++++++++++++++++++++++ net/vmw_vsock/virtio_transport_common.c | 3 ++- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h index 3357ee62d..5549298c1 100644 --- a/include/net/af_vsock.h +++ b/include/net/af_vsock.h @@ -229,6 +229,9 @@ struct sock *vsock_find_bound_socket_net(struct sockaddr_vm *addr, struct sock *vsock_find_connected_socket_net(struct sockaddr_vm *src, struct sockaddr_vm *dst, struct net *net); +bool vsock_check_source(const struct vsock_sock *vsk, + const struct vsock_transport *transport, + const struct sockaddr_vm *src); void vsock_remove_sock(struct vsock_sock *vsk); void vsock_for_each_connected_socket(struct vsock_transport *transport, void (*fn)(struct sock *sk)); diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index a33b2a2d3..f840498b5 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -438,6 +438,38 @@ struct sock *vsock_find_connected_socket(struct sockaddr_vm *src, } EXPORT_SYMBOL_GPL(vsock_find_connected_socket); +/** + * vsock_check_source - validate a packet source against a socket peer + * @vsk: socket receiving the packet + * @transport: transport receiving the packet + * @src: source address from the packet + * + * Return: true if the packet arrived on the socket's assigned transport and + * its source matches the stored peer. Loopback packets are generated + * internally and always use the local CID as their source, including + * connections using a valid CID alias. + * + * The caller must hold the socket lock and must not call this for listening + * sockets, which accept packets from any source and have no assigned + * transport. + */ +bool vsock_check_source(const struct vsock_sock *vsk, + const struct vsock_transport *transport, + const struct sockaddr_vm *src) +{ + if (vsk->transport != transport) + return false; + + if (src->svm_port != vsk->remote_addr.svm_port) + return false; + + if (src->svm_cid == vsk->remote_addr.svm_cid) + return true; + + return transport->get_local_cid() == VMADDR_CID_LOCAL; +} +EXPORT_SYMBOL_GPL(vsock_check_source); + void vsock_remove_sock(struct vsock_sock *vsk) { /* Transport reassignment must not remove the binding. */ diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c index e4ebaa70f..6301c108a 100644 --- a/net/vmw_vsock/virtio_transport_common.c +++ b/net/vmw_vsock/virtio_transport_common.c @@ -1823,7 +1823,8 @@ void virtio_transport_recv_pkt(struct virtio_transport *t, * lock_sock (note: listener sockets are not assigned to any transport) */ if (sock_flag(sk, SOCK_DONE) || - (sk->sk_state != TCP_LISTEN && vsk->transport != &t->transport)) { + (sk->sk_state != TCP_LISTEN && + !vsock_check_source(vsk, &t->transport, &src))) { (void)virtio_transport_reset_no_sock(t, skb, net); release_sock(sk); sock_put(sk); -- 2.54.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH net v3 1/2] vsock/virtio: validate packet source for connected sockets 2026-08-23 17:58 ` [PATCH net v3 1/2] vsock/virtio: validate packet source for connected sockets Daehyeon Ko @ 2026-08-25 22:32 ` Bobby Eshleman 0 siblings, 0 replies; 6+ messages in thread From: Bobby Eshleman @ 2026-08-25 22:32 UTC (permalink / raw) To: Daehyeon Ko Cc: netdev, sgarzare, stefanha, davem, edumazet, kuba, pabeni, horms, mst, jasowangio, xuanzhuo, eperezma, bryan-bt.tan, vishnu.dasa, bcm-kernel-feedback-list, virtualization, kvm, linux-kernel On Mon, Aug 24, 2026 at 02:58:57AM +0900, Daehyeon Ko wrote: > virtio_transport_recv_pkt() looks up sockets first by the full source and > destination tuple, then by destination only in the bound table. The > fallback is needed for listening and connecting sockets, but sockets remain > in the bound table after connect(), so it can also return a non-listening > socket. > > The fallback does not validate the source address. In TCP_SYN_SENT, a > RESPONSE from an unrelated source can transition the victim socket to > TCP_ESTABLISHED while its stored remote address remains unchanged. > Subsequent RW packets from that source are delivered through the same > destination-only fallback. > > This was reproduced with capability-empty processes under different UIDs. > The attacker discovered the target tuple through unprivileged AF_VSOCK > sock_diag and caused the victim socket to read 16 attacker-chosen bytes; > the intended peer-side socket read 0 of those 16 bytes. > > Add vsock_check_source() to validate the transport, source port and source > CID against the peer stored in a non-listening socket. The local transport > is the CID exception because its packets are generated internally with > VMADDR_CID_LOCAL as their source, including connections using CID aliases. > > Use the helper after lock_sock() in the virtio receive path. > > Fixes: 06a8fc78367d ("VSOCK: Introduce virtio_vsock_common.ko") > Closes: https://lore.kernel.org/netdev/20260813121236.2328599-1-4ncienth@gmail.com/ > Cc: stable@vger.kernel.org > Suggested-by: Stefano Garzarella <sgarzare@redhat.com> > Assisted-by: Codex:gpt-5.6-sol > Signed-off-by: Daehyeon Ko <4ncienth@gmail.com> > --- > include/net/af_vsock.h | 3 +++ > net/vmw_vsock/af_vsock.c | 32 +++++++++++++++++++++++++ > net/vmw_vsock/virtio_transport_common.c | 3 ++- > 3 files changed, 37 insertions(+), 1 deletion(-) > > diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h > index 3357ee62d..5549298c1 100644 > --- a/include/net/af_vsock.h > +++ b/include/net/af_vsock.h > @@ -229,6 +229,9 @@ struct sock *vsock_find_bound_socket_net(struct sockaddr_vm *addr, > struct sock *vsock_find_connected_socket_net(struct sockaddr_vm *src, > struct sockaddr_vm *dst, > struct net *net); > +bool vsock_check_source(const struct vsock_sock *vsk, > + const struct vsock_transport *transport, > + const struct sockaddr_vm *src); > void vsock_remove_sock(struct vsock_sock *vsk); > void vsock_for_each_connected_socket(struct vsock_transport *transport, > void (*fn)(struct sock *sk)); > diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c > index a33b2a2d3..f840498b5 100644 > --- a/net/vmw_vsock/af_vsock.c > +++ b/net/vmw_vsock/af_vsock.c > @@ -438,6 +438,38 @@ struct sock *vsock_find_connected_socket(struct sockaddr_vm *src, > } > EXPORT_SYMBOL_GPL(vsock_find_connected_socket); > > +/** > + * vsock_check_source - validate a packet source against a socket peer > + * @vsk: socket receiving the packet > + * @transport: transport receiving the packet > + * @src: source address from the packet > + * > + * Return: true if the packet arrived on the socket's assigned transport and > + * its source matches the stored peer. Loopback packets are generated > + * internally and always use the local CID as their source, including > + * connections using a valid CID alias. > + * > + * The caller must hold the socket lock and must not call this for listening > + * sockets, which accept packets from any source and have no assigned > + * transport. > + */ > +bool vsock_check_source(const struct vsock_sock *vsk, > + const struct vsock_transport *transport, > + const struct sockaddr_vm *src) > +{ > + if (vsk->transport != transport) > + return false; > + > + if (src->svm_port != vsk->remote_addr.svm_port) > + return false; > + > + if (src->svm_cid == vsk->remote_addr.svm_cid) > + return true; > + > + return transport->get_local_cid() == VMADDR_CID_LOCAL; > +} > +EXPORT_SYMBOL_GPL(vsock_check_source); > + > void vsock_remove_sock(struct vsock_sock *vsk) > { > /* Transport reassignment must not remove the binding. */ > diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c > index e4ebaa70f..6301c108a 100644 > --- a/net/vmw_vsock/virtio_transport_common.c > +++ b/net/vmw_vsock/virtio_transport_common.c > @@ -1823,7 +1823,8 @@ void virtio_transport_recv_pkt(struct virtio_transport *t, > * lock_sock (note: listener sockets are not assigned to any transport) > */ > if (sock_flag(sk, SOCK_DONE) || > - (sk->sk_state != TCP_LISTEN && vsk->transport != &t->transport)) { > + (sk->sk_state != TCP_LISTEN && > + !vsock_check_source(vsk, &t->transport, &src))) { > (void)virtio_transport_reset_no_sock(t, skb, net); > release_sock(sk); > sock_put(sk); > -- > 2.54.0 > Reviewed-by: Bobby Eshleman <bobbyeshleman@meta.com> ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH net v3 2/2] vsock/vmci: validate packet source for connected sockets 2026-08-23 17:58 [PATCH net v3 0/2] vsock: validate packet sources after bound lookup fallback Daehyeon Ko 2026-08-23 17:58 ` [PATCH net v3 1/2] vsock/virtio: validate packet source for connected sockets Daehyeon Ko @ 2026-08-23 17:58 ` Daehyeon Ko 2026-08-24 17:59 ` sashiko-bot 2026-08-25 9:19 ` Paolo Abeni 1 sibling, 2 replies; 6+ messages in thread From: Daehyeon Ko @ 2026-08-23 17:58 UTC (permalink / raw) To: netdev Cc: sgarzare, stefanha, bobbyeshleman, davem, edumazet, kuba, pabeni, horms, mst, jasowangio, xuanzhuo, eperezma, bryan-bt.tan, vishnu.dasa, bcm-kernel-feedback-list, virtualization, kvm, linux-kernel, Sashiko vmci_transport_recv_stream_cb() looks up sockets first by the full source and destination tuple, then by destination only in the bound table. The fallback can select a non-listening socket without checking whether the packet came from its stored peer. This was reproduced with two VMCI contexts. A RST from the context not stored in a TCP_SYN_SENT socket reset that socket after it was selected by the destination-only lookup. VMCI can process notification packets in bottom-half context when the socket is not owned by user context, or defer packets to a workqueue. Use vsock_check_source() after taking the socket lock in the bottom-half path, and recheck after lock_sock() in the workqueue path. Listening sockets continue to accept packets from any source. Fixes: d021c344051a ("VSOCK: Introduce VM Sockets") Reported-by: Sashiko <sashiko-bot@kernel.org> Closes: https://lore.kernel.org/netdev/20260814121255.6B5001F000E9@smtp.kernel.org/ Cc: stable@vger.kernel.org Suggested-by: Stefano Garzarella <sgarzare@redhat.com> Assisted-by: Codex:gpt-5.6-sol Signed-off-by: Daehyeon Ko <4ncienth@gmail.com> --- net/vmw_vsock/vmci_transport.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c index 1c4ee039c..b612a9893 100644 --- a/net/vmw_vsock/vmci_transport.c +++ b/net/vmw_vsock/vmci_transport.c @@ -680,11 +680,13 @@ static int vmci_transport_recv_stream_cb(void *data, struct vmci_datagram *dg) struct vmci_transport_packet *pkt; struct vsock_sock *vsk; bool bh_process_pkt; + bool drop_pkt; int err; sk = NULL; err = VMCI_SUCCESS; bh_process_pkt = false; + drop_pkt = false; /* Ignore incoming packets from resources that aren't vsock * implementations. @@ -765,17 +767,26 @@ static int vmci_transport_recv_stream_cb(void *data, struct vmci_datagram *dg) bh_lock_sock(sk); if (!sock_owned_by_user(sk)) { - /* The local context ID may be out of date, update it. */ - vsk->local_addr.svm_cid = dst.svm_cid; + if (sk->sk_state != TCP_LISTEN && + !vsock_check_source(vsk, &vmci_transport, &src)) { + drop_pkt = true; + err = VMCI_ERROR_NO_ACCESS; + } else { + /* The local context ID may be out of date, update it. */ + vsk->local_addr.svm_cid = dst.svm_cid; - if (sk->sk_state == TCP_ESTABLISHED) - vmci_trans(vsk)->notify_ops->handle_notify_pkt( - sk, pkt, true, &dst, &src, - &bh_process_pkt); + if (sk->sk_state == TCP_ESTABLISHED) + vmci_trans(vsk)->notify_ops->handle_notify_pkt(sk, pkt, true, + &dst, &src, + &bh_process_pkt); + } } bh_unlock_sock(sk); + if (drop_pkt) + goto out; + if (!bh_process_pkt) { struct vmci_transport_recv_pkt_info *recv_pkt_info; @@ -900,6 +911,7 @@ static void vmci_transport_recv_pkt_work(struct work_struct *work) { struct vmci_transport_recv_pkt_info *recv_pkt_info; struct vmci_transport_packet *pkt; + struct sockaddr_vm src; struct sock *sk; recv_pkt_info = @@ -908,6 +920,10 @@ static void vmci_transport_recv_pkt_work(struct work_struct *work) pkt = &recv_pkt_info->pkt; lock_sock(sk); + vsock_addr_init(&src, pkt->dg.src.context, pkt->src_port); + if (sk->sk_state != TCP_LISTEN && + !vsock_check_source(vsock_sk(sk), &vmci_transport, &src)) + goto out; /* The local context ID may be out of date. */ vsock_sk(sk)->local_addr.svm_cid = pkt->dg.dst.context; @@ -937,6 +953,7 @@ static void vmci_transport_recv_pkt_work(struct work_struct *work) break; } +out: release_sock(sk); kfree(recv_pkt_info); /* Release reference obtained in the stream callback when we fetched -- 2.54.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH net v3 2/2] vsock/vmci: validate packet source for connected sockets 2026-08-23 17:58 ` [PATCH net v3 2/2] vsock/vmci: " Daehyeon Ko @ 2026-08-24 17:59 ` sashiko-bot 2026-08-25 9:19 ` Paolo Abeni 1 sibling, 0 replies; 6+ messages in thread From: sashiko-bot @ 2026-08-24 17:59 UTC (permalink / raw) To: Daehyeon Ko; +Cc: kvm Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: New issues: - [High] Legitimate connection requests to bound but non-listening sockets (TCP_CLOSE) or concurrently closing sockets are silently dropped instead of generating a connection reset (RST), causing clients to hang until timeout. Pre-existing issues: - [High] Dynamically allocated `recv_pkt_info` work items are queued to the global `system_wq` but are not flushed or canceled when the module is unloaded, leading to a kernel panic. -- --- Patch [2]: [PATCH net v3 2/2] vsock/vmci: validate packet source for connected sockets --- commit 0c47d3fbd6e3da162ec0e88ab935d6073c395e19 Author: Daehyeon Ko <4ncienth@gmail.com> vsock/vmci: validate packet source for connected sockets This commit adds source validation for connected sockets in the VMCI transport to prevent packets from unverified sources from being processed. It updates both the bottom-half fast path and the workqueue path to verify the packet's source. Link: https://lore.kernel.org/netdev/20260814121255.6B5001F000E9@smtp.kernel.org/ > diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c > index 1c4ee039c1662..b612a9893856a 100644 > --- a/net/vmw_vsock/vmci_transport.c > +++ b/net/vmw_vsock/vmci_transport.c [ ... ] > @@ -765,17 +767,26 @@ static int vmci_transport_recv_stream_cb(void *data, struct vmci_datagram *dg) > bh_lock_sock(sk); > > if (!sock_owned_by_user(sk)) { > - /* The local context ID may be out of date, update it. */ > - vsk->local_addr.svm_cid = dst.svm_cid; > + if (sk->sk_state != TCP_LISTEN && > + !vsock_check_source(vsk, &vmci_transport, &src)) { > + drop_pkt = true; > + err = VMCI_ERROR_NO_ACCESS; > + } else { [Severity: High] Does this code silently drop connection requests to bound but non-listening sockets (TCP_CLOSE)? If a client attempts to connect to a bound port that isn't listening yet, the socket is found in the TCP_CLOSE state. Since the state is not TCP_LISTEN, it calls vsock_check_source(), which checks against the socket's remote_addr. Because the socket is not connected, the port is 0 and won't match the client's ephemeral source port, causing vsock_check_source() to return false. By setting drop_pkt = true, the packet is completely dropped. Could this prevent the client from receiving the expected connection reset (RST), causing them to hang indefinitely instead of seeing ECONNREFUSED? > + /* The local context ID may be out of date, update it. */ > + vsk->local_addr.svm_cid = dst.svm_cid; > > - if (sk->sk_state == TCP_ESTABLISHED) > - vmci_trans(vsk)->notify_ops->handle_notify_pkt( > - sk, pkt, true, &dst, &src, > - &bh_process_pkt); > + if (sk->sk_state == TCP_ESTABLISHED) > + vmci_trans(vsk)->notify_ops->handle_notify_pkt(sk, pkt, true, > + &dst, &src, > + &bh_process_pkt); > + } > } > > bh_unlock_sock(sk); > > + if (drop_pkt) > + goto out; > + > if (!bh_process_pkt) { > struct vmci_transport_recv_pkt_info *recv_pkt_info; [Severity: High] This is a pre-existing issue, but does queuing these work items to the global system_wq create a use-after-free risk during module unload? Looking at vmci_transport_recv_stream_cb(), it dynamically allocates a work item and schedules it: INIT_WORK(&recv_pkt_info->work, vmci_transport_recv_pkt_work); schedule_work(&recv_pkt_info->work); However, vmci_transport_exit() cancels a specific cleanup work item but does not flush system_wq or track these pending recv_pkt_info items before unloading. If packets arrive for a port bound by a listening socket of a different transport (e.g., virtio_transport), this code bypasses vsock_check_source() and schedules the work. Since the target socket belongs to a different transport, the vmci_transport module reference count can remain at zero. If the module is unloaded while this work is still pending, could the kernel worker thread attempt to execute the unmapped vmci_transport_recv_pkt_work function and panic? [ ... ] > @@ -900,6 +911,7 @@ static void vmci_transport_recv_pkt_work(struct work_struct *work) > { > struct vmci_transport_recv_pkt_info *recv_pkt_info; > struct vmci_transport_packet *pkt; > + struct sockaddr_vm src; > struct sock *sk; > > recv_pkt_info = > @@ -908,6 +920,10 @@ static void vmci_transport_recv_pkt_work(struct work_struct *work) > pkt = &recv_pkt_info->pkt; > > lock_sock(sk); > + vsock_addr_init(&src, pkt->dg.src.context, pkt->src_port); > + if (sk->sk_state != TCP_LISTEN && > + !vsock_check_source(vsock_sk(sk), &vmci_transport, &src)) > + goto out; [Severity: High] Similarly, does this early exit bypass the logic meant to send connection resets for closed sockets? The default case in the switch statement below this code was specifically designed to send a reset: switch (sk->sk_state) { ... default: /* Because this function does not run in the same context as * vmci_transport_recv_stream_cb it is possible that the * socket has closed. We need to let the other side know or it * could be sitting in a connect and hang forever. Send a * reset to prevent that. */ vmci_transport_send_reset(sk, pkt); break; } Will jumping to the out label bypass this reset logic when a socket closes concurrently? > > /* The local context ID may be out of date. */ > vsock_sk(sk)->local_addr.svm_cid = pkt->dg.dst.context; -- Sashiko AI review · https://sashiko.dev/#/patchset/20260823175858.351431-1-4ncienth@gmail.com?part=2 ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net v3 2/2] vsock/vmci: validate packet source for connected sockets 2026-08-23 17:58 ` [PATCH net v3 2/2] vsock/vmci: " Daehyeon Ko 2026-08-24 17:59 ` sashiko-bot @ 2026-08-25 9:19 ` Paolo Abeni 1 sibling, 0 replies; 6+ messages in thread From: Paolo Abeni @ 2026-08-25 9:19 UTC (permalink / raw) To: 4ncienth Cc: netdev, sgarzare, stefanha, bobbyeshleman, davem, edumazet, kuba, pabeni, horms, mst, jasowangio, xuanzhuo, eperezma, bryan-bt.tan, vishnu.dasa, bcm-kernel-feedback-list, virtualization, kvm, linux-kernel, sashiko-bot This is an AI-generated review of your patch. The human sending this email has considered the AI review valid, or at least plausible. Full review at: https://netdev-ai.bots.linux.dev/sashiko/ --- vsock/vmci: validate packet source for connected sockets This adds a vsock_check_source() test to the VMCI stream receive paths so that a non-listening socket found by the destination-only bound-table lookup no longer processes packets from a context other than its stored peer. The check is applied both under bh_lock_sock() in vmci_transport_recv_stream_cb() and after lock_sock() in vmci_transport_recv_pkt_work(). Closes: https://lore.kernel.org/netdev/20260814121255.6B5001F000E9@smtp.kernel.org/ > diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c > index 1c4ee039c1662..b612a9893856a 100644 > --- a/net/vmw_vsock/vmci_transport.c > +++ b/net/vmw_vsock/vmci_transport.c [ ... ] > @@ -765,17 +767,26 @@ static int vmci_transport_recv_stream_cb(void *data, struct vmci_datagram *dg) > bh_lock_sock(sk); > > if (!sock_owned_by_user(sk)) { > - /* The local context ID may be out of date, update it. */ > - vsk->local_addr.svm_cid = dst.svm_cid; > + if (sk->sk_state != TCP_LISTEN && > + !vsock_check_source(vsk, &vmci_transport, &src)) { > + drop_pkt = true; > + err = VMCI_ERROR_NO_ACCESS; > + } else { > + /* The local context ID may be out of date, update it. */ > + vsk->local_addr.svm_cid = dst.svm_cid; > > - if (sk->sk_state == TCP_ESTABLISHED) > - vmci_trans(vsk)->notify_ops->handle_notify_pkt( > - sk, pkt, true, &dst, &src, > - &bh_process_pkt); > + if (sk->sk_state == TCP_ESTABLISHED) > + vmci_trans(vsk)->notify_ops->handle_notify_pkt(sk, pkt, true, > + &dst, &src, > + &bh_process_pkt); > + } > } > > bh_unlock_sock(sk); > > + if (drop_pkt) > + goto out; > + [Severity: Medium] Should these two new exits still emit an RST before dropping the packet? Consider a stream socket that called bind() but never listen(). __vsock_bind_connectible() puts it in the bound table with sk_state TCP_CLOSE, remote_addr left as {VMADDR_CID_ANY, VMADDR_PORT_ANY}, and vsk->transport still NULL, because vsock_assign_transport() is only called for connectible sockets from vsock_connect() (and at create time for SOCK_DGRAM). A REQUEST from a remote context to that port misses vsock_find_connected_socket(), is matched by vsock_find_bound_socket(), and then reaches the new check. vsock_check_source() fails on its very first test: net/vmw_vsock/af_vsock.c:vsock_check_source() { if (vsk->transport != transport) return false; ... } So drop_pkt is set and "goto out" skips the kmalloc/schedule_work() handoff entirely. vmci_transport_send_reset_bh() is only reached on the "no socket found" and allocation-failure paths, so nothing is sent back. The same happens on the deferred path below, where the new "goto out" jumps over the whole sk_state switch, including the default: arm whose in-tree comment says the reset is required: > @@ -908,6 +920,10 @@ static void vmci_transport_recv_pkt_work(struct work_struct *work) > pkt = &recv_pkt_info->pkt; > > lock_sock(sk); > + vsock_addr_init(&src, pkt->dg.src.context, pkt->src_port); > + if (sk->sk_state != TCP_LISTEN && > + !vsock_check_source(vsock_sk(sk), &vmci_transport, &src)) > + goto out; > > /* The local context ID may be out of date. */ > vsock_sk(sk)->local_addr.svm_cid = pkt->dg.dst.context; net/vmw_vsock/vmci_transport.c:vmci_transport_recv_pkt_work() { ... default: /* Because this function does not run in the same context as * vmci_transport_recv_stream_cb it is possible that the * socket has closed. We need to let the other side know or it * could be sitting in a connect and hang forever. Send a * reset to prevent that. */ vmci_transport_send_reset(sk, pkt); break; } Before this change that arm did transmit an RST for exactly this case, since vmci_transport_send_reset() handles an unbound remote_addr by replying to the packet's own source: net/vmw_vsock/vmci_transport.c:vmci_transport_send_reset() { ... if (vsock_addr_bound(&vsk->remote_addr)) { dst_ptr = &vsk->remote_addr; } else { vsock_addr_init(&dst, pkt->dg.src.context, pkt->src_port); dst_ptr = &dst; } ... } With the reply gone, does the remote connect() now block for vsk->connect_timeout and return -ETIMEDOUT instead of -ECONNRESET? The same loss of the reply would apply to a socket disconnected via connect(AF_UNSPEC), which resets remote_addr to {VMADDR_CID_ANY, VMADDR_PORT_ANY}. Returning VMCI_ERROR_NO_ACCESS from the datagram callback does not turn into a protocol reply, so is there anything left that notifies the peer? For comparison, the virtio side runs the same source test but resets the sender before dropping: net/vmw_vsock/virtio_transport_common.c:virtio_transport_recv_pkt() { ... if (sock_flag(sk, SOCK_DONE) || (sk->sk_state != TCP_LISTEN && !vsock_check_source(vsk, &t->transport, &src))) { (void)virtio_transport_reset_no_sock(t, skb, net); ... } Would it make sense to follow that convention here, and to mention the new drop-without-reply semantics in the changelog? -- This is an AI-generated review. ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-08-25 22:32 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-08-23 17:58 [PATCH net v3 0/2] vsock: validate packet sources after bound lookup fallback Daehyeon Ko 2026-08-23 17:58 ` [PATCH net v3 1/2] vsock/virtio: validate packet source for connected sockets Daehyeon Ko 2026-08-25 22:32 ` Bobby Eshleman 2026-08-23 17:58 ` [PATCH net v3 2/2] vsock/vmci: " Daehyeon Ko 2026-08-24 17:59 ` sashiko-bot 2026-08-25 9:19 ` Paolo Abeni
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox