summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJohan Hovold <johan@kernel.org>2026-09-30 15:18:45 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-10-01 11:05:17 +0200
commit8df07fe93573e9e548d6645273e9bcb6eb74059e (patch)
treefc212e82f862627f6fccc39d07231d0ef12f7dc6 /drivers
parent8167c1f071426706c233e93ecfd13aba7d5c06c8 (diff)
downloadlinux-stable-8df07fe93573e9e548d6645273e9bcb6eb74059e.tar.gz
linux-stable-8df07fe93573e9e548d6645273e9bcb6eb74059e.zip
tty: fix saved termios reset race
Resetting saved termios state on device registration is needed where a minor number can be reused for an entirely different device and where the old settings may prevent the port from even being opened (e.g. when CLOCAL is not set). Not all TTY drivers guarantee that the minor number is no longer in use when registering devices however, something which can lead to a use-after-free when closing a TTY (and saving its termios) races with re-registration. Add a new TTY_DRIVER_RESET_SAVED_TERMIOS flag to request that any saved termios state is reset on registration and only set it for drivers that make sure that the minor number is no longer in use. Fixes: 93857edd9829 ("tty: reset termios state on device registration") Reported-by: Chengfeng Ye <nicoyip.dev@gmail.com> Link: https://lore.kernel.org/20260926184154.3017929-1-nicoyip.dev@gmail.com Cc: stable@kernel.org # 4.12 Signed-off-by: Johan Hovold <johan@kernel.org> Link: https://patch.msgid.link/20260930131845.1809256-1-johan@kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/staging/greybus/uart.c3
-rw-r--r--drivers/tty/tty_io.c18
-rw-r--r--drivers/usb/class/cdc-acm.c2
-rw-r--r--drivers/usb/serial/usb-serial.c3
4 files changed, 15 insertions, 11 deletions
diff --git a/drivers/staging/greybus/uart.c b/drivers/staging/greybus/uart.c
index 24b4dab06..172cf900e 100644
--- a/drivers/staging/greybus/uart.c
+++ b/drivers/staging/greybus/uart.c
@@ -948,7 +948,8 @@ static int gb_tty_init(void)
int retval = 0;
gb_tty_driver = tty_alloc_driver(GB_NUM_MINORS, TTY_DRIVER_REAL_RAW |
- TTY_DRIVER_DYNAMIC_DEV);
+ TTY_DRIVER_DYNAMIC_DEV |
+ TTY_DRIVER_RESET_SAVED_TERMIOS);
if (IS_ERR(gb_tty_driver)) {
pr_err("Can not allocate tty driver\n");
retval = PTR_ERR(gb_tty_driver);
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 1c30faae9..1a6c8a1bc 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -3256,14 +3256,16 @@ struct device *tty_register_device_attr(struct tty_driver *driver,
goto err_put;
if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) {
- /*
- * Free any saved termios data so that the termios state is
- * reset when reusing a minor number.
- */
- tp = driver->termios[index];
- if (tp) {
- driver->termios[index] = NULL;
- kfree(tp);
+ if (driver->flags & TTY_DRIVER_RESET_SAVED_TERMIOS) {
+ /*
+ * Free any saved termios data so that the termios
+ * state is reset when reusing a minor number.
+ */
+ tp = driver->termios[index];
+ if (tp) {
+ driver->termios[index] = NULL;
+ kfree(tp);
+ }
}
retval = tty_cdev_add(driver, devt, index, 1);
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 7bc5329fa..eeb401c0e 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -2140,7 +2140,7 @@ static int __init acm_init(void)
{
int retval;
acm_tty_driver = tty_alloc_driver(ACM_TTY_MINORS, TTY_DRIVER_REAL_RAW |
- TTY_DRIVER_DYNAMIC_DEV);
+ TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_RESET_SAVED_TERMIOS);
if (IS_ERR(acm_tty_driver))
return PTR_ERR(acm_tty_driver);
acm_tty_driver->driver_name = "acm",
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 17edc057a..06e246426 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -1313,7 +1313,8 @@ static int __init usb_serial_init(void)
int result;
usb_serial_tty_driver = tty_alloc_driver(USB_SERIAL_TTY_MINORS,
- TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV);
+ TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV |
+ TTY_DRIVER_RESET_SAVED_TERMIOS);
if (IS_ERR(usb_serial_tty_driver))
return PTR_ERR(usb_serial_tty_driver);