Skip to content

Commit d9d4b1e

Browse files
AlanSternbentiss
authored andcommitted
HID: Fix assumption that devices have inputs
The syzbot fuzzer found a slab-out-of-bounds write bug in the hid-gaff driver. The problem is caused by the driver's assumption that the device must have an input report. While this will be true for all normal HID input devices, a suitably malicious device can violate the assumption. The same assumption is present in over a dozen other HID drivers. This patch fixes them by checking that the list of hid_inputs for the hid_device is nonempty before allowing it to be used. Reported-and-tested-by: [email protected] Signed-off-by: Alan Stern <[email protected]> CC: <[email protected]> Signed-off-by: Benjamin Tissoires <[email protected]>
1 parent fe2199c commit d9d4b1e

14 files changed

+126
-37
lines changed

drivers/hid/hid-axff.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,20 @@ static int axff_init(struct hid_device *hid)
6363
{
6464
struct axff_device *axff;
6565
struct hid_report *report;
66-
struct hid_input *hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
66+
struct hid_input *hidinput;
6767
struct list_head *report_list =&hid->report_enum[HID_OUTPUT_REPORT].report_list;
68-
struct input_dev *dev = hidinput->input;
68+
struct input_dev *dev;
6969
int field_count = 0;
7070
int i, j;
7171
int error;
7272

73+
if (list_empty(&hid->inputs)) {
74+
hid_err(hid, "no inputs found\n");
75+
return -ENODEV;
76+
}
77+
hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
78+
dev = hidinput->input;
79+
7380
if (list_empty(report_list)) {
7481
hid_err(hid, "no output reports found\n");
7582
return -ENODEV;

drivers/hid/hid-dr.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,19 @@ static int drff_init(struct hid_device *hid)
7575
{
7676
struct drff_device *drff;
7777
struct hid_report *report;
78-
struct hid_input *hidinput = list_first_entry(&hid->inputs,
79-
struct hid_input, list);
78+
struct hid_input *hidinput;
8079
struct list_head *report_list =
8180
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
82-
struct input_dev *dev = hidinput->input;
81+
struct input_dev *dev;
8382
int error;
8483

84+
if (list_empty(&hid->inputs)) {
85+
hid_err(hid, "no inputs found\n");
86+
return -ENODEV;
87+
}
88+
hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
89+
dev = hidinput->input;
90+
8591
if (list_empty(report_list)) {
8692
hid_err(hid, "no output reports found\n");
8793
return -ENODEV;

drivers/hid/hid-emsff.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,19 @@ static int emsff_init(struct hid_device *hid)
4747
{
4848
struct emsff_device *emsff;
4949
struct hid_report *report;
50-
struct hid_input *hidinput = list_first_entry(&hid->inputs,
51-
struct hid_input, list);
50+
struct hid_input *hidinput;
5251
struct list_head *report_list =
5352
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
54-
struct input_dev *dev = hidinput->input;
53+
struct input_dev *dev;
5554
int error;
5655

56+
if (list_empty(&hid->inputs)) {
57+
hid_err(hid, "no inputs found\n");
58+
return -ENODEV;
59+
}
60+
hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
61+
dev = hidinput->input;
62+
5763
if (list_empty(report_list)) {
5864
hid_err(hid, "no output reports found\n");
5965
return -ENODEV;

drivers/hid/hid-gaff.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,20 @@ static int gaff_init(struct hid_device *hid)
6464
{
6565
struct gaff_device *gaff;
6666
struct hid_report *report;
67-
struct hid_input *hidinput = list_entry(hid->inputs.next,
68-
struct hid_input, list);
67+
struct hid_input *hidinput;
6968
struct list_head *report_list =
7069
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
7170
struct list_head *report_ptr = report_list;
72-
struct input_dev *dev = hidinput->input;
71+
struct input_dev *dev;
7372
int error;
7473

74+
if (list_empty(&hid->inputs)) {
75+
hid_err(hid, "no inputs found\n");
76+
return -ENODEV;
77+
}
78+
hidinput = list_entry(hid->inputs.next, struct hid_input, list);
79+
dev = hidinput->input;
80+
7581
if (list_empty(report_list)) {
7682
hid_err(hid, "no output reports found\n");
7783
return -ENODEV;

drivers/hid/hid-holtekff.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,13 +124,19 @@ static int holtekff_init(struct hid_device *hid)
124124
{
125125
struct holtekff_device *holtekff;
126126
struct hid_report *report;
127-
struct hid_input *hidinput = list_entry(hid->inputs.next,
128-
struct hid_input, list);
127+
struct hid_input *hidinput;
129128
struct list_head *report_list =
130129
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
131-
struct input_dev *dev = hidinput->input;
130+
struct input_dev *dev;
132131
int error;
133132

133+
if (list_empty(&hid->inputs)) {
134+
hid_err(hid, "no inputs found\n");
135+
return -ENODEV;
136+
}
137+
hidinput = list_entry(hid->inputs.next, struct hid_input, list);
138+
dev = hidinput->input;
139+
134140
if (list_empty(report_list)) {
135141
hid_err(hid, "no output report found\n");
136142
return -ENODEV;

drivers/hid/hid-lg2ff.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,17 @@ int lg2ff_init(struct hid_device *hid)
5050
{
5151
struct lg2ff_device *lg2ff;
5252
struct hid_report *report;
53-
struct hid_input *hidinput = list_entry(hid->inputs.next,
54-
struct hid_input, list);
55-
struct input_dev *dev = hidinput->input;
53+
struct hid_input *hidinput;
54+
struct input_dev *dev;
5655
int error;
5756

57+
if (list_empty(&hid->inputs)) {
58+
hid_err(hid, "no inputs found\n");
59+
return -ENODEV;
60+
}
61+
hidinput = list_entry(hid->inputs.next, struct hid_input, list);
62+
dev = hidinput->input;
63+
5864
/* Check that the report looks ok */
5965
report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7);
6066
if (!report)

drivers/hid/hid-lg3ff.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,19 @@ static const signed short ff3_joystick_ac[] = {
117117

118118
int lg3ff_init(struct hid_device *hid)
119119
{
120-
struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
121-
struct input_dev *dev = hidinput->input;
120+
struct hid_input *hidinput;
121+
struct input_dev *dev;
122122
const signed short *ff_bits = ff3_joystick_ac;
123123
int error;
124124
int i;
125125

126+
if (list_empty(&hid->inputs)) {
127+
hid_err(hid, "no inputs found\n");
128+
return -ENODEV;
129+
}
130+
hidinput = list_entry(hid->inputs.next, struct hid_input, list);
131+
dev = hidinput->input;
132+
126133
/* Check that the report looks ok */
127134
if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 35))
128135
return -ENODEV;

drivers/hid/hid-lg4ff.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1253,8 +1253,8 @@ static int lg4ff_handle_multimode_wheel(struct hid_device *hid, u16 *real_produc
12531253

12541254
int lg4ff_init(struct hid_device *hid)
12551255
{
1256-
struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
1257-
struct input_dev *dev = hidinput->input;
1256+
struct hid_input *hidinput;
1257+
struct input_dev *dev;
12581258
struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
12591259
struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
12601260
const struct usb_device_descriptor *udesc = &(hid_to_usb_dev(hid)->descriptor);
@@ -1266,6 +1266,13 @@ int lg4ff_init(struct hid_device *hid)
12661266
int mmode_ret, mmode_idx = -1;
12671267
u16 real_product_id;
12681268

1269+
if (list_empty(&hid->inputs)) {
1270+
hid_err(hid, "no inputs found\n");
1271+
return -ENODEV;
1272+
}
1273+
hidinput = list_entry(hid->inputs.next, struct hid_input, list);
1274+
dev = hidinput->input;
1275+
12691276
/* Check that the report looks ok */
12701277
if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7))
12711278
return -1;

drivers/hid/hid-lgff.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,12 +115,19 @@ static void hid_lgff_set_autocenter(struct input_dev *dev, u16 magnitude)
115115

116116
int lgff_init(struct hid_device* hid)
117117
{
118-
struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
119-
struct input_dev *dev = hidinput->input;
118+
struct hid_input *hidinput;
119+
struct input_dev *dev;
120120
const signed short *ff_bits = ff_joystick;
121121
int error;
122122
int i;
123123

124+
if (list_empty(&hid->inputs)) {
125+
hid_err(hid, "no inputs found\n");
126+
return -ENODEV;
127+
}
128+
hidinput = list_entry(hid->inputs.next, struct hid_input, list);
129+
dev = hidinput->input;
130+
124131
/* Check that the report looks ok */
125132
if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7))
126133
return -ENODEV;

drivers/hid/hid-logitech-hidpp.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2084,8 +2084,8 @@ static void hidpp_ff_destroy(struct ff_device *ff)
20842084
static int hidpp_ff_init(struct hidpp_device *hidpp, u8 feature_index)
20852085
{
20862086
struct hid_device *hid = hidpp->hid_dev;
2087-
struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
2088-
struct input_dev *dev = hidinput->input;
2087+
struct hid_input *hidinput;
2088+
struct input_dev *dev;
20892089
const struct usb_device_descriptor *udesc = &(hid_to_usb_dev(hid)->descriptor);
20902090
const u16 bcdDevice = le16_to_cpu(udesc->bcdDevice);
20912091
struct ff_device *ff;
@@ -2094,6 +2094,13 @@ static int hidpp_ff_init(struct hidpp_device *hidpp, u8 feature_index)
20942094
int error, j, num_slots;
20952095
u8 version;
20962096

2097+
if (list_empty(&hid->inputs)) {
2098+
hid_err(hid, "no inputs found\n");
2099+
return -ENODEV;
2100+
}
2101+
hidinput = list_entry(hid->inputs.next, struct hid_input, list);
2102+
dev = hidinput->input;
2103+
20972104
if (!dev) {
20982105
hid_err(hid, "Struct input_dev not set!\n");
20992106
return -EINVAL;

0 commit comments

Comments
 (0)