Skip to content

Commit 35556be

Browse files
Marc Zyngierbentiss
authored andcommitted
HID: core: Sanitize event code and type when mapping input
When calling into hid_map_usage(), the passed event code is blindly stored as is, even if it doesn't fit in the associated bitmap. This event code can come from a variety of sources, including devices masquerading as input devices, only a bit more "programmable". Instead of taking the event code at face value, check that it actually fits the corresponding bitmap, and if it doesn't: - spit out a warning so that we know which device is acting up - NULLify the bitmap pointer so that we catch unexpected uses Code paths that can make use of untrusted inputs can now check that the mapping was indeed correct and bail out if not. Cc: [email protected] Signed-off-by: Marc Zyngier <[email protected]> Signed-off-by: Benjamin Tissoires <[email protected]>
1 parent bce1305 commit 35556be

File tree

3 files changed

+35
-13
lines changed

3 files changed

+35
-13
lines changed

drivers/hid/hid-input.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
11321132
}
11331133

11341134
mapped:
1135+
/* Mapping failed, bail out */
1136+
if (!bit)
1137+
return;
1138+
11351139
if (device->driver->input_mapped &&
11361140
device->driver->input_mapped(device, hidinput, field, usage,
11371141
&bit, &max) < 0) {

drivers/hid/hid-multitouch.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,8 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
856856
code = BTN_0 + ((usage->hid - 1) & HID_USAGE);
857857

858858
hid_map_usage(hi, usage, bit, max, EV_KEY, code);
859+
if (!*bit)
860+
return -1;
859861
input_set_capability(hi->input, EV_KEY, code);
860862
return 1;
861863

include/linux/hid.h

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -959,34 +959,49 @@ static inline void hid_device_io_stop(struct hid_device *hid) {
959959
* @max: maximal valid usage->code to consider later (out parameter)
960960
* @type: input event type (EV_KEY, EV_REL, ...)
961961
* @c: code which corresponds to this usage and type
962+
*
963+
* The value pointed to by @bit will be set to NULL if either @type is
964+
* an unhandled event type, or if @c is out of range for @type. This
965+
* can be used as an error condition.
962966
*/
963967
static inline void hid_map_usage(struct hid_input *hidinput,
964968
struct hid_usage *usage, unsigned long **bit, int *max,
965-
__u8 type, __u16 c)
969+
__u8 type, unsigned int c)
966970
{
967971
struct input_dev *input = hidinput->input;
968-
969-
usage->type = type;
970-
usage->code = c;
972+
unsigned long *bmap = NULL;
973+
unsigned int limit = 0;
971974

972975
switch (type) {
973976
case EV_ABS:
974-
*bit = input->absbit;
975-
*max = ABS_MAX;
977+
bmap = input->absbit;
978+
limit = ABS_MAX;
976979
break;
977980
case EV_REL:
978-
*bit = input->relbit;
979-
*max = REL_MAX;
981+
bmap = input->relbit;
982+
limit = REL_MAX;
980983
break;
981984
case EV_KEY:
982-
*bit = input->keybit;
983-
*max = KEY_MAX;
985+
bmap = input->keybit;
986+
limit = KEY_MAX;
984987
break;
985988
case EV_LED:
986-
*bit = input->ledbit;
987-
*max = LED_MAX;
989+
bmap = input->ledbit;
990+
limit = LED_MAX;
988991
break;
989992
}
993+
994+
if (unlikely(c > limit || !bmap)) {
995+
pr_warn_ratelimited("%s: Invalid code %d type %d\n",
996+
input->name, c, type);
997+
*bit = NULL;
998+
return;
999+
}
1000+
1001+
usage->type = type;
1002+
usage->code = c;
1003+
*max = limit;
1004+
*bit = bmap;
9901005
}
9911006

9921007
/**
@@ -1000,7 +1015,8 @@ static inline void hid_map_usage_clear(struct hid_input *hidinput,
10001015
__u8 type, __u16 c)
10011016
{
10021017
hid_map_usage(hidinput, usage, bit, max, type, c);
1003-
clear_bit(c, *bit);
1018+
if (*bit)
1019+
clear_bit(usage->code, *bit);
10041020
}
10051021

10061022
/**

0 commit comments

Comments
 (0)