nullpointer dereference in V4L2CaptureThread when in-use USB3 uvcvideo device drops of the bus: [5473614.803782] usb 4-4.4: New USB device strings: Mfr=6, Product=7, SerialNumber=3 [5473614.803784] usb 4-4.4: Product: HDMI to U3 capture [5473614.803785] usb 4-4.4: Manufacturer: Video Grabber [5473614.803787] usb 4-4.4: SerialNumber: 20000130041415 [5473614.804178] uvcvideo: Found UVC 1.00 device HDMI to U3 capture (1e4e:701f) [5473614.818515] uvcvideo: UVC non compliance - GET_DEF(PROBE) not supported. Enabling workaround. [5473614.818716] uvcvideo 4-4.4:1.0: Entity type for entity Extension 4 was not initialized! [5473614.818718] uvcvideo 4-4.4:1.0: Entity type for entity Processing 3 was not initialized! [5473614.818720] uvcvideo 4-4.4:1.0: Entity type for entity Camera 1 was not initialized! [5473614.869980] systemd-udevd[16462]: Process '/usr/sbin/alsactl -E HOME=/run/alsa restore 3' failed with exit code 99. [5473633.057731] usb 4-4.4: reset SuperSpeed Gen 1 USB device number 58 using xhci_hcd [5473635.636401] usb 4-4.4: USB disconnect, device number 58 [5473635.642127] BUG: kernel NULL pointer dereference, address: 0000000000000000 [5473635.642132] #PF: supervisor read access in kernel mode [5473635.642133] #PF: error_code(0x0000) - not-present page [5473635.642135] PGD 0 P4D 0 [5473635.642139] Oops: 0000 [#1] SMP [5473635.642142] CPU: 0 PID: 16509 Comm: V4L2CaptureThre Not tainted 5.4.26 #2 [5473635.642144] Hardware name: Gigabyte Technology Co., Ltd. AB350M-D3H/AB350M-D3H-CF, BIOS F31 05/06/2019 [5473635.642151] RIP: 0010:usb_ifnum_to_if+0x21/0x37 [5473635.642153] Code: ff ff 5b 5d 41 5c 41 5d c3 48 8b 87 98 03 00 00 48 85 c0 74 2a 0f b6 78 04 31 d2 39 d7 7e 1d 48 8b 8c d0 98 00 00 00 48 ff c2 <4c> 8b 01 45 0f b6 40 02 41 39 f0 75 e4 48 89 c8 eb 03 31 c0 c3 c3 [5473635.642155] RSP: 0018:ffffa140c109fb98 EFLAGS: 00010202 [5473635.642157] RAX: ffff89f4e64d2c00 RBX: ffff89f60d4b1000 RCX: 0000000000000000 [5473635.642159] RDX: 0000000000000001 RSI: 0000000000000001 RDI: 0000000000000004 [5473635.642160] RBP: ffff89f5b095fa88 R08: 00000000ffffffed R09: 0000000000000001 [5473635.642162] R10: 000000000000000b R11: 0045e025810cb2e0 R12: 0000000000000000 [5473635.642163] R13: ffff89f5b095fa88 R14: ffff89f5b095fad8 R15: ffff89f3d2f60000 [5473635.642165] FS: 00007f9a5c6ce700(0000) GS:ffff89f61ee00000(0000) knlGS:0000000000000000 [5473635.642167] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [5473635.642168] CR2: 0000000000000000 CR3: 00000003c193f000 CR4: 00000000003406f0 [5473635.642170] Call Trace: [5473635.642175] usb_hcd_alloc_bandwidth+0x1e8/0x2d9 [5473635.642179] usb_set_interface+0x1b4/0x290 [5473635.642187] uvc_video_stop_streaming+0x2f/0x75 [uvcvideo] [5473635.642192] uvc_stop_streaming+0x17/0x43 [uvcvideo] [5473635.642196] __vb2_queue_cancel+0x6c/0x2fd [videobuf2_common] [5473635.642201] vb2_core_streamoff+0x2b/0x73 [videobuf2_common] [5473635.642205] uvc_queue_streamoff+0x25/0x39 [uvcvideo] [5473635.642209] uvc_ioctl_streamoff+0x38/0x47 [uvcvideo] [5473635.642213] __video_do_ioctl+0x279/0x3c1 [5473635.642219] ? _raw_spin_unlock_irqrestore+0xd/0xe [5473635.642222] ? try_to_wake_up+0x290/0x363 [5473635.642225] video_usercopy+0x28b/0x46d [5473635.642227] ? v4l_g_ctrl+0x11f/0x11f [5473635.642230] ? vtime_delta.isra.10+0x9/0x1e [5473635.642233] v4l2_ioctl+0x42/0x48 [5473635.642236] vfs_ioctl+0x19/0x26 [5473635.642238] do_vfs_ioctl+0x526/0x54e [5473635.642241] ? finish_task_switch+0x1d4/0x218 [5473635.642245] ? timekeeping_get_ns+0x19/0x2c [5473635.642248] ? paravirt_sched_clock+0x5/0x8 [5473635.642250] ksys_ioctl+0x39/0x58 [5473635.642252] __x64_sys_ioctl+0x11/0x14 [5473635.642255] do_syscall_64+0x83/0x91 [5473635.642258] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [5473635.642261] RIP: 0033:0x7f9a614a5427 [5473635.642264] Code: 00 00 90 48 8b 05 69 aa 0c 00 64 c7 00 26 00 00 00 48 c7 c0 ff ff ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 39 aa 0c 00 f7 d8 64 89 01 48 [5473635.642265] RSP: 002b:00007f9a5c6cd258 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 [5473635.642268] RAX: ffffffffffffffda RBX: 00002059db1a35f0 RCX: 00007f9a614a5427 [5473635.642269] RDX: 00007f9a5c6cd2ac RSI: 0000000040045613 RDI: 0000000000000017 [5473635.642270] RBP: 00007f9a5c6cd2f0 R08: 0000000000000000 R09: 00007f9a5c6cd3d8 [5473635.642272] R10: 00007ffeaab6e090 R11: 0000000000000246 R12: 00002059db230158 [5473635.642273] R13: 00002059db230000 R14: 00002059db230000 R15: 00007f9a5c6cd2ac [5473635.642275] Modules linked in: cfg80211 snd_usb_audio bnep bluetooth uvcvideo videobuf2_vmalloc videobuf2_memops snd_usbmidi_lib videobuf2_v4l2 snd_rawmidi videobuf2_common [last unloaded: snd_usb_audio] [5473635.642282] CR2: 0000000000000000 [5473635.642284] ---[ end trace cbc4d60c1db09b1c ]--- [5473635.642287] RIP: 0010:usb_ifnum_to_if+0x21/0x37 [5473635.642289] Code: ff ff 5b 5d 41 5c 41 5d c3 48 8b 87 98 03 00 00 48 85 c0 74 2a 0f b6 78 04 31 d2 39 d7 7e 1d 48 8b 8c d0 98 00 00 00 48 ff c2 <4c> 8b 01 45 0f b6 40 02 41 39 f0 75 e4 48 89 c8 eb 03 31 c0 c3 c3 [5473635.642291] RSP: 0018:ffffa140c109fb98 EFLAGS: 00010202 [5473635.642292] RAX: ffff89f4e64d2c00 RBX: ffff89f60d4b1000 RCX: 0000000000000000 [5473635.642293] RDX: 0000000000000001 RSI: 0000000000000001 RDI: 0000000000000004 [5473635.642295] RBP: ffff89f5b095fa88 R08: 00000000ffffffed R09: 0000000000000001 [5473635.642296] R10: 000000000000000b R11: 0045e025810cb2e0 R12: 0000000000000000 [5473635.642297] R13: ffff89f5b095fa88 R14: ffff89f5b095fad8 R15: ffff89f3d2f60000 [5473635.642299] FS: 00007f9a5c6ce700(0000) GS:ffff89f61ee00000(0000) knlGS:0000000000000000 [5473635.642300] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [5473635.642302] CR2: 0000000000000000 CR3: 00000003c193f000 CR4: 00000000003406f0 [5473635.700061] show_signal_msg: 3729 callbacks suppressed [5473635.700065] chrome[16497]: segfault at 0 ip 000056399a1110f4 sp 00007ffeaaa675c0 error 4 in chrome[563997639000+7349000] [5473635.700080] Code: 48 89 de 31 d2 4c 89 f1 e8 b9 20 fa ff eb 07 48 8b 1d b0 fd 10 05 48 89 df 5b 41 5e 5d e9 64 2e 00 00 cc cc cc cc 55 48 89 e5 <48> 8b 0f 4c 8b 47 08 4c 89 c0 48 29 c8 74 41 48 c1 f8 03 48 bf ab
Older report for USB2 webcam with same stack backtrace: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1827452
Interestingly, usb_set_interface() already calls usb_ifnum_to_if() once, which did not fail. Then after calling usb_disable_interface() it calls usb_hcd_alloc_bandwidth(), which does another call to usb_ifnum_to_if(), which faulted with the null deref. The fault is at: mov rax, [rdx + 0x398] test rax, rax jz early_exit_since_config_is_null [...] mov rcx, [rax + rdx*8 + 0x98] inc rdx -> mov r8, [rcx] movzx r8d, byte ptr [r8 + 2] [...] So I think the fault is at [...] for (i = 0; i < config->desc.bNumInterfaces; i++) -> if (config->interface[i]->altsetting[0].desc.bInterfaceNumber == ifnum) ^^^^^^^^^^^^nullptr return config->interface[i]; [...] usb_set_interface() only checks for dev->state == USB_STATE_SUSPENDED, maybe it also needs to check for dev->state == USB_STATE_NOTATTACHED? The disconnect message indicates this would have been the state the device was in, from usb_disconnect(): [...] usb_set_device_state(udev, USB_STATE_NOTATTACHED); dev_info(&udev->dev, "USB disconnect, device number %d\n", udev->devnum); [...]
The problem is not that usb_set_interface() does inadequate checking; the problem is that the uvc_video driver calls usb_set_interface() at an inappropriate time -- i.e., after its remove routine has returned. (I don't know this for certain, but it seems likely given the context of the bug.)
I'm guessing that's the device disconnect callback? static void uvc_disconnect(struct usb_interface *intf) { struct uvc_device *dev = usb_get_intfdata(intf); /* Set the USB interface data to NULL. This can be done outside the * lock, as there's no other reader. */ usb_set_intfdata(intf, NULL); if (intf->cur_altsetting->desc.bInterfaceSubClass == UVC_SC_VIDEOSTREAMING) return; uvc_unregister_video(dev); kref_put(&dev->ref, uvc_delete); } Meanwhile uvc_stop_streaming is a vb2_ops (videobuf2) callback from the V4L2CaptureThread. I'm guessing then that uvc_disconnect() should wait for videobufs to be stopped before returning?
Yes. I'm not familiar with this driver, but it looks like uvc_unregister_video() (or one of the routines it calls) is supposed to do the waiting.