diff options
author | Peter Hurley <peter@hurleysoftware.com> | 2015-06-27 09:21:32 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-07-23 18:05:53 -0400 |
commit | 3b19e032295647b7be2aa3be62510db4aaeda759 (patch) | |
tree | 42d49b560e263749594dd73e5b149460bdad3dfd | |
parent | 52721d9d3334c1cb1f76219a161084094ec634dc (diff) |
n_tty: signal and flush atomically
When handling signalling char, claim the termios write lock before
signalling waiting readers and writers to prevent further i/o
before flushing the echo and output buffers. This prevents a
userspace signal handler which may output from racing the terminal
flush.
Reference: Bugzilla #99351 ("Output truncated in ssh session after...")
Fixes: commit d2b6f44779d3 ("n_tty: Fix signal handling flushes")
Reported-by: Filipe Brandenburger <filbranden@google.com>
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/tty/n_tty.c | 16 |
1 files changed, 13 insertions, 3 deletions
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index c9c27f69e101..ee8bfacf2071 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c | |||
@@ -1108,19 +1108,29 @@ static void eraser(unsigned char c, struct tty_struct *tty) | |||
1108 | * Locking: ctrl_lock | 1108 | * Locking: ctrl_lock |
1109 | */ | 1109 | */ |
1110 | 1110 | ||
1111 | static void isig(int sig, struct tty_struct *tty) | 1111 | static void __isig(int sig, struct tty_struct *tty) |
1112 | { | 1112 | { |
1113 | struct n_tty_data *ldata = tty->disc_data; | ||
1114 | struct pid *tty_pgrp = tty_get_pgrp(tty); | 1113 | struct pid *tty_pgrp = tty_get_pgrp(tty); |
1115 | if (tty_pgrp) { | 1114 | if (tty_pgrp) { |
1116 | kill_pgrp(tty_pgrp, sig, 1); | 1115 | kill_pgrp(tty_pgrp, sig, 1); |
1117 | put_pid(tty_pgrp); | 1116 | put_pid(tty_pgrp); |
1118 | } | 1117 | } |
1118 | } | ||
1119 | 1119 | ||
1120 | if (!L_NOFLSH(tty)) { | 1120 | static void isig(int sig, struct tty_struct *tty) |
1121 | { | ||
1122 | struct n_tty_data *ldata = tty->disc_data; | ||
1123 | |||
1124 | if (L_NOFLSH(tty)) { | ||
1125 | /* signal only */ | ||
1126 | __isig(sig, tty); | ||
1127 | |||
1128 | } else { /* signal and flush */ | ||
1121 | up_read(&tty->termios_rwsem); | 1129 | up_read(&tty->termios_rwsem); |
1122 | down_write(&tty->termios_rwsem); | 1130 | down_write(&tty->termios_rwsem); |
1123 | 1131 | ||
1132 | __isig(sig, tty); | ||
1133 | |||
1124 | /* clear echo buffer */ | 1134 | /* clear echo buffer */ |
1125 | mutex_lock(&ldata->output_lock); | 1135 | mutex_lock(&ldata->output_lock); |
1126 | ldata->echo_head = ldata->echo_tail = 0; | 1136 | ldata->echo_head = ldata->echo_tail = 0; |