⬢ DragonFlyBSD Kernel Audit
DF-5359 / fix.diff
← back to finding ↓ download raw
--- sys/bus/u4b/serial/uipaq.c
+++ sys/bus/u4b/serial/uipaq.c
@@ -1126,13 +1126,21 @@ uipaq_attach(device_t dev)
 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
 	req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
 	USETW(req.wValue, UCDC_LINE_DTR);
 	USETW(req.wIndex, 0x0);
 	USETW(req.wLength, 0);
-	for (i = 0; i != 64; i++) {
+	/*
+	 * NOTE: The original WinCE warm-up loop retried 64 times with a
+	 * 100ms request timeout plus a 100ms pause and no early-out, which
+	 * allows an unresponsive or crafted device to stall the per-bus USB
+	 * explore thread (and the device enum lock) for up to ~13 seconds
+	 * per insertion.  Retry only while the request is timing out --
+	 * which is the genuine "device not ready yet" case -- and give up
+	 * immediately when the request succeeded, was actively rejected,
+	 * or the device is gone.  16 * (100ms + 100ms) still gives the
+	 * device ~3 seconds to become ready.
+	 */
+	for (i = 0; i != 16; i++) {
 		error =
 		    usbd_do_request_flags(uaa->device, NULL, &req,
 		    NULL, 0, NULL, 100);
-		if (error == 0)
+		if (error != USB_ERR_TIMEOUT)
 			break;
 		usb_pause_mtx(NULL, hz / 10);
 	}