[PATCH] media: usbtv: fix use-after-free on device disconnect
From: YuanZhe Liu
Date: Sun Nov 01 2026 - 03:31:08 EST
usbtv_audio_init() passes the USB interface as the owning device of the
ALSA card with snd_card_set_dev():
rv = snd_card_new(&usbtv->udev->dev, ...);
...
snd_card_set_dev(card, usbtv->dev);
snd_card_set_dev() is a plain pointer assignment. It replaces the device
that snd_card_new() took a reference on, the USB device, with the
interface device, without taking a reference on the latter, and the
reference on the USB device is leaked. snd_card_do_free() still puts
card->dev at the end, so the card drops a reference it never owned.
usbtv_audio_free() releases the card with snd_card_free_when_closed(), so
the card outlives the disconnect as long as user space keeps a sound
device open. On the USB side, usb_disable_device() drops the last
reference to the interface right after the driver has been unbound.
Closing the last sound file descriptor then runs release_card_device()
and snd_card_do_free(), and put_device(card->dev) is called on the
already freed struct usb_interface:
Read of size 1 at addr ffff8881024a008c
...
kobject_put
put_device
snd_card_do_free
release_card_device
device_release
kobject_cleanup
kobject_release
kobject_put
snd_card_file_remove
snd_ctl_release
__fput
Pass the interface device as the parent to snd_card_new() instead. The
reference taken by snd_card_init() and the one dropped by
snd_card_do_free() are then balanced, and the card keeps the interface
alive until the card itself is released. This also fixes the leaked
reference on the USB device. The sysfs location of the card and the
device name used in messages stay the same.
Fixes: 63ddf68de52e ("[media] usbtv: add audio support")
Cc: stable@xxxxxxxxxxxxxxx
Co-developed-by: Bin Yu <byu@xxxxxxxxxxxxx>
Signed-off-by: Bin Yu <byu@xxxxxxxxxxxxx>
Co-developed-by: Cheng Wen <wencheng@xxxxxxxxxxxxx>
Signed-off-by: Cheng Wen <wencheng@xxxxxxxxxxxxx>
Signed-off-by: YuanZhe Liu <25031212351@xxxxxxxxxxxxxxxxx>
---
drivers/media/usb/usbtv/usbtv-audio.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/media/usb/usbtv/usbtv-audio.c b/drivers/media/usb/usbtv/usbtv-audio.c
index ae0a14e5ed2a..6bdb64051cf2 100644
--- a/drivers/media/usb/usbtv/usbtv-audio.c
+++ b/drivers/media/usb/usbtv/usbtv-audio.c
@@ -333,7 +333,7 @@ int usbtv_audio_init(struct usbtv *usbtv)
INIT_WORK(&usbtv->snd_trigger, snd_usbtv_trigger);
atomic_set(&usbtv->snd_stream, 0);
- rv = snd_card_new(&usbtv->udev->dev, SNDRV_DEFAULT_IDX1, "usbtv",
+ rv = snd_card_new(usbtv->dev, SNDRV_DEFAULT_IDX1, "usbtv",
THIS_MODULE, 0, &card);
if (rv < 0)
return rv;
@@ -348,8 +348,6 @@ int usbtv_audio_init(struct usbtv *usbtv)
"USBTV Audio at bus %d device %d", usbtv->udev->bus->busnum,
usbtv->udev->devnum);
- snd_card_set_dev(card, usbtv->dev);
-
usbtv->snd = card;
rv = snd_pcm_new(card, "USBTV Audio", 0, 0, 1, &pcm);
--
2.34.1