* [PATCH v3 0/3] virtio: fix callback synchronization and avq cleanup on reset
@ 2026-09-11 21:20 Michael S. Tsirkin
2026-09-11 21:20 ` [PATCH v3 1/3] virtio: synchronize callbacks after device reset Michael S. Tsirkin
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Michael S. Tsirkin @ 2026-09-11 21:20 UTC (permalink / raw)
To: virtualization
Cc: jasowangio, eperezma, xuanzhuo, jiri, kmehltretter, sashiko-bot,
linux-kernel
Two issues with virtio device reset:
1. Karl Mehltretter reported that virtio_reset_device() promises
callbacks are not in progress after reset, but only PCI transports
actually synchronize callbacks - other transports leave a window
where a handler already executing keeps running while the driver
tears down state.
2. sashiko reported a race in virtio_pci_modern: the avq interrupt
handler calls virtqueue_get_buf concurrently with
virtqueue_detach_unused_buf in vp_modern_avq_cleanup, and there
is no synchronize_irq between reset and cleanup.
Fix 1 by adding virtio_synchronize_cbs in the core after reset,
then dropping the now-redundant per-transport sync calls. Fix 2 by
moving avq cleanup from vp_reset to vp_del_vqs, which runs after
callbacks have been synchronized - and is where buffer teardown
conceptually belongs.
Changes v2->v3:
patch 1: unchanged
patch 2: split from v2 patch 2 - legacy part only
patch 3: new - v2 just dropped the sync from modern vp_reset,
leaving avq_cleanup there before the removed sync. v3
moves avq_cleanup out of vp_reset entirely into vp_del_vqs,
fixing the race. Adds NULL check for admin_vq.info needed
because find_vqs error paths call vp_del_vqs before it is
allocated.
Michael S. Tsirkin (3):
virtio: synchronize callbacks after device reset
virtio_pci_legacy: drop callback sync on reset
virtio_pci_modern: move avq cleanup from reset to del_vqs
drivers/virtio/virtio.c | 2 ++
drivers/virtio/virtio_pci_common.c | 2 ++
drivers/virtio/virtio_pci_common.h | 1 +
drivers/virtio/virtio_pci_legacy.c | 2 --
drivers/virtio/virtio_pci_modern.c | 10 ++++------
5 files changed, 9 insertions(+), 8 deletions(-)
--
MST
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v3 1/3] virtio: synchronize callbacks after device reset 2026-09-11 21:20 [PATCH v3 0/3] virtio: fix callback synchronization and avq cleanup on reset Michael S. Tsirkin @ 2026-09-11 21:20 ` Michael S. Tsirkin 2026-09-11 22:50 ` Karl Mehltretter 2026-09-11 21:20 ` [PATCH v3 3/3] virtio_pci_modern: move avq cleanup from reset to del_vqs Michael S. Tsirkin 2026-09-11 21:20 ` [PATCH v3 2/3] virtio_pci_legacy: drop callback sync on reset Michael S. Tsirkin 2 siblings, 1 reply; 8+ messages in thread From: Michael S. Tsirkin @ 2026-09-11 21:20 UTC (permalink / raw) To: virtualization Cc: jasowangio, eperezma, xuanzhuo, jiri, kmehltretter, sashiko-bot, linux-kernel virtio_reset_device says: Note: this guarantees that vq callbacks are not in progress but in practice, only virtio pci correctly synchronizes the cbs. On other transports, a callback that is already executing, keeps running while the driver tears down the state it uses. Add virtio_synchronize_cbs to virtio_reset_device fixing this for all transports that correctly implement synchronize_cbs(). Reported-by: Karl Mehltretter <kmehltretter@gmail.com> Link: https://lore.kernel.org/all/20260818040433.66986-1-kmehltretter@gmail.com/ Fixes: c46eccdaadab ("virtio: document virtio_reset_device") Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Assisted-by: LLM --- Changes v2->v3: unchanged drivers/virtio/virtio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index b6c9e927bef5..a8588d7ad109 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -264,6 +264,8 @@ void virtio_reset_device(struct virtio_device *dev) #endif dev->config->reset(dev); + /* Flush pending VQ/configuration callbacks. */ + virtio_synchronize_cbs(dev); } EXPORT_SYMBOL_GPL(virtio_reset_device); -- MST ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v3 1/3] virtio: synchronize callbacks after device reset 2026-09-11 21:20 ` [PATCH v3 1/3] virtio: synchronize callbacks after device reset Michael S. Tsirkin @ 2026-09-11 22:50 ` Karl Mehltretter 0 siblings, 0 replies; 8+ messages in thread From: Karl Mehltretter @ 2026-09-11 22:50 UTC (permalink / raw) To: Michael S. Tsirkin Cc: virtualization, jasowangio, eperezma, xuanzhuo, jiri, sashiko-bot, linux-kernel On Fri, Sep 11, 2026 at 05:20:09PM +0100, Michael S. Tsirkin wrote: > Add virtio_synchronize_cbs to virtio_reset_device fixing this for all > transports that correctly implement synchronize_cbs(). > I ran 1,200 instrumented virtio-input reset cycles on x86-64 PCI and arm64 virtio-mmio under KASAN, KCSAN and lockdep. All 173 callback/reset overlaps completed before reset returned. Tested-by: Karl Mehltretter <kmehltretter@gmail.com> Acked-by: Karl Mehltretter <kmehltretter@gmail.com> Thanks, Karl ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v3 3/3] virtio_pci_modern: move avq cleanup from reset to del_vqs 2026-09-11 21:20 [PATCH v3 0/3] virtio: fix callback synchronization and avq cleanup on reset Michael S. Tsirkin 2026-09-11 21:20 ` [PATCH v3 1/3] virtio: synchronize callbacks after device reset Michael S. Tsirkin @ 2026-09-11 21:20 ` Michael S. Tsirkin 2026-09-11 22:48 ` Karl Mehltretter 2026-09-11 21:20 ` [PATCH v3 2/3] virtio_pci_legacy: drop callback sync on reset Michael S. Tsirkin 2 siblings, 1 reply; 8+ messages in thread From: Michael S. Tsirkin @ 2026-09-11 21:20 UTC (permalink / raw) To: virtualization Cc: jasowangio, eperezma, xuanzhuo, jiri, kmehltretter, sashiko-bot, linux-kernel vp_modern_avq_cleanup() detaches unused buffers from the admin virtqueue and completes pending commands with -EIO. Calling it from vp_reset() is incorrect: virtqueue_get_buf in the avq interrupt handler can race with virtqueue_detach_unused_buf in cleanup, and get_buf after detach is not documented as valid. The root cause is that detaching buffers does not belong in reset at all - reset quiesces the device, while cleanup belongs where the virtqueue is about to be destroyed, in del_vqs. Move the call to vp_del_vqs(), which runs after virtio_synchronize_cbs() has already guaranteed that no interrupt handler is in progress, eliminating the race. Reported-by: sashiko-bot@kernel.org Closes: https://lore.kernel.org/virtualization/20260911125745.E0A2F1F00899@smtp.kernel.org/ Fixes: 4c3b54af907e ("virtio_pci_modern: use completion instead of busy loop to wait on admin cmd result") Cc: Jiri Pirko <jiri@resnulli.us> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Assisted-by: LLM --- New in v3. v2 dropped sync from modern vp_reset in one combined patch, leaving avq_cleanup in vp_reset. v3 moves avq_cleanup out of vp_reset entirely into vp_del_vqs, fixing the race. Adds NULL check for admin_vq.info for find_vqs error paths. drivers/virtio/virtio_pci_common.c | 2 ++ drivers/virtio/virtio_pci_common.h | 1 + drivers/virtio/virtio_pci_modern.c | 10 ++++------ 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c index b90c174450b2..28b254ee4726 100644 --- a/drivers/virtio/virtio_pci_common.c +++ b/drivers/virtio/virtio_pci_common.c @@ -270,6 +270,8 @@ void vp_del_vqs(struct virtio_device *vdev) struct virtqueue *vq, *n; int i; + vp_modern_avq_cleanup(vdev); + list_for_each_entry_safe(vq, n, &vdev->vqs, list) { info = vp_is_avq(vdev, vq->index) ? vp_dev->admin_vq.info : vp_dev->vqs[vq->index]; diff --git a/drivers/virtio/virtio_pci_common.h b/drivers/virtio/virtio_pci_common.h index 8cd01de27baf..a4ff6ec903a3 100644 --- a/drivers/virtio/virtio_pci_common.h +++ b/drivers/virtio/virtio_pci_common.h @@ -194,6 +194,7 @@ struct virtio_device *virtio_pci_vf_get_pf_dev(struct pci_dev *pdev); #endif bool vp_is_avq(struct virtio_device *vdev, unsigned int index); +void vp_modern_avq_cleanup(struct virtio_device *vdev); void vp_modern_avq_done(struct virtqueue *vq); int vp_modern_admin_cmd_exec(struct virtio_device *vdev, struct virtio_admin_cmd *cmd); diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci_modern.c index 6d8ae2a6a8ca..ef76f35c6b2c 100644 --- a/drivers/virtio/virtio_pci_modern.c +++ b/drivers/virtio/virtio_pci_modern.c @@ -345,7 +345,7 @@ static void vp_modern_avq_activate(struct virtio_device *vdev) virtio_pci_admin_cmd_cap_init(vdev); } -static void vp_modern_avq_cleanup(struct virtio_device *vdev) +void vp_modern_avq_cleanup(struct virtio_device *vdev) { struct virtio_pci_device *vp_dev = to_vp_device(vdev); struct virtio_admin_cmd *cmd; @@ -354,6 +354,9 @@ static void vp_modern_avq_cleanup(struct virtio_device *vdev) if (!virtio_has_feature(vdev, VIRTIO_F_ADMIN_VQ)) return; + if (!vp_dev->admin_vq.info) + return; + vq = vp_dev->admin_vq.info->vq; if (!vq) return; @@ -557,11 +560,6 @@ static void vp_reset(struct virtio_device *vdev) */ while (vp_modern_get_status(mdev)) msleep(1); - - vp_modern_avq_cleanup(vdev); - - /* Flush pending VQ/configuration callbacks. */ - vp_synchronize_vectors(vdev); } static int vp_active_vq(struct virtqueue *vq, u16 msix_vec) -- MST ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v3 3/3] virtio_pci_modern: move avq cleanup from reset to del_vqs 2026-09-11 21:20 ` [PATCH v3 3/3] virtio_pci_modern: move avq cleanup from reset to del_vqs Michael S. Tsirkin @ 2026-09-11 22:48 ` Karl Mehltretter 2026-09-11 22:51 ` Michael S. Tsirkin 0 siblings, 1 reply; 8+ messages in thread From: Karl Mehltretter @ 2026-09-11 22:48 UTC (permalink / raw) To: Michael S. Tsirkin Cc: virtualization, jasowangio, eperezma, xuanzhuo, jiri, sashiko-bot, linux-kernel On Fri, Sep 11, 2026 at 05:20:15PM +0100, Michael S. Tsirkin wrote: > New in v3. v2 dropped sync from modern vp_reset in one combined > patch, leaving avq_cleanup in vp_reset. v3 moves avq_cleanup out > of vp_reset entirely into vp_del_vqs, fixing the race. Adds NULL > check for admin_vq.info for find_vqs error paths. > I think patch 3 introduces a use-after-free in the MSI-X setup error path. With VP_VQ_VECTOR_POLICY_EACH, vp_setup_vq() stores the admin queue's info pointer before request_irq(). If request_irq() fails, vp_del_vq() frees info but leaves admin_vq.info set. vp_find_vqs_msix() then calls vp_del_vqs(). vp_del_vqs() now calls vp_modern_avq_cleanup() first and dereferences the freed pointer: vq = vp_dev->admin_vq.info->vq; No interrupt needs to fire. I reproduced this on v3 with KASAN by returning -ENOMEM only for the admin queue's request_irq(): BUG: KASAN: slab-use-after-free in vp_modern_avq_cleanup+0xf4/0x110 KASAN shows the allocation in vp_setup_vq(), the free in vp_find_one_vq_msix(), and the access in vp_modern_avq_cleanup(). Adding *p_info = NULL after vp_del_vq() made the same test fall back and boot without a KASAN report. Thanks, Karl ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v3 3/3] virtio_pci_modern: move avq cleanup from reset to del_vqs 2026-09-11 22:48 ` Karl Mehltretter @ 2026-09-11 22:51 ` Michael S. Tsirkin 0 siblings, 0 replies; 8+ messages in thread From: Michael S. Tsirkin @ 2026-09-11 22:51 UTC (permalink / raw) To: Karl Mehltretter Cc: virtualization, jasowangio, eperezma, xuanzhuo, jiri, sashiko-bot, linux-kernel On Sat, Sep 12, 2026 at 12:48:54AM +0200, Karl Mehltretter wrote: > On Fri, Sep 11, 2026 at 05:20:15PM +0100, Michael S. Tsirkin wrote: > > New in v3. v2 dropped sync from modern vp_reset in one combined > > patch, leaving avq_cleanup in vp_reset. v3 moves avq_cleanup out > > of vp_reset entirely into vp_del_vqs, fixing the race. Adds NULL > > check for admin_vq.info for find_vqs error paths. > > > > I think patch 3 introduces a use-after-free in the MSI-X setup error > path. > > With VP_VQ_VECTOR_POLICY_EACH, vp_setup_vq() stores the admin queue's > info pointer before request_irq(). If request_irq() fails, vp_del_vq() > frees info but leaves admin_vq.info set. > > vp_find_vqs_msix() then calls vp_del_vqs(). vp_del_vqs() now calls > vp_modern_avq_cleanup() first and dereferences the freed pointer: > > vq = vp_dev->admin_vq.info->vq; > > No interrupt needs to fire. > > I reproduced this on v3 with KASAN by returning -ENOMEM only for the > admin queue's request_irq(): > > BUG: KASAN: slab-use-after-free in vp_modern_avq_cleanup+0xf4/0x110 > > KASAN shows the allocation in vp_setup_vq(), the free in > vp_find_one_vq_msix(), and the access in vp_modern_avq_cleanup(). Adding > *p_info = NULL after vp_del_vq() made the same test fall back and boot > without a KASAN report. > > Thanks, > Karl Right. Besides, poking at modern from common is ugly. I'll rework this, thanks a lot for the testing! -- MST ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v3 2/3] virtio_pci_legacy: drop callback sync on reset 2026-09-11 21:20 [PATCH v3 0/3] virtio: fix callback synchronization and avq cleanup on reset Michael S. Tsirkin 2026-09-11 21:20 ` [PATCH v3 1/3] virtio: synchronize callbacks after device reset Michael S. Tsirkin 2026-09-11 21:20 ` [PATCH v3 3/3] virtio_pci_modern: move avq cleanup from reset to del_vqs Michael S. Tsirkin @ 2026-09-11 21:20 ` Michael S. Tsirkin 2026-09-11 22:51 ` Karl Mehltretter 2 siblings, 1 reply; 8+ messages in thread From: Michael S. Tsirkin @ 2026-09-11 21:20 UTC (permalink / raw) To: virtualization Cc: jasowangio, eperezma, xuanzhuo, jiri, kmehltretter, sashiko-bot, linux-kernel The virtio core now synchronizes callbacks after reset, so the legacy PCI transport no longer needs to do it itself. Assisted-by: LLM Signed-off-by: Michael S. Tsirkin <mst@redhat.com> --- Changes v2->v3: split from v2 patch 2 (legacy part only) drivers/virtio/virtio_pci_legacy.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/virtio/virtio_pci_legacy.c b/drivers/virtio/virtio_pci_legacy.c index d9cbb02b35a1..8115aa39e01e 100644 --- a/drivers/virtio/virtio_pci_legacy.c +++ b/drivers/virtio/virtio_pci_legacy.c @@ -98,8 +98,6 @@ static void vp_reset(struct virtio_device *vdev) /* Flush out the status write, and flush in device writes, * including MSi-X interrupts, if any. */ vp_legacy_get_status(&vp_dev->ldev); - /* Flush pending VQ/configuration callbacks. */ - vp_synchronize_vectors(vdev); } static u16 vp_config_vector(struct virtio_pci_device *vp_dev, u16 vector) -- MST ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v3 2/3] virtio_pci_legacy: drop callback sync on reset 2026-09-11 21:20 ` [PATCH v3 2/3] virtio_pci_legacy: drop callback sync on reset Michael S. Tsirkin @ 2026-09-11 22:51 ` Karl Mehltretter 0 siblings, 0 replies; 8+ messages in thread From: Karl Mehltretter @ 2026-09-11 22:51 UTC (permalink / raw) To: Michael S. Tsirkin Cc: virtualization, jasowangio, eperezma, xuanzhuo, jiri, sashiko-bot, linux-kernel On Fri, Sep 11, 2026 at 05:20:18PM +0100, Michael S. Tsirkin wrote: > The virtio core now synchronizes callbacks after reset, > so the legacy PCI transport no longer needs to do it itself. > I ran 200 instrumented virtio-input reset cycles over legacy INTx under KASAN and lockdep. All 19 callback/reset overlaps completed before reset returned. Tested-by: Karl Mehltretter <kmehltretter@gmail.com> Acked-by: Karl Mehltretter <kmehltretter@gmail.com> Thanks, Karl ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-09-11 22:52 UTC | newest] Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-09-11 21:20 [PATCH v3 0/3] virtio: fix callback synchronization and avq cleanup on reset Michael S. Tsirkin 2026-09-11 21:20 ` [PATCH v3 1/3] virtio: synchronize callbacks after device reset Michael S. Tsirkin 2026-09-11 22:50 ` Karl Mehltretter 2026-09-11 21:20 ` [PATCH v3 3/3] virtio_pci_modern: move avq cleanup from reset to del_vqs Michael S. Tsirkin 2026-09-11 22:48 ` Karl Mehltretter 2026-09-11 22:51 ` Michael S. Tsirkin 2026-09-11 21:20 ` [PATCH v3 2/3] virtio_pci_legacy: drop callback sync on reset Michael S. Tsirkin 2026-09-11 22:51 ` Karl Mehltretter
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®