Skip to content

Commit e1e6620

Browse files
arndbgregkh
authored andcommitted
tty: improve tty_insert_flip_char() fast path
commit 979990c6284814617d8f2179d197f72ff62b5d85 upstream. kernelci.org reports a crazy stack usage for the VT code when CONFIG_KASAN is enabled: drivers/tty/vt/keyboard.c: In function 'kbd_keycode': drivers/tty/vt/keyboard.c:1452:1: error: the frame size of 2240 bytes is larger than 2048 bytes [-Werror=frame-larger-than=] The problem is that tty_insert_flip_char() gets inlined many times into kbd_keycode(), and also into other functions, and each copy requires 128 bytes for stack redzone to check for a possible out-of-bounds access on the 'ch' and 'flags' arguments that are passed into tty_insert_flip_string_flags as a variable-length string. This introduces a new __tty_insert_flip_char() function for the slow path, which receives the two arguments by value. This completely avoids the problem and the stack usage goes back down to around 100 bytes. Without KASAN, this is also slightly better, as we don't have to spill the arguments to the stack but can simply pass 'ch' and 'flag' in registers, saving a few bytes in .text for each call site. This should be backported to linux-4.0 or later, which first introduced the stack sanitizer in the kernel. Fixes: c420f16 ("kasan: enable stack instrumentation") Signed-off-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent c576160 commit e1e6620

2 files changed

Lines changed: 26 additions & 1 deletion

File tree

drivers/tty/tty_buffer.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,30 @@ int tty_insert_flip_string_flags(struct tty_port *port,
361361
}
362362
EXPORT_SYMBOL(tty_insert_flip_string_flags);
363363

364+
/**
365+
* __tty_insert_flip_char - Add one character to the tty buffer
366+
* @port: tty port
367+
* @ch: character
368+
* @flag: flag byte
369+
*
370+
* Queue a single byte to the tty buffering, with an optional flag.
371+
* This is the slow path of tty_insert_flip_char.
372+
*/
373+
int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag)
374+
{
375+
struct tty_buffer *tb = port->buf.tail;
376+
int flags = (flag == TTY_NORMAL) ? TTYB_NORMAL : 0;
377+
378+
if (!tty_buffer_request_room(port, 1))
379+
return 0;
380+
381+
*flag_buf_ptr(tb, tb->used) = flag;
382+
*char_buf_ptr(tb, tb->used++) = ch;
383+
384+
return 1;
385+
}
386+
EXPORT_SYMBOL(__tty_insert_flip_char);
387+
364388
/**
365389
* tty_schedule_flip - push characters to ldisc
366390
* @port: tty port to push from

include/linux/tty_flip.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ extern int tty_prepare_flip_string(struct tty_port *port,
1212
unsigned char **chars, size_t size);
1313
extern void tty_flip_buffer_push(struct tty_port *port);
1414
void tty_schedule_flip(struct tty_port *port);
15+
int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag);
1516

1617
static inline int tty_insert_flip_char(struct tty_port *port,
1718
unsigned char ch, char flag)
@@ -26,7 +27,7 @@ static inline int tty_insert_flip_char(struct tty_port *port,
2627
*char_buf_ptr(tb, tb->used++) = ch;
2728
return 1;
2829
}
29-
return tty_insert_flip_string_flags(port, &ch, &flag, 1);
30+
return __tty_insert_flip_char(port, ch, flag);
3031
}
3132

3233
static inline int tty_insert_flip_string(struct tty_port *port,

0 commit comments

Comments
 (0)