All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Johan Hovold" <johan@kernel.org>
Cc: linux-usb@vger.kernel.org
Subject: Re: [PATCH 02/11] USB: serial: io_edgeport: fix potential fifo corruption
Date: Wed, 21 Oct 2026 14:31:22 +0000	[thread overview]
Message-ID: <sashiko-outbox-180379@kernel.org> (raw)
In-Reply-To: <20261021141154.2324793-3-johan@kernel.org>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] usb: serial: io_edgeport: race in process_rcvd_status() allows FIFO corruption
--

commit 3c973c9c441546b1507dc5bafcc938334e398bb6
Author: Johan Hovold <johan@kernel.org>

USB: serial: io_edgeport: fix potential fifo corruption

This commit initializes maxTxCredits to zero when opening a port and rejects
subsequent open responses in process_rcvd_status() if maxTxCredits is already
non-zero, preventing a device from changing the buffer size after the tx fifo
has been allocated.

Link: https://sashiko.dev/#/patchset/20260714101316.823942-1-shpark061104%40gmail.com?part=1

> diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
> index cdf41e86ba448..0cc4f41299e03 100644
> --- a/drivers/usb/serial/io_edgeport.c
> +++ b/drivers/usb/serial/io_edgeport.c
> @@ -878,7 +878,11 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
>  	}
>  
>  	/* initialize our port settings */
> +	spin_lock_irq(&edge_port->ep_lock);
>  	edge_port->txCredits = 0;	/* Can't send any data yet */
> +	edge_port->maxTxCredits = 0;
> +	spin_unlock_irq(&edge_port->ep_lock);
> +
>  	/* Must always set this bit to enable ints! */
>  	edge_port->shadowMCR = MCR_MASTER_IE;
>  	edge_port->chaseResponsePending = false;
> @@ -1750,6 +1754,7 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial,
>  	struct tty_struct *tty;
>  	struct device *dev;
>  	__u8 code = edge_serial->rxStatusCode;
> +	unsigned long flags;
>  
>  	/* switch the port pointer to the one being currently talked about */
>  	if (edge_serial->rxPort >= edge_serial->serial->num_ports)
> @@ -1793,10 +1798,17 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial,
>  	}
>  
>  	if (code == IOSP_STATUS_OPEN_RSP) {
> +		spin_lock_irqsave(&edge_port->ep_lock, flags);
> +		/* reject stray open responses to avoid FIFO corruption */
> +		if (edge_port->maxTxCredits != 0) {
> +			spin_unlock_irqrestore(&edge_port->ep_lock, flags);
> +			return;
> +		}
>  		edge_port->txCredits = GET_TX_BUFFER_SIZE(byte3);
>  		edge_port->maxTxCredits = edge_port->txCredits;
>  		dev_dbg(dev, "%s - Port %u Open Response Initial MSR = %02x TxBufferSize = %d\n",
>  			__func__, edge_serial->rxPort, byte2, edge_port->txCredits);
> +		spin_unlock_irqrestore(&edge_port->ep_lock, flags);
>  		handle_new_msr(edge_port, byte2);
>  
>  		/* send the current line settings to the port so we are

[Severity: High]
Could an unsolicited IOSP_STATUS_OPEN_RSP message race with edge_open() in
drivers/usb/serial/io_edgeport.c and still corrupt edge_port->txfifo?

In process_rcvd_status(), edge_port->ep_lock only covers the check and
assignment of edge_port->maxTxCredits, without checking
edge_port->openPending, and the lock is dropped before clearing
edge_port->openPending:

	if (code == IOSP_STATUS_OPEN_RSP) {
		spin_lock_irqsave(&edge_port->ep_lock, flags);
		/* reject stray open responses to avoid FIFO corruption */
		if (edge_port->maxTxCredits != 0) {
			spin_unlock_irqrestore(&edge_port->ep_lock, flags);
			return;
		}
		edge_port->txCredits = GET_TX_BUFFER_SIZE(byte3);
		edge_port->maxTxCredits = edge_port->txCredits;
		...
		spin_unlock_irqrestore(&edge_port->ep_lock, flags);
		handle_new_msr(edge_port, byte2);
		...
		/* we have completed the open */
		edge_port->openPending = false;
		edge_port->open = true;
		wake_up(&edge_port->wait_open);
		return;
	}

Meanwhile, in edge_open(), edge_port->maxTxCredits is cleared under
edge_port->ep_lock before edge_port->openPending is set outside the lock, and
after wait_event_timeout() returns, edge_port->maxTxCredits is read without
holding edge_port->ep_lock:

	spin_lock_irq(&edge_port->ep_lock);
	edge_port->txCredits = 0;	/* Can't send any data yet */
	edge_port->maxTxCredits = 0;
	spin_unlock_irq(&edge_port->ep_lock);
	...
	edge_port->openPending = true;
	edge_port->open        = false;
	response = send_iosp_ext_cmd(edge_port, IOSP_CMD_OPEN_PORT, 0);
	...
	wait_event_timeout(edge_port->wait_open, !edge_port->openPending,
								OPEN_TIMEOUT);
	...
	edge_port->txfifo.size	= edge_port->maxTxCredits;
	edge_port->txfifo.fifo	= kmalloc(edge_port->maxTxCredits, GFP_KERNEL);

