Skip to content

Commit

Permalink
tty: improve tty_insert_flip_char() fast path
Browse files Browse the repository at this point in the history
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.

Cc: stable@vger.kernel.org
Fixes: c420f16 ("kasan: enable stack instrumentation")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Arnd Bergmann authored and Greg Kroah-Hartman committed Jul 30, 2017
1 parent a449f12 commit 979990c
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 1 deletion.
24 changes: 24 additions & 0 deletions drivers/tty/tty_buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,30 @@ int tty_insert_flip_string_flags(struct tty_port *port,
}
EXPORT_SYMBOL(tty_insert_flip_string_flags);

/**
* __tty_insert_flip_char - Add one character to the tty buffer
* @port: tty port
* @ch: character
* @flag: flag byte
*
* Queue a single byte to the tty buffering, with an optional flag.
* This is the slow path of tty_insert_flip_char.
*/
int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag)
{
struct tty_buffer *tb = port->buf.tail;
int flags = (flag == TTY_NORMAL) ? TTYB_NORMAL : 0;

if (!tty_buffer_request_room(port, 1))
return 0;

*flag_buf_ptr(tb, tb->used) = flag;
*char_buf_ptr(tb, tb->used++) = ch;

return 1;
}
EXPORT_SYMBOL(__tty_insert_flip_char);

/**
* tty_schedule_flip - push characters to ldisc
* @port: tty port to push from
Expand Down
3 changes: 2 additions & 1 deletion include/linux/tty_flip.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ extern int tty_prepare_flip_string(struct tty_port *port,
unsigned char **chars, size_t size);
extern void tty_flip_buffer_push(struct tty_port *port);
void tty_schedule_flip(struct tty_port *port);
int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag);

static inline int tty_insert_flip_char(struct tty_port *port,
unsigned char ch, char flag)
Expand All @@ -26,7 +27,7 @@ static inline int tty_insert_flip_char(struct tty_port *port,
*char_buf_ptr(tb, tb->used++) = ch;
return 1;
}
return tty_insert_flip_string_flags(port, &ch, &flag, 1);
return __tty_insert_flip_char(port, ch, flag);
}

static inline int tty_insert_flip_string(struct tty_port *port,
Expand Down

0 comments on commit 979990c

Please sign in to comment.