[PATCH RFC] usbip: vhci_hcd: keep interrupts disabled during URB giveback

"syzbot" <[email protected]>
Newsgroups dev.linux.lists.syzbot
Message-ID <[email protected]>
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:
 <TASK>
 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
 </TASK>

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: [email protected]
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" <[email protected]>
To: <[email protected]>
To: "Shuah Khan" <[email protected]>
To: "Valentina Manea" <[email protected]>
To: "Takahiro Hirofuchi" <[email protected]>
Cc: "Hongren Zheng" <[email protected]>
Cc: <[email protected]>

---
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 [email protected].
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.