Input: add safety guards to input_set_keycode()
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-ws Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
This commit is contained in:
parent
f729a1b0f8
commit
cb222aed03
|
@ -878,16 +878,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -943,9 +945,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
|
||||||
|
|
Loading…
Reference in New Issue