| From: Sudip Mukherjee <sudipm.mukherjee@gmail.com> |
| Date: Thu, 12 Dec 2019 13:16:02 +0000 |
| Subject: tty: link tty and port before configuring it as console |
| |
| commit fb2b90014d782d80d7ebf663e50f96d8c507a73c upstream. |
| |
| There seems to be a race condition in tty drivers and I could see on |
| many boot cycles a NULL pointer dereference as tty_init_dev() tries to |
| do 'tty->port->itty = tty' even though tty->port is NULL. |
| 'tty->port' will be set by the driver and if the driver has not yet done |
| it before we open the tty device we can get to this situation. By adding |
| some extra debug prints, I noticed that: |
| |
| 6.650130: uart_add_one_port |
| 6.663849: register_console |
| 6.664846: tty_open |
| 6.674391: tty_init_dev |
| 6.675456: tty_port_link_device |
| |
| uart_add_one_port() registers the console, as soon as it registers, the |
| userspace tries to use it and that leads to tty_open() but |
| uart_add_one_port() has not yet done tty_port_link_device() and so |
| tty->port is not yet configured when control reaches tty_init_dev(). |
| |
| Further look into the code and tty_port_link_device() is done by |
| uart_add_one_port(). After registering the console uart_add_one_port() |
| will call tty_port_register_device_attr_serdev() and |
| tty_port_link_device() is called from this. |
| |
| Call add tty_port_link_device() before uart_configure_port() is done and |
| add a check in tty_port_link_device() so that it only links the port if |
| it has not been done yet. |
| |
| Suggested-by: Jiri Slaby <jslaby@suse.com> |
| Signed-off-by: Sudip Mukherjee <sudipm.mukherjee@gmail.com> |
| Link: https://lore.kernel.org/r/20191212131602.29504-1-sudipm.mukherjee@gmail.com |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| drivers/tty/serial/serial_core.c | 1 + |
| drivers/tty/tty_port.c | 3 ++- |
| 2 files changed, 3 insertions(+), 1 deletion(-) |
| |
| --- a/drivers/tty/serial/serial_core.c |
| +++ b/drivers/tty/serial/serial_core.c |
| @@ -2639,6 +2639,7 @@ int uart_add_one_port(struct uart_driver |
| lockdep_set_class(&uport->lock, &port_lock_key); |
| } |
| |
| + tty_port_link_device(port, drv->tty_driver, uport->line); |
| uart_configure_port(drv, state, uport); |
| |
| /* |
| --- a/drivers/tty/tty_port.c |
| +++ b/drivers/tty/tty_port.c |
| @@ -49,7 +49,8 @@ void tty_port_link_device(struct tty_por |
| { |
| if (WARN_ON(index >= driver->num)) |
| return; |
| - driver->ports[index] = port; |
| + if (!driver->ports[index]) |
| + driver->ports[index] = port; |
| } |
| EXPORT_SYMBOL_GPL(tty_port_link_device); |
| |