From 2554b504bfdae9a0d3a44d7a9aad521c6c7b9b8a Mon Sep 17 00:00:00 2001 From: Brian Bloniarz Date: Sun, 6 Mar 2016 13:16:30 -0800 Subject: [PATCH] Fix OpenSSH pty regression on close commit 0f40fbbcc34e093255a2b2d70b6b0fb48c3f39aa 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) f8747d4a466ab2cafe56112c51b3379f9fdb7a12 tty: Fix pty master read() after slave closes 2) 52bce7f8d4fc633c9a9d0646eef58ba6ae9a3b73 pty, n_tty: Simplify input processing on final close 3) 1a48632ffed61352a7810ce089dc5a8bcd505a60 pty: Fix input race when closing Inspired by analysis and patch from Marc Aurele La France Reported-by: Volth Reported-by: Marc Aurele La France BugLink: https://bugzilla.mindrot.org/show_bug.cgi?id=52 BugLink: https://bugzilla.mindrot.org/show_bug.cgi?id=2492 Signed-off-by: Brian Bloniarz Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman [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: Ben Hutchings --- drivers/tty/n_tty.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 9f56f4d819ee5..2d7c57e11dd59 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -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)) { + 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)) -- 2.47.3