usb_stream_start() submits the first two capture and playback URBs and only afterwards assigns sk->idle_inurb, sk->idle_outurb, sk->completed_inurb and sk->completed_outurb to the remaining two URBs of each direction. A transfer can complete as soon as usb_submit_urb() has been called, so the completion handler i_capture_start() or i_playback_start() may run before those pointers are set. While the stream is still being synchronized (state below usb_stream_sync1), stream_start() then calls playback_prep_freqn(sk, sk->idle_outurb) with sk->idle_outurb still NULL, and the packet descriptors are written through that NULL pointer: Oops: general protection fault, probably for non-canonical address 0xdffffc0000000018: 0000 [#1] SMP KASAN KASAN: null-ptr-deref in range [0x00000000000000c0-0x00000000000000c7] RIP: 0010:playback_prep_freqn+0x11c/0x4a0 sound/usb/usx2y/usb_stream.c:33 Call Trace: stream_start+0x5dc/0x8d0 sound/usb/usx2y/usb_stream.c:596 i_capture_start+0x3da/0x710 sound/usb/usx2y/usb_stream.c:654 __usb_hcd_giveback_urb+0x238/0x550 drivers/usb/core/hcd.c:1657 usb_giveback_urb_bh+0x20b/0x530 drivers/usb/core/hcd.c:1691 tasklet_hi_action+0xa/0x20 kernel/softirq.c:994 handle_softirqs+0x16f/0x440 kernel/softirq.c:645 The four URBs referenced by these pointers are allocated long before and do not depend on any transfer state, so assign them before the submit loop. Keeping the assignment inside the retry path also restores a well-defined URB rotation when the start frame mismatch handling kills and resubmits the streams. Fixes: 030a07e441296c372f946cd4065b5d831d8dc40c ("ALSA: Add USB US122L driver") Cc: stable@vger.kernel.org Co-developed-by: Bin Yu Signed-off-by: Bin Yu Co-developed-by: Cheng Wen Signed-off-by: Cheng Wen Signed-off-by: YuanZhe Liu <25031212351@stu.xidian.edu.cn> --- sound/usb/usx2y/usb_stream.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/usb/usx2y/usb_stream.c b/sound/usb/usx2y/usb_stream.c index 3122cf653273..7d621280fba3 100644 --- a/sound/usb/usx2y/usb_stream.c +++ b/sound/usb/usx2y/usb_stream.c @@ -682,6 +682,10 @@ int usb_stream_start(struct usb_stream_kernel *sk) s->sync_packet = -1; s->inpacket_head = -1; sk->iso_frame_balance = 0; + sk->idle_inurb = sk->inurb[USB_STREAM_NURBS - 2]; + sk->idle_outurb = sk->outurb[USB_STREAM_NURBS - 2]; + sk->completed_inurb = sk->inurb[USB_STREAM_NURBS - 1]; + sk->completed_outurb = sk->outurb[USB_STREAM_NURBS - 1]; ++try; for (u = 0; u < 2; u++) { struct urb *inurb = sk->inurb[u]; @@ -739,11 +743,6 @@ int usb_stream_start(struct usb_stream_kernel *sk) return -EFAULT; } - sk->idle_inurb = sk->inurb[USB_STREAM_NURBS - 2]; - sk->idle_outurb = sk->outurb[USB_STREAM_NURBS - 2]; - sk->completed_inurb = sk->inurb[USB_STREAM_NURBS - 1]; - sk->completed_outurb = sk->outurb[USB_STREAM_NURBS - 1]; - /* wait, check */ { int wait_ms = 3000; -- 2.34.1