* [PATCH] usb-storage: ene_ub6250: don't let the card-type probe hang forever
@ 2026-09-29 14:46 xy521521
0 siblings, 0 replies; only message in thread
From: xy521521 @ 2026-09-29 14:46 UTC (permalink / raw)
To: stern
Cc: Hongyu Xie, gregkh, linux-usb, usb-storage, linux-kernel,
syzbot+30552b4cbe99d6d91306, stable
From: Hongyu Xie <xiehongyu1@kylinos.cn>
ene_ub6250_probe() queries the card type with ene_get_card_type() while
holding us->dev_mutex (the locking added by commit 445fc368c6bc
("usb-storage: ene_ub6250: fix race between scan work and probe")).
The query is a bulk-only transaction: CBW, 1-byte data-in and CSW, each
transferred by usb_stor_bulk_transfer_buf(), which waits for URB
completion with MAX_SCHEDULE_TIMEOUT.
That unbounded wait is safe only while a SCSI command is being handled,
because the command's abort machinery (usb_stor_stop_transport() via
US_FLIDX_ABORTING) is the only thing that can terminate it. At probe
time no SCSI command exists, so a device that passes enumeration but
never services bulk transfers wedges the probe forever:
hub_event: usb_stor_msg_common() <- ene_send_scsi_cmd
<- ene_ub6250_probe (holds us->dev_mutex)
events_freezable: usb_stor_scan_dwork (blocked on us->dev_mutex)
syzbot reports the second worker as "INFO: task hung in
usb_stor_scan_dwork"; the hub_event worker is stuck in the same wait
but sleeps interruptibly, which the hung-task detector ignores.
Bound the three probe-time transfers with a 30 s timeout through a new
usb_stor_bulk_transfer_buf_timeout() helper, so a dead device fails the
probe cleanly and the existing error path unwinds via
usb_stor_disconnect().
Fixes: 445fc368c6bc ("usb-storage: ene_ub6250: fix race between scan work and probe")
Reported-by: syzbot+30552b4cbe99d6d91306@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=30552b4cbe99d6d91306
Cc: stable@vger.kernel.org
Signed-off-by: Hongyu Xie <xiehongyu1@kylinos.cn>
---
drivers/usb/storage/ene_ub6250.c | 55 ++++++++++++++++++++++++--------
drivers/usb/storage/transport.c | 31 ++++++++++++++----
drivers/usb/storage/transport.h | 3 ++
3 files changed, 69 insertions(+), 20 deletions(-)
diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c
index 895f90c7a3fa..109336bd7e30 100644
--- a/drivers/usb/storage/ene_ub6250.c
+++ b/drivers/usb/storage/ene_ub6250.c
@@ -24,6 +24,13 @@
#define DRV_NAME "ums_eneub6250"
+/*
+ * Bound for the probe-time card-type query. It runs under us->dev_mutex
+ * with no SCSI command in flight, so nothing else would terminate the
+ * bulk transfer wait if the device stopped responding.
+ */
+#define ENE_PROBE_TIMEOUT (30 * HZ)
+
MODULE_DESCRIPTION("Driver for ENE UB6250 reader");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS("USB_STORAGE");
@@ -487,7 +494,8 @@ static void ene_ub6250_info_destructor(void *extra)
kfree(info->bbuf);
}
-static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg)
+static int ene_send_scsi_cmd_timeout(struct us_data *us, u8 fDir, void *buf,
+ int use_sg, int timeout)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
@@ -499,8 +507,9 @@ static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg)
/* usb_stor_dbg(us, "transport --- ene_send_scsi_cmd\n"); */
/* send cmd to out endpoint */
- result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
- bcb, US_BULK_CB_WRAP_LEN, NULL);
+ result = usb_stor_bulk_transfer_buf_timeout(us, us->send_bulk_pipe,
+ bcb, US_BULK_CB_WRAP_LEN, NULL,
+ timeout);
if (result != USB_STOR_XFER_GOOD) {
usb_stor_dbg(us, "send cmd to out endpoint fail ---\n");
return USB_STOR_TRANSPORT_ERROR;
@@ -517,6 +526,10 @@ static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg)
/* Bulk */
if (use_sg) {
result = usb_stor_bulk_srb(us, pipe, us->srb);
+ } else if (timeout) {
+ result = usb_stor_bulk_transfer_buf_timeout(us, pipe,
+ buf, transfer_length, &partial,
+ timeout);
} else {
result = usb_stor_bulk_transfer_sg(us, pipe, buf,
transfer_length, 0, &partial);
@@ -528,20 +541,25 @@ static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg)
}
/* Get CSW for device status */
- result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
- US_BULK_CS_WRAP_LEN, &cswlen);
+ result = usb_stor_bulk_transfer_buf_timeout(us, us->recv_bulk_pipe,
+ bcs, US_BULK_CS_WRAP_LEN, &cswlen,
+ timeout);
if (result == USB_STOR_XFER_SHORT && cswlen == 0) {
usb_stor_dbg(us, "Received 0-length CSW; retrying...\n");
- result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
- bcs, US_BULK_CS_WRAP_LEN, &cswlen);
+ result = usb_stor_bulk_transfer_buf_timeout(us,
+ us->recv_bulk_pipe, bcs,
+ US_BULK_CS_WRAP_LEN, &cswlen,
+ timeout);
}
if (result == USB_STOR_XFER_STALLED) {
/* get the status again */
usb_stor_dbg(us, "Attempting to get CSW (2nd try)...\n");
- result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
- bcs, US_BULK_CS_WRAP_LEN, NULL);
+ result = usb_stor_bulk_transfer_buf_timeout(us,
+ us->recv_bulk_pipe, bcs,
+ US_BULK_CS_WRAP_LEN, NULL,
+ timeout);
}
if (result != USB_STOR_XFER_GOOD)
@@ -567,6 +585,15 @@ static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg)
return USB_STOR_TRANSPORT_GOOD;
}
+/*
+ * Unbounded variant for command-path callers: the command's abort
+ * machinery terminates usb_stor_msg_common()'s wait if the device dies.
+ */
+static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg)
+{
+ return ene_send_scsi_cmd_timeout(us, fDir, buf, use_sg, 0);
+}
+
static int do_scsi_request_sense(struct us_data *us, struct scsi_cmnd *srb)
{
struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
@@ -1826,7 +1853,8 @@ static int ms_scsi_write(struct us_data *us, struct scsi_cmnd *srb)
* ENE MS Card
*/
-static int ene_get_card_type(struct us_data *us, u16 index, void *buf)
+static int ene_get_card_type(struct us_data *us, u16 index, void *buf,
+ int timeout)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
@@ -1839,7 +1867,7 @@ static int ene_get_card_type(struct us_data *us, u16 index, void *buf)
bcb->CDB[2] = (unsigned char)(index>>8);
bcb->CDB[3] = (unsigned char)index;
- result = ene_send_scsi_cmd(us, FDIR_READ, buf, 0);
+ result = ene_send_scsi_cmd_timeout(us, FDIR_READ, buf, 0, timeout);
return result;
}
@@ -2193,7 +2221,7 @@ static int ene_init(struct us_data *us)
struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
u8 *bbuf = info->bbuf;
- result = ene_get_card_type(us, REG_CARD_STATUS, bbuf);
+ result = ene_get_card_type(us, REG_CARD_STATUS, bbuf, 0);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
@@ -2358,7 +2386,8 @@ static int ene_ub6250_probe(struct usb_interface *intf,
/* probe card type */
mutex_lock(&us->dev_mutex);
- result = ene_get_card_type(us, REG_CARD_STATUS, info->bbuf);
+ result = ene_get_card_type(us, REG_CARD_STATUS, info->bbuf,
+ ENE_PROBE_TIMEOUT);
mutex_unlock(&us->dev_mutex);
if (result != USB_STOR_XFER_GOOD) {
usb_stor_disconnect(intf);
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index 9a4bf86e7b6a..c586d2021b7e 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -378,12 +378,18 @@ static int usb_stor_intr_transfer(struct us_data *us, void *buf,
}
/*
- * Transfer one buffer via bulk pipe, without timeouts, but allowing early
- * termination. Return codes are USB_STOR_XFER_xxx. If the bulk pipe
- * stalls during the transfer, the halt is automatically cleared.
+ * Transfer one buffer via bulk pipe, allowing early termination. Return
+ * codes are USB_STOR_XFER_xxx. If the bulk pipe stalls during the
+ * transfer, the halt is automatically cleared.
+ *
+ * A nonzero timeout bounds the wait for URB completion. It must be used
+ * only when no SCSI command is being handled: usb_stor_msg_common()
+ * otherwise waits indefinitely, relying on the active command's abort
+ * machinery to terminate the wait.
*/
-int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
- void *buf, unsigned int length, unsigned int *act_len)
+int usb_stor_bulk_transfer_buf_timeout(struct us_data *us, unsigned int pipe,
+ void *buf, unsigned int length, unsigned int *act_len,
+ int timeout)
{
int result;
@@ -392,14 +398,25 @@ int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
/* fill and submit the URB */
usb_fill_bulk_urb(us->current_urb, us->pusb_dev, pipe, buf, length,
usb_stor_blocking_completion, NULL);
- result = usb_stor_msg_common(us, 0);
+ result = usb_stor_msg_common(us, timeout);
/* store the actual length of the data transferred */
if (act_len)
*act_len = us->current_urb->actual_length;
- return interpret_urb_result(us, pipe, length, result,
+ return interpret_urb_result(us, pipe, length, result,
us->current_urb->actual_length);
}
+EXPORT_SYMBOL_GPL(usb_stor_bulk_transfer_buf_timeout);
+
+/*
+ * Same as usb_stor_bulk_transfer_buf_timeout() with an unbounded wait.
+ */
+int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
+ void *buf, unsigned int length, unsigned int *act_len)
+{
+ return usb_stor_bulk_transfer_buf_timeout(us, pipe, buf, length,
+ act_len, 0);
+}
EXPORT_SYMBOL_GPL(usb_stor_bulk_transfer_buf);
/*
diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
index 74ffd0d7e7b6..dc0442efc24d 100644
--- a/drivers/usb/storage/transport.h
+++ b/drivers/usb/storage/transport.h
@@ -77,6 +77,9 @@ extern int usb_stor_clear_halt(struct us_data *us, unsigned int pipe);
extern int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe,
u8 request, u8 requesttype, u16 value, u16 index,
void *data, u16 size);
+extern int usb_stor_bulk_transfer_buf_timeout(struct us_data *us,
+ unsigned int pipe, void *buf, unsigned int length,
+ unsigned int *act_len, int timeout);
extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
void *buf, unsigned int length, unsigned int *act_len);
extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe,
--
2.32.0
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-09-29 14:46 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-29 14:46 [PATCH] usb-storage: ene_ub6250: don't let the card-type probe hang forever xy521521
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®