| From 966031f340185eddd05affcf72b740549f056348 Mon Sep 17 00:00:00 2001 |
| From: Linus Torvalds <torvalds@linux-foundation.org> |
| Date: Wed, 20 Dec 2017 17:57:06 -0800 |
| Subject: n_tty: fix EXTPROC vs ICANON interaction with TIOCINQ (aka FIONREAD) |
| |
| From: Linus Torvalds <torvalds@linux-foundation.org> |
| |
| commit 966031f340185eddd05affcf72b740549f056348 upstream. |
| |
| We added support for EXTPROC back in 2010 in commit 26df6d13406d ("tty: |
| Add EXTPROC support for LINEMODE") and the intent was to allow it to |
| override some (all?) ICANON behavior. Quoting from that original commit |
| message: |
| |
| There is a new bit in the termios local flag word, EXTPROC. |
| When this bit is set, several aspects of the terminal driver |
| are disabled. Input line editing, character echo, and mapping |
| of signals are all disabled. This allows the telnetd to turn |
| off these functions when in linemode, but still keep track of |
| what state the user wants the terminal to be in. |
| |
| but the problem turns out that "several aspects of the terminal driver |
| are disabled" is a bit ambiguous, and you can really confuse the n_tty |
| layer by setting EXTPROC and then causing some of the ICANON invariants |
| to no longer be maintained. |
| |
| This fixes at least one such case (TIOCINQ) becoming unhappy because of |
| the confusion over whether ICANON really means ICANON when EXTPROC is set. |
| |
| This basically makes TIOCINQ match the case of read: if EXTPROC is set, |
| we ignore ICANON. Also, make sure to reset the ICANON state ie EXTPROC |
| changes, not just if ICANON changes. |
| |
| Fixes: 26df6d13406d ("tty: Add EXTPROC support for LINEMODE") |
| Reported-by: Tetsuo Handa <penguin-kernel@i-love.sakura.ne.jp> |
| Reported-by: syzkaller <syzkaller@googlegroups.com> |
| Cc: Jiri Slaby <jslaby@suse.com> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/tty/n_tty.c | 4 ++-- |
| 1 file changed, 2 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/tty/n_tty.c |
| +++ b/drivers/tty/n_tty.c |
| @@ -1764,7 +1764,7 @@ static void n_tty_set_termios(struct tty |
| { |
| struct n_tty_data *ldata = tty->disc_data; |
| |
| - if (!old || (old->c_lflag ^ tty->termios.c_lflag) & ICANON) { |
| + if (!old || (old->c_lflag ^ tty->termios.c_lflag) & (ICANON | EXTPROC)) { |
| bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE); |
| ldata->line_start = ldata->read_tail; |
| if (!L_ICANON(tty) || !read_cnt(ldata)) { |
| @@ -2427,7 +2427,7 @@ static int n_tty_ioctl(struct tty_struct |
| return put_user(tty_chars_in_buffer(tty), (int __user *) arg); |
| case TIOCINQ: |
| down_write(&tty->termios_rwsem); |
| - if (L_ICANON(tty)) |
| + if (L_ICANON(tty) && !L_EXTPROC(tty)) |
| retval = inq_canon(ldata); |
| else |
| retval = read_cnt(ldata); |