[PATCH 05/24] serial: 8250: clear subdriver state on port unregister

From: Greg Kroah-Hartman

Date: Tue Oct 27 2026 - 07:13:23 EST


From: Joshua Rogers <linux@xxxxxxxxx>

When serial8250_unregister_port() re-adds a port as a fallback ISA port,
it only partially resets the port state via serial8250_init_port(). All
subdriver-owned function pointers and per-driver state copied during
registration (such as startup, shutdown, handle_break, get_mctrl,
set_mctrl, set_termios, private_data, dma, gpios, and rs485 callbacks)
are left intact. After the original driver module is unloaded, these
become dangling pointers that can trigger use-after-free on subsequent
port operations.

Clear all subdriver-copied fields and call serial8250_set_defaults() to
restore default I/O accessors before re-adding the fallback port.

Cc: stable <stable@xxxxxxxxxx>
Cc: Jiri Slaby <jirislaby@xxxxxxxxxx>
Cc: John Ogness <john.ogness@xxxxxxxxxxxxx>
Cc: Crescent Hsieh <crescentcy.hsieh@xxxxxxxx>
Cc: "Uwe Kleine-König (The Capable Hub)" <u.kleine-koenig@xxxxxxxxxxxx>
Cc: Fushuai Wang <wangfushuai@xxxxxxxxx>
Signed-off-by: Joshua Rogers <linux@xxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
---
drivers/tty/serial/8250/8250_core.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)

diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 0951d3e42e1f..673fde55828a 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -956,7 +956,35 @@ void serial8250_unregister_port(struct uart_8250_port *uart)
uart->port.dev = &serial8250_isa_devs->dev;
uart->port.port_id = uart->port.line;
uart->capabilities = 0;
+
+ /*
+ * Clear subdriver-owned state copied by
+ * serial8250_register_8250_port() to prevent dangling
+ * pointers after the original driver module is unloaded.
+ */
+ uart->port.private_data = NULL;
+ uart->port.set_termios = NULL;
+ uart->port.set_ldisc = NULL;
+ uart->port.get_mctrl = NULL;
+ uart->port.set_mctrl = NULL;
+ uart->port.get_divisor = NULL;
+ uart->port.set_divisor = NULL;
+ uart->port.startup = NULL;
+ uart->port.shutdown = NULL;
+ uart->port.throttle = NULL;
+ uart->port.unthrottle = NULL;
+ uart->port.handle_break = NULL;
+ uart->port.rs485_config = NULL;
+ memset(&uart->port.rs485, 0, sizeof(uart->port.rs485));
+ memset(&uart->port.rs485_supported, 0,
+ sizeof(uart->port.rs485_supported));
+ uart->gpios = NULL;
+ uart->dma = NULL;
+ uart->rs485_start_tx = NULL;
+ uart->rs485_stop_tx = NULL;
+
serial8250_init_port(uart);
+ serial8250_set_defaults(uart);
serial8250_apply_quirks(uart);
uart_add_one_port(&serial8250_reg, &uart->port);
} else {

--
2.56.0