From: "Michael S. Tsirkin" <mst@redhat.com>
To: Stefano Garzarella <sgarzare@redhat.com>
Cc: jrmmhm.kernel@eldare.de, "Stefan Hajnoczi" <stefanha@redhat.com>,
"Bobby Eshleman" <bobbyeshleman@meta.com>,
"Jason Wang" <jasowangio@gmail.com>,
"Eugenio Pérez" <eperezma@redhat.com>,
"Xuan Zhuo" <xuanzhuo@linux.alibaba.com>,
"David S. Miller" <davem@davemloft.net>,
"Eric Dumazet" <edumazet@kernel.org>,
"Jakub Kicinski" <kuba@kernel.org>,
"Paolo Abeni" <pabeni@redhat.com>,
"Simon Horman" <horms@kernel.org>,
virtualization@lists.linux.dev, kvm@vger.kernel.org,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
stable@vger.kernel.org
Subject: Re: [PATCH net v2] vsock/virtio: clear vqs[] to avoid a UAF on a failed PM restore
Date: Fri, 30 Oct 2026 10:21:09 -0400 [thread overview]
Message-ID: <20261030101918-mutt-send-email-mst@kernel.org> (raw)
In-Reply-To: <auSZtMqcTz3r1nRk@sgarzare-redhat>
On Fri, Oct 30, 2026 at 02:51:26PM +0100, Stefano Garzarella wrote:
> On Wed, Oct 28, 2026 at 07:22:43PM +0100, Jerome Mohm via B4 Relay wrote:
> > From: Jerome Mohm <jrmmhm.kernel@eldare.de>
> >
> > virtio_vsock_vqs_del() frees the virtqueues via del_vqs() but never
> > clears vsock->vqs[]. If a later virtio_vsock_restore() fails to
> > reallocate them (its error path is a bare "goto out" that only unlocks
> > and returns), the driver is left bound with a dangling vqs[]. The next
> > virtio_vsock_vqs_del() - on a second freeze or on remove/unbind - then
> > passes a freed vring_virtqueue to virtqueue_detach_unused_buf(), a slab
> > use-after-free. KASAN on a guest with a virtio-vsock device on
> > virtio-pci, after a restore made to fail by fault injection:
> >
> > BUG: KASAN: slab-use-after-free in virtqueue_detach_unused_buf
> > Read of size 4 at addr ... by task repro
> > virtqueue_detach_unused_buf
> > virtio_vsock_vqs_del (net/vmw_vsock/virtio_transport.c:785)
> > virtio_vsock_remove
> > virtio_dev_remove
> > ... unbind_store
> > Freed by task ...:
> > kfree
> > vp_del_vqs
> > virtio_vsock_freeze <- the preceding freeze freed the vq
> > Allocated by task 1:
> > vring_create_virtqueue
> > virtio_vsock_vqs_init
> > virtio_vsock_probe <- original allocation at probe
> >
> > That second virtio_vsock_vqs_del() also repeats del_vqs(), which not
> > every transport tolerates. virtio-mmio's vm_del_vqs() always ends in
> > free_irq(), but after the failed vm_find_vqs() the device no longer
> > holds its IRQ, so on virtio-mmio the second call also warns:
> >
> > Trying to free already-free IRQ 51
> > WARNING: kernel/irq/manage.c:1894 at free_irq+0x23e/0x840
> > vm_del_vqs
> > virtio_vsock_vqs_del
> > virtio_vsock_remove (or virtio_vsock_freeze)
> >
> > virtio-pci's vp_del_vqs() is idempotent, so the PCI case shows only
> > the use-after-free.
> >
> > Clear vsock->vqs[] after del_vqs() and when virtio_find_vqs() fails in
> > virtio_vsock_vqs_init(), and treat an empty vqs[] as "no virtqueues
> > are live": virtio_vsock_vqs_del() then still resets the device
> > (virtio_dev_remove() expects a reset device) and purges the send
> > queue, but skips the detach loops and del_vqs(). find_vqs() cleans up
> > after itself on failure, so skipping the second del_vqs() leaks
> > nothing. Clearing the stale pointers follows virtio_blk
> > commit 0739c2c6a015 ("virtio_blk: NULL out vqs to avoid double free on
> > failed resume").
> >
> > The use-after-free was found with the help of an LLM coding assistant
> > (Anthropic's Claude); the free_irq() warning on virtio-mmio was reported
> > by the netdev Sashiko AI review of an earlier version of this patch.
> >
> > Testing: on a private VM with a KASAN fuzz kernel, over virtio-pci and
> > over virtio-mmio (QEMU microvm). The restore allocation failure was
> > forced with CONFIG_FAILSLAB steered by the fault-injection stacktrace
> > filter to the virtio-vsock restore path only; a guest-root program
> > drives a pm_test=devices freeze/restore cycle (so .restore returns
> > -ENOMEM) and then unbinds the device, or runs a second freeze/restore
> > cycle. Without a fix (v7.3-rc5 based) the PCI run reports the
> > slab-use-after-free above. With only the vqs[] clearing (v1 of this
> > patch, on net 363c8c79220d) the MMIO runs report the free_irq warning on
> > remove and on the second freeze. With this patch on the same base,
> > restore still fails with -ENOMEM on both transports and neither report
> > appears; the device works again after a second, successful
> > freeze/restore cycle and after unbind/bind, and a normal freeze/restore
> > and unbind/bind still leave a working device. A find_vqs() failure after
> > some virtqueues were set up was not exercised (each restore attempt
> > failed at its first allocation, before any virtqueue was set up); that
> > clear is covered by code reading only. The three single-VM tests of
> > tools/testing/selftests/vsock/vmtest.sh (vm_server_host_client,
> > vm_client_host_server, vm_loopback; 44 vsock_test cases each) pass on
> > this tree, as on net; on both kernels the host-side runs skip the SO_INQ
> > cases (SO_INQ not supported by the host kernel). The ns_* tests of
> > vmtest.sh were not run (they need root on the host). checkpatch.pl
> > --strict is clean and the fuzz-config build is warning-free. The
>
> Do we really need to write in a commit message that checkpatch.pl --strict
> is clean?
>
> Descriptive commits are great, but we're going a bit too far here.
It's just what AI writes if you tell it to make it checkpatch.pl
clean in the prompt.
> Please
> include only the relevant information; for example, I think the part after
> "Testing:" could be summarized in a few lines or removed altogether.
Yea please write it yourself and make it concise. My eyes glazed over
in the 1st paragraph.
> > reproducer needs guest root, CONFIG_FAILSLAB with
> > CONFIG_FAULT_INJECTION_DEBUG_FS and
> > CONFIG_FAULT_INJECTION_STACKTRACE_FILTER, and CONFIG_HIBERNATION with
> > CONFIG_PM_DEBUG for pm_test; it is available on request.
> >
> > Fixes: bd50c5dc182b ("vsock/virtio: add support for device suspend/resume")
> > Cc: stable@vger.kernel.org
> > Signed-off-by: Jerome Mohm <jrmmhm.kernel@eldare.de>
> > ---
> > The use-after-free was found with the help of Anthropic's Claude; the
> > virtio-mmio warning comes from the netdev Sashiko review.
>
> This is already in the commit description, no?
>
> >
> > Changes in v2:
> > - Skip the detach loops and del_vqs() in virtio_vsock_vqs_del() when no
> > virtqueues are live, so the teardown after a failed restore does not
> > free virtio-mmio's IRQ a second time (Sashiko review).
> > - Use an empty vqs[] as the 'no live virtqueues' marker instead of v1's
> > per-loop NULL checks, and purge the send queue before the early
> > return.
> > - Commit message: cite only virtio_blk 0739c2c6a015; drop the wrong
> > virtio_rtc and virtio_console references (Sashiko review). Drop the
> > commit ID from the code comment.
> > - Tested on virtio-mmio (QEMU microvm) as well as virtio-pci.
> > - Drop the Assisted-by trailer (removed upstream); tool use is
> > disclosed above instead.
> > - Link to v1: https://patch.msgid.link/20261001-vsock-restore-uaf-send-v1-1-5da60f707506@eldare.de
> > ---
> > net/vmw_vsock/virtio_transport.c | 24 +++++++++++++++++++++---
> > 1 file changed, 21 insertions(+), 3 deletions(-)
> >
> > diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
> > index 4f9aa9c4c3aa..bba594b7fc14 100644
> > --- a/net/vmw_vsock/virtio_transport.c
> > +++ b/net/vmw_vsock/virtio_transport.c
> > @@ -714,8 +714,14 @@ static int virtio_vsock_vqs_init(struct virtio_vsock *vsock)
> > atomic_set(&vsock->queued_replies, 0);
> >
> > ret = virtio_find_vqs(vdev, VSOCK_VQ_MAX, vsock->vqs, vqs_info, NULL);
> > - if (ret < 0)
> > + if (ret < 0) {
> > + /* On failure virtio_find_vqs() can leave freed virtqueues or
> > + * error pointers in vsock->vqs[]. Clear it: an empty vqs[]
> > + * tells virtio_vsock_vqs_del() that no virtqueues are live.
> > + */
> > + memset(vsock->vqs, 0, sizeof(vsock->vqs));
>
> Should we move this in the virtio_find_vqs() ?
>
> Maybe not for this patch, but for long term it could be a good idea IMO.
>
> > return ret;
> > + }
> >
> > virtio_vsock_update_guest_cid(vsock);
> >
> > @@ -781,6 +787,15 @@ static void virtio_vsock_vqs_del(struct virtio_vsock *vsock)
> > */
> > virtio_reset_device(vdev);
> >
> > + virtio_vsock_skb_queue_purge(&vsock->send_pkt_queue);
> > +
> > + /* No virtqueues are live, e.g. after a failed restore: they were
> > + * already deleted, and a second del_vqs() is not safe on every
> > + * transport (virtio-mmio would free its IRQ again).
> > + */
> > + if (!vsock->vqs[VSOCK_VQ_RX])
> > + return;
> > +
> > mutex_lock(&vsock->rx_lock);
> > while ((skb = virtqueue_detach_unused_buf(vsock->vqs[VSOCK_VQ_RX])))
> > kfree_skb(skb);
> > @@ -791,10 +806,13 @@ static void virtio_vsock_vqs_del(struct virtio_vsock *vsock)
> > kfree_skb(skb);
> > mutex_unlock(&vsock->tx_lock);
> >
> > - virtio_vsock_skb_queue_purge(&vsock->send_pkt_queue);
> > -
> > /* Delete virtqueues and flush outstanding callbacks if any */
> > vdev->config->del_vqs(vdev);
> > +
> > + /* The virtqueues are freed: clear the stale pointers, so that a
> > + * virtio_vsock_vqs_del() after a failed restore skips them.
> > + */
> > + memset(vsock->vqs, 0, sizeof(vsock->vqs));
>
> Same above, should we introduce a virtio_del_vqs() to do both and call it in
> all drivers?
>
> Or skip del_vqs() if vdev->vqs is empty.
>
> I guess this issue could be spread around virtio drivers, so would be nice
> to add common API in the virtio core to be used in all of them.
>
> That said, for a fix, this patch LGTM, my comments were more for a long term
> work.
>
> With a fixed commit message I can give my R-b.
>
> Thanks,
> Stefano
>
> > }
> >
> > static int virtio_vsock_probe(struct virtio_device *vdev)
> >
> > ---
> > base-commit: 363c8c79220d0db4d65dcd570529ddda15067cb5
> > change-id: 20261001-vsock-restore-uaf-send-1fc7396fa1bd
> >
> > Best regards,
> > --
> > Jerome Mohm <jrmmhm.kernel@eldare.de>
> >
> >
prev parent reply other threads:[~2026-10-30 14:21 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-28 18:22 [PATCH net v2] vsock/virtio: clear vqs[] to avoid a UAF on a failed PM restore Jerome Mohm via B4 Relay
2026-10-30 13:51 ` Stefano Garzarella
2026-10-30 14:21 ` Michael S. Tsirkin [this message]
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=20261030101918-mutt-send-email-mst@kernel.org \
--to=mst@redhat.com \
--cc=bobbyeshleman@meta.com \
--cc=davem@davemloft.net \
--cc=edumazet@kernel.org \
--cc=eperezma@redhat.com \
--cc=horms@kernel.org \
--cc=jasowangio@gmail.com \
--cc=jrmmhm.kernel@eldare.de \
--cc=kuba@kernel.org \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=sgarzare@redhat.com \
--cc=stable@vger.kernel.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