Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: syzbot+403741a091bf41d4ae79@syzkaller.appspotmail.com
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
CC: <stable@vger.kernel.org>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

authored by

Alan Stern and committed by
Benjamin Tissoires
d9d4b1e4 fe2199cf

+126 -37
+9 -2
drivers/hid/hid-axff.c
··· 63 63 { 64 64 struct axff_device *axff; 65 65 struct hid_report *report; 66 - struct hid_input *hidinput = list_first_entry(&hid->inputs, struct hid_input, list); 66 + struct hid_input *hidinput; 67 67 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; 69 69 int field_count = 0; 70 70 int i, j; 71 71 int error; 72 + 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; 72 79 73 80 if (list_empty(report_list)) { 74 81 hid_err(hid, "no output reports found\n");
+9 -3
drivers/hid/hid-dr.c
··· 75 75 { 76 76 struct drff_device *drff; 77 77 struct hid_report *report; 78 - struct hid_input *hidinput = list_first_entry(&hid->inputs, 79 - struct hid_input, list); 78 + struct hid_input *hidinput; 80 79 struct list_head *report_list = 81 80 &hid->report_enum[HID_OUTPUT_REPORT].report_list; 82 - struct input_dev *dev = hidinput->input; 81 + struct input_dev *dev; 83 82 int error; 83 + 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; 84 90 85 91 if (list_empty(report_list)) { 86 92 hid_err(hid, "no output reports found\n");
+9 -3
drivers/hid/hid-emsff.c
··· 47 47 { 48 48 struct emsff_device *emsff; 49 49 struct hid_report *report; 50 - struct hid_input *hidinput = list_first_entry(&hid->inputs, 51 - struct hid_input, list); 50 + struct hid_input *hidinput; 52 51 struct list_head *report_list = 53 52 &hid->report_enum[HID_OUTPUT_REPORT].report_list; 54 - struct input_dev *dev = hidinput->input; 53 + struct input_dev *dev; 55 54 int error; 55 + 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; 56 62 57 63 if (list_empty(report_list)) { 58 64 hid_err(hid, "no output reports found\n");
+9 -3
drivers/hid/hid-gaff.c
··· 64 64 { 65 65 struct gaff_device *gaff; 66 66 struct hid_report *report; 67 - struct hid_input *hidinput = list_entry(hid->inputs.next, 68 - struct hid_input, list); 67 + struct hid_input *hidinput; 69 68 struct list_head *report_list = 70 69 &hid->report_enum[HID_OUTPUT_REPORT].report_list; 71 70 struct list_head *report_ptr = report_list; 72 - struct input_dev *dev = hidinput->input; 71 + struct input_dev *dev; 73 72 int error; 73 + 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; 74 80 75 81 if (list_empty(report_list)) { 76 82 hid_err(hid, "no output reports found\n");
+9 -3
drivers/hid/hid-holtekff.c
··· 124 124 { 125 125 struct holtekff_device *holtekff; 126 126 struct hid_report *report; 127 - struct hid_input *hidinput = list_entry(hid->inputs.next, 128 - struct hid_input, list); 127 + struct hid_input *hidinput; 129 128 struct list_head *report_list = 130 129 &hid->report_enum[HID_OUTPUT_REPORT].report_list; 131 - struct input_dev *dev = hidinput->input; 130 + struct input_dev *dev; 132 131 int error; 132 + 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; 133 139 134 140 if (list_empty(report_list)) { 135 141 hid_err(hid, "no output report found\n");
+9 -3
drivers/hid/hid-lg2ff.c
··· 50 50 { 51 51 struct lg2ff_device *lg2ff; 52 52 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; 56 55 int error; 56 + 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; 57 63 58 64 /* Check that the report looks ok */ 59 65 report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7);
+9 -2
drivers/hid/hid-lg3ff.c
··· 117 117 118 118 int lg3ff_init(struct hid_device *hid) 119 119 { 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; 122 122 const signed short *ff_bits = ff3_joystick_ac; 123 123 int error; 124 124 int i; 125 + 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; 125 132 126 133 /* Check that the report looks ok */ 127 134 if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 35))
+9 -2
drivers/hid/hid-lg4ff.c
··· 1253 1253 1254 1254 int lg4ff_init(struct hid_device *hid) 1255 1255 { 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; 1258 1258 struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; 1259 1259 struct hid_report *report = list_entry(report_list->next, struct hid_report, list); 1260 1260 const struct usb_device_descriptor *udesc = &(hid_to_usb_dev(hid)->descriptor); ··· 1265 1265 int error, i, j; 1266 1266 int mmode_ret, mmode_idx = -1; 1267 1267 u16 real_product_id; 1268 + 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; 1268 1275 1269 1276 /* Check that the report looks ok */ 1270 1277 if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7))
+9 -2
drivers/hid/hid-lgff.c
··· 115 115 116 116 int lgff_init(struct hid_device* hid) 117 117 { 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; 120 120 const signed short *ff_bits = ff_joystick; 121 121 int error; 122 122 int i; 123 + 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; 123 130 124 131 /* Check that the report looks ok */ 125 132 if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7))
+9 -2
drivers/hid/hid-logitech-hidpp.c
··· 2084 2084 static int hidpp_ff_init(struct hidpp_device *hidpp, u8 feature_index) 2085 2085 { 2086 2086 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; 2089 2089 const struct usb_device_descriptor *udesc = &(hid_to_usb_dev(hid)->descriptor); 2090 2090 const u16 bcdDevice = le16_to_cpu(udesc->bcdDevice); 2091 2091 struct ff_device *ff; ··· 2093 2093 struct hidpp_ff_private_data *data; 2094 2094 int error, j, num_slots; 2095 2095 u8 version; 2096 + 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; 2096 2103 2097 2104 if (!dev) { 2098 2105 hid_err(hid, "Struct input_dev not set!\n");
+9 -3
drivers/hid/hid-microsoft.c
··· 328 328 329 329 static int ms_init_ff(struct hid_device *hdev) 330 330 { 331 - struct hid_input *hidinput = list_entry(hdev->inputs.next, 332 - struct hid_input, list); 333 - struct input_dev *input_dev = hidinput->input; 331 + struct hid_input *hidinput; 332 + struct input_dev *input_dev; 334 333 struct ms_data *ms = hid_get_drvdata(hdev); 334 + 335 + if (list_empty(&hdev->inputs)) { 336 + hid_err(hdev, "no inputs found\n"); 337 + return -ENODEV; 338 + } 339 + hidinput = list_entry(hdev->inputs.next, struct hid_input, list); 340 + input_dev = hidinput->input; 335 341 336 342 if (!(ms->quirks & MS_QUIRK_FF)) 337 343 return 0;
+9 -3
drivers/hid/hid-sony.c
··· 2254 2254 2255 2255 static int sony_init_ff(struct sony_sc *sc) 2256 2256 { 2257 - struct hid_input *hidinput = list_entry(sc->hdev->inputs.next, 2258 - struct hid_input, list); 2259 - struct input_dev *input_dev = hidinput->input; 2257 + struct hid_input *hidinput; 2258 + struct input_dev *input_dev; 2259 + 2260 + if (list_empty(&sc->hdev->inputs)) { 2261 + hid_err(sc->hdev, "no inputs found\n"); 2262 + return -ENODEV; 2263 + } 2264 + hidinput = list_entry(sc->hdev->inputs.next, struct hid_input, list); 2265 + input_dev = hidinput->input; 2260 2266 2261 2267 input_set_capability(input_dev, EV_FF, FF_RUMBLE); 2262 2268 return input_ff_create_memless(input_dev, NULL, sony_play_effect);
+9 -3
drivers/hid/hid-tmff.c
··· 124 124 struct tmff_device *tmff; 125 125 struct hid_report *report; 126 126 struct list_head *report_list; 127 - struct hid_input *hidinput = list_entry(hid->inputs.next, 128 - struct hid_input, list); 129 - struct input_dev *input_dev = hidinput->input; 127 + struct hid_input *hidinput; 128 + struct input_dev *input_dev; 130 129 int error; 131 130 int i; 131 + 132 + if (list_empty(&hid->inputs)) { 133 + hid_err(hid, "no inputs found\n"); 134 + return -ENODEV; 135 + } 136 + hidinput = list_entry(hid->inputs.next, struct hid_input, list); 137 + input_dev = hidinput->input; 132 138 133 139 tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL); 134 140 if (!tmff)
+9 -3
drivers/hid/hid-zpff.c
··· 54 54 { 55 55 struct zpff_device *zpff; 56 56 struct hid_report *report; 57 - struct hid_input *hidinput = list_entry(hid->inputs.next, 58 - struct hid_input, list); 59 - struct input_dev *dev = hidinput->input; 57 + struct hid_input *hidinput; 58 + struct input_dev *dev; 60 59 int i, error; 60 + 61 + if (list_empty(&hid->inputs)) { 62 + hid_err(hid, "no inputs found\n"); 63 + return -ENODEV; 64 + } 65 + hidinput = list_entry(hid->inputs.next, struct hid_input, list); 66 + dev = hidinput->input; 61 67 62 68 for (i = 0; i < 4; i++) { 63 69 report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, i, 1);