Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

serial_core: Fix race in uart_handle_dcd_change

If a serial driver is called post hangup with a second DCD event then we
will attempt to get the ldisc of NULL. Check we have a tty before trying to
do anything with it.

This is still only safe within the uart layer if the caller holds the
relevant uart locks. We could do with a version where the tty is passed for
more general use.

Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Alan Cox and committed by
Greg Kroah-Hartman
43eca0ae 84c3b848

+7 -4
+7 -4
drivers/tty/serial/serial_core.c
··· 2501 2501 { 2502 2502 struct uart_state *state = uport->state; 2503 2503 struct tty_port *port = &state->port; 2504 - struct tty_ldisc *ld = tty_ldisc_ref(port->tty); 2504 + struct tty_ldisc *ld = NULL; 2505 2505 struct pps_event_time ts; 2506 + struct tty_struct *tty = port->tty; 2506 2507 2508 + if (tty) 2509 + ld = tty_ldisc_ref(tty); 2507 2510 if (ld && ld->ops->dcd_change) 2508 2511 pps_get_ts(&ts); 2509 2512 ··· 2519 2516 if (port->flags & ASYNC_CHECK_CD) { 2520 2517 if (status) 2521 2518 wake_up_interruptible(&port->open_wait); 2522 - else if (port->tty) 2523 - tty_hangup(port->tty); 2519 + else if (tty) 2520 + tty_hangup(tty); 2524 2521 } 2525 2522 2526 2523 if (ld && ld->ops->dcd_change) 2527 - ld->ops->dcd_change(port->tty, status, &ts); 2524 + ld->ops->dcd_change(tty, status, &ts); 2528 2525 if (ld) 2529 2526 tty_ldisc_deref(ld); 2530 2527 }