• Peter Hurley's avatar
    n_tty: Fix poll() after buffer-limited eof push read · 58837c43
    Peter Hurley authored
    commit ac8f3bf8 upstream.
    
    commit 40d5e090 ("n_tty: Fix EOF push handling") fixed EOF push
    for reads. However, that approach still allows a condition mismatch
    between poll() and read(), where poll() returns POLLIN but read()
    blocks. This state can happen when a previous read() returned because
    the user buffer was full and the next character was an EOF not at the
    beginning of the line. While the next read() will properly identify
    the condition and advance the read buffer tail without improperly
    indicating an EOF file condition (ie., read() will not mistakenly
    return 0), poll() will mistakenly indicate POLLIN.
    
    Although a possible solution would be to peek at the input buffer
    in n_tty_poll(), the better solution in this patch is to eat the
    EOF during the previous read() (ie., fix the problem by eliminating
    the condition).
    
    The current canon line buffer copy limits the scan for next end-of-line
    to the smaller of either,
       a. the remaining user buffer size
       b. completed lines in the input buffer
    When the remaining user buffer size is exactly one less than the
    end-of-line marked by EOF push, the EOF is not scanned nor skipped
    but left for subsequent reads. In the example below, the scan
    index 'eol' has stopped at the EOF because it is past the scan
    limit of 5 (not because it has found the next set bit in read_flags)
    
       user buffer [*nr = 5]    _ _ _ _ _
    
       read_flags               0 0 0 0 0   1
       input buffer             h e l l o [EOF]
                                ^           ^
                               /           /
                             tail        eol
    
       result: found = 0, tail += 5, *nr += 5
    
    Instead, allow the scan to peek ahead 1 byte (while still limiting the
    scan to completed lines in the input buffer). For the example above,
    
       result: found = 1, tail += 6, *nr += 5
    
    Because the scan limit is now bumped +1 byte, when the scan is
    completed, the tail advance and the user buffer copy limit is
    re-clamped to *nr when EOF is _not_ found.
    
    Fixes: 40d5e090 ("n_tty: Fix EOF push handling")
    Signed-off-by: default avatarPeter Hurley <peter@hurleysoftware.com>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    [ luis: backported to 3.16: adjusted context ]
    Signed-off-by: default avatarLuis Henriques <luis.henriques@canonical.com>
    58837c43
n_tty.c 63.8 KB