• Peter Hurley's avatar
    tty: Fix recursive deadlock in tty_perform_flush() · e7f3880c
    Peter Hurley authored
    tty_perform_flush() can deadlock when called while holding
    a line discipline reference. By definition, all ldisc drivers
    hold a ldisc reference, so calls originating from ldisc drivers
    must not block for a ldisc reference.
    
    The deadlock can occur when:
      CPU 0                    |  CPU 1
                               |
    tty_ldisc_ref(tty)         |
    ....                       | <line discipline halted>
    tty_ldisc_ref_wait(tty)    |
                               |
    
    CPU 0 cannot progess because it cannot obtain an ldisc reference
    with the line discipline has been halted (thus no new references
    are granted).
    CPU 1 cannot progress because an outstanding ldisc reference
    has not been released.
    
    An in-tree call-tree audit of tty_perform_flush() [1] shows 5
    ldisc drivers calling tty_perform_flush() indirectly via
    n_tty_ioctl_helper() and 2 ldisc drivers calling directly.
    A single tty driver safely uses the function.
    
    [1]
    Recursive usage:
    
    /* These functions are line discipline ioctls and thus
     * recursive wrt line discipline references */
    
    tty_perform_flush() - ./drivers/tty/tty_ioctl.c
        n_tty_ioctl_helper()
            hci_uart_tty_ioctl(default) - drivers/bluetooth/hci_ldisc.c (N_HCI)
            n_hdlc_tty_ioctl(default) - drivers/tty/n_hdlc.c (N_HDLC)
            gsmld_ioctl(default) - drivers/tty/n_gsm.c (N_GSM0710)
            n_tty_ioctl(default) - drivers/tty/n_tty.c (N_TTY)
            gigaset_tty_ioctl(default) - drivers/isdn/gigaset/ser-gigaset.c (N_GIGASET_M101)
        ppp_synctty_ioctl(TCFLSH) - drivers/net/ppp/pps_synctty.c
        ppp_asynctty_ioctl(TCFLSH) - drivers/net/ppp/ppp_async.c
    
    Non-recursive use:
    
    tty_perform_flush() - drivers/tty/tty_ioctl.c
        ipw_ioctl(TCFLSH) - drivers/tty/ipwireless/tty.c
           /* This function is a tty i/o ioctl method, which
            * is invoked by tty_ioctl() */
    Signed-off-by: default avatarPeter Hurley <peter@hurleysoftware.com>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    e7f3880c
tty_ioctl.c 31.4 KB