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

serial: core: Prevent unsafe uart port access, part 3

For tty operations which may expect uart port to have been removed
but still have other necessary work to accomplish, check for NULL
uart port; specifically uart_close(), uart_hangup() and sub-functions
(uart_shutdown() and uart_port_shutdown()).

Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Peter Hurley and committed by
Greg Kroah-Hartman
af224ca2 9ed19428

+20 -10
+20 -10
drivers/tty/serial/serial_core.c
··· 257 257 * This routine will shutdown a serial port; interrupts are disabled, and 258 258 * DTR is dropped if the hangup on close termio flag is on. Calls to 259 259 * uart_shutdown are serialised by the per-port semaphore. 260 + * 261 + * uport == NULL if uart_port has already been removed 260 262 */ 261 263 static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) 262 264 { ··· 277 275 /* 278 276 * Turn off DTR and RTS early. 279 277 */ 280 - if (uart_console(uport) && tty) 278 + if (uport && uart_console(uport) && tty) 281 279 uport->cons->cflag = tty->termios.c_cflag; 282 280 283 281 if (!tty || C_HUPCL(tty)) ··· 1462 1460 * Calls to uart_close() are serialised via the tty_lock in 1463 1461 * drivers/tty/tty_io.c:tty_release() 1464 1462 * drivers/tty/tty_io.c:do_tty_hangup() 1465 - * This runs from a workqueue and can sleep for a _short_ time only. 1466 1463 */ 1467 1464 static void uart_close(struct tty_struct *tty, struct file *filp) 1468 1465 { ··· 1480 1479 return; 1481 1480 } 1482 1481 1483 - uport = state->uart_port; 1484 1482 port = &state->port; 1485 1483 pr_debug("uart_close(%d) called\n", tty->index); 1486 1484 1487 - if (!port->count || tty_port_close_start(port, tty, filp) == 0) 1485 + if (tty_port_close_start(port, tty, filp) == 0) 1488 1486 return; 1487 + 1488 + mutex_lock(&port->mutex); 1489 + uport = uart_port_check(state); 1489 1490 1490 1491 /* 1491 1492 * At this point, we stop accepting input. To do this, we 1492 1493 * disable the receive line status interrupts. 1493 1494 */ 1494 - if (tty_port_initialized(port)) { 1495 + if (tty_port_initialized(port) && 1496 + !WARN(!uport, "detached port still initialized!\n")) { 1495 1497 spin_lock_irq(&uport->lock); 1496 1498 uport->ops->stop_rx(uport); 1497 1499 spin_unlock_irq(&uport->lock); ··· 1506 1502 uart_wait_until_sent(tty, uport->timeout); 1507 1503 } 1508 1504 1509 - mutex_lock(&port->mutex); 1510 1505 uart_shutdown(tty, state); 1511 1506 tty_port_tty_set(port, NULL); 1512 1507 ··· 1516 1513 if (port->close_delay) 1517 1514 msleep_interruptible(jiffies_to_msecs(port->close_delay)); 1518 1515 spin_lock_irq(&port->lock); 1519 - } else if (!uart_console(uport)) { 1516 + } else if (uport && !uart_console(uport)) { 1520 1517 spin_unlock_irq(&port->lock); 1521 1518 uart_change_pm(state, UART_PM_STATE_OFF); 1522 1519 spin_lock_irq(&port->lock); ··· 1603 1600 { 1604 1601 struct uart_state *state = tty->driver_data; 1605 1602 struct tty_port *port = &state->port; 1603 + struct uart_port *uport; 1606 1604 unsigned long flags; 1607 1605 1608 1606 pr_debug("uart_hangup(%d)\n", tty->index); 1609 1607 1610 1608 mutex_lock(&port->mutex); 1609 + uport = uart_port_check(state); 1610 + WARN(!uport, "hangup of detached port!\n"); 1611 + 1611 1612 if (tty_port_active(port)) { 1612 1613 uart_flush_buffer(tty); 1613 1614 uart_shutdown(tty, state); ··· 1620 1613 spin_unlock_irqrestore(&port->lock, flags); 1621 1614 tty_port_set_active(port, 0); 1622 1615 tty_port_tty_set(port, NULL); 1623 - if (!uart_console(state->uart_port)) 1616 + if (uport && !uart_console(uport)) 1624 1617 uart_change_pm(state, UART_PM_STATE_OFF); 1625 1618 wake_up_interruptible(&port->open_wait); 1626 1619 wake_up_interruptible(&port->delta_msr_wait); ··· 1628 1621 mutex_unlock(&port->mutex); 1629 1622 } 1630 1623 1624 + /* uport == NULL if uart_port has already been removed */ 1631 1625 static void uart_port_shutdown(struct tty_port *port) 1632 1626 { 1633 1627 struct uart_state *state = container_of(port, struct uart_state, port); ··· 1646 1638 /* 1647 1639 * Free the IRQ and disable the port. 1648 1640 */ 1649 - uport->ops->shutdown(uport); 1641 + if (uport) 1642 + uport->ops->shutdown(uport); 1650 1643 1651 1644 /* 1652 1645 * Ensure that the IRQ handler isn't running on another CPU. 1653 1646 */ 1654 - synchronize_irq(uport->irq); 1647 + if (uport) 1648 + synchronize_irq(uport->irq); 1655 1649 } 1656 1650 1657 1651 static int uart_carrier_raised(struct tty_port *port)