From: sashiko-bot@kernel.org
To: "Joonho Lee" <mynameisjune111@gmail.com>, linux-sound@vger.kernel.org
Cc: virtualization@lists.linux.dev,
"Michael S. Tsirkin" <mst@redhat.com>,
"Eugenio Perez" <eperezma@redhat.com>
Subject: Re: [PATCH v5 03/11] ALSA: virtio: Retain queued messages through device reset
Date: Wed, 28 Oct 2026 00:15:04 +0000 [thread overview]
Message-ID: <sashiko-outbox-187265@kernel.org> (raw)
In-Reply-To: <20261027234334.32551-4-mynameisjune111@gmail.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] ALSA: virtio: NULL vqueue dereference in virtsnd_pcm_msg_send() after freeze
- [High] ALSA: virtio: virtsnd_reset_vqs() leaves stale substream state on reset
--
commit 00a0945381a2dc9d6b91d5ecac16bfd8128b97f3
Author: Joonho Lee <mynameisjune111@gmail.com>
ALSA: virtio: Retain queued messages through device reset
This patch retains the control virtqueue through snd_card_free() during
device removal, blocks new control messages and cancels pending ones across
device reset, and detaches unused virtqueue buffers in virtsnd_reset_vqs()
before deleting the virtqueues.
> diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c
> index 6f35276416fed..df7091b74a521 100644
> --- a/sound/virtio/virtio_card.c
> +++ b/sound/virtio/virtio_card.c
> @@ -337,6 +337,38 @@ static int virtsnd_probe(struct virtio_device *vdev)
> return rc;
> }
>
> +/**
> + * virtsnd_reset_vqs() - Stop device access and unmap outstanding buffers.
> + * @snd: VirtIO sound device.
> + *
> + * Context: Any context that permits to sleep.
> + */
> +static void virtsnd_reset_vqs(struct virtio_snd *snd)
> +{
> + struct virtio_device *vdev = snd->vdev;
> + unsigned int i;
> +
> + virtio_reset_device(vdev);
> +
> + /* Deleting a virtqueue does not unmap its outstanding descriptors. */
> + for (i = 0; i < VIRTIO_SND_VQ_MAX; ++i) {
> + struct virtio_snd_queue *queue = &snd->queues[i];
> + unsigned long flags;
> + void *msg;
> +
> + spin_lock_irqsave(&queue->lock, flags);
> + if (queue->vqueue)
> + while ((msg = virtqueue_detach_unused_buf(queue->vqueue)))
> + if (i == VIRTIO_SND_VQ_TX || i == VIRTIO_SND_VQ_RX)
> + virtsnd_pcm_msg_cancel(msg);
> + spin_unlock_irqrestore(&queue->lock, flags);
> + }
> +
> + vdev->config->del_vqs(vdev);
> + for (i = 0; i < VIRTIO_SND_VQ_MAX; ++i)
> + snd->queues[i].vqueue = NULL;
> +}
[Severity: High]
Can this lead to a NULL pointer dereference in virtsnd_pcm_msg_send() after
virtsnd_freeze() clears snd->queues[i].vqueue?
During system sleep, do_pcm_suspend() -> snd_pcm_suspend_all() leaves
vss->stopped as false (either because the substream was not running, because
virtsnd_pcm_sync_stop() flushed the queue and cleared vss->stopped, or
because virtsnd_pcm_msg_cancel() only clears vss->xfer_enabled).
virtsnd_freeze() then calls virtsnd_reset_vqs(), which deletes the
virtqueues and sets snd->queues[i].vqueue = NULL, but unlike the control
queue, nothing blocks submissions to the TX/RX PCM queues.
If virtsnd_restore() fails (for example in virtsnd_find_vqs() or feature
negotiation), snd->queues[VIRTIO_SND_VQ_TX/RX].vqueue remains NULL. If
userspace then issues SNDRV_PCM_IOCTL_SYNC_PTR with an advanced appl_ptr,
snd_pcm_common_ioctl() only checks for SNDRV_PCM_STATE_DISCONNECTED (and
snd_power_wait() is a no-op since virtio-snd does not update
card->power_state), calling:
snd_pcm_sync_ptr()
-> pcm_lib_apply_appl_ptr()
-> virtsnd_pcm_pb_ack() / virtsnd_pcm_cp_ack()
In sound/virtio/virtio_pcm_ops.c:virtsnd_pcm_pb_ack():
scoped_guard(spinlock_irqsave, &queue->lock) {
guard(spinlock)(&vss->lock);
transfer.indirect = vss->pcm_indirect;
if (vss->stopped) {
rc = -EPIPE;
} else {
rc = snd_pcm_indirect_playback_transfer(substream,
&transfer.indirect,
virtsnd_pcm_trans_copy);
}
Because vss->stopped is false, this calls virtsnd_pcm_trans_copy() ->
virtsnd_pcm_msg_send():
struct virtqueue *vqueue = virtsnd_pcm_queue(vss)->vqueue;
...
rc = virtqueue_add_sgs(vqueue, psgs, 2, 1, msg, GFP_ATOMIC);
which passes a NULL vqueue to virtqueue_add_sgs() under the spinlocks. Even
when virtsnd_restore() succeeds, the same SNDRV_PCM_IOCTL_SYNC_PTR -> ack()
path can queue PCM buffers onto the newly recreated virtqueue while the
substream is still in SNDRV_PCM_STATE_SUSPENDED (or SNDRV_PCM_STATE_SETUP)
before VIRTIO_SND_R_PCM_SET_PARAMS and VIRTIO_SND_R_PCM_PREPARE have been
sent to the reset device.
[ ... ]
> diff --git a/sound/virtio/virtio_pcm_msg.c b/sound/virtio/virtio_pcm_msg.c
> index 5371f4985fd06..762480363b861 100644
> --- a/sound/virtio/virtio_pcm_msg.c
> +++ b/sound/virtio/virtio_pcm_msg.c
> @@ -307,6 +307,35 @@ unsigned int virtsnd_pcm_msg_pending_num(struct virtio_pcm_substream *vss)
> return vss->msg_count;
> }
>
> +/**
> + * virtsnd_pcm_msg_cancel() - Cancel a message detached during device reset.
> + * @msg: Message returned by virtqueue_detach_unused_buf().
> + *
> + * Reset cancellation retires the queue token without treating it as a device
> + * completion. In particular, it does not advance the PCM hardware pointer or
> + * schedule period work.
> + *
> + * Context: Process context with the PCM queue lock held.
> + */
> +void virtsnd_pcm_msg_cancel(struct virtio_pcm_msg *msg)
> +{
> + struct virtio_pcm_substream *vss = msg->substream;
> + bool wake;
> +
> + {
> + guard(spinlock)(&vss->lock);
> + msg->length = 0;
> + vss->xfer_enabled = false;
> + if (WARN_ON_ONCE(!vss->msg_count))
> + return;
> + vss->msg_count--;
> + wake = !vss->msg_count;
> + }
> +
> + if (wake)
> + wake_up_all(&vss->msg_empty);
> +}
[Severity: High]
Should virtsnd_reset_vqs() / virtsnd_pcm_msg_cancel() also reconcile
vss->stopped and vss->suspended when resetting the device during
virtsnd_freeze()?
First, if virtsnd_pcm_sync_stop() fails or times out during
snd_pcm_suspend_all() before virtsnd_freeze() (or if a prior stop/start
failed before suspend), vss->stopped remains true while buffers remain
queued. virtsnd_freeze() -> virtsnd_reset_vqs() then resets the VirtIO
device and detaches all pending buffers via virtsnd_pcm_msg_cancel(),
decrementing vss->msg_count to 0, but leaves vss->stopped as true.
After virtsnd_restore(), vss->stopped blocks virtsnd_pcm_prepare() and
virtsnd_pcm_hw_params() with -EBADFD:
sound/virtio/virtio_pcm_ops.c:virtsnd_pcm_prepare() {
scoped_guard(spinlock_irqsave, &vss->lock)
stopped = vss->stopped;
if (stopped) {
dev_err(&vdev->dev, "SID %u: stream release failed\n",
vss->sid);
substream->runtime->stop_operating = true;
return -EBADFD;
}
And if userspace tries to recover via snd_pcm_sync_stop() or by closing and
reopening the substream via virtsnd_pcm_open():
sound/virtio/virtio_pcm_ops.c:virtsnd_pcm_open() {
...
scoped_guard(spinlock_irqsave, &vss->lock)
vss->stopped |= !!vss->msg_count;
vss->suspended = false;
return virtsnd_pcm_sync_stop(substream);
}
virtsnd_pcm_sync_stop() sees vss->stopped == true and sends
VIRTIO_SND_R_PCM_RELEASE to the freshly reset device before
VIRTIO_SND_R_PCM_SET_PARAMS has been sent. If the device rejects RELEASE for
the unconfigured stream, virtsnd_pcm_sync_stop() fails and leaves
vss->stopped set, permanently wedging the substream.
Second, if a substream has queued buffers while in a state where
snd_pcm_running() is false at suspend time (such as SNDRV_PCM_STATE_PAUSED,
capture SNDRV_PCM_STATE_DRAINING, or playback SNDRV_PCM_STATE_PREPARED with
pre-queued buffers), snd_pcm_do_suspend() skips
virtsnd_pcm_trigger(SNDRV_PCM_TRIGGER_SUSPEND) while snd_pcm_post_suspend()
places the substream into SNDRV_PCM_STATE_SUSPENDED with vss->suspended ==
false. When virtsnd_pcm_msg_cancel() drains vss->msg_count to 0 without
setting vss->suspended = true, a subsequent virtsnd_pcm_prepare() after
virtsnd_restore() sees !vss->suspended and virtsnd_pcm_msg_pending_num(vss)
== 0, skips virtsnd_pcm_dev_set_params(), and sends VIRTIO_SND_R_PCM_PREPARE
to a reset device that has no stream parameters configured.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261027234334.32551-1-mynameisjune111@gmail.com?part=3
next prev parent reply other threads:[~2026-10-28 0:15 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-27 23:43 [PATCH v5 00/11] ALSA: virtio: staged capture and dsnoop recovery Joonho Lee
2026-10-27 23:43 ` [PATCH v5 01/11] ALSA: virtio: Propagate PCM send failures through ACK Joonho Lee
2026-10-28 0:09 ` sashiko-bot
2026-10-27 23:43 ` [PATCH v5 02/11] ALSA: virtio: Recover PCM state after a failed start Joonho Lee
2026-10-28 0:18 ` sashiko-bot
2026-10-27 23:43 ` [PATCH v5 03/11] ALSA: virtio: Retain queued messages through device reset Joonho Lee
2026-10-28 0:15 ` sashiko-bot [this message]
2026-10-27 23:43 ` [PATCH v5 04/11] ALSA: virtio: Keep PCM DMA buffers alive through device ownership Joonho Lee
2026-10-27 23:59 ` sashiko-bot
2026-10-27 23:43 ` [PATCH v5 05/11] ALSA: virtio: Keep control payloads alive through DMA completion Joonho Lee
2026-10-27 23:55 ` sashiko-bot
2026-10-27 23:43 ` [PATCH v5 06/11] ALSA: virtio: wait through signals for PCM teardown Joonho Lee
2026-10-28 0:07 ` sashiko-bot
2026-10-27 23:43 ` [PATCH v5 07/11] ALSA: virtio: stage VZ capture and restart paused streams Joonho Lee
2026-10-28 0:19 ` sashiko-bot
2026-10-27 23:43 ` [PATCH v5 08/11] ALSA: virtio: account staged capture reads before RX refill Joonho Lee
2026-10-27 23:43 ` [PATCH v5 09/11] ALSA: virtio: prioritize staged capture period work Joonho Lee
2026-10-28 0:03 ` sashiko-bot
2026-10-27 23:43 ` [PATCH v5 10/11] ALSA: pcm: mark stop-threshold accesses for capture policy sampling Joonho Lee
2026-10-27 23:43 ` [PATCH v5 11/11] ALSA: virtio-snd: fix dsnoop capture with staged buffers Joonho Lee
2026-10-28 0:13 ` sashiko-bot
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-187265@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=eperezma@redhat.com \
--cc=linux-sound@vger.kernel.org \
--cc=mst@redhat.com \
--cc=mynameisjune111@gmail.com \
--cc=sashiko-reviews@lists.linux.dev \
--cc=virtualization@lists.linux.dev \
/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