Linux Documentation
 help / color / mirror / Atom feed
From: netdev-bot+sashiko@kernel.org
To: bobbyeshleman@meta.com
Cc: sgarzare@redhat.com, davem@davemloft.net, kuba@kernel.org,
	pabeni@redhat.com, horms@kernel.org, corbet@lwn.net,
	skhan@linuxfoundation.org, stefanha@redhat.com, mst@redhat.com,
	jasowangio@gmail.com, xuanzhuo@linux.alibaba.com,
	eperezma@redhat.com, shuah@kernel.org, rdunlap@infradead.org,
	donald.hunter@gmail.com, edumazet@kernel.org,
	virtualization@lists.linux.dev, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org,
	kvm@vger.kernel.org, linux-kselftest@vger.kernel.org,
	sargun@sargun.me, jlinbox@meta.com, bobbyeshleman@gmail.com
Subject: Re: [PATCH net-next v3 4/7] vsock: add a netlink command to assign the g2h device to a netns
Date: Tue, 13 Oct 2026 22:51:55 +0000	[thread overview]
Message-ID: <179193191574.434549.17107426250790354528@kernel.org> (raw)
In-Reply-To: <20261012-vsock-guest-ns-v3-4-b32447c66b23@meta.com>

Thank you for your contribution! Sashiko AI review found 4 potential
issue(s) to consider.

Critical: 0 · High: 0 · Medium: 2 · Low: 2

If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).

- [Medium] Take a namespace that cannot reach the assigned G2H device, on
  a system with vhost-vsock (H2G) and vsock_loopback loaded.
- [Medium] `vsock_g2h_reset_unreachable()` in net/vmw_vsock/af_vsock.c
  resets sockets without lock_sock() while the device stays live.
- [Low] No in-tree transport sets the new capability at this commit.
- [Low] `vsock_g2h_net_assign()` in net/vmw_vsock/af_vsock.c sends the
  success reply before it commits the assignment.

--

vsock: add a netlink command to assign the g2h device to a netns

This patch adds a vsock generic netlink family with two commands.
VSOCK_CMD_DEV_NETNS_SET moves the guest's G2H vsock device into the
caller's network namespace, and VSOCK_CMD_DEV_NETNS_GET reports where the
device is. After a move, connected sockets that can no longer reach the
device are closed with ECONNRESET, and the assignment holds a reference on
the target namespace.

Link: https://lore.kernel.org/all/20200427142518.uwssa6dtasrp3bfc@steredhat/

> diff --git a/Documentation/admin-guide/sysctl/net.rst b/Documentation/admin-guide/sysctl/net.rst
> index fe43e85959583..9276479004c0f 100644
> --- a/Documentation/admin-guide/sysctl/net.rst
> +++ b/Documentation/admin-guide/sysctl/net.rst
> @@ -529,6 +529,43 @@ their hosts. The behavior of VSOCK sockets in a network namespace is determined

[ ... ]

> +Support is transport dependent. A G2H transport that does not implement the
> +move refuses the command with ``EOPNOTSUPP``. Of the in-tree guest transports,
> +only virtio-vsock implements it.

[Severity: Low]
This is a minor point. Is this sentence accurate at this commit?

No in-tree transport sets netns_assign_allow yet, so this check in
vsock_g2h_net_assign() always fails:

	if (!vsock_net_assignable(transport_g2h)) {

As a result, VSOCK_CMD_DEV_NETNS_SET returns -EOPNOTSUPP (or -ENODEV) for
every G2H transport. The new exports vsock_g2h_net_get(), vsock_g2h_net_eq()
and vsock_maybe_set_connected() also have no callers yet.

The next patch in the series, "vsock/virtio: support guest device network
namespace", adds .netns_assign_allow = true to virtio_transport and calls
those helpers. So the mismatch only exists at bisect points between the two
patches. Could this sentence move into that patch?

> diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
> index 8f34bf68f9164..e663be3bbfa0b 100644
> --- a/net/vmw_vsock/af_vsock.c
> +++ b/net/vmw_vsock/af_vsock.c

[ ... ]

> @@ -564,7 +632,12 @@ static bool vsock_use_local_transport(unsigned int remote_cid)
>  		return true;
>  
>  	if (transport_g2h) {
> -		return remote_cid == transport_g2h->get_local_cid();
> +		u32 cid = __vsock_registered_transport_cid(&transport_g2h, net);
> +
> +		/* The device may be unreachable from @net, in which case
> +		 * @remote_cid is not the local CID.
> +		 */
> +		return cid != VMADDR_CID_ANY && remote_cid == cid;
>  	} else {
>  		return remote_cid == VMADDR_CID_HOST;
>  	}

[Severity: Medium]
Suppose the G2H device has been assigned to a local mode namespace, and
vhost-vsock and vsock_loopback are also loaded. What happens in a namespace
that can no longer reach the device?

In that namespace, IOCTL_VM_SOCKETS_GET_LOCAL_CID in vsock_dev_do_ioctl()
gets VMADDR_CID_ANY from transport_g2h and falls back to transport_h2g:

	cid = vsock_registered_transport_cid(&transport_g2h, net);
	if (cid == VMADDR_CID_ANY)
		cid = vsock_registered_transport_cid(&transport_h2g,
						     net);

vhost_transport_get_local_cid() returns VHOST_VSOCK_DEFAULT_HOST_CID, so the
namespace is told its local CID is 2. __vsock_find_cid(net, 2) is also true
through the transport_h2g && cid == VMADDR_CID_HOST check, so bind() to
CID 2 succeeds.

A connect() to CID 2 then enters the transport_g2h branch above, because the
pointer is non-NULL. It returns false because cid is VMADDR_CID_ANY, so the
remote_cid == VMADDR_CID_HOST loopback fallback in the else branch is never
reached.

vsock_assign_transport() then picks transport_g2h for
remote_cid <= VMADDR_CID_HOST and fails at the new check:

	if (vsock_g2h_unreachable(new_transport, sock_net(sk))) {
		ret = -ENETUNREACH;

Should an unreachable G2H transport be treated the same as an absent one
here, so that connecting to the namespace's own reported CID uses loopback?
The later virtio patch in the series makes this path reachable and does not
change this logic.

[ ... ]

> @@ -742,8 +823,267 @@ bool vsock_find_cid(unsigned int cid)

[ ... ]

> +/* Close every connected socket of @t that can no longer reach the g2h device.
> + */
> +static void vsock_g2h_reset_unreachable(const struct vsock_transport *t)
> +{
> +	struct vsock_sock *vsk, *tmp;
> +	struct sock *sk;
> +	int i;
> +
> +	lockdep_assert_held(&vsock_register_mutex);
> +
> +	spin_lock_bh(&vsock_table_lock);
> +
> +	for (i = 0; i < ARRAY_SIZE(vsock_connected_table); i++) {
> +		list_for_each_entry_safe(vsk, tmp, &vsock_connected_table[i],
> +					 connected_table) {
> +			sk = sk_vsock(vsk);
> +
> +			if (vsk->transport != t ||
> +			    sk->sk_state == TCP_CLOSE ||
> +			    vsock_g2h_reachable_sk(vsk))
> +				continue;
> +
> +			/* If close has already been scheduled for this socket,
> +			 * we can skip.
> +			 */
> +			if (vsk->close_work_scheduled)
> +				continue;
> +
> +			sk->sk_state = TCP_CLOSE;
> +			sk->sk_err = ECONNRESET;
> +			sk_error_report(sk);
> +
> +			__vsock_remove_connected(vsk);

[Severity: Medium]
Can these writes race with the socket's own state machine?

Only vsock_register_mutex and vsock_table_lock are held here, and neither
one excludes lock_sock() holders. close_work_scheduled is read the same way.

The existing lockless resets, virtio_vsock_reset_sock() and
vhost_vsock_reset_orphans(), only run when the device is going away. Here
the device keeps running, so its RX path can work on the same socket at the
same time.

With the later virtio patch, virtio_transport_rx_work() checks
vsock_g2h_net_eq(net) for each packet but does not synchronize with the
swap. That patch's commit message also notes that an assign can land while
rx_work is draining a batch:

CPU1 (assign)                      CPU2 (rx_work)
                                   vsock_g2h_net_eq(net) returns true
vsock_g2h_net_swap()
                                   virtio_transport_recv_pkt()
                                     lock_sock(sk)
                                     sk_state is TCP_ESTABLISHED
vsock_g2h_reset_unreachable()
  sk->sk_state = TCP_CLOSE
  sk->sk_err = ECONNRESET
  __vsock_remove_connected(vsk)
                                     virtio_transport_recv_connected()
                                       virtio_transport_do_close()
                                         sk->sk_state = TCP_CLOSING

If an incoming SHUTDOWN or RST arrives at that point, doesn't the socket end
up in TCP_CLOSING with ECONNRESET set and outside the connected table?

There is a similar window on the send side. vsock_connectible_sendmsg() may
already have passed its sk_err check and could enqueue one more chunk
through the device after the sweep. KCSAN would also likely report these
unannotated stores against the locked writers.

Refcounting looks balanced, because vsock_remove_connected() re-checks table
membership. So the effect appears to be limited to inconsistent socket
state.

[ ... ]

> +static int vsock_g2h_net_assign(struct net *net, struct sk_buff *msg,
> +				struct genl_info *info)
> +{

[ ... ]

> +	ret = -EMSGSIZE;
> +	hdr = genlmsg_iput(msg, info);
> +	if (!hdr)
> +		goto unlock;
> +	genlmsg_end(msg, hdr);
> +
> +	ret = genlmsg_reply(msg, info);
> +	msg = NULL;
> +	if (ret)
> +		goto unlock;
> +
> +	old = vsock_g2h_net_swap(net, &old_tracker);
> +
> +	/* See vsock_maybe_set_connected() comment about synchronizing with
> +	 * connecting sockets.
> +	 */
> +	vsock_g2h_reset_unreachable(transport_g2h);

[Severity: Low]
Is this ordering intended? The success reply goes out before
vsock_g2h_net_swap() and vsock_g2h_reset_unreachable() run.

This means userspace can see VSOCK_CMD_DEV_NETNS_SET succeed while
vsock_g2h_net still points at the old namespace and the established sockets
there are still open. Those sockets' send and receive paths take lock_sock(),
not vsock_register_mutex, so the mutex does not hold them off.

The move also depends on the reply being delivered. genlmsg_reply() does a
MSG_DONTWAIT unicast, so if the requester's receive buffer is full it
returns -EAGAIN and the swap is skipped. Neither the commit message nor the
docs mention this failure mode.

Could the swap and the sweep run first, with the reply sent after them?

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261012-vsock-guest-ns-v3-0-b32447c66b23%40meta.com

  parent reply	other threads:[~2026-10-13 22:51 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-12 22:48 [PATCH net-next v3 0/7] vsock: assign the guest vsock device to a network namespace Bobby Eshleman
2026-10-12 22:48 ` [PATCH net-next v3 1/7] vsock: constify the transport in vsock_for_each_connected_socket() Bobby Eshleman
2026-10-12 22:48 ` [PATCH net-next v3 2/7] vsock: rename the vsock pernet operations Bobby Eshleman
2026-10-12 22:48 ` [PATCH net-next v3 3/7] vsock: pass the netns to ->has_remote_cid() Bobby Eshleman
2026-10-12 22:48 ` [PATCH net-next v3 4/7] vsock: add a netlink command to assign the g2h device to a netns Bobby Eshleman
2026-10-13  1:44   ` Daniel Pereira
2026-10-13 17:34     ` Bobby Eshleman
2026-10-13 22:51   ` netdev-bot+sashiko [this message]
2026-10-12 22:48 ` [PATCH net-next v3 5/7] vsock/virtio: support guest device network namespace Bobby Eshleman
2026-10-13 22:51   ` netdev-bot+sashiko
2026-10-12 22:48 ` [PATCH net-next v3 6/7] selftests/vsock: test the guest vsock " Bobby Eshleman
2026-10-13 22:51   ` netdev-bot+sashiko
2026-10-12 22:48 ` [PATCH net-next v3 7/7] selftests/vsock: test the netns assign privilege checks Bobby Eshleman
2026-10-13 22:52   ` netdev-bot+sashiko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=179193191574.434549.17107426250790354528@kernel.org \
    --to=netdev-bot+sashiko@kernel.org \
    --cc=bobbyeshleman@gmail.com \
    --cc=bobbyeshleman@meta.com \
    --cc=corbet@lwn.net \
    --cc=davem@davemloft.net \
    --cc=donald.hunter@gmail.com \
    --cc=edumazet@kernel.org \
    --cc=eperezma@redhat.com \
    --cc=horms@kernel.org \
    --cc=jasowangio@gmail.com \
    --cc=jlinbox@meta.com \
    --cc=kuba@kernel.org \
    --cc=kvm@vger.kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=mst@redhat.com \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=rdunlap@infradead.org \
    --cc=sargun@sargun.me \
    --cc=sgarzare@redhat.com \
    --cc=shuah@kernel.org \
    --cc=skhan@linuxfoundation.org \
    --cc=stefanha@redhat.com \
    --cc=virtualization@lists.linux.dev \
    --cc=xuanzhuo@linux.alibaba.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox