* [PATCH v2] ALSA: usb-audio: Disconnect components on probe errors
@ 2026-06-18 12:22 Cen Zhang
2026-06-18 15:44 ` Takashi Iwai
0 siblings, 1 reply; 3+ messages in thread
From: Cen Zhang @ 2026-06-18 12:22 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai
Cc: linux-sound, linux-kernel, baijiaju1990, zzzccc427
MIDI 2.0 input URBs can be submitted before usb_audio_probe() has
finished building and registering the card. If a later setup step fails,
cleanup can reach the card or MIDI 2.0 endpoint free path while those URBs
are still owned by the USB core. The normal disconnect path avoids this by
publishing the disconnected state and killing/draining URBs before endpoint
storage and coherent transfer buffers are released.
The buggy scenario involves two paths. Each column shows path order:
probe error path: USB completion path:
1. start_input_streams() submits 1. The HCD still owns a
input URBs. submitted input URB.
2. A later setup helper returns 2. input_urb_complete() runs
an error. with urb->context in ep.
3. Cleanup frees endpoint storage 3. The completion reads ep
and URB buffers. state and can requeue URBs.
Factor the component release sequence out of __usb_audio_disconnect() and
call it when usb_audio_probe() is about to free a card that never claimed
an interface. The helper preserves the existing disconnect release order,
including snd_usb_midi_v2_disconnect_all().
Also make the MIDI 2.0 endpoint destructor perform the local disconnect,
kill and drain sequence only when the endpoint has not already been
disconnected, so the internal MIDI 2.0 create-error cleanup is synchronized
without repeating the stop sequence after normal disconnect.
Validation reproduced this kernel report:
BUG: KASAN: slab-use-after-free in input_urb_complete+0x37/0x1b0
Workqueue: usb_hub_wq hub_event
RIP: 0010:_raw_spin_unlock_irq+0x2e/0x50
Read of size 8
Call trace:
dump_stack_lvl+0x77/0xb0
print_report+0xce/0x5f0
input_urb_complete+0x37/0x1b0 (sound/usb/midi2.c:186)
srso_alias_return_thunk+0x5/0xfbef5
__virt_addr_valid+0x19f/0x330
kasan_report+0xe0/0x110
__usb_hcd_giveback_urb+0x112/0x1d0
dummy_timer+0xaaa/0x19a0
lock_is_held_type+0x9a/0x110
__lock_acquire+0x467/0x28b0
mark_held_locks+0x40/0x70
_raw_spin_unlock_irqrestore+0x44/0x60
lockdep_hardirqs_on_prepare+0xbb/0x1a0
__hrtimer_run_queues+0x101/0x520
hrtimer_run_softirq+0xd0/0x130
handle_softirqs+0x15b/0x670
__irq_exit_rcu+0xd0/0x170
irq_exit_rcu+0xe/0x20
sysvec_apic_timer_interrupt+0x6c/0x80
asm_sysvec_apic_timer_interrupt+0x1a/0x20
Fixes: d9c99876868c ("ALSA: usb-audio: Create UMP blocks from USB MIDI GTBs")
Assisted-by: Codex:gpt-5.5
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
---
v2:
Factor USB-audio component disconnect into the probe error path and guard
MIDI 2.0 endpoint kill/drain with ep->disconnected, per maintainer feedback.
sound/usb/card.c | 70 +++++++++++++++++++++++++----------------------
sound/usb/midi2.c | 5 ++++
2 files changed, 43 insertions(+), 32 deletions(-)
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 6a3b576fb067..b36f513dccb9 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -905,6 +905,40 @@ static int try_to_register_card(struct snd_usb_audio *chip, int ifnum)
return 0;
}
+static void usb_audio_disconnect_components(struct snd_usb_audio *chip)
+{
+ struct snd_usb_stream *as;
+ struct snd_usb_endpoint *ep;
+ struct usb_mixer_interface *mixer;
+ struct list_head *p;
+
+ /* release the pcm resources */
+ list_for_each_entry(as, &chip->pcm_list, list) {
+ snd_usb_stream_disconnect(as);
+ }
+ /* release the endpoint resources */
+ list_for_each_entry(ep, &chip->ep_list, list) {
+ snd_usb_endpoint_release(ep);
+ }
+ /* release the midi resources */
+ list_for_each(p, &chip->midi_list) {
+ snd_usbmidi_disconnect(p);
+ }
+ snd_usb_midi_v2_disconnect_all(chip);
+ /*
+ * Nice to check quirk && quirk->shares_media_device and
+ * then call the snd_media_device_delete(). Don't have
+ * access to the quirk here. snd_media_device_delete()
+ * accesses mixer_list
+ */
+ snd_media_device_delete(chip);
+
+ /* release mixer resources */
+ list_for_each_entry(mixer, &chip->mixer_list, list) {
+ snd_usb_mixer_disconnect(mixer);
+ }
+}
+
/*
* probe the active usb device
*
@@ -1077,8 +1111,10 @@ static int usb_audio_probe(struct usb_interface *intf,
* decrement before memory is possibly returned.
*/
atomic_dec(&chip->active);
- if (!chip->num_interfaces)
+ if (!chip->num_interfaces) {
+ usb_audio_disconnect_components(chip);
snd_card_free(chip->card);
+ }
}
return err;
}
@@ -1091,48 +1127,18 @@ static bool __usb_audio_disconnect(struct usb_interface *intf,
struct snd_usb_audio *chip,
struct snd_card *card)
{
- struct list_head *p;
-
guard(mutex)(®ister_mutex);
if (platform_ops && platform_ops->disconnect_cb)
platform_ops->disconnect_cb(chip);
if (atomic_inc_return(&chip->shutdown) == 1) {
- struct snd_usb_stream *as;
- struct snd_usb_endpoint *ep;
- struct usb_mixer_interface *mixer;
-
/* wait until all pending tasks done;
* they are protected by snd_usb_lock_shutdown()
*/
snd_refcount_sync(&chip->usage_count);
snd_card_disconnect(card);
- /* release the pcm resources */
- list_for_each_entry(as, &chip->pcm_list, list) {
- snd_usb_stream_disconnect(as);
- }
- /* release the endpoint resources */
- list_for_each_entry(ep, &chip->ep_list, list) {
- snd_usb_endpoint_release(ep);
- }
- /* release the midi resources */
- list_for_each(p, &chip->midi_list) {
- snd_usbmidi_disconnect(p);
- }
- snd_usb_midi_v2_disconnect_all(chip);
- /*
- * Nice to check quirk && quirk->shares_media_device and
- * then call the snd_media_device_delete(). Don't have
- * access to the quirk here. snd_media_device_delete()
- * accesses mixer_list
- */
- snd_media_device_delete(chip);
-
- /* release mixer resources */
- list_for_each_entry(mixer, &chip->mixer_list, list) {
- snd_usb_mixer_disconnect(mixer);
- }
+ usb_audio_disconnect_components(chip);
}
if (chip->quirk_flags & QUIRK_FLAG_DISABLE_AUTOSUSPEND)
diff --git a/sound/usb/midi2.c b/sound/usb/midi2.c
index 04aeb9052f13..3ec633291772 100644
--- a/sound/usb/midi2.c
+++ b/sound/usb/midi2.c
@@ -470,6 +470,11 @@ static int create_midi2_endpoint(struct snd_usb_midi2_interface *umidi,
static void free_midi2_endpoint(struct snd_usb_midi2_endpoint *ep)
{
list_del(&ep->list);
+ if (!ep->disconnected) {
+ ep->disconnected = 1;
+ kill_midi_urbs(ep, false);
+ drain_urb_queue(ep);
+ }
free_midi_urbs(ep);
kfree(ep);
}
--
2.43.0
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH v2] ALSA: usb-audio: Disconnect components on probe errors
2026-06-18 12:22 [PATCH v2] ALSA: usb-audio: Disconnect components on probe errors Cen Zhang
@ 2026-06-18 15:44 ` Takashi Iwai
2026-06-18 16:57 ` Cen Zhang
0 siblings, 1 reply; 3+ messages in thread
From: Takashi Iwai @ 2026-06-18 15:44 UTC (permalink / raw)
To: Cen Zhang
Cc: Jaroslav Kysela, Takashi Iwai, linux-sound, linux-kernel, baijiaju1990
On Thu, 18 Jun 2026 14:22:09 +0200,
Cen Zhang wrote:
>
> MIDI 2.0 input URBs can be submitted before usb_audio_probe() has
> finished building and registering the card. If a later setup step fails,
> cleanup can reach the card or MIDI 2.0 endpoint free path while those URBs
> are still owned by the USB core. The normal disconnect path avoids this by
> publishing the disconnected state and killing/draining URBs before endpoint
> storage and coherent transfer buffers are released.
>
> The buggy scenario involves two paths. Each column shows path order:
>
> probe error path: USB completion path:
> 1. start_input_streams() submits 1. The HCD still owns a
> input URBs. submitted input URB.
> 2. A later setup helper returns 2. input_urb_complete() runs
> an error. with urb->context in ep.
> 3. Cleanup frees endpoint storage 3. The completion reads ep
> and URB buffers. state and can requeue URBs.
>
> Factor the component release sequence out of __usb_audio_disconnect() and
> call it when usb_audio_probe() is about to free a card that never claimed
> an interface. The helper preserves the existing disconnect release order,
> including snd_usb_midi_v2_disconnect_all().
>
> Also make the MIDI 2.0 endpoint destructor perform the local disconnect,
> kill and drain sequence only when the endpoint has not already been
> disconnected, so the internal MIDI 2.0 create-error cleanup is synchronized
> without repeating the stop sequence after normal disconnect.
>
> Validation reproduced this kernel report:
> BUG: KASAN: slab-use-after-free in input_urb_complete+0x37/0x1b0
> Workqueue: usb_hub_wq hub_event
> RIP: 0010:_raw_spin_unlock_irq+0x2e/0x50
> Read of size 8
> Call trace:
> dump_stack_lvl+0x77/0xb0
> print_report+0xce/0x5f0
> input_urb_complete+0x37/0x1b0 (sound/usb/midi2.c:186)
> srso_alias_return_thunk+0x5/0xfbef5
> __virt_addr_valid+0x19f/0x330
> kasan_report+0xe0/0x110
> __usb_hcd_giveback_urb+0x112/0x1d0
> dummy_timer+0xaaa/0x19a0
> lock_is_held_type+0x9a/0x110
> __lock_acquire+0x467/0x28b0
> mark_held_locks+0x40/0x70
> _raw_spin_unlock_irqrestore+0x44/0x60
> lockdep_hardirqs_on_prepare+0xbb/0x1a0
> __hrtimer_run_queues+0x101/0x520
> hrtimer_run_softirq+0xd0/0x130
> handle_softirqs+0x15b/0x670
> __irq_exit_rcu+0xd0/0x170
> irq_exit_rcu+0xe/0x20
> sysvec_apic_timer_interrupt+0x6c/0x80
> asm_sysvec_apic_timer_interrupt+0x1a/0x20
>
> Fixes: d9c99876868c ("ALSA: usb-audio: Create UMP blocks from USB MIDI GTBs")
> Assisted-by: Codex:gpt-5.5
> Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
> ---
> v2:
> Factor USB-audio component disconnect into the probe error path and guard
> MIDI 2.0 endpoint kill/drain with ep->disconnected, per maintainer feedback.
Please split this to two patches. One is a quick fix for
free_midi2_endpoint() based on your original one, and another is
usb_audio_disconnect_components() I suggested -- those are basically
two distinct fixes. And, the latter one isn't tied with the MIDI2
issue, rather a generic hardening, and I'm going to apply the second
one after 7.2 merge window, while taking the first one for 7.2-rc1.
thanks,
Takashi
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH v2] ALSA: usb-audio: Disconnect components on probe errors
2026-06-18 15:44 ` Takashi Iwai
@ 2026-06-18 16:57 ` Cen Zhang
0 siblings, 0 replies; 3+ messages in thread
From: Cen Zhang @ 2026-06-18 16:57 UTC (permalink / raw)
To: Takashi Iwai
Cc: Jaroslav Kysela, Takashi Iwai, linux-sound, linux-kernel, baijiaju1990
Hi Takashi,
> Please split this to two patches. One is a quick fix for
> free_midi2_endpoint() based on your original one, and another is
> usb_audio_disconnect_components() I suggested -- those are basically
> two distinct fixes. And, the latter one isn't tied with the MIDI2
> issue, rather a generic hardening, and I'm going to apply the second
> one after 7.2 merge window, while taking the first one for 7.2-rc1.
>
Thanks for the clarification.
Sorry, I misunderstood your suggestion earlier and mixed the two fixes together.
I will split the change into two patches as suggested:
Best regards,
Cen Zhang
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-06-18 16:57 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-18 12:22 [PATCH v2] ALSA: usb-audio: Disconnect components on probe errors Cen Zhang
2026-06-18 15:44 ` Takashi Iwai
2026-06-18 16:57 ` Cen Zhang
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®