Kernel KVM virtualization development
 help / color / mirror / Atom feed
* [PATCH net v4 0/2] vsock: validate packet sources after bound lookup fallback
@ 2026-08-26  0:39 Daehyeon Ko
  2026-08-26  0:39 ` [PATCH net v4 1/2] vsock/virtio: validate packet source for connected sockets Daehyeon Ko
  2026-08-26  0:39 ` [PATCH net v4 2/2] vsock/vmci: " Daehyeon Ko
  0 siblings, 2 replies; 3+ messages in thread
From: Daehyeon Ko @ 2026-08-26  0:39 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.

V4 preserves VMCI's existing RST behavior when source validation fails.
The reset is addressed from the received packet so that a bound but
non-listening or concurrently closed socket still notifies the sender,
without directing the reset to a connected socket's stored peer.

The v3 regression was reproduced in three x86_64 KASAN boots: a REQUEST to
a bound but non-listening socket returned VMCI_ERROR_NO_ACCESS but no RST
arrived within one second. With v4, the sending context received the
expected RST in all three boots. The original VMCI source-validation oracle
also passed in three v4 boots: a matched RST reset the pending socket while
a mismatched-context RST left it pending. No KASAN report occurred.

Patch 1 is unchanged from v3 (identical stable patch-id) and carries
Bobby's Reviewed-by for that revision. Its v3 validation covered the
cross-UID injection oracle, local CID aliases, selected VSOCK selftests,
and W=1 changed-object builds under allmodconfig and allyesconfig.

The current-tree guest-CID vhost probe could not be rerun because the test
user lacks access to /dev/vhost-vsock.

---
Changes in v4:
- Preserve RST replies when VMCI source validation rejects a packet.
- Address those replies from the received packet rather than the socket's
  stored peer.
- Add a bound-but-not-listening VMCI regression oracle.
- Rebase to the current net tree.

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.

v3:
https://lore.kernel.org/r/20260823175858.351431-1-4ncienth@gmail.com
v2:
https://lore.kernel.org/r/20260820001517.2148196-1-4ncienth@gmail.com
v1:
https://lore.kernel.org/r/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          | 34 ++++++++++++++++++++-----
 4 files changed, 65 insertions(+), 7 deletions(-)


base-commit: dc4b95b8fee95113587e93ca116356032d271371

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH net v4 1/2] vsock/virtio: validate packet source for connected sockets
  2026-08-26  0:39 [PATCH net v4 0/2] vsock: validate packet sources after bound lookup fallback Daehyeon Ko
@ 2026-08-26  0:39 ` Daehyeon Ko
  2026-08-26  0:39 ` [PATCH net v4 2/2] vsock/vmci: " Daehyeon Ko
  1 sibling, 0 replies; 3+ messages in thread
From: Daehyeon Ko @ 2026-08-26  0:39 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>
Reviewed-by: Bobby Eshleman <bobbyeshleman@meta.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);

base-commit: dc4b95b8fee95113587e93ca116356032d271371

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH net v4 2/2] vsock/vmci: validate packet source for connected sockets
  2026-08-26  0:39 [PATCH net v4 0/2] vsock: validate packet sources after bound lookup fallback Daehyeon Ko
  2026-08-26  0:39 ` [PATCH net v4 1/2] vsock/virtio: validate packet source for connected sockets Daehyeon Ko
@ 2026-08-26  0:39 ` Daehyeon Ko
  1 sibling, 0 replies; 3+ messages in thread
From: Daehyeon Ko @ 2026-08-26  0:39 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-bot

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.

Reply with a RST addressed from the received packet before dropping a
source that fails validation. This preserves the existing reset behavior
for bound non-listening and concurrently closed sockets without directing
the reset to a connected socket's stored peer.

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>
Suggested-by: Paolo Abeni <pabeni@redhat.com>
Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Daehyeon Ko <4ncienth@gmail.com>
---
 net/vmw_vsock/vmci_transport.c | 34 ++++++++++++++++++++++++++++------
 1 file changed, 28 insertions(+), 6 deletions(-)

diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c
index 1c4ee039c..1f186e8f8 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,29 @@ 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) {
+		if (vmci_transport_send_reset_bh(&dst, &src, pkt) < 0)
+			pr_err("unable to send reset\n");
+		goto out;
+	}
+
 	if (!bh_process_pkt) {
 		struct vmci_transport_recv_pkt_info *recv_pkt_info;
 
@@ -900,6 +914,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 +923,12 @@ 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)) {
+		vmci_transport_reply_reset(pkt);
+		goto out;
+	}
 
 	/* The local context ID may be out of date. */
 	vsock_sk(sk)->local_addr.svm_cid = pkt->dg.dst.context;
@@ -937,6 +958,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

^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-08-26  0:40 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-26  0:39 [PATCH net v4 0/2] vsock: validate packet sources after bound lookup fallback Daehyeon Ko
2026-08-26  0:39 ` [PATCH net v4 1/2] vsock/virtio: validate packet source for connected sockets Daehyeon Ko
2026-08-26  0:39 ` [PATCH net v4 2/2] vsock/vmci: " Daehyeon Ko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox