[PATCH v2 2/2] nfc: pn533: add timeout to USB frame send completion wait

From: Zhao Feng

Date: Tue Oct 27 2026 - 03:02:37 EST


pn533_usb_send_frame() waits unboundedly for the out URB to complete.
A device that never completes the transfer makes the task sleep
forever in TASK_UNINTERRUPTIBLE while holding the command mutex, as
reported by syzbot (hung task in pn533_usb_send_frame).

Use a 1 second timeout instead. On timeout, kill the URB and return
-ETIMEDOUT so the command in progress fails gracefully instead of
hanging the task.

The transfer may complete between the timeout expiring and
usb_kill_urb(); in that case urb->status is 0 after the kill and the
send proceeds normally instead of reporting a spurious failure,
mirroring what usb_start_wait_urb() does.

Fixes: 9dab880d675b ("nfc: pn533: Wait for out_urb's completion in pn533_usb_send_frame()")
Reported-by: syzbot+1c5368988052dc2d8201@xxxxxxxxxxxxxxxxxxxxxxxxx
Closes: https://syzbot.org/bug?extid=1c5368988052dc2d8201
Signed-off-by: Zhao Feng <zhaofeng2@xxxxxxxxxxxxxxxxxxxx>
Cc: <stable@xxxxxxxxxxxxxxx>
---
v2: check urb->status after killing the URB on timeout and carry on if
the transfer completed in the race window; add Fixes tag and Cc
stable; the pn533_wq_cmd() error handling fix is now patch 1/2.
Issues reported by the Sashiko AI review.

drivers/nfc/pn533/usb.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/drivers/nfc/pn533/usb.c b/drivers/nfc/pn533/usb.c
index 0b7e3b118d..265baf2213 100644
--- a/drivers/nfc/pn533/usb.c
+++ b/drivers/nfc/pn533/usb.c
@@ -30,6 +30,9 @@
#define ACS_VENDOR_ID 0x072f
#define ACR122U_PRODUCT_ID 0x2200

+/* How long to wait for the out URB to complete */
+#define PN533_USB_SEND_TIMEOUT_MS 1000
+
static const struct usb_device_id pn533_usb_table[] = {
{ USB_DEVICE(PN533_VENDOR_ID, PN533_PRODUCT_ID),
.driver_info = PN533_DEVICE_STD },
@@ -184,8 +187,20 @@ static int pn533_usb_send_frame(struct pn533 *dev,
if (rc)
return rc;

- wait_for_completion(&arg.done);
- phy->out_urb->context = cntx;
+ if (!wait_for_completion_timeout(&arg.done,
+ msecs_to_jiffies(PN533_USB_SEND_TIMEOUT_MS))) {
+ usb_kill_urb(phy->out_urb);
+ phy->out_urb->context = cntx;
+ /*
+ * The transfer may have completed between the timeout
+ * expiring and the urb being killed; if so, carry on as
+ * usual instead of reporting a bogus failure.
+ */
+ if (phy->out_urb->status)
+ return -ETIMEDOUT;
+ } else {
+ phy->out_urb->context = cntx;
+ }

if (dev->protocol_type == PN533_PROTO_REQ_RESP) {
/* request for response for sent packet directly */
--
2.39.2