6.6-stable review patch. If anyone has any objections, please let me know. ------------------ From: Karl Mehltretter [ Upstream commit 1a0e4fbce5d9c1bc179a35a2fd9ed142664299e3 ] serial_core_add_one_port() allocates uport->tty_groups after uart_configure_port(), which may register the console. If the allocation fails, the driver unwinds the port while its console remains registered. The earlier uport->name allocation has a related failure path that leaves state->uart_port linked to a port being freed. Failslab reproduced a NULL dereference in PL011 console output and a KASAN use-after-free in i.MX console output after failed binds. Allocate the name and tty_groups before linking the port and configuring it. Reserve space for the optional driver attribute group because config_port() may populate uport->attr_group during configuration. Fixes: 266dcff03eed ("Serial: allow port drivers to have a default attribute group") Fixes: f7048b15900f ("tty: serial_core: Add name field to uart_port struct") Reported-by: Sashiko Closes: https://lore.kernel.org/all/20260719070454.D6FA21F000E9@smtp.kernel.org/ Assisted-by: Claude:claude-fable-5 Signed-off-by: Karl Mehltretter Link: https://patch.msgid.link/20260731181844.11330-2-kmehltretter@gmail.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/tty/serial/serial_core.c | 37 ++++++++++++++++---------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index ee5da5d2bc91d..d3abab6177b10 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -3160,7 +3160,6 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u struct tty_port *port; int ret = 0; struct device *tty_dev; - int num_groups; if (uport->line >= drv->nr) return -EINVAL; @@ -3174,6 +3173,25 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u goto out; } + uport->name = kasprintf(GFP_KERNEL, "%s%d", drv->dev_name, + drv->tty_driver->name_base + uport->line); + if (!uport->name) { + ret = -ENOMEM; + goto out; + } + + /* + * uart_configure_port() may set uport->attr_group and register the + * console. Allocate room for both groups and a NULL terminator first. + */ + uport->tty_groups = kcalloc(3, sizeof(*uport->tty_groups), GFP_KERNEL); + if (!uport->tty_groups) { + kfree(uport->name); + ret = -ENOMEM; + goto out; + } + uport->tty_groups[0] = &tty_dev_attr_group; + /* Link the port to the driver state table and vice versa */ atomic_set(&state->refcount, 1); init_waitqueue_head(&state->remove_wait); @@ -3183,12 +3201,6 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u state->pm_state = UART_PM_STATE_UNDEFINED; uport->cons = drv->cons; uport->minor = drv->tty_driver->minor_start + uport->line; - uport->name = kasprintf(GFP_KERNEL, "%s%d", drv->dev_name, - drv->tty_driver->name_base + uport->line); - if (!uport->name) { - ret = -ENOMEM; - goto out; - } /* * If this port is in use as a console then the spinlock is already @@ -3205,17 +3217,6 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u port->console = uart_console(uport); - num_groups = 2; - if (uport->attr_group) - num_groups++; - - uport->tty_groups = kcalloc(num_groups, sizeof(*uport->tty_groups), - GFP_KERNEL); - if (!uport->tty_groups) { - ret = -ENOMEM; - goto out; - } - uport->tty_groups[0] = &tty_dev_attr_group; if (uport->attr_group) uport->tty_groups[1] = uport->attr_group; -- 2.53.0