media: usbtv: keep device alive while ALSA card exists

The ALSA PCM callbacks store the driver state in pcm->private_data. An
open PCM file can outlive USB disconnect because usbtv_audio_free() uses
snd_card_free_when_closed(). The disconnect path can then drop the V4L2
device reference and free struct usbtv before ALSA releases the substream,
so a later close dereferences freed memory in snd_usbtv_pcm_close().

Take a V4L2 device reference for the ALSA card and drop it from the card
private_free callback. This keeps struct usbtv valid until ALSA has closed
the remaining files and freed the card.

Closes: https://lore.kernel.org/r/178144969601.60470.4852887710381872458@gmail.com
Fixes: 63ddf68de5 ("[media] usbtv: add audio support")
Cc: stable@vger.kernel.org
Signed-off-by: Shuangpeng Bai <shuangpeng.kernel@gmail.com>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
This commit is contained in:
Shuangpeng Bai 2026-07-06 16:24:06 -04:00 committed by Hans Verkuil
parent 76e379754b
commit fc530fe168

View File

@ -317,6 +317,13 @@ static const struct snd_pcm_ops snd_usbtv_pcm_ops = {
.pointer = snd_usbtv_pointer,
};
static void usbtv_audio_card_free(struct snd_card *card)
{
struct usbtv *usbtv = card->private_data;
v4l2_device_put(&usbtv->v4l2_dev);
}
int usbtv_audio_init(struct usbtv *usbtv)
{
int rv;
@ -331,6 +338,10 @@ int usbtv_audio_init(struct usbtv *usbtv)
if (rv < 0)
return rv;
v4l2_device_get(&usbtv->v4l2_dev);
card->private_data = usbtv;
card->private_free = usbtv_audio_card_free;
strscpy(card->driver, usbtv->dev->driver->name, sizeof(card->driver));
strscpy(card->shortname, "usbtv", sizeof(card->shortname));
snprintf(card->longname, sizeof(card->longname),