Re: [PATCH v2 3/6] hv_netvsc: Remove GPADL teardown special case for old Hyper-V hosts

[email protected] Wed, 05 Aug 2026 21:01:13 +0000
Newsgroups org.kernel.vger.linux-hyperv
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 2 potential issue(=
s) to consider:

Pre-existing issues:
- [Critical] vmbus_teardown_gpadl masks vmbus_post_msg failures, leading to=
 Use-After-Free/Memory Corruption in guest.
- [High] Missing synchronization between `netvsc_device_remove` and concurr=
ent TX path, leading to use-after-free or NULL pointer dereference in the V=
MBus ring buffer.
--

--- Patch [3]: [PATCH v2 3/6] hv_netvsc: Remove GPADL teardown special case=
 for old Hyper-V hosts ---
commit 25bcea31eec6bb56b8730b7c31834e06d41d6a61
Author: Michael Kelley <[email protected]>

hv_netvsc: Remove GPADL teardown special case for old Hyper-V hosts

This commit removes the special case handling of GPADL teardown for
Hyper-V hosts earlier than Windows Server 2016 and Windows 10. The
receive and send GPADL teardowns are now always performed after the
VMBus channel is closed.

> diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
> index 4d319c50955ed..4295b96b43127 100644
> --- a/drivers/net/hyperv/netvsc.c
> +++ b/drivers/net/hyperv/netvsc.c
> @@ -695,17 +695,8 @@ void netvsc_device_remove(struct hv_device *device)
>  		=3D rtnl_dereference(net_device_ctx->nvdev);
>  	int i;
> =20
> -	/*
> -	 * Revoke receive buffer. If host is pre-Win2016 then tear down
> -	 * receive buffer GPADL. Do the same for send buffer.
> -	 */
>  	netvsc_revoke_recv_buf(device, net_device, ndev);
> -	if (vmbus_proto_version < VERSION_WIN10)
> -		netvsc_teardown_recv_gpadl(device, net_device, ndev);
> -
>  	netvsc_revoke_send_buf(device, net_device, ndev);
> -	if (vmbus_proto_version < VERSION_WIN10)
> -		netvsc_teardown_send_gpadl(device, net_device, ndev);
> =20
>  	RCU_INIT_POINTER(net_device_ctx->nvdev, NULL);
> =20

[ ... ]

> @@ -733,14 +724,9 @@ void netvsc_device_remove(struct hv_device *device)
>  	/* Now, we can close the channel safely */
>  	vmbus_close(device->channel);

[Severity: High]
This isn't a bug introduced by this patch, but is it possible for a=20
concurrent TX path to race here and cause a use-after-free or NULL=20
pointer dereference?

In drivers/net/hyperv/netvsc_drv.c:netvsc_remove(),=20
rndis_filter_device_remove() is called before unregister_netdevice(),
which stops the TX queues:

netvsc_remove() {
	if (nvdev)
		rndis_filter_device_remove(dev, nvdev);
=09
	unregister_netdevice(net);
}

When netvsc_device_remove() (called from rndis_filter_device_remove)=20
clears the net_device_ctx->nvdev pointer and immediately calls=20
vmbus_close(), it doesn't wait for concurrent RCU readers like=20
netvsc_start_xmit() to finish.

If a concurrent TX thread has already read the pointer, couldn't it
proceed to write to the VMBus ring buffer, which has just been freed
and unmapped by vmbus_close()?

> -	/*
> -	 * If host is Win2016 or higher then we do the GPADL tear down
> -	 * here after VMBus is closed.
> -	*/
> -	if (vmbus_proto_version >=3D VERSION_WIN10) {
> -		netvsc_teardown_recv_gpadl(device, net_device, ndev);
> -		netvsc_teardown_send_gpadl(device, net_device, ndev);
> -	}
> +	/* Must do the GPADL teardown after channel is closed */
> +	netvsc_teardown_recv_gpadl(device, net_device, ndev);

[Severity: Critical]
This is a pre-existing issue, but does this teardown sequence handle=20
vmbus_post_msg() failures correctly?

Looking at drivers/hv/channel.c:vmbus_teardown_gpadl(), it appears to
mask the failure code for non-confidential VMs:

vmbus_teardown_gpadl() {
post_msg_err:
	/* ... */
	if (gpadl->decrypted)
		ret =3D set_memory_encrypted((unsigned long)gpadl->buffer,
					PFN_UP(gpadl->size));
	else
		ret =3D 0;
}

If vmbus_post_msg() fails (e.g., returning -ENOBUFS), this overwrites=20
the error with 0. The caller, netvsc_teardown_recv_gpadl(), assumes=20
a return value of 0 means the host successfully tore down the GPADL:

netvsc_teardown_recv_gpadl() {
	if (net_device->recv_buf_gpadl_handle.gpadl_handle) {
		ret =3D vmbus_teardown_gpadl(device->channel,
					   &net_device->recv_buf_gpadl_handle);
		/* If we failed here, we might as well return and have a leak
		 * rather than continue and a bugchk
		 */
		if (ret !=3D 0) { ... }
	}
}

Since vmbus_teardown_gpadl() silently returns 0 on failure, the network
driver will proceed to free the receive/send buffers.

Could the host still consider these buffers active and overwrite the newly
freed memory with incoming network packets, leading to guest memory=20
corruption?

> +	netvsc_teardown_send_gpadl(device, net_device, ndev);
> =20
>  	/* Release all resources */
>  	free_netvsc_device_rcu(net_device);

--=20
Sashiko AI review =C2=B7 https://sashiko.dev/#/patchset/20260805203751.2678=
[email protected]?part=3D3