| From 626ff609f460c2902dbbb36934ba19015d406dba Mon Sep 17 00:00:00 2001 |
| From: Dmitry Torokhov <dmitry.torokhov@gmail.com> |
| Date: Mon, 25 May 2020 16:27:40 -0700 |
| Subject: [PATCH] vt: keyboard: avoid signed integer overflow in k_ascii |
| |
| commit b86dab054059b970111b5516ae548efaae5b3aae upstream. |
| |
| When k_ascii is invoked several times in a row there is a potential for |
| signed integer overflow: |
| |
| UBSAN: Undefined behaviour in drivers/tty/vt/keyboard.c:888:19 signed integer overflow: |
| 10 * 1111111111 cannot be represented in type 'int' |
| CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.6.11 #1 |
| Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 |
| Call Trace: |
| <IRQ> |
| __dump_stack lib/dump_stack.c:77 [inline] |
| dump_stack+0xce/0x128 lib/dump_stack.c:118 |
| ubsan_epilogue+0xe/0x30 lib/ubsan.c:154 |
| handle_overflow+0xdc/0xf0 lib/ubsan.c:184 |
| __ubsan_handle_mul_overflow+0x2a/0x40 lib/ubsan.c:205 |
| k_ascii+0xbf/0xd0 drivers/tty/vt/keyboard.c:888 |
| kbd_keycode drivers/tty/vt/keyboard.c:1477 [inline] |
| kbd_event+0x888/0x3be0 drivers/tty/vt/keyboard.c:1495 |
| |
| While it can be worked around by using check_mul_overflow()/ |
| check_add_overflow(), it is better to introduce a separate flag to |
| signal that number pad is being used to compose a symbol, and |
| change type of the accumulator from signed to unsigned, thus |
| avoiding undefined behavior when it overflows. |
| |
| Reported-by: Kyungtae Kim <kt0755@gmail.com> |
| Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> |
| Cc: stable <stable@vger.kernel.org> |
| Link: https://lore.kernel.org/r/20200525232740.GA262061@dtor-ws |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c |
| index 15d33fa0c925..568b2171f335 100644 |
| --- a/drivers/tty/vt/keyboard.c |
| +++ b/drivers/tty/vt/keyboard.c |
| @@ -127,7 +127,11 @@ static DEFINE_SPINLOCK(func_buf_lock); /* guard 'func_buf' and friends */ |
| static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */ |
| static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ |
| static bool dead_key_next; |
| -static int npadch = -1; /* -1 or number assembled on pad */ |
| + |
| +/* Handles a number being assembled on the number pad */ |
| +static bool npadch_active; |
| +static unsigned int npadch_value; |
| + |
| static unsigned int diacr; |
| static char rep; /* flag telling character repeat */ |
| |
| @@ -845,12 +849,12 @@ static void k_shift(struct vc_data *vc, unsigned char value, char up_flag) |
| shift_state &= ~(1 << value); |
| |
| /* kludge */ |
| - if (up_flag && shift_state != old_state && npadch != -1) { |
| + if (up_flag && shift_state != old_state && npadch_active) { |
| if (kbd->kbdmode == VC_UNICODE) |
| - to_utf8(vc, npadch); |
| + to_utf8(vc, npadch_value); |
| else |
| - put_queue(vc, npadch & 0xff); |
| - npadch = -1; |
| + put_queue(vc, npadch_value & 0xff); |
| + npadch_active = false; |
| } |
| } |
| |
| @@ -868,7 +872,7 @@ static void k_meta(struct vc_data *vc, unsigned char value, char up_flag) |
| |
| static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag) |
| { |
| - int base; |
| + unsigned int base; |
| |
| if (up_flag) |
| return; |
| @@ -882,10 +886,12 @@ static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag) |
| base = 16; |
| } |
| |
| - if (npadch == -1) |
| - npadch = value; |
| - else |
| - npadch = npadch * base + value; |
| + if (!npadch_active) { |
| + npadch_value = 0; |
| + npadch_active = true; |
| + } |
| + |
| + npadch_value = npadch_value * base + value; |
| } |
| |
| static void k_lock(struct vc_data *vc, unsigned char value, char up_flag) |
| -- |
| 2.27.0 |
| |