Linux virtualization list
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Haishuang Yan" <yanhaishuang@cmss.chinamobile.com>
Cc: virtualization@lists.linux.dev, bpf@vger.kernel.org,
	"Michael S. Tsirkin" <mst@redhat.com>,
	"Eugenio Perez" <eperezma@redhat.com>
Subject: Re: [PATCH net v2 3/3] virtio_net: Keep AF_XDP zero-copy pools bound across suspend
Date: Mon, 09 Nov 2026 11:39:33 +0000	[thread overview]
Message-ID: <sashiko-outbox-204885@kernel.org> (raw)
In-Reply-To: <20261108193845.73621-4-yanhaishuang@cmss.chinamobile.com>

Thank you for your contribution! Sashiko AI review found 4 potential
issues to consider:
- [High] virtio_net: virtnet_xsk_pools_attach() attaches unmapped AF_XDP
  pool
- [Medium] virtio_net: UAF on vi->rq in virtnet_xsk_pool_disable() after
  failed restore
- [Medium] virtio_net: DMA map leak in virtnet_xsk_pool_disable() after
  XDP detach
- [Medium] virtio_net: missing rtnl_lock() around xsk_pool_dma_unmap()
  on freeze
--

commit f8bbdffa48d34460262d93d81019cacaef0e299f
Author: Haishuang Yan <yanhaishuang@cmss.chinamobile.com>

virtio_net: Keep AF_XDP zero-copy pools bound across suspend

This commit preserves AF_XDP zero-copy pools across suspend and resume by
releasing only the per-queue driver state on freeze while keeping the pools
DMA-mapped, then re-attaching them to the newly allocated queues on
restore.

> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index f9d227060375c..d9c920f421268 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c

[ ... ]

> @@ -5808,6 +5810,7 @@ static int virtnet_restore_up(struct virtio_device *vdev)
>  err_destroy_pools:
>  	virtio_reset_device(vdev);
>  	free_unused_bufs(vi);
> +	virtnet_xsk_pools_release(vi);
>  	virtnet_destroy_page_pools(vi);
>  	virtnet_del_vqs(vi);
>  	return err;
> @@ -6038,6 +6041,13 @@ static int virtnet_xsk_pool_disable(struct net_device *dev, u16 qid)
>  	rq = &vi->rq[qid];
>  
>  	pool = rq->xsk_pool;
> +	if (!pool) {
> +		/* Binding it again on restore failed, only the DMA map is left */
> +		pool = xsk_get_pool_from_qid(dev, qid);
> +		if (pool)
> +			xsk_pool_dma_unmap(pool, 0);
> +		return 0;
> +	}

[Severity: Medium]
Can virtnet_xsk_pool_disable() dereference a freed or NULL vi->rq after a
failed restore?

If virtnet_restore_up() fails (for example at err_destroy_pools, or
earlier in init_vqs()), virtnet_del_vqs() -> virtnet_free_queues() frees
vi->rq and vi->sq while the net_device and bound AF_XDP pools remain
registered.  When the socket is later closed, virtnet_xsk_pool_disable()
reads vi->rq[qid].xsk_pool from the dangling vi->rq pointer.

[Severity: Medium]
Can this fallback also leak the pool's DMA mappings if XDP is detached
before the socket is closed?

When virtnet_xsk_pool_attach() fails on restore for a pool bound to an XDP
queue (qid >= curr_qp), rq->xsk_pool is left NULL while the pool stays
DMA-mapped.  If the XDP program is then removed via virtnet_xdp_set(),
netif_set_real_num_rx_queues() lowers dev->real_num_rx_queues to
curr_qp <= qid (and dev->real_num_tx_queues is also curr_qp).  When the
socket is subsequently closed, xsk_get_pool_from_qid(dev, qid) returns
NULL because qid is no longer below real_num_rx_queues or
real_num_tx_queues, skipping xsk_pool_dma_unmap().

Unmapping the pool directly in virtnet_xsk_pools_attach() when
virtnet_xsk_pool_attach() fails would avoid leaving a half-bound DMA map
behind.

> @@ -6053,6 +6063,133 @@ static int virtnet_xsk_pool_disable(struct net_device *dev, u16 qid)
>  	return err;
>  }
>  
> +/*
> + * Freeze frees the receive and send queues, but the AF_XDP sockets stay
> + * bound and the xsk core keeps their pools. Release only the driver state
> + * of the zero-copy pools here, once the device is reset and the buffers
> + * posted to it are back in the pools. The pools stay DMA mapped, since the
> + * DMA device is still the same after restore and the buffers on their free
> + * lists keep their DMA addresses.
> + *
> + * A pool left above curr_queue_pairs by removing XDP is not bound again
> + * on restore, so unmap it as well.
> + */
> +static void virtnet_xsk_pools_release(struct virtnet_info *vi)
> +{
> +	int i;
> +
> +	for (i = 0; i < vi->max_queue_pairs; i++) {
> +		struct receive_queue *rq = &vi->rq[i];
> +		struct send_queue *sq = &vi->sq[i];
> +
> +		if (rq->xsk_pool) {
> +			if (i >= vi->curr_queue_pairs)
> +				xsk_pool_dma_unmap(rq->xsk_pool, 0);

[Severity: Medium]
Does calling xsk_pool_dma_unmap() here without holding rtnl_lock() race on
pool->umem->xsk_dma_list?

remove_vq_common() calls virtnet_xsk_pools_release() outside rtnl_lock()
during virtnet_freeze().  xp_dma_unmap() walks and deletes entries from
pool->umem->xsk_dma_list, which is protected by rtnl_lock.  If an xdp_umem
is shared across multiple devices via XDP_SHARED_UMEM, concurrent async
suspends can corrupt xsk_dma_list.

[ ... ]

> +/*
> + * On restore, set the zero-copy pools up again on the new queues before
> + * they are filled and their NAPI is enabled.
> + */
> +static void virtnet_xsk_pools_attach(struct virtnet_info *vi)
> +{
> +	struct xsk_buff_pool *pool;
> +	int i, err;
> +
> +	ASSERT_RTNL();
> +
> +	for (i = 0; i < vi->curr_queue_pairs; i++) {
> +		pool = xsk_get_pool_from_qid(vi->dev, i);
> +		if (!pool || !pool->umem->zc)
> +			continue;
> +
> +		/* The pool stays DMA mapped until it is disabled */
> +		err = virtnet_xsk_pool_attach(vi, i, pool);

[Severity: High]
Can virtnet_xsk_pools_attach() re-attach a pool that was already
DMA-unmapped by virtnet_xsk_pools_release()?

If a pool is bound to an XDP queue qid, detaching XDP lowers
vi->curr_queue_pairs below qid, and the next freeze unmaps the pool in
virtnet_xsk_pools_release() via xsk_pool_dma_unmap().  xp_dma_unmap() sets
pool->dma_pages = NULL and pool->dev = NULL, but pool->umem->zc and
dev->_rx[qid].pool remain set.  If XDP is re-attached after resume (raising
vi->curr_queue_pairs above qid again) and the system suspends a second
time, virtnet_xsk_pools_attach() sees pool->umem->zc == true and attaches
the unmapped pool to the queue, leading to a NULL pointer dereference on
pool->dma_pages or pool->dev during RX/TX.

Should this check pool->dma_pages instead of pool->umem->zc, or re-map the
pool when pool->dma_pages is NULL?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261108193845.73621-1-yanhaishuang@cmss.chinamobile.com?part=3

  reply	other threads:[~2026-11-09 11:39 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-08 19:38 [PATCH net v2 0/3] virtio_net: AF_XDP zero-copy fixes for arm64 and suspend Haishuang Yan
2026-11-08 19:38 ` [PATCH net v2 1/3] virtio_net: Don't DMA map the kernel image for the AF_XDP TX header Haishuang Yan
2026-11-09 11:39   ` sashiko-bot
2026-11-08 19:38 ` [PATCH net v2 2/3] virtio_net: Disable AF_XDP pools on queues above curr_queue_pairs Haishuang Yan
2026-11-09 11:39   ` sashiko-bot
2026-11-09 12:34   ` netdev-bot+sashiko
2026-11-10 11:20     ` Haishuang Yan
2026-11-08 19:38 ` [PATCH net v2 3/3] virtio_net: Keep AF_XDP zero-copy pools bound across suspend Haishuang Yan
2026-11-09 11:39   ` sashiko-bot [this message]
2026-11-09 12:34   ` netdev-bot+sashiko
2026-11-10 11:21     ` Haishuang Yan

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=sashiko-outbox-204885@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=eperezma@redhat.com \
    --cc=mst@redhat.com \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=virtualization@lists.linux.dev \
    --cc=yanhaishuang@cmss.chinamobile.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