drivers/usb/core/devio.c | 96 ++++++++++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 46 deletions(-) Index: usb-3.1/drivers/usb/core/devio.c =================================================================== --- usb-3.1.orig/drivers/usb/core/devio.c +++ usb-3.1/drivers/usb/core/devio.c @@ -796,8 +796,8 @@ static int proc_control(struct dev_state if (ctrl.bRequestType & 0x80) { if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.wLength)) { - free_page((unsigned long)tbuf); - return -EINVAL; + ret = -EINVAL; + goto done; } pipe = usb_rcvctrlpipe(dev, 0); snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT, NULL, 0); @@ -811,15 +811,15 @@ static int proc_control(struct dev_state tbuf, max(i, 0)); if ((i > 0) && ctrl.wLength) { if (copy_to_user(ctrl.data, tbuf, i)) { - free_page((unsigned long)tbuf); - return -EFAULT; + ret = -EFAULT; + goto done; } } } else { if (ctrl.wLength) { if (copy_from_user(tbuf, ctrl.data, ctrl.wLength)) { - free_page((unsigned long)tbuf); - return -EFAULT; + ret = -EFAULT; + goto done; } } pipe = usb_sndctrlpipe(dev, 0); @@ -833,14 +833,16 @@ static int proc_control(struct dev_state usb_lock_device(dev); snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE, NULL, 0); } - free_page((unsigned long)tbuf); if (i < 0 && i != -EPIPE) { dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL " "failed cmd %s rqt %u rq %u len %u ret %d\n", current->comm, ctrl.bRequestType, ctrl.bRequest, ctrl.wLength, i); } - return i; + ret = i; + done: + free_page((unsigned long) tbuf); + return ret; } static int proc_bulk(struct dev_state *ps, void __user *arg) @@ -874,8 +876,8 @@ static int proc_bulk(struct dev_state *p tmo = bulk.timeout; if (bulk.ep & 0x80) { if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) { - kfree(tbuf); - return -EINVAL; + ret = -EINVAL; + goto done; } snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, NULL, 0); @@ -886,15 +888,15 @@ static int proc_bulk(struct dev_state *p if (!i && len2) { if (copy_to_user(bulk.data, tbuf, len2)) { - kfree(tbuf); - return -EFAULT; + ret = -EFAULT; + goto done; } } } else { if (len1) { if (copy_from_user(tbuf, bulk.data, len1)) { - kfree(tbuf); - return -EFAULT; + ret = -EFAULT; + goto done; } } snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, tbuf, len1); @@ -904,10 +906,10 @@ static int proc_bulk(struct dev_state *p usb_lock_device(dev); snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, NULL, 0); } + ret = (i < 0 ? i : len2); + done: kfree(tbuf); - if (i < 0) - return i; - return len2; + return ret; } static int proc_resetep(struct dev_state *ps, void __user *arg) @@ -1052,7 +1054,7 @@ static int proc_do_submiturb(struct dev_ { struct usbdevfs_iso_packet_desc *isopkt = NULL; struct usb_host_endpoint *ep; - struct async *as; + struct async *as = NULL; struct usb_ctrlrequest *dr = NULL; const struct cred *cred = current_cred(); unsigned int u, totlen, isofrmlen; @@ -1099,19 +1101,17 @@ static int proc_do_submiturb(struct dev_ if (!dr) return -ENOMEM; if (copy_from_user(dr, uurb->buffer, 8)) { - kfree(dr); - return -EFAULT; + ret = -EFAULT; + goto error; } if (uurb->buffer_length < (le16_to_cpup(&dr->wLength) + 8)) { - kfree(dr); - return -EINVAL; + ret = -EINVAL; + goto error; } ret = check_ctrlrecip(ps, dr->bRequestType, le16_to_cpup(&dr->wIndex)); - if (ret) { - kfree(dr); - return ret; - } + if (ret) + goto error; uurb->number_of_packets = 0; uurb->buffer_length = le16_to_cpup(&dr->wLength); uurb->buffer += 8; @@ -1167,22 +1167,22 @@ static int proc_do_submiturb(struct dev_ if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL))) return -ENOMEM; if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) { - kfree(isopkt); - return -EFAULT; + ret = -EFAULT; + goto error; } for (totlen = u = 0; u < uurb->number_of_packets; u++) { /* arbitrary limit, * sufficient for USB 2.0 high-bandwidth iso */ if (isopkt[u].length > 8192) { - kfree(isopkt); - return -EINVAL; + ret = -EINVAL; + goto error; } totlen += isopkt[u].length; } /* 3072 * 64 microframes */ if (totlen > 196608) { - kfree(isopkt); - return -EINVAL; + ret = -EINVAL; + goto error; } uurb->buffer_length = totlen; break; @@ -1193,24 +1193,20 @@ static int proc_do_submiturb(struct dev_ if (uurb->buffer_length > 0 && !access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) { - kfree(isopkt); - kfree(dr); - return -EFAULT; + ret = -EFAULT; + goto error; } as = alloc_async(uurb->number_of_packets); if (!as) { - kfree(isopkt); - kfree(dr); - return -ENOMEM; + ret = -ENOMEM; + goto error; } if (uurb->buffer_length > 0) { as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL); if (!as->urb->transfer_buffer) { - kfree(isopkt); - kfree(dr); - free_async(as); - return -ENOMEM; + ret = -ENOMEM; + goto error; } /* Isochronous input data may end up being discontiguous * if some of the packets are short. Clear the buffer so @@ -1244,6 +1240,7 @@ static int proc_do_submiturb(struct dev_ as->urb->transfer_buffer_length = uurb->buffer_length; as->urb->setup_packet = (unsigned char *)dr; + dr = NULL; as->urb->start_frame = uurb->start_frame; as->urb->number_of_packets = uurb->number_of_packets; if (uurb->type == USBDEVFS_URB_TYPE_ISO || @@ -1259,6 +1256,7 @@ static int proc_do_submiturb(struct dev_ totlen += isopkt[u].length; } kfree(isopkt); + isopkt = NULL; as->ps = ps; as->userurb = arg; if (is_in && uurb->buffer_length > 0) @@ -1274,8 +1272,8 @@ static int proc_do_submiturb(struct dev_ if (!is_in && uurb->buffer_length > 0) { if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, uurb->buffer_length)) { - free_async(as); - return -EFAULT; + ret = -EFAULT; + goto error; } } snoop_urb(ps->dev, as->userurb, as->urb->pipe, @@ -1321,10 +1319,16 @@ static int proc_do_submiturb(struct dev_ snoop_urb(ps->dev, as->userurb, as->urb->pipe, 0, ret, COMPLETE, NULL, 0); async_removepending(as); - free_async(as); - return ret; + goto error; } return 0; + + error: + kfree(isopkt); + kfree(dr); + if (as) + free_async(as); + return ret; } static int proc_submiturb(struct dev_state *ps, void __user *arg)