| From 510cccb5b0c8868a2b302a0ab524da7912da648b Mon Sep 17 00:00:00 2001 |
| From: Dmitry Torokhov <dmitry.torokhov@gmail.com> |
| Date: Mon, 27 Jun 2016 14:12:34 -0700 |
| Subject: tty/vt/keyboard: fix OOB access in do_compute_shiftstate() |
| |
| From: Dmitry Torokhov <dmitry.torokhov@gmail.com> |
| |
| commit 510cccb5b0c8868a2b302a0ab524da7912da648b upstream. |
| |
| The size of individual keymap in drivers/tty/vt/keyboard.c is NR_KEYS, |
| which is currently 256, whereas number of keys/buttons in input device (and |
| therefor in key_down) is much larger - KEY_CNT - 768, and that can cause |
| out-of-bound access when we do |
| |
| sym = U(key_maps[0][k]); |
| |
| with large 'k'. |
| |
| To fix it we should not attempt iterating beyond smaller of NR_KEYS and |
| KEY_CNT. |
| |
| Also while at it let's switch to for_each_set_bit() instead of open-coding |
| it. |
| |
| Reported-by: Sasha Levin <sasha.levin@oracle.com> |
| Reviewed-by: Guenter Roeck <linux@roeck-us.net> |
| Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/tty/vt/keyboard.c | 30 +++++++++--------------------- |
| 1 file changed, 9 insertions(+), 21 deletions(-) |
| |
| --- a/drivers/tty/vt/keyboard.c |
| +++ b/drivers/tty/vt/keyboard.c |
| @@ -366,34 +366,22 @@ static void to_utf8(struct vc_data *vc, |
| |
| static void do_compute_shiftstate(void) |
| { |
| - unsigned int i, j, k, sym, val; |
| + unsigned int k, sym, val; |
| |
| shift_state = 0; |
| memset(shift_down, 0, sizeof(shift_down)); |
| |
| - for (i = 0; i < ARRAY_SIZE(key_down); i++) { |
| - |
| - if (!key_down[i]) |
| + for_each_set_bit(k, key_down, min(NR_KEYS, KEY_CNT)) { |
| + sym = U(key_maps[0][k]); |
| + if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK) |
| continue; |
| |
| - k = i * BITS_PER_LONG; |
| - |
| - for (j = 0; j < BITS_PER_LONG; j++, k++) { |
| - |
| - if (!test_bit(k, key_down)) |
| - continue; |
| - |
| - sym = U(key_maps[0][k]); |
| - if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK) |
| - continue; |
| - |
| - val = KVAL(sym); |
| - if (val == KVAL(K_CAPSSHIFT)) |
| - val = KVAL(K_SHIFT); |
| + val = KVAL(sym); |
| + if (val == KVAL(K_CAPSSHIFT)) |
| + val = KVAL(K_SHIFT); |
| |
| - shift_down[val]++; |
| - shift_state |= (1 << val); |
| - } |
| + shift_down[val]++; |
| + shift_state |= BIT(val); |
| } |
| } |
| |