]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
Fix OpenSSH pty regression on close
authorBrian Bloniarz <brian.bloniarz@gmail.com>
Sun, 6 Mar 2016 21:16:30 +0000 (13:16 -0800)
committerBen Hutchings <ben@decadent.org.uk>
Mon, 22 Aug 2016 21:37:53 +0000 (22:37 +0100)
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 <tsi@tuyoix.net>

Reported-by: Volth <openssh@volth.com>
Reported-by: Marc 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=2492
Signed-off-by: Brian Bloniarz <brian.bloniarz@gmail.com>
Reviewed-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg 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: Ben Hutchings <ben@decadent.org.uk>
drivers/tty/n_tty.c

index 9f56f4d819ee55bb33ff314a20d76c95957b2a97..2d7c57e11dd5931df405d292f835805f9e4d1004 100644 (file)
@@ -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))