If an unsolicited IOSP_STATUS_OPEN_RSP arrives on the bulk-in endpoint (which
can already be active from edge_startup(), another open port, or the
interrupt urb submitted earlier in edge_open()) and runs the ep_lock section
in process_rcvd_status() just before edge_open() takes ep_lock:

1. edge_open() resets edge_port->maxTxCredits = 0 under ep_lock and sets
   edge_port->openPending = true.
2. The in-flight process_rcvd_status() finishes handle_new_msr() and
   change_port_settings(), then sets edge_port->openPending = false and
   edge_port->open = true, waking edge_open().
3. edge_open() observes edge_port->maxTxCredits == 0, sets
   edge_port->txfifo.size = 0, and calls kmalloc(0, GFP_KERNEL), storing
   ZERO_SIZE_PTR in edge_port->txfifo.fifo.
4. Because edge_port->maxTxCredits was reset to 0, a second
   IOSP_STATUS_OPEN_RSP passes the edge_port->maxTxCredits != 0 check in
   process_rcvd_status() and sets edge_port->txCredits and
   edge_port->maxTxCredits to a non-zero value (or races between setting
   edge_port->txfifo.size and calling kmalloc()).
5. Subsequent edge_write() calls then compute a non-zero copySize from
   edge_port->txCredits while edge_port->txfifo.size is 0, causing memcpy()
   to dereference ZERO_SIZE_PTR or overflow edge_port->txfifo.fifo.

In this commit, an unsolicited IOSP_STATUS_OPEN_RSP on a closed port also
sets edge_port->open = true while edge_port->txfifo.fifo and
edge_port->write_urb are null. Follow-up commits ("USB: serial: io_edgeport:
fix potential NULL-deref at open" and "USB: serial: io_edgeport: move initial
termios update to open()") move setting edge_port->open = true and calling
change_port_settings() into edge_open(), but the unsynchronized
openPending and maxTxCredits race remains present.

Should edge_port->openPending also be synchronized under edge_port->ep_lock
and checked in process_rcvd_status() before accepting IOSP_STATUS_OPEN_RSP?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261021141154.2324793-1-johan@kernel.org?part=2

  reply	other threads:[~2026-10-21 14:31 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-21 14:11 [PATCH 00/11] USB: serial: io_edgeport: fixes and sync commands Johan Hovold
2026-10-21 14:11 ` [PATCH 01/11] USB: serial: io_edgeport: fix NULL-deref on early status Johan Hovold
2026-10-21 14:20   ` sashiko-bot
2026-10-21 14:11 ` [PATCH 02/11] USB: serial: io_edgeport: fix potential fifo corruption Johan Hovold
2026-10-21 14:31   ` sashiko-bot [this message]
2026-10-21 14:11 ` [PATCH 03/11] USB: serial: io_edgeport: fix potential close() use-after-free Johan Hovold
2026-10-21 14:37   ` sashiko-bot
2026-10-21 14:11 ` [PATCH 04/11] USB: serial: io_edgeport: fix potential NULL-deref at open Johan Hovold
2026-10-21 14:28   ` sashiko-bot
2026-10-21 14:11 ` [PATCH 05/11] USB: serial: io_edgeport: serialise MCR accesses Johan Hovold
2026-10-21 14:26   ` sashiko-bot
2026-10-21 15:27     ` Johan Hovold
2026-10-21 14:11 ` [PATCH 06/11] USB: serial: io_edgeport: drop redundant sanity checks Johan Hovold
2026-10-21 14:24   ` sashiko-bot
2026-10-21 14:11 ` [PATCH 07/11] USB: serial: io_edgeport: drop redundant open " Johan Hovold
2026-10-21 14:42   ` sashiko-bot
2026-10-21 14:11 ` [PATCH 08/11] USB: serial: io_edgeport: move initial termios update to open() Johan Hovold
2026-10-21 14:25   ` sashiko-bot
2026-10-21 14:11 ` [PATCH 09/11] USB: serial: io_edgeport: deassert DTR/RTS on close() and B0 Johan Hovold
2026-10-21 14:22   ` sashiko-bot
2026-10-21 14:11 ` [PATCH 10/11] USB: serial: io_edgeport: replace atomic command allocations Johan Hovold
2026-10-21 14:19   ` sashiko-bot
2026-10-21 14:11 ` [PATCH 11/11] USB: serial: io_edgeport: switch to synchronous commands Johan Hovold
2026-10-21 14:23   ` sashiko-bot
2026-10-21 15:43     ` Johan Hovold

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-180379@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=johan@kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.