Commit 3fa10cc8 authored by Jiri Slaby's avatar Jiri Slaby Committed by Greg Kroah-Hartman

TTY: n_tty, do not dereference user buffer

copy_from_read_buf currently copies data to a user buffer and then
checks if the data is single EOF. But it checks it by accessing the
user buffer. First, the buffer may be changed by other threads of the
user program already. Second, it accesses the buffer without any
checks. It might be write-only for example.

Fix this by inspecting contents of the tty (kernel) buffer instead.
Note that "n == 1" is necessary, but not sufficient. But we check
later that there is nothing left by "!tty->read_cnt" condition.

There is still an issue with the current code that EOF being wrapped
to the start of the circular buffer will result in an inappropriate
losing of the EOF character. But this is not intended to be fixed by
this patch.
Signed-off-by: default avatarJiri Slaby <jslaby@suse.cz>
Reported-by: default avatarEmil Goode <emilgoode@gmail.com>
Cc: Howard Chu <hyc@symas.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 5d1a33fa
...@@ -1630,6 +1630,7 @@ static int copy_from_read_buf(struct tty_struct *tty, ...@@ -1630,6 +1630,7 @@ static int copy_from_read_buf(struct tty_struct *tty,
int retval; int retval;
size_t n; size_t n;
unsigned long flags; unsigned long flags;
bool is_eof;
retval = 0; retval = 0;
spin_lock_irqsave(&tty->read_lock, flags); spin_lock_irqsave(&tty->read_lock, flags);
...@@ -1639,15 +1640,15 @@ static int copy_from_read_buf(struct tty_struct *tty, ...@@ -1639,15 +1640,15 @@ static int copy_from_read_buf(struct tty_struct *tty,
if (n) { if (n) {
retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n); retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
n -= retval; n -= retval;
is_eof = n == 1 &&
tty->read_buf[tty->read_tail] == EOF_CHAR(tty);
tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n); tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
spin_lock_irqsave(&tty->read_lock, flags); spin_lock_irqsave(&tty->read_lock, flags);
tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1); tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
tty->read_cnt -= n; tty->read_cnt -= n;
/* Turn single EOF into zero-length read */ /* Turn single EOF into zero-length read */
if (L_EXTPROC(tty) && tty->icanon && n == 1) { if (L_EXTPROC(tty) && tty->icanon && is_eof && !tty->read_cnt)
if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty)) n = 0;
n--;
}
spin_unlock_irqrestore(&tty->read_lock, flags); spin_unlock_irqrestore(&tty->read_lock, flags);
*b += n; *b += n;
*nr -= n; *nr -= n;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment