Re: [syzbot] [sound?] [usb?] general protection fault in snd_usbmidi_do_output

Hillf Danton
2025-09-23T07:40:31Z

> Date: Mon, 22 Sep 2025 09:54:28 -0700 [thread overview]
> Hello,
>
> syzbot found the following issue on:
>
> HEAD commit: 3b08f56fbbb9 Merge tag 'x86-urgent-2025-09-20' of git://gi..
> git tree: upstream
> console output: https://syzkaller.appspot.com/x/log.txt?x=176950e2580000
> kernel config: https://syzkaller.appspot.com/x/.config?x=927198eca77e75d9
> dashboard link: https://syzkaller.appspot.com/bug?extid=f02665daa2abeef4a947
> compiler: gcc (Debian 12.2.0-14+deb12u1) 12.2.0, GNU ld (GNU Binutils for Debian) 2.40
> syz repro: https://syzkaller.appspot.com/x/repro.syz?x=14006712580000
> C reproducer: https://syzkaller.appspot.com/x/repro.c?x=14e950e2580000

#syz test upstream master

--- x/sound/usb/midi.c
+++ y/sound/usb/midi.c
@@ -307,6 +307,8 @@ static void snd_usbmidi_do_output(struct
for (;;) {
if (!(ep->active_urbs & (1 << urb_index))) {
urb = ep->urbs[urb_index].urb;
+ if (!urb)
+ goto next;
urb->transfer_buffer_length = 0;
ep->umidi->usb_protocol_ops->output(ep, urb);
if (urb->transfer_buffer_length == 0)
@@ -319,6 +321,7 @@ static void snd_usbmidi_do_output(struct
break;
ep->active_urbs |= 1 << urb_index;
}
+ next:
if (++urb_index >= OUTPUT_URBS)
urb_index = 0;
if (urb_index == ep->next_urb)
@@ -1396,13 +1399,19 @@ static int snd_usbmidi_in_endpoint_creat
static void snd_usbmidi_out_endpoint_clear(struct snd_usb_midi_out_endpoint *ep)
{
unsigned int i;
+ unsigned long flags;

+ spin_lock_irqsave(&ep->buffer_lock, flags);
for (i = 0; i < OUTPUT_URBS; ++i)
if (ep->urbs[i].urb) {
- free_urb_and_buffer(ep->umidi, ep->urbs[i].urb,
- ep->max_transfer);
+ struct urb *urb = ep->urbs[i].urb;
+
ep->urbs[i].urb = NULL;
+ spin_unlock_irqrestore(&ep->buffer_lock, flags);
+ free_urb_and_buffer(ep->umidi, urb, ep->max_transfer);
+ spin_lock_irqsave(&ep->buffer_lock, flags);
}
+ spin_unlock_irqrestore(&ep->buffer_lock, flags);
}

static void snd_usbmidi_out_endpoint_delete(struct snd_usb_midi_out_endpoint *ep)
@@ -1522,15 +1531,23 @@ static void snd_usbmidi_free(struct snd_
{
int i;

+ timer_shutdown_sync(&umidi->error_timer);
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
struct snd_usb_midi_endpoint *ep = &umidi->endpoints[i];
- if (ep->out)
+ int j;
+
+ if (ep->out) {
+ for (j = 0; j < OUTPUT_URBS; ++j)
+ usb_kill_urb(ep->out->urbs[j].urb);
snd_usbmidi_out_endpoint_delete(ep->out);
- if (ep->in)
+ }
+ if (ep->in) {
+ for (j = 0; j < INPUT_URBS; ++j)
+ usb_kill_urb(ep->in->urbs[j]);
snd_usbmidi_in_endpoint_delete(ep->in);
+ }
}
mutex_destroy(&umidi->mutex);
- timer_shutdown_sync(&umidi->error_timer);
kfree(umidi);
}

--