• Peter Hurley's avatar
    n_tty: Fix read buffer overwrite when no newline · b1ff43a8
    Peter Hurley authored
    commit fb5ef9e7 upstream.
    
    In canon mode, the read buffer head will advance over the buffer tail
    if the input > 4095 bytes without receiving a line termination char.
    
    Discard additional input until a line termination is received.
    Before evaluating for overflow, the 'room' value is normalized for
    I_PARMRK and 1 byte is reserved for line termination (even in !icanon
    mode, in case the mode is switched). The following table shows the
    transform:
    
     actual buffer |  'room' value before overflow calc
      space avail  |    !I_PARMRK    |    I_PARMRK
     --------------------------------------------------
          0        |       -1        |       -1
          1        |        0        |        0
          2        |        1        |        0
          3        |        2        |        0
          4+       |        3        |        1
    
    When !icanon or when icanon and the read buffer contains newlines,
    normalized 'room' values of -1 and 0 are clamped to 0, and
    'overflow' is 0, so read_head is not adjusted and the input i/o loop
    exits (setting no_room if called from flush_to_ldisc()). No input
    is discarded since the reader does have input available to read
    which ensures forward progress.
    
    When icanon and the read buffer does not contain newlines and the
    normalized 'room' value is 0, then overflow and room are reset to 1,
    so that the i/o loop will process the next input char normally
    (except for parity errors which are ignored). Thus, erasures, signalling
    chars, 7-bit mode, etc. will continue to be handled properly.
    
    If the input char processed was not a line termination char, then
    the canon_head index will not have advanced, so the normalized 'room'
    value will now be -1 and 'overflow' will be set, which indicates the
    read_head can safely be reset, effectively erasing the last char
    processed.
    
    If the input char processed was a line termination, then the
    canon_head index will have advanced, so 'overflow' is cleared to 0,
    the read_head is not reset, and 'room' is cleared to 0, which exits
    the i/o loop (because the reader now have input available to read
    which ensures forward progress).
    
    Note that it is possible for a line termination to be received, and
    for the reader to copy the line to the user buffer before the
    input i/o loop is ready to process the next input char. This is
    why the i/o loop recomputes the room/overflow state with every
    input char while handling overflow.
    
    Finally, if the input data was processed without receiving
    a line termination (so that overflow is still set), the pty
    driver must receive a write wakeup. A pty writer may be waiting
    to write more data in n_tty_write() but without unthrottling
    here that wakeup will not arrive, and forward progress will halt.
    (Normally, the pty writer is woken when the reader reads data out
    of the buffer and more space become available).
    Signed-off-by: default avatarPeter Hurley <peter@hurleysoftware.com>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    (backported from commit fb5ef9e7)
    Signed-off-by: default avatarJoseph Salisbury <joseph.salisbury@canonical.com>
    b1ff43a8
n_tty.c 63.3 KB