From: sashiko-bot@kernel.org
To: "Michael Zaidman" <michael.zaidman@gmail.com>
Cc: linux-input@vger.kernel.org, linux-serial@vger.kernel.org,
linux-gpio@vger.kernel.org, dmitry.torokhov@gmail.com
Subject: Re: [PATCH v3 01/16] HID: ft260: add serial driver
Date: Sat, 14 Nov 2026 23:39:38 +0000 [thread overview]
Message-ID: <sashiko-outbox-215117@kernel.org> (raw)
In-Reply-To: <20261114230800.1344401-2-michael.zaidman@gmail.com>
Thank you for your contribution! Sashiko AI review found 3 potential
issues to consider:
- [High] HID: ft260: UAF on port->hdev and premature xmit_fifo free on
disconnect
- [High] HID: ft260: use-after-free in ft260_uart_activate() on remove
race
- [Medium] HID: ft260: missing UART_COUNT_MAX check in
ft260_uart_add_port()
--
commit 0485244a5cc12377d97264627f49ff95e6a060c7
Author: Christina Quast <contact@christina-quast.de>
HID: ft260: add serial driver
This commit adds a TTY serial driver (/dev/ttyFTx) for the UART interface
of FT260 USB HID devices.
> diff --git a/drivers/hid/hid-ft260.c b/drivers/hid/hid-ft260.c
> index 64c9c940db46e..982e2ca7a2de6 100644
> --- a/drivers/hid/hid-ft260.c
> +++ b/drivers/hid/hid-ft260.c
[ ... ]
> @@ -1001,51 +1101,478 @@ static const struct attribute_group ft260_attr_group = {
> }
> };
>
> +static int ft260_uart_add_port(struct ft260_device *port)
> {
> + int index = 0, ret = 0;
> struct ft260_device *dev;
> +
> + spin_lock_init(&port->write_lock);
> + if (kfifo_alloc(&port->xmit_fifo, FIFO_SIZE, GFP_KERNEL))
> + return -ENOMEM;
> +
> + mutex_lock(&ft260_uart_list_lock);
> + list_for_each_entry(dev, &ft260_uart_device_list, device_list) {
> + if (dev->index != index)
> + break;
> + index++;
> + }
> +
> + port->index = index;
> + list_add_tail(&port->device_list, &ft260_uart_device_list);
> + mutex_unlock(&ft260_uart_list_lock);
> +
> + return ret;
> +}
[Severity: Medium]
Does ft260_uart_add_port() need to check if index >= UART_COUNT_MAX before
adding the port? When a fifth FT260 UART interface is probed,
ft260_uart_probe() passes dev->index == 4 to
tty_port_register_device_attr(), which triggers a WARN_ON(index >=
driver->num) in tty_port_link_device() because ft260_tty_driver was
allocated with UART_COUNT_MAX (4) lines.
While commit "HID: ft260: uart: fix the serial driver" fixes the unsorted
list insertion here, the missing UART_COUNT_MAX bounds check remains at
the end of the series.
> +
> +static void ft260_uart_port_put(struct ft260_device *port)
> +{
> + tty_port_put(&port->port);
> +}
> +
> +static void ft260_uart_port_remove(struct ft260_device *port)
> +{
> + timer_delete_sync(&port->wakeup_timer);
> +
> + mutex_lock(&ft260_uart_list_lock);
> + list_del(&port->device_list);
> + mutex_unlock(&ft260_uart_list_lock);
> +
> + tty_port_tty_vhangup(&port->port);
> +
> + spin_lock(&port->write_lock);
> + kfifo_free(&port->xmit_fifo);
> + spin_unlock(&port->write_lock);
> +}
[Severity: High]
Can freeing port->xmit_fifo in ft260_uart_port_remove() and leaving
port->hdev accessible after ft260_remove() cause a use-after-free?
struct ft260_device stays alive until the final tty_port reference is
dropped in ft260_uart_cleanup() -> ft260_uart_port_destroy(), whereas
ft260_remove() calls ft260_uart_port_remove(), hid_hw_close(hdev), and
hid_hw_stop(hdev), after which usbhid_disconnect() -> hid_destroy_device()
frees hdev. If a process keeps an open file descriptor across
ft260_remove() and reopens it (for example via /proc/self/fd/<fd>),
tty_open_by_driver() takes the tty_reopen() path into tty_port_open() ->
ft260_uart_activate(), which resets the already freed port->xmit_fifo and
calls ft260_uart_change_speed() -> ft260_hid_feature_report_set() on the
freed port->hdev. Because ft260_uart_activate() also ignores the return
value of ft260_uart_change_speed() and clears TTY_IO_ERROR, the reopen
succeeds and subsequent ft260_uart_write() and ft260_uart_set_termios()
calls operate on the freed FIFO and freed hdev as well.
Commit "HID: ft260: uart: fix the serial driver" and commit "HID: ft260:
uart: add modem pins control via ioctl" add a port->removed flag for the
modem control ioctls, but ft260_uart_port_activate() and
ft260_uart_change_speed() still do not check port->removed and
port->xmit_fifo is still freed in ft260_uart_port_remove() rather than
ft260_uart_port_destroy().
[ ... ]
> +static int ft260_uart_install(struct tty_driver *driver, struct tty_struct *tty)
> +{
> + int idx = tty->index;
> + struct ft260_device *port = ft260_uart_port_get(idx);
> + int ret;
> +
> + if (!port)
> + return -ENODEV;
> +
> + ret = tty_standard_install(driver, tty);
> if (ret) {
> + ft260_uart_port_put(port);
> return ret;
> }
>
> + tty->driver_data = port;
> + return 0;
> +}
[ ... ]
> +static int ft260_uart_activate(struct tty_port *tport, struct tty_struct *tty)
> +{
> + struct ft260_device *port =
> + container_of(tport, struct ft260_device, port);
> +
> + /*
> + * Set the TTY IO error marker - we will only clear this
> + * once we have successfully opened the port.
> + */
> + set_bit(TTY_IO_ERROR, &tty->flags);
> +
> + spin_lock(&port->write_lock);
> + kfifo_reset(&port->xmit_fifo);
> + spin_unlock(&port->write_lock);
> +
> + ft260_uart_change_speed(port, &tty->termios, NULL);
> + clear_bit(TTY_IO_ERROR, &tty->flags);
> +
> + if (port->reschedule_work) {
> + mod_timer(&port->wakeup_timer, jiffies +
> + msecs_to_jiffies(FT260_WAKEUP_NEEDED_AFTER_MS));
> + }
> +
> + return 0;
> +}
[Severity: High]
What prevents ft260_uart_activate() from running after ft260_remove() when
tty_open() races with disconnect?
CPU0 CPU1
tty_open()
tty_init_dev()
ft260_uart_install()
ft260_uart_port_get()
tty->driver_data = port
usbhid_disconnect()
hid_destroy_device()
ft260_remove()
ft260_uart_port_remove()
list_del(&port->device_list)
tty_port_tty_vhangup(&port->port)
kfifo_free(&port->xmit_fifo)
hid_hw_close(hdev)
hid_hw_stop(hdev)
kfree(hdev)
ft260_uart_open()
tty_port_open()
tty_port_tty_set()
ft260_uart_activate()
kfifo_reset(&port->xmit_fifo)
ft260_uart_change_speed()
ft260_hid_feature_report_set(port->hdev, ...)
<-- use-after-free on port->hdev
Between ft260_uart_install() and tty_port_open(), port->port.tty is still
NULL, so tty_port_tty_vhangup() in ft260_uart_port_remove() sees no tty to
hang up. tty_open() then enters ft260_uart_activate(), resets the freed
port->xmit_fifo, dereferences the freed port->hdev, and clears
TTY_IO_ERROR so the open succeeds on the removed device. Even after commit
"HID: ft260: uart: fix the serial driver" and commit "HID: ft260: uart:
add modem pins control via ioctl", ft260_uart_port_activate() still does
not check whether the device was removed under a lock synchronized with
disconnect.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261114230800.1344401-1-michael.zaidman@gmail.com?part=1
next prev parent reply other threads:[~2026-11-14 23:39 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-14 23:07 [PATCH v3 00/16] HID: ft260: add UART and GPIO support, plus I2C fixes Michael Zaidman
2026-11-14 23:07 ` [PATCH v3 01/16] HID: ft260: add serial driver Michael Zaidman
2026-11-14 23:39 ` sashiko-bot [this message]
2026-11-14 23:07 ` [PATCH v3 02/16] HID: ft260: uart: fix the " Michael Zaidman
2026-11-14 23:37 ` sashiko-bot
2026-11-14 23:07 ` [PATCH v3 03/16] HID: ft260: add GPIO support Michael Zaidman
2026-11-14 23:25 ` sashiko-bot
2026-11-14 23:07 ` [PATCH v3 04/16] HID: ft260: i2c: reduce driver module loading time Michael Zaidman
2026-11-14 23:12 ` sashiko-bot
2026-11-14 23:07 ` [PATCH v3 05/16] HID: ft260: fix sysfs store failure notice for big numbers Michael Zaidman
2026-11-14 23:17 ` sashiko-bot
2026-11-14 23:07 ` [PATCH v3 06/16] HID: ft260: i2c: reduce bus-error message severity Michael Zaidman
2026-11-14 23:12 ` sashiko-bot
2026-11-14 23:07 ` [PATCH v3 07/16] HID: ft260: uart: enable flow control Michael Zaidman
2026-11-14 23:19 ` sashiko-bot
2026-11-14 23:07 ` [PATCH v3 08/16] HID: ft260: uart: add modem pins control via ioctl Michael Zaidman
2026-11-14 23:20 ` sashiko-bot
2026-11-14 23:07 ` [PATCH v3 09/16] HID: ft260: group sysfs attrs per HID interface Michael Zaidman
2026-11-14 23:14 ` sashiko-bot
2026-11-14 23:07 ` [PATCH v3 10/16] HID: ft260: i2c: fix large write transaction failure Michael Zaidman
2026-11-14 23:12 ` sashiko-bot
2026-11-14 23:07 ` [PATCH v3 11/16] HID: ft260: workaround for TN_189 errata endpoint STALL after enumeration Michael Zaidman
2026-11-14 23:27 ` sashiko-bot
2026-11-14 23:07 ` [PATCH v3 12/16] HID: ft260: i2c: abort in-flight transfers with STOP before reset Michael Zaidman
2026-11-14 23:16 ` sashiko-bot
2026-11-14 23:07 ` [PATCH v3 13/16] HID: ft260: i2c: reject an I2C clock outside the supported range Michael Zaidman
2026-11-14 23:15 ` sashiko-bot
2026-11-14 23:07 ` [PATCH v3 14/16] HID: ft260: i2c: fix i2c_reset sysfs store return value Michael Zaidman
2026-11-14 23:15 ` sashiko-bot
2026-11-14 23:07 ` [PATCH v3 15/16] HID: ft260: i2c: recover a bus held by a slave Michael Zaidman
2026-11-14 23:25 ` sashiko-bot
2026-11-14 23:08 ` [PATCH v3 16/16] HID: ft260: use lock guards Michael Zaidman
2026-11-14 23:21 ` sashiko-bot
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-215117@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=dmitry.torokhov@gmail.com \
--cc=linux-gpio@vger.kernel.org \
--cc=linux-input@vger.kernel.org \
--cc=linux-serial@vger.kernel.org \
--cc=michael.zaidman@gmail.com \
--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.