Commit 2554b504 authored by Brian Bloniarz's avatar Brian Bloniarz Committed by Ben Hutchings

Fix OpenSSH pty regression on close

commit 0f40fbbc upstream.

OpenSSH expects the (non-blocking) read() of pty master to return
EAGAIN only if it has received all of the slave-side output after
it has received SIGCHLD. This used to work on pre-3.12 kernels.

This fix effectively forces non-blocking read() and poll() to
block for parallel i/o to complete for all ttys. It also unwinds
these changes:

1) f8747d4a
   tty: Fix pty master read() after slave closes

2) 52bce7f8
   pty, n_tty: Simplify input processing on final close

3) 1a48632f
   pty: Fix input race when closing

Inspired by analysis and patch from Marc Aurele La France <tsi@tuyoix.net>
Reported-by: default avatarVolth <openssh@volth.com>
Reported-by: default avatarMarc Aurele La France <tsi@tuyoix.net>
BugLink: https://bugzilla.mindrot.org/show_bug.cgi?id=52
BugLink: https://bugzilla.mindrot.org/show_bug.cgi?id=2492Signed-off-by: default avatarBrian Bloniarz <brian.bloniarz@gmail.com>
Reviewed-by: default avatarPeter Hurley <peter@hurleysoftware.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
[bwh: Backported to 3.16:
 - No need to unwind commits 2 and 3
 - Keep using tty_flush_to_ldisc() rather than adding tty_buffer_flush_work()]]
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
parent 402c9224
......@@ -2251,15 +2251,14 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
ldata->minimum_to_wake = (minimum - (b - buf));
if (!input_available_p(tty, 0)) {
if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
up_read(&tty->termios_rwsem);
tty_flush_to_ldisc(tty);
down_read(&tty->termios_rwsem);
if (!input_available_p(tty, 0)) {
if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
retval = -EIO;
break;
}
} else {
if (tty_hung_up_p(file))
break;
if (!timeout)
......@@ -2467,6 +2466,11 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
poll_wait(file, &tty->write_wait, wait);
if (input_available_p(tty, 1))
mask |= POLLIN | POLLRDNORM;
else {
tty_flush_to_ldisc(tty);
if (input_available_p(tty, 1))
mask |= POLLIN | POLLRDNORM;
}
if (tty->packet && tty->link->ctrl_status)
mask |= POLLPRI | POLLIN | POLLRDNORM;
if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment