summaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorBrian Bloniarz <brian.bloniarz@gmail.com>2016-03-06 16:16:30 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-05-01 16:22:54 -0400
commit0f40fbbcc34e093255a2b2d70b6b0fb48c3f39aa (patch)
treeedfa996be5ce50cd79dcfdfa96bb9d8490418660 /drivers/tty
parentd11df61853f1d45035b7f5a6702c9b48d5f09a49 (diff)
Fix OpenSSH pty regression on close
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> Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/n_hdlc.c4
-rw-r--r--drivers/tty/n_tty.c70
-rw-r--r--drivers/tty/pty.c4
-rw-r--r--drivers/tty/tty_buffer.c34
4 files changed, 42 insertions, 70 deletions
diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c
index bcaba17688f6..a7fa016f31eb 100644
--- a/drivers/tty/n_hdlc.c
+++ b/drivers/tty/n_hdlc.c
@@ -599,7 +599,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
599 add_wait_queue(&tty->read_wait, &wait); 599 add_wait_queue(&tty->read_wait, &wait);
600 600
601 for (;;) { 601 for (;;) {
602 if (test_bit(TTY_OTHER_DONE, &tty->flags)) { 602 if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
603 ret = -EIO; 603 ret = -EIO;
604 break; 604 break;
605 } 605 }
@@ -827,7 +827,7 @@ static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
827 /* set bits for operations that won't block */ 827 /* set bits for operations that won't block */
828 if (n_hdlc->rx_buf_list.head) 828 if (n_hdlc->rx_buf_list.head)
829 mask |= POLLIN | POLLRDNORM; /* readable */ 829 mask |= POLLIN | POLLRDNORM; /* readable */
830 if (test_bit(TTY_OTHER_DONE, &tty->flags)) 830 if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
831 mask |= POLLHUP; 831 mask |= POLLHUP;
832 if (tty_hung_up_p(filp)) 832 if (tty_hung_up_p(filp))
833 mask |= POLLHUP; 833 mask |= POLLHUP;
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index fb76a7d80e7e..bdf0e6e89991 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1917,18 +1917,6 @@ static inline int input_available_p(struct tty_struct *tty, int poll)
1917 return ldata->commit_head - ldata->read_tail >= amt; 1917 return ldata->commit_head - ldata->read_tail >= amt;
1918} 1918}
1919 1919
1920static inline int check_other_done(struct tty_struct *tty)
1921{
1922 int done = test_bit(TTY_OTHER_DONE, &tty->flags);
1923 if (done) {
1924 /* paired with cmpxchg() in check_other_closed(); ensures
1925 * read buffer head index is not stale
1926 */
1927 smp_mb__after_atomic();
1928 }
1929 return done;
1930}
1931
1932/** 1920/**
1933 * copy_from_read_buf - copy read data directly 1921 * copy_from_read_buf - copy read data directly
1934 * @tty: terminal device 1922 * @tty: terminal device
@@ -2124,7 +2112,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
2124 struct n_tty_data *ldata = tty->disc_data; 2112 struct n_tty_data *ldata = tty->disc_data;
2125 unsigned char __user *b = buf; 2113 unsigned char __user *b = buf;
2126 DEFINE_WAIT_FUNC(wait, woken_wake_function); 2114 DEFINE_WAIT_FUNC(wait, woken_wake_function);
2127 int c, done; 2115 int c;
2128 int minimum, time; 2116 int minimum, time;
2129 ssize_t retval = 0; 2117 ssize_t retval = 0;
2130 long timeout; 2118 long timeout;
@@ -2183,32 +2171,35 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
2183 break; 2171 break;
2184 } 2172 }
2185 2173
2186 done = check_other_done(tty);
2187
2188 if (!input_available_p(tty, 0)) { 2174 if (!input_available_p(tty, 0)) {
2189 if (done) {
2190 retval = -EIO;
2191 break;
2192 }
2193 if (tty_hung_up_p(file))
2194 break;
2195 if (!timeout)
2196 break;
2197 if (file->f_flags & O_NONBLOCK) {
2198 retval = -EAGAIN;
2199 break;
2200 }
2201 if (signal_pending(current)) {
2202 retval = -ERESTARTSYS;
2203 break;
2204 }
2205 up_read(&tty->termios_rwsem); 2175 up_read(&tty->termios_rwsem);
2176 tty_buffer_flush_work(tty->port);
2177 down_read(&tty->termios_rwsem);
2178 if (!input_available_p(tty, 0)) {
2179 if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
2180 retval = -EIO;
2181 break;
2182 }
2183 if (tty_hung_up_p(file))
2184 break;
2185 if (!timeout)
2186 break;
2187 if (file->f_flags & O_NONBLOCK) {
2188 retval = -EAGAIN;
2189 break;
2190 }
2191 if (signal_pending(current)) {
2192 retval = -ERESTARTSYS;
2193 break;
2194 }
2195 up_read(&tty->termios_rwsem);
2206 2196
2207 timeout = wait_woken(&wait, TASK_INTERRUPTIBLE, 2197 timeout = wait_woken(&wait, TASK_INTERRUPTIBLE,
2208 timeout); 2198 timeout);
2209 2199
2210 down_read(&tty->termios_rwsem); 2200 down_read(&tty->termios_rwsem);
2211 continue; 2201 continue;
2202 }
2212 } 2203 }
2213 2204
2214 if (ldata->icanon && !L_EXTPROC(tty)) { 2205 if (ldata->icanon && !L_EXTPROC(tty)) {
@@ -2386,12 +2377,17 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
2386 2377
2387 poll_wait(file, &tty->read_wait, wait); 2378 poll_wait(file, &tty->read_wait, wait);
2388 poll_wait(file, &tty->write_wait, wait); 2379 poll_wait(file, &tty->write_wait, wait);
2389 if (check_other_done(tty))
2390 mask |= POLLHUP;
2391 if (input_available_p(tty, 1)) 2380 if (input_available_p(tty, 1))
2392 mask |= POLLIN | POLLRDNORM; 2381 mask |= POLLIN | POLLRDNORM;
2382 else {
2383 tty_buffer_flush_work(tty->port);
2384 if (input_available_p(tty, 1))
2385 mask |= POLLIN | POLLRDNORM;
2386 }
2393 if (tty->packet && tty->link->ctrl_status) 2387 if (tty->packet && tty->link->ctrl_status)
2394 mask |= POLLPRI | POLLIN | POLLRDNORM; 2388 mask |= POLLPRI | POLLIN | POLLRDNORM;
2389 if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
2390 mask |= POLLHUP;
2395 if (tty_hung_up_p(file)) 2391 if (tty_hung_up_p(file))
2396 mask |= POLLHUP; 2392 mask |= POLLHUP;
2397 if (tty->ops->write && !tty_is_writelocked(tty) && 2393 if (tty->ops->write && !tty_is_writelocked(tty) &&
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index a8a292fd564f..ee0e84798399 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -59,7 +59,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
59 if (!tty->link) 59 if (!tty->link)
60 return; 60 return;
61 set_bit(TTY_OTHER_CLOSED, &tty->link->flags); 61 set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
62 tty_flip_buffer_push(tty->link->port); 62 wake_up_interruptible(&tty->link->read_wait);
63 wake_up_interruptible(&tty->link->write_wait); 63 wake_up_interruptible(&tty->link->write_wait);
64 if (tty->driver->subtype == PTY_TYPE_MASTER) { 64 if (tty->driver->subtype == PTY_TYPE_MASTER) {
65 set_bit(TTY_OTHER_CLOSED, &tty->flags); 65 set_bit(TTY_OTHER_CLOSED, &tty->flags);
@@ -247,9 +247,7 @@ static int pty_open(struct tty_struct *tty, struct file *filp)
247 goto out; 247 goto out;
248 248
249 clear_bit(TTY_IO_ERROR, &tty->flags); 249 clear_bit(TTY_IO_ERROR, &tty->flags);
250 /* TTY_OTHER_CLOSED must be cleared before TTY_OTHER_DONE */
251 clear_bit(TTY_OTHER_CLOSED, &tty->link->flags); 250 clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
252 clear_bit(TTY_OTHER_DONE, &tty->link->flags);
253 set_bit(TTY_THROTTLED, &tty->flags); 251 set_bit(TTY_THROTTLED, &tty->flags);
254 return 0; 252 return 0;
255 253
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index a946e49a2626..aa80dc94ddc2 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -37,29 +37,6 @@
37 37
38#define TTY_BUFFER_PAGE (((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~0xFF) 38#define TTY_BUFFER_PAGE (((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~0xFF)
39 39
40/*
41 * If all tty flip buffers have been processed by flush_to_ldisc() or
42 * dropped by tty_buffer_flush(), check if the linked pty has been closed.
43 * If so, wake the reader/poll to process
44 */
45static inline void check_other_closed(struct tty_struct *tty)
46{
47 unsigned long flags, old;
48
49 /* transition from TTY_OTHER_CLOSED => TTY_OTHER_DONE must be atomic */
50 for (flags = ACCESS_ONCE(tty->flags);
51 test_bit(TTY_OTHER_CLOSED, &flags);
52 ) {
53 old = flags;
54 __set_bit(TTY_OTHER_DONE, &flags);
55 flags = cmpxchg(&tty->flags, old, flags);
56 if (old == flags) {
57 wake_up_interruptible(&tty->read_wait);
58 break;
59 }
60 }
61}
62
63/** 40/**
64 * tty_buffer_lock_exclusive - gain exclusive access to buffer 41 * tty_buffer_lock_exclusive - gain exclusive access to buffer
65 * tty_buffer_unlock_exclusive - release exclusive access 42 * tty_buffer_unlock_exclusive - release exclusive access
@@ -254,8 +231,6 @@ void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld)
254 if (ld && ld->ops->flush_buffer) 231 if (ld && ld->ops->flush_buffer)
255 ld->ops->flush_buffer(tty); 232 ld->ops->flush_buffer(tty);
256 233
257 check_other_closed(tty);
258
259 atomic_dec(&buf->priority); 234 atomic_dec(&buf->priority);
260 mutex_unlock(&buf->lock); 235 mutex_unlock(&buf->lock);
261} 236}
@@ -522,10 +497,8 @@ static void flush_to_ldisc(struct work_struct *work)
522 */ 497 */
523 count = smp_load_acquire(&head->commit) - head->read; 498 count = smp_load_acquire(&head->commit) - head->read;
524 if (!count) { 499 if (!count) {
525 if (next == NULL) { 500 if (next == NULL)
526 check_other_closed(tty);
527 break; 501 break;
528 }
529 buf->head = next; 502 buf->head = next;
530 tty_buffer_free(port, head); 503 tty_buffer_free(port, head);
531 continue; 504 continue;
@@ -614,3 +587,8 @@ bool tty_buffer_cancel_work(struct tty_port *port)
614{ 587{
615 return cancel_work_sync(&port->buf.work); 588 return cancel_work_sync(&port->buf.work);
616} 589}
590
591void tty_buffer_flush_work(struct tty_port *port)
592{
593 flush_work(&port->buf.work);
594}