sound/usb/bcd2000/bcd2000.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-)
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)
© 2016 - 2026 Red Hat, Inc.