Skip to content

Commit e144c58

Browse files
peterhurleygregkh
authored andcommitted
serial: core: Fix crashes while echoing when closing
While closing, new rx data may be received after the input buffers have been flushed but before stop_rx() halts receiving [1]. The new data might not be processed by flush_to_ldisc() until after uart_shutdown() and normal input processing is re-enabled (ie., tty->closing = 0). The race is outlined below: CPU 0 | CPU 1 | uart_close() | tty_port_close_start() | tty->closing = 1 | tty_ldisc_flush() | | => IRQ | while (LSR & data ready) | uart_insert_char() | tty_flip_buffer_push() | <= EOI stop_rx() | . uart_shutdown() | . free xmit.buf | . tty_port_tty_set(NULL) | . tty->closing = 0 | . | flush_to_ldisc() | n_tty_receive_buf_common() | __receive_buf() | ... | commit_echoes() | uart_flush_chars() | __uart_start() | ** OOPS on port.tty deref ** tty_ldisc_flush() | Input processing must be prevented from echoing (tty->closing = 1) until _after_ the input buffers have been flushed again at the end of uart_close(). [1] In fact, some input may actually be buffered _after_ stop_rx() since the rx interrupt may have already triggered but not yet been handled when stop_rx() disables rx interrupts. Fixes: 2e75891 ("serial: core: Flush ldisc after dropping port mutex in uart_close()") Reported-by: Robert Elliott <elliott@hp.com> Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 7525a99 commit e144c58

File tree

1 file changed

+2
-1
lines changed

1 file changed

+2
-1
lines changed

drivers/tty/serial/serial_core.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1418,7 +1418,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
14181418
mutex_lock(&port->mutex);
14191419
uart_shutdown(tty, state);
14201420
tty_port_tty_set(port, NULL);
1421-
tty->closing = 0;
1421+
14221422
spin_lock_irqsave(&port->lock, flags);
14231423

14241424
if (port->blocked_open) {
@@ -1444,6 +1444,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
14441444
mutex_unlock(&port->mutex);
14451445

14461446
tty_ldisc_flush(tty);
1447+
tty->closing = 0;
14471448
}
14481449

14491450
static void uart_wait_until_sent(struct tty_struct *tty, int timeout)

0 commit comments

Comments
 (0)