* [PATCH 0/1] ALSA: bcd2000: fix use-after-free of MIDI URBs on disconnect
@ 2026-09-23 10:31 Yuanzhe Liu
2026-09-23 10:31 ` [PATCH 1/1] ALSA: bcd2000: fix use-after-free of MIDI URBs on file close after disconnect Yuanzhe Liu
2026-10-30 17:37 ` [PATCH 0/1] ALSA: bcd2000: fix use-after-free of MIDI URBs on disconnect YuanZhe Liu
0 siblings, 2 replies; 8+ messages in thread
From: Yuanzhe Liu @ 2026-09-23 10:31 UTC (permalink / raw)
To: perex, tiwai; +Cc: linux-sound, linux-kernel, Yuanzhe Liu
Hi,
this single-patch series addresses a slab-use-after-free in the
snd-bcd2000 driver, observed on a Behringer BCD2000 USB DJ controller
under a KASAN-enabled kernel (7.1.2, x86_64, CONFIG_SND_BCD2000=y).
Root-cause walkthrough
----------------------
The bug is a lifetime mismatch between driver disconnect and ALSA rawmidi
file lifetime:
1. A userspace process (e.g. amidi) opens /dev/snd/midiC0D0.
2. The USB interface is unbound (via USBDEVFS_DISCONNECT ioctl or physical
unplug).
3. bcd2000_disconnect() runs:
snd_card_disconnect(bcd2k->card);
bcd2000_free_usb_related_resources(bcd2k, interface);
snd_card_disconnect() only marks the card disconnected and stops new
opens, but returns immediately while open file descriptors still exist.
bcd2000_free_usb_related_resources() proceeds to free both
bcd2k->midi_out_urb and bcd2k->midi_in_urb via usb_free_urb().
4. Later, the process closes the rawmidi fd (or exits):
snd_rawmidi_release -> close_substream -> bcd2000_midi_output_close()
Because bcd2k->midi_out_active was set (and left set by completion
re-submissions), bcd2000_midi_output_close() calls
usb_kill_urb(bcd2k->midi_out_urb), reading the already-freed URB
object (slab-use-after-free at urb->dev).
Patch summary
-------------
Patch 1 fixes the bug via two complementary changes:
- Switch snd_card_disconnect() to snd_card_disconnect_sync(), which
waits for all open card files to be closed before returning. The
rawmidi close callbacks (and their usb_kill_urb()) run while the URBs
are still valid. devices_mutex held during disconnect is not taken by
rawmidi close, so the wait cannot deadlock.
- Add an atomic shutdown flag set at the beginning of disconnect and
checked in bcd2000_midi_send() and both URB completions, preventing
URBs from being re-submitted after disconnect. Also NULL the URB
pointers after usb_free_urb() so any stray access becomes an
immediate NULL dereference rather than a silent UAF.
Crash report addressed
----------------------
Report 1: slab-use-after-free in usb_kill_urb (read of size 8 at urb->dev,
sound/usb/bcd2000/bcd2000.c:182 <- sound/core/rawmidi.c:560).
Condensed splat appended below the diffstat.
Yuanzhe Liu (1):
ALSA: bcd2000: fix use-after-free of MIDI URBs on file close after
disconnect
sound/usb/bcd2000/bcd2000.c | 25 ++++++++++++++++++++-----
1 file changed, 20 insertions(+), 5 deletions(-)
--
Crash excerpt:
BUG: KASAN: slab-use-after-free in usb_kill_urb+0x74/0x80 drivers/usb/core/urb.c:706
Read of size 8 at addr ffff8880078e7d40 by task amidi/30287
Call Trace:
usb_kill_urb+0x74/0x80 drivers/usb/core/urb.c:706
bcd2000_midi_output_close+0xd4/0x140 sound/usb/bcd2000/bcd2000.c:182
close_substream.part.0+0x15f/0x8d0 sound/core/rawmidi.c:560
close_substream sound/core/rawmidi.c:585 [inline]
rawmidi_release_priv+0x21d/0x290 sound/core/rawmidi.c:580
snd_rawmidi_release+0x4e/0xa0 sound/core/rawmidi.c:610
__fput+0x3a6/0xac0 fs/file_table.c:510
task_work_run+0x158/0x220 kernel/task_work.c:233
do_exit+0x87b/0x22d0 kernel/exit.c:976
Allocated by task 34:
usb_alloc_urb+0x67/0x190 drivers/usb/core/urb.c:75
bcd2000_init_midi sound/usb/bcd2000/bcd2000.c:319 [inline]
bcd2000_probe+0x5a0/0x1350 sound/usb/bcd2000/bcd2000.c:401
usb_probe_interface+0x395/0x850 drivers/usb/core/driver.c:396
Freed by task 30294:
usb_free_urb+0xbb/0x100 drivers/usb/core/urb.c:96
bcd2000_free_usb_related_resources sound/usb/bcd2000/bcd2000.c:354 [inline]
bcd2000_disconnect+0xfc/0x280 sound/usb/bcd2000/bcd2000.c:433
usb_unbind_interface+0x188/0x770 drivers/usb/core/driver.c:458
usb_driver_release_interface+0x105/0x180 drivers/usb/core/driver.c:640
proc_ioctl drivers/usb/core/devio.c:2359 [inline]
usbdev_ioctl+0x6f05/0x86d0 drivers/usb/core/devio.c:2826
The buggy address belongs to the object at ffff8880078e7d00
which belongs to the cache kmalloc-192 of size 192
The buggy address is located 64 bytes inside of
freed 192-byte region [ffff8880078e7d00, ffff8880078e7dc0)
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH 1/1] ALSA: bcd2000: fix use-after-free of MIDI URBs on file close after disconnect 2026-09-23 10:31 [PATCH 0/1] ALSA: bcd2000: fix use-after-free of MIDI URBs on disconnect Yuanzhe Liu @ 2026-09-23 10:31 ` Yuanzhe Liu 2026-10-30 17:37 ` [PATCH 0/1] ALSA: bcd2000: fix use-after-free of MIDI URBs on disconnect YuanZhe Liu 1 sibling, 0 replies; 8+ messages in thread From: Yuanzhe Liu @ 2026-09-23 10:31 UTC (permalink / raw) To: perex, tiwai; +Cc: linux-sound, linux-kernel, Yuanzhe Liu, stable Closing a rawmidi fd of the BCD2000 after its USB interface has been unbound crashes with a slab-use-after-free in usb_kill_urb(): BUG: KASAN: slab-use-after-free in usb_kill_urb+0x74/0x80 Read of size 8 at addr ffff8880078e7d40 by task amidi/30287 usb_kill_urb+0x74/0x80 drivers/usb/core/urb.c:706 bcd2000_midi_output_close+0xd4/0x140 sound/usb/bcd2000/bcd2000.c:182 close_substream.part.0+0x15f/0x8d0 sound/core/rawmidi.c:560 rawmidi_release_priv+0x21d/0x290 sound/core/rawmidi.c:580 snd_rawmidi_release+0x4e/0xa0 sound/core/rawmidi.c:610 __fput+0x3a6/0xac0 fs/file_table.c:510 Allocated by: usb_alloc_urb <- bcd2000_init_midi <- bcd2000_probe Freed by: usb_free_urb <- bcd2000_free_usb_related_resources <- bcd2000_disconnect <- usb_driver_release_interface <- usbdev_ioctl (USBDEVFS_DISCONNECT) Root cause: bcd2000_disconnect() calls snd_card_disconnect(), which only blocks *new* opens, and then immediately kills and frees midi_out_urb and midi_in_urb. Already-open rawmidi fds, however, keep working: their ->close() callback bcd2000_midi_output_close() unconditionally calls usb_kill_urb(bcd2k->midi_out_urb) when midi_out_active is set (which it is, since the completion handler re-submits the out URB), and the URB completion callbacks re-submit the URBs via bcd2k->midi_{in,out}_urb. Both dereference pointers that were freed in disconnect -- a UAF. No physical unplug is needed; USBDEVFS_DISCONNECT on the usbfs node triggers the same path. Fix the lifetime mismatch in two parts: - Wait for the users that are already there: use snd_card_disconnect_sync() instead of snd_card_disconnect() so that disconnect blocks until all open card files are released. The rawmidi close callbacks then run (and call usb_kill_urb()) while the URBs are still valid, and no userspace-triggered callback can run afterwards. devices_mutex held by bcd2000_disconnect() is not taken by the rawmidi close path, so the wait cannot deadlock. - Mark the device shut down before freeing: add an atomic shutdown flag, set first in bcd2000_disconnect(), and check it in bcd2000_midi_send() and in both URB completion handlers so no new URB submission can be queued while disconnect frees the old ones. Also NULL the URB pointers after usb_free_urb() so any stray access becomes an immediate, diagnosable NULL dereference instead of a silent UAF. Cc: stable@vger.kernel.org Signed-off-by: Yuanzhe Liu <25031212351@stu.xidian.edu.cn> --- sound/usb/bcd2000/bcd2000.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/sound/usb/bcd2000/bcd2000.c b/sound/usb/bcd2000/bcd2000.c index bebb48c..cbf6d39 100644 --- a/sound/usb/bcd2000/bcd2000.c +++ b/sound/usb/bcd2000/bcd2000.c @@ -55,6 +55,7 @@ struct bcd2000 { struct urb *midi_in_urb; struct usb_anchor anchor; + atomic_t shutdown; }; static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; @@ -131,7 +132,7 @@ static void bcd2000_midi_send(struct bcd2000 *bcd2k) BUILD_BUG_ON(sizeof(device_cmd_prefix) >= BUFSIZE); midi_out_substream = READ_ONCE(bcd2k->midi_out_substream); - if (!midi_out_substream) + if (!midi_out_substream || atomic_read(&bcd2k->shutdown)) return; /* copy command prefix bytes */ @@ -212,7 +213,7 @@ static void bcd2000_output_complete(struct urb *urb) dev_warn(&urb->dev->dev, PREFIX "output urb->status: %d\n", urb->status); - if (urb->status == -ESHUTDOWN) + if (urb->status == -ESHUTDOWN || atomic_read(&bcd2k->shutdown)) return; /* check if there is more data userspace wants to send */ @@ -228,7 +229,8 @@ static void bcd2000_input_complete(struct urb *urb) dev_warn(&urb->dev->dev, PREFIX "input urb->status: %i\n", urb->status); - if (!bcd2k || urb->status == -ESHUTDOWN) + if (!bcd2k || urb->status == -ESHUTDOWN || + atomic_read(&bcd2k->shutdown)) return; if (urb->actual_length > 0) @@ -353,6 +355,8 @@ static void bcd2000_free_usb_related_resources(struct bcd2000 *bcd2k, usb_free_urb(bcd2k->midi_out_urb); usb_free_urb(bcd2k->midi_in_urb); + bcd2k->midi_out_urb = NULL; + bcd2k->midi_in_urb = NULL; if (bcd2k->intf) { usb_set_intfdata(bcd2k->intf, NULL); @@ -427,8 +431,19 @@ static void bcd2000_disconnect(struct usb_interface *interface) guard(mutex)(&devices_mutex); - /* make sure that userspace cannot create new requests */ - snd_card_disconnect(bcd2k->card); + /* + * Make sure that the URB completion handlers and the rawmidi ops + * don't touch the USB device or the URBs any longer. + */ + atomic_set(&bcd2k->shutdown, 1); + + /* + * Make sure that userspace cannot create new requests, and wait + * until all already-open files are closed so that the rawmidi + * close callbacks (which may kill the out URB) run while the + * URBs are still valid. + */ + snd_card_disconnect_sync(bcd2k->card); bcd2000_free_usb_related_resources(bcd2k, interface); -- 2.45.1.windows.1 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 0/1] ALSA: bcd2000: fix use-after-free of MIDI URBs on disconnect 2026-09-23 10:31 [PATCH 0/1] ALSA: bcd2000: fix use-after-free of MIDI URBs on disconnect Yuanzhe Liu 2026-09-23 10:31 ` [PATCH 1/1] ALSA: bcd2000: fix use-after-free of MIDI URBs on file close after disconnect Yuanzhe Liu @ 2026-10-30 17:37 ` YuanZhe Liu 2026-10-31 18:06 ` Takashi Iwai 1 sibling, 1 reply; 8+ messages in thread From: YuanZhe Liu @ 2026-10-30 17:37 UTC (permalink / raw) To: perex, tiwai, Takashi Iwai; +Cc: linux-sound, linux-kernel Hi Takashi, Could you please advise on the status of this series and whether any further work is needed, considering the related upstream fixes? [PATCH 0/1] ALSA: bcd2000: fix use-after-free of MIDI URBs on disconnect The series addresses MIDI URB lifetime on BCD2000 disconnect. I noticed the related upstream commit below and would appreciate your guidance on whether this series is still needed. Related upstream fix: https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux/+/459d3a64766f5ca2f1886daeaf24582831a5f5ab I am copying this address for visibility. Original submission: https://lore.landau.one/lkml/20260923103116.1666-1-25031212351@stu.xidian.edu.cn/T/ Thanks, YuanZhe ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 0/1] ALSA: bcd2000: fix use-after-free of MIDI URBs on disconnect 2026-10-30 17:37 ` [PATCH 0/1] ALSA: bcd2000: fix use-after-free of MIDI URBs on disconnect YuanZhe Liu @ 2026-10-31 18:06 ` Takashi Iwai 2026-10-31 18:44 ` [PATCH v2] ALSA: bcd2000: Wait for open files before freeing the MIDI URBs YuanZhe Liu 2026-10-31 19:09 ` [PATCH v3] ALSA: bcd2000: Fix use-after-free of MIDI URBs on file close YuanZhe Liu 0 siblings, 2 replies; 8+ messages in thread From: Takashi Iwai @ 2026-10-31 18:06 UTC (permalink / raw) To: YuanZhe Liu; +Cc: perex, tiwai, Takashi Iwai, linux-sound, linux-kernel On Fri, 30 Oct 2026 18:37:13 +0100, YuanZhe Liu wrote: > > Hi Takashi, > > Could you please advise on the status of this series and whether any > further work is needed, considering the related upstream fixes? > > [PATCH 0/1] ALSA: bcd2000: fix use-after-free of MIDI URBs on > disconnect > > The series addresses MIDI URB lifetime on BCD2000 disconnect. I noticed > the related upstream commit below and would appreciate your guidance on > whether this series is still needed. > > Related upstream fix: > https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux/+/459d3a64766f5ca2f1886daeaf24582831a5f5ab > > I am copying this address for visibility. > > Original submission: > https://lore.landau.one/lkml/20260923103116.1666-1-25031212351@stu.xidian.edu.cn/T/ The patch doesn't seem applied cleanly to the latest code. If the fix is still valid to the latest code, could you rebase and resubmit? thanks, Takashi ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2] ALSA: bcd2000: Wait for open files before freeing the MIDI URBs 2026-10-31 18:06 ` Takashi Iwai @ 2026-10-31 18:44 ` YuanZhe Liu 2026-10-31 18:59 ` sashiko-bot 2026-10-31 19:09 ` [PATCH v3] ALSA: bcd2000: Fix use-after-free of MIDI URBs on file close YuanZhe Liu 1 sibling, 1 reply; 8+ messages in thread From: YuanZhe Liu @ 2026-10-31 18:44 UTC (permalink / raw) To: Jaroslav Kysela, Takashi Iwai; +Cc: linux-sound, linux-kernel, stable bcd2000_disconnect() calls snd_card_disconnect(), which only prevents new opens, and then frees the MIDI URBs. A rawmidi file that was already open can still be closed afterwards, and its close callback, bcd2000_midi_output_close(), calls usb_kill_urb() on midi_out_urb. The URB pointers are cleared on disconnect and their accesses are serialized with midi_lock, but bcd2000_midi_output_close() reads midi_out_urb without that lock. The check can therefore pass just before the pointer is cleared, and usb_kill_urb() then runs on the URB that has already been freed: BUG: KASAN: slab-use-after-free in usb_kill_urb+0x74/0x80 Read of size 8 at addr ffff8880078e7d40 usb_kill_urb bcd2000_midi_output_close close_substream rawmidi_release_priv snd_rawmidi_release Allocated by: usb_alloc_urb <- bcd2000_init_midi <- bcd2000_probe Freed by: usb_free_urb <- bcd2000_midi_free <- bcd2000_disconnect Use snd_card_disconnect_sync() instead, so that disconnect waits until all open files are released. The rawmidi close callbacks then run while the URBs are still valid, and no userspace-triggered callback can run afterwards. The devices_mutex held by bcd2000_disconnect() is not taken by the rawmidi close path, so the wait cannot deadlock. Fixes: b47a22290d58 ("ALSA: MIDI driver for Behringer BCD2000 USB device") Cc: stable@vger.kernel.org Signed-off-by: YuanZhe Liu <25031212351@stu.xidian.edu.cn> --- v2: rebased onto v7.3-rc7. The URB pointer clearing and the locking are already handled by 459d3a64766f ("ALSA: bcd2000: clear the URB pointers on disconnect") and 221253723dc5 ("ALSA: bcd2000: Fix race between rawmidi and disconnect"), so this version only keeps the change of the disconnect ordering, as suggested by Takashi Iwai. sound/usb/bcd2000/bcd2000.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/usb/bcd2000/bcd2000.c b/sound/usb/bcd2000/bcd2000.c index 2bd49bf82748..a5e8ea92532c 100644 --- a/sound/usb/bcd2000/bcd2000.c +++ b/sound/usb/bcd2000/bcd2000.c @@ -451,8 +451,13 @@ static void bcd2000_disconnect(struct usb_interface *interface) guard(mutex)(&devices_mutex); - /* make sure that userspace cannot create new requests */ - snd_card_disconnect(bcd2k->card); + /* + * Make sure that userspace cannot create new requests, and wait + * until all already-open files are closed so that the rawmidi + * close callbacks (which may kill the out URB) run while the + * URBs are still valid. + */ + snd_card_disconnect_sync(bcd2k->card); bcd2000_free_usb_related_resources(bcd2k, interface); -- 2.34.1 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v2] ALSA: bcd2000: Wait for open files before freeing the MIDI URBs 2026-10-31 18:44 ` [PATCH v2] ALSA: bcd2000: Wait for open files before freeing the MIDI URBs YuanZhe Liu @ 2026-10-31 18:59 ` sashiko-bot 0 siblings, 0 replies; 8+ messages in thread From: sashiko-bot @ 2026-10-31 18:59 UTC (permalink / raw) To: YuanZhe Liu; +Cc: linux-sound Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] ALSA: bcd2000: deadlock in bcd2000_disconnect() via snd_card_disconnect_sync() -- commit b86f69d1ff1d65cb943f4d36efce05abcc0a498d Author: YuanZhe Liu <25031212351@stu.xidian.edu.cn> ALSA: bcd2000: Wait for open files before freeing the MIDI URBs This commit replaces snd_card_disconnect() with snd_card_disconnect_sync() in bcd2000_disconnect() so that open rawmidi files are closed before freeing the MIDI URBs. > diff --git a/sound/usb/bcd2000/bcd2000.c b/sound/usb/bcd2000/bcd2000.c > index 2bd49bf827489..a5e8ea92532c5 100644 > --- a/sound/usb/bcd2000/bcd2000.c > +++ b/sound/usb/bcd2000/bcd2000.c > @@ -451,8 +451,13 @@ static void bcd2000_disconnect(struct usb_interface *interface) > > guard(mutex)(&devices_mutex); > > - /* make sure that userspace cannot create new requests */ > - snd_card_disconnect(bcd2k->card); > + /* > + * Make sure that userspace cannot create new requests, and wait > + * until all already-open files are closed so that the rawmidi > + * close callbacks (which may kill the out URB) run while the > + * URBs are still valid. > + */ > + snd_card_disconnect_sync(bcd2k->card); [Severity: High] Can calling snd_card_disconnect_sync() inside bcd2000_disconnect() deadlock or stall USB disconnect processing? In sound/core/init.c, snd_card_disconnect_sync() sleeps uninterruptibly until all open file descriptors on the card are closed: sound/core/init.c:snd_card_disconnect_sync() { snd_card_disconnect(card); guard(spinlock_irq)(&card->files_lock); wait_event_lock_irq(card->remove_sleep, list_empty(&card->files_list), card->files_lock); } However, bcd2000_disconnect() is invoked by usb_unbind_interface() with device_lock(&interface->dev) held, and from usb_disconnect() -> usb_disable_device() or usbfs ioctls (usbdev_do_ioctl()) with usb_lock_device(udev) held, and then acquires devices_mutex. If a process holding an open ALSA fd on bcd2k->card unbinds the driver via sysfs (/sys/bus/usb/drivers/snd-bcd2000/unbind) or issues a usbfs ioctl that unbinds the interface (such as USBDEVFS_DISCONNECT, USBDEVFS_DISCONNECT_CLAIM, USBDEVFS_RESET, or USBDEVFS_SETCONFIGURATION), bcd2000_disconnect() runs synchronously in that process's syscall context and sleeps in snd_card_disconnect_sync() waiting for that same process to close its ALSA fd. An ABBA deadlock with usb_lock_device(udev) is also possible during usb_disconnect(): the hub worker holds usb_lock_device(udev) while waiting in snd_card_disconnect_sync() for open ALSA fds to close. If a process holds both a usbfs fd (/dev/bus/usb/...) with a lower fd number and an ALSA fd on the same device and exits (do_exit() -> close_files()) or closes the usbfs fd first, usbdev_release() blocks on usb_lock_device(udev) before the process can close the ALSA fd. Even on a normal physical unplug, waiting in bcd2000_disconnect() for userspace to close all ALSA fds blocks hub_event() on hub_wq in TASK_UNINTERRUPTIBLE while holding devices_mutex and before device_del() emits remove uevents, defeating the asynchronous teardown intended by snd_card_free_when_closed(bcd2k->card) at the end of bcd2000_disconnect(). Instead of blocking in snd_card_disconnect_sync(), would it be safer to keep snd_card_disconnect() and Either serialize midi_out_urb in bcd2000_midi_output_close() or defer usb_free_urb() to a card->private_free callback that runs when snd_card_free_when_closed() finishes? -- Sashiko AI review · https://sashiko.dev/#/patchset/20261031184405.15307-1-25031212351@stu.xidian.edu.cn?part=1 ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v3] ALSA: bcd2000: Fix use-after-free of MIDI URBs on file close 2026-10-31 18:06 ` Takashi Iwai 2026-10-31 18:44 ` [PATCH v2] ALSA: bcd2000: Wait for open files before freeing the MIDI URBs YuanZhe Liu @ 2026-10-31 19:09 ` YuanZhe Liu 2026-11-01 15:32 ` Takashi Iwai 1 sibling, 1 reply; 8+ messages in thread From: YuanZhe Liu @ 2026-10-31 19:09 UTC (permalink / raw) To: Jaroslav Kysela, Takashi Iwai Cc: Bin Yu, Cheng Wen, linux-sound, linux-kernel, stable bcd2000_disconnect() calls snd_card_disconnect(), which only prevents new opens, and then frees the MIDI URBs. A rawmidi file that was already open can still be closed afterwards, and its close callback, bcd2000_midi_output_close(), calls usb_kill_urb() on midi_out_urb. The URB pointers are cleared on disconnect and their accesses are serialized with midi_lock, but bcd2000_midi_output_close() reads midi_out_urb without that lock. The check can therefore pass just before the pointer is cleared, and usb_kill_urb() then runs on the URB that has already been freed: BUG: KASAN: slab-use-after-free in usb_kill_urb+0x74/0x80 Read of size 8 at addr ffff8880078e7d40 usb_kill_urb bcd2000_midi_output_close close_substream rawmidi_release_priv snd_rawmidi_release Allocated by: usb_alloc_urb <- bcd2000_init_midi <- bcd2000_probe Freed by: usb_free_urb <- bcd2000_midi_free <- bcd2000_disconnect Take the lock in bcd2000_midi_output_close() and reference the URB with usb_get_urb() before releasing it. The URB then stays valid until usb_put_urb() after usb_kill_urb() has returned, even if a disconnect frees it in the meantime. usb_kill_urb() itself cannot run under midi_lock, as the completion handler takes the same lock. Fixes: b47a22290d58 ("ALSA: MIDI driver for Behringer BCD2000 USB device") Cc: stable@vger.kernel.org Signed-off-by: YuanZhe Liu <25031212351@stu.xidian.edu.cn> --- v3: reference the URB under midi_lock in bcd2000_midi_output_close() instead of waiting for open files in bcd2000_disconnect(), which would block the USB disconnect path on userspace. sound/usb/bcd2000/bcd2000.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/sound/usb/bcd2000/bcd2000.c b/sound/usb/bcd2000/bcd2000.c index 2bd49bf82748..0fd086cac955 100644 --- a/sound/usb/bcd2000/bcd2000.c +++ b/sound/usb/bcd2000/bcd2000.c @@ -183,10 +183,24 @@ static int bcd2000_midi_output_open(struct snd_rawmidi_substream *substream) static int bcd2000_midi_output_close(struct snd_rawmidi_substream *substream) { struct bcd2000 *bcd2k = substream->rmidi->private_data; + struct urb *urb = NULL; - if (bcd2k->midi_out_active && bcd2k->midi_out_urb) { - usb_kill_urb(bcd2k->midi_out_urb); - bcd2k->midi_out_active = 0; + /* + * Reference the URB under the lock so that it stays valid until + * usb_kill_urb() returns, even if a disconnect frees it in the + * meantime. usb_kill_urb() cannot run under the lock, as the + * completion handler takes the same lock. + */ + scoped_guard(spinlock_irqsave, &bcd2k->midi_lock) { + if (bcd2k->midi_out_active && bcd2k->midi_out_urb) { + urb = usb_get_urb(bcd2k->midi_out_urb); + bcd2k->midi_out_active = 0; + } + } + + if (urb) { + usb_kill_urb(urb); + usb_put_urb(urb); } return 0; -- 2.34.1 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v3] ALSA: bcd2000: Fix use-after-free of MIDI URBs on file close 2026-10-31 19:09 ` [PATCH v3] ALSA: bcd2000: Fix use-after-free of MIDI URBs on file close YuanZhe Liu @ 2026-11-01 15:32 ` Takashi Iwai 0 siblings, 0 replies; 8+ messages in thread From: Takashi Iwai @ 2026-11-01 15:32 UTC (permalink / raw) To: YuanZhe Liu Cc: Jaroslav Kysela, Takashi Iwai, Bin Yu, Cheng Wen, linux-sound, linux-kernel, stable On Sat, 31 Oct 2026 20:09:36 +0100, YuanZhe Liu wrote: > > bcd2000_disconnect() calls snd_card_disconnect(), which only prevents > new opens, and then frees the MIDI URBs. A rawmidi file that was > already open can still be closed afterwards, and its close callback, > bcd2000_midi_output_close(), calls usb_kill_urb() on midi_out_urb. > > The URB pointers are cleared on disconnect and their accesses are > serialized with midi_lock, but bcd2000_midi_output_close() reads > midi_out_urb without that lock. The check can therefore pass just > before the pointer is cleared, and usb_kill_urb() then runs on the URB > that has already been freed: > > BUG: KASAN: slab-use-after-free in usb_kill_urb+0x74/0x80 > Read of size 8 at addr ffff8880078e7d40 > usb_kill_urb > bcd2000_midi_output_close > close_substream > rawmidi_release_priv > snd_rawmidi_release > > Allocated by: usb_alloc_urb <- bcd2000_init_midi <- bcd2000_probe > Freed by: usb_free_urb <- bcd2000_midi_free > <- bcd2000_disconnect > > Take the lock in bcd2000_midi_output_close() and reference the URB with > usb_get_urb() before releasing it. The URB then stays valid until > usb_put_urb() after usb_kill_urb() has returned, even if a disconnect > frees it in the meantime. usb_kill_urb() itself cannot run under > midi_lock, as the completion handler takes the same lock. > > Fixes: b47a22290d58 ("ALSA: MIDI driver for Behringer BCD2000 USB device") > Cc: stable@vger.kernel.org > Signed-off-by: YuanZhe Liu <25031212351@stu.xidian.edu.cn> Applied now. Thanks. Takashi ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-11-01 15:32 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-09-23 10:31 [PATCH 0/1] ALSA: bcd2000: fix use-after-free of MIDI URBs on disconnect Yuanzhe Liu 2026-09-23 10:31 ` [PATCH 1/1] ALSA: bcd2000: fix use-after-free of MIDI URBs on file close after disconnect Yuanzhe Liu 2026-10-30 17:37 ` [PATCH 0/1] ALSA: bcd2000: fix use-after-free of MIDI URBs on disconnect YuanZhe Liu 2026-10-31 18:06 ` Takashi Iwai 2026-10-31 18:44 ` [PATCH v2] ALSA: bcd2000: Wait for open files before freeing the MIDI URBs YuanZhe Liu 2026-10-31 18:59 ` sashiko-bot 2026-10-31 19:09 ` [PATCH v3] ALSA: bcd2000: Fix use-after-free of MIDI URBs on file close YuanZhe Liu 2026-11-01 15:32 ` Takashi Iwai
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.