]>
Commit | Line | Data |
---|---|---|
63e03c28 GKH |
1 | From 979990c6284814617d8f2179d197f72ff62b5d85 Mon Sep 17 00:00:00 2001 |
2 | From: Arnd Bergmann <arnd@arndb.de> | |
3 | Date: Tue, 20 Jun 2017 23:10:41 +0200 | |
4 | Subject: tty: improve tty_insert_flip_char() fast path | |
5 | ||
6 | From: Arnd Bergmann <arnd@arndb.de> | |
7 | ||
8 | commit 979990c6284814617d8f2179d197f72ff62b5d85 upstream. | |
9 | ||
10 | kernelci.org reports a crazy stack usage for the VT code when CONFIG_KASAN | |
11 | is enabled: | |
12 | ||
13 | drivers/tty/vt/keyboard.c: In function 'kbd_keycode': | |
14 | drivers/tty/vt/keyboard.c:1452:1: error: the frame size of 2240 bytes is larger than 2048 bytes [-Werror=frame-larger-than=] | |
15 | ||
16 | The problem is that tty_insert_flip_char() gets inlined many times into | |
17 | kbd_keycode(), and also into other functions, and each copy requires 128 | |
18 | bytes for stack redzone to check for a possible out-of-bounds access on | |
19 | the 'ch' and 'flags' arguments that are passed into | |
20 | tty_insert_flip_string_flags as a variable-length string. | |
21 | ||
22 | This introduces a new __tty_insert_flip_char() function for the slow | |
23 | path, which receives the two arguments by value. This completely avoids | |
24 | the problem and the stack usage goes back down to around 100 bytes. | |
25 | ||
26 | Without KASAN, this is also slightly better, as we don't have to | |
27 | spill the arguments to the stack but can simply pass 'ch' and 'flag' | |
28 | in registers, saving a few bytes in .text for each call site. | |
29 | ||
30 | This should be backported to linux-4.0 or later, which first introduced | |
31 | the stack sanitizer in the kernel. | |
32 | ||
33 | Fixes: c420f167db8c ("kasan: enable stack instrumentation") | |
34 | Signed-off-by: Arnd Bergmann <arnd@arndb.de> | |
35 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
63e03c28 GKH |
36 | |
37 | --- | |
38 | drivers/tty/tty_buffer.c | 24 ++++++++++++++++++++++++ | |
39 | include/linux/tty_flip.h | 3 ++- | |
40 | 2 files changed, 26 insertions(+), 1 deletion(-) | |
41 | ||
42 | --- a/drivers/tty/tty_buffer.c | |
43 | +++ b/drivers/tty/tty_buffer.c | |
44 | @@ -362,6 +362,30 @@ int tty_insert_flip_string_flags(struct | |
45 | EXPORT_SYMBOL(tty_insert_flip_string_flags); | |
46 | ||
47 | /** | |
48 | + * __tty_insert_flip_char - Add one character to the tty buffer | |
49 | + * @port: tty port | |
50 | + * @ch: character | |
51 | + * @flag: flag byte | |
52 | + * | |
53 | + * Queue a single byte to the tty buffering, with an optional flag. | |
54 | + * This is the slow path of tty_insert_flip_char. | |
55 | + */ | |
56 | +int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag) | |
57 | +{ | |
58 | + struct tty_buffer *tb = port->buf.tail; | |
59 | + int flags = (flag == TTY_NORMAL) ? TTYB_NORMAL : 0; | |
60 | + | |
61 | + if (!tty_buffer_request_room(port, 1)) | |
62 | + return 0; | |
63 | + | |
64 | + *flag_buf_ptr(tb, tb->used) = flag; | |
65 | + *char_buf_ptr(tb, tb->used++) = ch; | |
66 | + | |
67 | + return 1; | |
68 | +} | |
69 | +EXPORT_SYMBOL(__tty_insert_flip_char); | |
70 | + | |
71 | +/** | |
72 | * tty_schedule_flip - push characters to ldisc | |
73 | * @port: tty port to push from | |
74 | * | |
75 | --- a/include/linux/tty_flip.h | |
76 | +++ b/include/linux/tty_flip.h | |
77 | @@ -12,6 +12,7 @@ extern int tty_prepare_flip_string(struc | |
78 | unsigned char **chars, size_t size); | |
79 | extern void tty_flip_buffer_push(struct tty_port *port); | |
80 | void tty_schedule_flip(struct tty_port *port); | |
81 | +int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag); | |
82 | ||
83 | static inline int tty_insert_flip_char(struct tty_port *port, | |
84 | unsigned char ch, char flag) | |
85 | @@ -26,7 +27,7 @@ static inline int tty_insert_flip_char(s | |
86 | *char_buf_ptr(tb, tb->used++) = ch; | |
87 | return 1; | |
88 | } | |
89 | - return tty_insert_flip_string_flags(port, &ch, &flag, 1); | |
90 | + return __tty_insert_flip_char(port, ch, flag); | |
91 | } | |
92 | ||
93 | static inline int tty_insert_flip_string(struct tty_port *port, |