[PATCH] serial: imx: cancel RS485 trigger hrtimers in shutdown and remove

Fan Wu <[email protected]>
Newsgroups org.kernel.vger.linux-serial,dev.linux.lists.imx,org.infradead.lists.linux-arm-kernel,org.kernel.vger.linux-kernel,org.kernel.vger.stable
Message-ID <[email protected]>
The rs485 delay hrtimers trigger_start_tx and trigger_stop_tx are
embedded in the devm allocated struct imx_port, and their callbacks
reach the port through container_of() and touch registers under the
port lock.  Nothing cancels them synchronously: the tx paths only
call hrtimer_try_to_cancel(), which does not wait for a running
callback, and the bounded wait in imx_uart_shutdown() can give up,
force tx_state to OFF, and leave a timer armed.  After
imx_uart_remove() returns, devm frees the port and a late callback
dereferences freed memory.

Cancel both timers at the end of imx_uart_shutdown(), after the port
lock is dropped and before the clocks are disabled, and again in
imx_uart_remove() before the devm free: serial core does not call the
driver shutdown on every path that reaches remove().

This issue was found by an in-house static analysis tool.

Fixes: bd78ecd6056d ("serial: imx: use hrtimers for rs485 delays")
Cc: [email protected]
Assisted-by: Codex:gpt-5.6
Signed-off-by: Fan Wu <[email protected]>
---
 drivers/tty/serial/imx.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 251a50c8aa38..86c99f73c50a 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -1707,6 +1707,10 @@ static void imx_uart_shutdown(struct uart_port *port)
 
 	uart_port_unlock_irqrestore(&sport->port, flags);
 
+	/* The rs485 trigger callbacks take the port lock and touch registers. */
+	hrtimer_cancel(&sport->trigger_start_tx);
+	hrtimer_cancel(&sport->trigger_stop_tx);
+
 	clk_disable_unprepare(sport->clk_per);
 	clk_disable_unprepare(sport->clk_ipg);
 }
@@ -2649,6 +2653,10 @@ static void imx_uart_remove(struct platform_device *pdev)
 	struct imx_port *sport = platform_get_drvdata(pdev);
 
 	uart_remove_one_port(&imx_uart_uart_driver, &sport->port);
+
+	/* Serial core can reach remove() without calling the driver shutdown. */
+	hrtimer_cancel(&sport->trigger_start_tx);
+	hrtimer_cancel(&sport->trigger_stop_tx);
 }
 
 static void imx_uart_restore_context(struct imx_port *sport)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.