The USB core API requires that usb_hcd_giveback_urb() is called with interrupts disabled. When tx_complete() is invoked by __usb_hcd_giveback_urb(), it uses this_cpu_ptr() (which relies on smp_processor_id()), expecting to be executed in an atomic context where preemption is disabled. However, in vhci_recv_ret_submit() and several other places in the vhci driver, interrupts are explicitly re-enabled using spin_unlock_irqrestore() just before calling usb_hcd_giveback_urb(). Because interrupts (and thus preemption) are enabled, the URB completion handler runs in a preemptible kthread context, leading to the following crash: BUG: using smp_processor_id() in preemptible [00000000] code: vhci_rx/5870 caller is tx_complete+0x15f/0x710 drivers/net/usb/usbnet.c:1301 Call Trace: dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120 check_preemption_disabled+0xd3/0xe0 lib/smp_processor_id.c:47 tx_complete+0x15f/0x710 drivers/net/usb/usbnet.c:1301 __usb_hcd_giveback_urb+0x374/0x530 drivers/usb/core/hcd.c:1657 vhci_recv_ret_submit drivers/usb/usbip/vhci_rx.c:107 [inline] vhci_rx_pdu drivers/usb/usbip/vhci_rx.c:242 [inline] vhci_rx_loop+0x645/0xa80 drivers/usb/usbip/vhci_rx.c:265 kthread+0x388/0x470 kernel/kthread.c:436 ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 To fix this, ensure that interrupts remain disabled while calling usb_hcd_giveback_urb(). This is done by changing spin_unlock_irqrestore() to spin_unlock() before the call, preserving the interrupt state established by spin_lock_irqsave(). After the call, the lock is re-acquired with spin_lock() and then spin_unlock_irqrestore() is called to exit the critical section and restore the original interrupt state. This approach also maintains compatibility with PREEMPT_RT kernels, where spin_lock_irqsave() maps to a sleeping lock and does not actually disable hardware interrupts. Relying on the lock's IRQ state preservation avoids crashing PREEMPT_RT kernels that would occur if local_irq_disable() and local_irq_restore() were used directly. Fixes: 04679b3489e0 ("Staging: USB/IP: add client driver") Assisted-by: Gemini:gemini-3.5-flash Gemini:gemini-3.1-pro-preview syzbot Reported-by: syzbot+04cd90bb99c6ef81a65d@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=04cd90bb99c6ef81a65d Link: https://syzkaller.appspot.com/ai_job?id=53c3fa68-e0fd-43a3-8fe6-832fabf5b714 To: "Greg Kroah-Hartman" To: To: "Shuah Khan" To: "Valentina Manea" To: "Takahiro Hirofuchi" Cc: "Hongren Zheng" Cc: --- diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index 39e8faf4c..b416d8271 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -940,9 +940,9 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) */ usb_hcd_unlink_urb_from_ep(hcd, urb); - spin_unlock_irqrestore(&vhci->lock, flags); + spin_unlock(&vhci->lock); usb_hcd_giveback_urb(hcd, urb, urb->status); - spin_lock_irqsave(&vhci->lock, flags); + spin_lock(&vhci->lock); } else { /* tcp connection is alive */ @@ -1008,11 +1008,11 @@ static void vhci_cleanup_unlink_list(struct vhci_device *vdev, list_del(&unlink->list); spin_unlock(&vdev->priv_lock); - spin_unlock_irqrestore(&vhci->lock, flags); + spin_unlock(&vhci->lock); usb_hcd_giveback_urb(hcd, urb, urb->status); - spin_lock_irqsave(&vhci->lock, flags); + spin_lock(&vhci->lock); spin_lock(&vdev->priv_lock); kfree(unlink); diff --git a/drivers/usb/usbip/vhci_rx.c b/drivers/usb/usbip/vhci_rx.c index a678e7c89..6db3a5a73 100644 --- a/drivers/usb/usbip/vhci_rx.c +++ b/drivers/usb/usbip/vhci_rx.c @@ -102,10 +102,13 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev, spin_lock_irqsave(&vhci->lock, flags); usb_hcd_unlink_urb_from_ep(vhci_hcd_to_hcd(vhci_hcd), urb); - spin_unlock_irqrestore(&vhci->lock, flags); + spin_unlock(&vhci->lock); usb_hcd_giveback_urb(vhci_hcd_to_hcd(vhci_hcd), urb, urb->status); + spin_lock(&vhci->lock); + spin_unlock_irqrestore(&vhci->lock, flags); + usbip_dbg_vhci_rx("Leave\n"); } @@ -173,9 +176,12 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev, spin_lock_irqsave(&vhci->lock, flags); usb_hcd_unlink_urb_from_ep(vhci_hcd_to_hcd(vhci_hcd), urb); - spin_unlock_irqrestore(&vhci->lock, flags); + spin_unlock(&vhci->lock); usb_hcd_giveback_urb(vhci_hcd_to_hcd(vhci_hcd), urb, urb->status); + + spin_lock(&vhci->lock); + spin_unlock_irqrestore(&vhci->lock, flags); } kfree(unlink); base-commit: 075b74841bd0065a3bda3440873c747938e69b68 -- This is an AI-generated patch subject to moderation. Reply with '#syz upstream' to Sign-off the patch as a human author and send it to the upstream kernel mailing lists. Reply with '#syz reject' to reject it ('#syz unreject' to undo). See https://goo.gle/syzbot-ai-patches for information about AI-generated patches. The person who has signed off on the patch is responsible for addressing comments. syzbot engineers can be reached at syzkaller@googlegroups.com.