mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [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; 7+ 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] 7+ 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; 7+ 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	[flat|nested] 7+ 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; 7+ 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] 7+ 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; 7+ 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] 7+ 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 19:09     ` [PATCH v3] ALSA: bcd2000: Fix use-after-free of MIDI URBs on file close YuanZhe Liu
  1 sibling, 0 replies; 7+ 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	[flat|nested] 7+ 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; 7+ 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	[flat|nested] 7+ messages in thread

* [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; 7+ 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] 7+ messages in thread

end of thread, other threads:[~2026-10-31 19:09 UTC | newest]

Thread overview: 7+ 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 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®