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