• Greg Kroah-Hartman's avatar
    serial: fix race between flush_to_ldisc and tty_open · f50a8b34
    Greg Kroah-Hartman authored
    commit fedb5760 upstream.
    
    There still is a race window after the commit b027e229
    ("tty: fix data race between tty_init_dev and flush of buf"),
    and we encountered this crash issue if receive_buf call comes
    before tty initialization completes in tty_open and
    tty->driver_data may be NULL.
    
    CPU0                                    CPU1
    ----                                    ----
                                      tty_open
                                       tty_init_dev
                                         tty_ldisc_unlock
                                           schedule
    flush_to_ldisc
     receive_buf
      tty_port_default_receive_buf
       tty_ldisc_receive_buf
        n_tty_receive_buf_common
          __receive_buf
           uart_flush_chars
            uart_start
            /*tty->driver_data is NULL*/
                                       tty->ops->open
                                       /*init tty->driver_data*/
    
    it can be fixed by extending ldisc semaphore lock in tty_init_dev
    to driver_data initialized completely after tty->ops->open(), but
    this will lead to get lock on one function and unlock in some other
    function, and hard to maintain, so fix this race only by checking
    tty->driver_data when receiving, and return if tty->driver_data
    is NULL, and n_tty_receive_buf_common maybe calls uart_unthrottle,
    so add the same check.
    
    Because the tty layer knows nothing about the driver associated with the
    device, the tty layer can not do anything here, it is up to the tty
    driver itself to check for this type of race.  Fix up the serial driver
    to correctly check to see if it is finished binding with the device when
    being called, and if not, abort the tty calls.
    
    [Description and problem report and testing from Li RongQing, I rewrote
    the patch to be in the serial layer, not in the tty core - gregkh]
    Reported-by: default avatarLi RongQing <lirongqing@baidu.com>
    Tested-by: default avatarLi RongQing <lirongqing@baidu.com>
    Signed-off-by: default avatarWang Li <wangli39@baidu.com>
    Signed-off-by: default avatarZhang Yu <zhangyu31@baidu.com>
    Signed-off-by: default avatarLi RongQing <lirongqing@baidu.com>
    Cc: stable <stable@vger.kernel.org>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    f50a8b34
serial_core.c 75.5 KB