[PATCH 17/24] serial: 8250_mxpcie: handle hangup during break
From: Greg Kroah-Hartman
Date: Tue Oct 27 2026 - 07:15:09 EST
From: Josef Bacik <josef@xxxxxxxxxxxxxx>
Ending a software break on a Moxa PCIe port in RS-485 2-wire mode
dereferences a NULL tty pointer if the port was hung up while the break
was being sent.
send_break() calls ->break_ctl(tty, -1), sleeps for the break duration
and then calls ->break_ctl(tty, 0), without excluding a concurrent
hangup. A hangup (a modem DCD drop, or the session leader exiting while
another process of the session is in TCSBRK/TCSBRKP) runs uart_hangup(),
which shuts the port down and clears port->state->port.tty. The second
call still reaches mxpcie8250_software_break_ctl() through
uart_break_ctl(), which then does:
struct tty_struct *tty = port->state->port.tty;
...
baud = tty_get_baud_rate(tty);
with tty == NULL.
The bug was found by code inspection and has not been reproduced.
Fix by taking a reference to the port's tty with tty_port_tty_get() and
only restoring the divisor when a tty is still attached; a hung up port
is shut down, and the next open programs the divisor again through
set_termios().
Fixes: ade78d3d253c ("serial: 8250_mxpcie: add break support for RS485 using MUEx50 features")
Cc: stable <stable@xxxxxxxxxx>
Cc: Jiri Slaby <jirislaby@xxxxxxxxxx>
Cc: Crescent Hsieh <crescentcy.hsieh@xxxxxxxx>
Cc: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx>
Cc: Linmao Li <lilinmao@xxxxxxxxxx>
Signed-off-by: Josef Bacik <josef@xxxxxxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
---
drivers/tty/serial/8250/8250_mxpcie.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_mxpcie.c b/drivers/tty/serial/8250/8250_mxpcie.c
index 4935a5d1c1a3..b3418c1ccb05 100644
--- a/drivers/tty/serial/8250/8250_mxpcie.c
+++ b/drivers/tty/serial/8250/8250_mxpcie.c
@@ -412,7 +412,7 @@ static int mxpcie8250_handle_irq(struct uart_port *port)
static void mxpcie8250_software_break_ctl(struct uart_port *port, int break_state)
{
struct uart_8250_port *up = up_to_u8250p(port);
- struct tty_struct *tty = port->state->port.tty;
+ struct tty_struct *tty;
unsigned int baud, quot;
u8 sfr, tx_byte = 0x01;
@@ -439,9 +439,14 @@ static void mxpcie8250_software_break_ctl(struct uart_port *port, int break_stat
serial_out(up, UART_FCR, UART_FCR_CLEAR_XMIT);
- baud = tty_get_baud_rate(tty);
- quot = uart_get_divisor(port, baud);
- serial8250_do_set_divisor(port, baud, quot);
+ /* A hangup during the break detaches the tty */
+ tty = tty_port_tty_get(&port->state->port);
+ if (tty) {
+ baud = tty_get_baud_rate(tty);
+ quot = uart_get_divisor(port, baud);
+ serial8250_do_set_divisor(port, baud, quot);
+ tty_kref_put(tty);
+ }
serial_out(up, UART_LCR, up->lcr);
}
}
--
2.56.0