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
next prev parent 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox