mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
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: 2e75891083
("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>
This commit is contained in:
parent
7525a9901b
commit
e144c58cad
@ -1418,7 +1418,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
|
||||
mutex_lock(&port->mutex);
|
||||
uart_shutdown(tty, state);
|
||||
tty_port_tty_set(port, NULL);
|
||||
tty->closing = 0;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
if (port->blocked_open) {
|
||||
@ -1444,6 +1444,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
|
||||
mutex_unlock(&port->mutex);
|
||||
|
||||
tty_ldisc_flush(tty);
|
||||
tty->closing = 0;
|
||||
}
|
||||
|
||||
static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
|
||||
|
Loading…
Reference in New Issue
Block a user