All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/1] ALSA: bcd2000: fix use-after-free of MIDI URBs on disconnect
@ 2026-09-23 10:15 Yuanzhe Liu
  0 siblings, 0 replies; 8+ messages in thread
From: Yuanzhe Liu @ 2026-09-23 10:15 UTC (permalink / raw)
  To: perex, tiwai; +Cc: linux-sound, linux-kernel, dev, 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 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
  1 sibling, 0 replies; 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

end of thread, other threads:[~2026-10-31 19:09 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
  -- strict thread matches above, loose matches on Subject: below --
2026-09-23 10:15 [PATCH 0/1] ALSA: bcd2000: fix use-after-free of MIDI URBs on disconnect Yuanzhe Liu

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.