1 From: Peter Hurley <peter@hurleysoftware.com>
3 commit 4291086b1f081b869c6d79e5b7441633dc3ace00 upstream.
5 The tty atomic_write_lock does not provide an exclusion guarantee for
6 the tty driver if the termios settings are LECHO & !OPOST. And since
7 it is unexpected and not allowed to call TTY buffer helpers like
8 tty_insert_flip_string concurrently, this may lead to crashes when
9 concurrect writers call pty_write. In that case the following two
11 * the ECHOing from a workqueue and
12 * pty_write from the process
13 race and can overflow the corresponding TTY buffer like follows.
15 If we look into tty_insert_flip_string_fixed_flag, there is:
16 int space = __tty_buffer_request_room(port, goal, flags);
17 struct tty_buffer *tb = port->buf.tail;
19 memcpy(char_buf_ptr(tb, tb->used), chars, space);
23 so the race of the two can result in something like this:
25 __tty_buffer_request_room
26 __tty_buffer_request_room
27 memcpy(buf(tb->used), ...)
29 memcpy(buf(tb->used), ...) ->BOOM
31 B's memcpy is past the tty_buffer due to the previous A's tb->used
34 Since the N_TTY line discipline input processing can output
35 concurrently with a tty write, obtain the N_TTY ldisc output_lock to
36 serialize echo output with normal tty writes. This ensures the tty
37 buffer helper tty_insert_flip_string is not called concurrently and
40 Note that this is nicely reproducible by an ordinary user using
41 forkpty and some setup around that (raw termios + ECHO). And it is
42 present in kernels at least after commit
43 d945cb9cce20ac7143c2de8d88b187f62db99bdc (pty: Rework the pty layer to
44 use the normal buffering logic) in 2.6.31-rc3.
46 js: add more info to the commit log
48 js: lock unconditionally
49 js: lock only the tty->ops->write call
51 References: CVE-2014-0196
52 Reported-and-tested-by: Jiri Slaby <jslaby@suse.cz>
53 Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
54 Signed-off-by: Jiri Slaby <jslaby@suse.cz>
55 Cc: Linus Torvalds <torvalds@linux-foundation.org>
56 Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
57 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
60 drivers/tty/n_tty.c | 4 ++++
61 1 file changed, 4 insertions(+)
63 --- a/drivers/tty/n_tty.c
64 +++ b/drivers/tty/n_tty.c
65 @@ -2066,8 +2066,12 @@ static ssize_t n_tty_write(struct tty_st
66 if (tty->ops->flush_chars)
67 tty->ops->flush_chars(tty);
69 + struct n_tty_data *ldata = tty->disc_data;
72 + mutex_lock(&ldata->output_lock);
73 c = tty->ops->write(tty, b, nr);
74 + mutex_unlock(&ldata->output_lock);