Skip to content

Commit 699dfb6

Browse files
jhovoldgregkh
authored andcommitted
USB: serial: digi_acceleport: fix write buffer corruption
commit 24ca1fe upstream. The digi_write_inb_command() is supposed to wait for the write urb to become available or return an error, but instead it updates the transfer buffer and tries to resubmit the urb on timeout. To make things worse, for commands like break control where no timeout is used, the driver would corrupt the urb immediately due to a broken jiffies comparison (on 32-bit machines this takes five minutes of uptime to trigger due to INITIAL_JIFFIES). Fix this by adding the missing return on timeout and waiting indefinitely when no timeout has been specified as intended. This issue was (sort of) flagged by Sashiko when reviewing an unrelated change to the driver. Link: https://sashiko.dev/#/patchset/20260610132232.356139-1-johan%40kernel.org?part=11 Fixes: 1da177e ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Johan Hovold <johan@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent bcfeae4 commit 699dfb6

1 file changed

Lines changed: 10 additions & 5 deletions

File tree

drivers/usb/serial/digi_acceleport.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -433,20 +433,22 @@ static int digi_write_inb_command(struct usb_serial_port *port,
433433
int len;
434434
struct digi_port *priv = usb_get_serial_port_data(port);
435435
unsigned char *data = port->write_urb->transfer_buffer;
436+
unsigned long expire;
436437
unsigned long flags;
437438

438439
dev_dbg(&port->dev, "digi_write_inb_command: TOP: port=%d, count=%d\n",
439440
priv->dp_port_num, count);
440441

441442
if (timeout)
442-
timeout += jiffies;
443-
else
444-
timeout = ULONG_MAX;
443+
expire = jiffies + timeout;
445444

446445
spin_lock_irqsave(&priv->dp_port_lock, flags);
447446
while (count > 0 && ret == 0) {
448-
while (priv->dp_write_urb_in_use &&
449-
time_before(jiffies, timeout)) {
447+
while (priv->dp_write_urb_in_use) {
448+
if (timeout && time_after(jiffies, expire)) {
449+
ret = -ETIMEDOUT;
450+
break;
451+
}
450452
cond_wait_interruptible_timeout_irqrestore(
451453
&priv->write_wait, DIGI_RETRY_TIMEOUT,
452454
&priv->dp_port_lock, flags);
@@ -455,6 +457,9 @@ static int digi_write_inb_command(struct usb_serial_port *port,
455457
spin_lock_irqsave(&priv->dp_port_lock, flags);
456458
}
457459

460+
if (ret)
461+
break;
462+
458463
/* len must be a multiple of 4 and small enough to */
459464
/* guarantee the write will send buffered data first, */
460465
/* so commands are in order with data and not split */

0 commit comments

Comments
 (0)