]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/4.9.52/tty-improve-tty_insert_flip_char-fast-path.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 4.9.52 / tty-improve-tty_insert_flip_char-fast-path.patch
CommitLineData
63e03c28
GKH
1From 979990c6284814617d8f2179d197f72ff62b5d85 Mon Sep 17 00:00:00 2001
2From: Arnd Bergmann <arnd@arndb.de>
3Date: Tue, 20 Jun 2017 23:10:41 +0200
4Subject: tty: improve tty_insert_flip_char() fast path
5
6From: Arnd Bergmann <arnd@arndb.de>
7
8commit 979990c6284814617d8f2179d197f72ff62b5d85 upstream.
9
10kernelci.org reports a crazy stack usage for the VT code when CONFIG_KASAN
11is enabled:
12
13drivers/tty/vt/keyboard.c: In function 'kbd_keycode':
14drivers/tty/vt/keyboard.c:1452:1: error: the frame size of 2240 bytes is larger than 2048 bytes [-Werror=frame-larger-than=]
15
16The problem is that tty_insert_flip_char() gets inlined many times into
17kbd_keycode(), and also into other functions, and each copy requires 128
18bytes for stack redzone to check for a possible out-of-bounds access on
19the 'ch' and 'flags' arguments that are passed into
20tty_insert_flip_string_flags as a variable-length string.
21
22This introduces a new __tty_insert_flip_char() function for the slow
23path, which receives the two arguments by value. This completely avoids
24the problem and the stack usage goes back down to around 100 bytes.
25
26Without KASAN, this is also slightly better, as we don't have to
27spill the arguments to the stack but can simply pass 'ch' and 'flag'
28in registers, saving a few bytes in .text for each call site.
29
30This should be backported to linux-4.0 or later, which first introduced
31the stack sanitizer in the kernel.
32
33Fixes: c420f167db8c ("kasan: enable stack instrumentation")
34Signed-off-by: Arnd Bergmann <arnd@arndb.de>
35Signed-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,