Commit 668160e5 authored by Alan Stern's avatar Alan Stern Committed by Jiri Kosina

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: default avatarAlan Stern <stern@rowland.harvard.edu>
CC: Oliver Neukum <oliver@neukum.org>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 61c901c5
...@@ -331,9 +331,12 @@ static int hid_submit_out(struct hid_device *hid) ...@@ -331,9 +331,12 @@ static int hid_submit_out(struct hid_device *hid)
usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) +
1 + (report->id > 0); 1 + (report->id > 0);
usbhid->urbout->dev = hid_to_usb_dev(hid); usbhid->urbout->dev = hid_to_usb_dev(hid);
memcpy(usbhid->outbuf, raw_report, if (raw_report) {
usbhid->urbout->transfer_buffer_length); memcpy(usbhid->outbuf, raw_report,
kfree(raw_report); usbhid->urbout->transfer_buffer_length);
kfree(raw_report);
usbhid->out[usbhid->outtail].raw_report = NULL;
}
dbg_hid("submitting out urb\n"); dbg_hid("submitting out urb\n");
...@@ -362,8 +365,11 @@ static int hid_submit_ctrl(struct hid_device *hid) ...@@ -362,8 +365,11 @@ static int hid_submit_ctrl(struct hid_device *hid)
if (dir == USB_DIR_OUT) { if (dir == USB_DIR_OUT) {
usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0); usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0);
usbhid->urbctrl->transfer_buffer_length = len; usbhid->urbctrl->transfer_buffer_length = len;
memcpy(usbhid->ctrlbuf, raw_report, len); if (raw_report) {
kfree(raw_report); memcpy(usbhid->ctrlbuf, raw_report, len);
kfree(raw_report);
usbhid->ctrl[usbhid->ctrltail].raw_report = NULL;
}
} else { } else {
int maxpacket, padlen; int maxpacket, padlen;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment