summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Slaby <jslaby@suse.cz>2012-04-26 20:13:00 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-04-29 22:13:54 -0400
commit3fa10cc83fb92750af11fab81e11ad96dc75d656 (patch)
treee583b1cafbf3b1ad5a5bab1ad481a2925b7e3742
parent5d1a33fa5573702394a4d09a9872f3f930c06d58 (diff)
downloadlinux-3fa10cc83fb92750af11fab81e11ad96dc75d656.tar.gz
linux-3fa10cc83fb92750af11fab81e11ad96dc75d656.tar.bz2
linux-3fa10cc83fb92750af11fab81e11ad96dc75d656.zip
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: Jiri Slaby <jslaby@suse.cz> Reported-by: Emil Goode <emilgoode@gmail.com> Cc: Howard Chu <hyc@symas.com> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/tty/n_tty.c9
1 files changed, 5 insertions, 4 deletions
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 94b6eda87afd..ee1c268f5f9d 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1630,6 +1630,7 @@ static int copy_from_read_buf(struct tty_struct *tty,
int retval;
size_t n;
unsigned long flags;
+ bool is_eof;
retval = 0;
spin_lock_irqsave(&tty->read_lock, flags);
@@ -1639,15 +1640,15 @@ static int copy_from_read_buf(struct tty_struct *tty,
if (n) {
retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
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);
spin_lock_irqsave(&tty->read_lock, flags);
tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
tty->read_cnt -= n;
/* Turn single EOF into zero-length read */
- if (L_EXTPROC(tty) && tty->icanon && n == 1) {
- if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty))
- n--;
- }
+ if (L_EXTPROC(tty) && tty->icanon && is_eof && !tty->read_cnt)
+ n = 0;
spin_unlock_irqrestore(&tty->read_lock, flags);
*b += n;
*nr -= n;