Commit 684ab0f2 authored by Dmitry Torokhov's avatar Dmitry Torokhov Committed by Khalid Elmously

Input: add safety guards to input_set_keycode()

BugLink: https://bugs.launchpad.net/bugs/1859865

commit cb222aed upstream.

If we happen to have a garbage in input device's keycode table with values
too big we'll end up doing clear_bit() with offset way outside of our
bitmaps, damaging other objects within an input device or even outside of
it. Let's add sanity checks to the returned old keycodes.

Reported-by: syzbot+c769968809f9359b07aa@syzkaller.appspotmail.com
Reported-by: syzbot+76f3a30e88d256644c78@syzkaller.appspotmail.com
Link: https://lore.kernel.org/r/20191207212757.GA245964@dtor-wsSigned-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarConnor Kuehl <connor.kuehl@canonical.com>
Signed-off-by: default avatarKhalid Elmously <khalid.elmously@canonical.com>
parent ffd92e18
...@@ -851,16 +851,18 @@ static int input_default_setkeycode(struct input_dev *dev, ...@@ -851,16 +851,18 @@ static int input_default_setkeycode(struct input_dev *dev,
} }
} }
__clear_bit(*old_keycode, dev->keybit); if (*old_keycode <= KEY_MAX) {
__set_bit(ke->keycode, dev->keybit); __clear_bit(*old_keycode, dev->keybit);
for (i = 0; i < dev->keycodemax; i++) {
for (i = 0; i < dev->keycodemax; i++) { if (input_fetch_keycode(dev, i) == *old_keycode) {
if (input_fetch_keycode(dev, i) == *old_keycode) { __set_bit(*old_keycode, dev->keybit);
__set_bit(*old_keycode, dev->keybit); /* Setting the bit twice is useless, so break */
break; /* Setting the bit twice is useless, so break */ break;
}
} }
} }
__set_bit(ke->keycode, dev->keybit);
return 0; return 0;
} }
...@@ -916,9 +918,13 @@ int input_set_keycode(struct input_dev *dev, ...@@ -916,9 +918,13 @@ int input_set_keycode(struct input_dev *dev,
* Simulate keyup event if keycode is not present * Simulate keyup event if keycode is not present
* in the keymap anymore * in the keymap anymore
*/ */
if (test_bit(EV_KEY, dev->evbit) && if (old_keycode > KEY_MAX) {
!is_event_supported(old_keycode, dev->keybit, KEY_MAX) && dev_warn(dev->dev.parent ?: &dev->dev,
__test_and_clear_bit(old_keycode, dev->key)) { "%s: got too big old keycode %#x\n",
__func__, old_keycode);
} else if (test_bit(EV_KEY, dev->evbit) &&
!is_event_supported(old_keycode, dev->keybit, KEY_MAX) &&
__test_and_clear_bit(old_keycode, dev->key)) {
struct input_value vals[] = { struct input_value vals[] = {
{ EV_KEY, old_keycode, 0 }, { EV_KEY, old_keycode, 0 },
input_value_sync input_value_sync
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment