aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2012-07-19 16:08:21 -0400
committerJiri Kosina <jkosina@suse.cz>2012-07-20 05:24:23 -0400
commit668160e5a80536251b4931a332dfe34d6ec2aeb7 (patch)
tree326dff1f73e54f8f57a49b090a9f0411cd22dfdb /drivers/hid
parent61c901c56905256a4a4d7c2af92d66200a2ee7f2 (diff)
HID: usbhid: fix use-after-free bug
This patch (as1592) fixes an obscure problem in the usbhid driver. Under some circumstances, a control or interrupt-OUT URB can be submitted twice. This will happen if the first submission fails; the queue pointers aren't updated, so the next time the queue is restarted the same URB will be submitted again. The problem is that raw_report gets deallocated during the first submission. The second submission will then dereference and try to free an already-freed region of memory. The patch fixes the problem by setting raw_report to NULL when it is deallocated and checking for NULL before dereferencing it. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> CC: Oliver Neukum <oliver@neukum.org> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/usbhid/hid-core.c16
1 files changed, 11 insertions, 5 deletions
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 482f936fc29b..6b9bad540702 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -331,9 +331,12 @@ static int hid_submit_out(struct hid_device *hid)
331 usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 331 usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) +
332 1 + (report->id > 0); 332 1 + (report->id > 0);
333 usbhid->urbout->dev = hid_to_usb_dev(hid); 333 usbhid->urbout->dev = hid_to_usb_dev(hid);
334 memcpy(usbhid->outbuf, raw_report, 334 if (raw_report) {
335 usbhid->urbout->transfer_buffer_length); 335 memcpy(usbhid->outbuf, raw_report,
336 kfree(raw_report); 336 usbhid->urbout->transfer_buffer_length);
337 kfree(raw_report);
338 usbhid->out[usbhid->outtail].raw_report = NULL;
339 }
337 340
338 dbg_hid("submitting out urb\n"); 341 dbg_hid("submitting out urb\n");
339 342
@@ -362,8 +365,11 @@ static int hid_submit_ctrl(struct hid_device *hid)
362 if (dir == USB_DIR_OUT) { 365 if (dir == USB_DIR_OUT) {
363 usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0); 366 usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0);
364 usbhid->urbctrl->transfer_buffer_length = len; 367 usbhid->urbctrl->transfer_buffer_length = len;
365 memcpy(usbhid->ctrlbuf, raw_report, len); 368 if (raw_report) {
366 kfree(raw_report); 369 memcpy(usbhid->ctrlbuf, raw_report, len);
370 kfree(raw_report);
371 usbhid->ctrl[usbhid->ctrltail].raw_report = NULL;
372 }
367 } else { 373 } else {
368 int maxpacket, padlen; 374 int maxpacket, padlen;
369 375