USB fixes for 5.4-rc5

Here are a number of small USB driver fixes for 5.4-rc5.
 
 More "fun" with some of the misc USB drivers as found by syzbot, and
 there are a number of other small bugfixes in here for reported issues.
 
 All have been in linux-next for a while with no reported issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCXbSNXA8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ylrbgCfdgF24UtCBMI1P5E+gFOVhuPg+vIAniTEHMRZ
 iZqdtEh5mJNPoWzE8wRd
 =9utt
 -----END PGP SIGNATURE-----

Merge tag 'usb-5.4-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB fixes from Greg KH:
 "Here are a number of small USB driver fixes for 5.4-rc5.

  More "fun" with some of the misc USB drivers as found by syzbot, and
  there are a number of other small bugfixes in here for reported
  issues.

  All have been in linux-next for a while with no reported issues"

* tag 'usb-5.4-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb:
  usb: cdns3: Error out if USB_DR_MODE_UNKNOWN in cdns3_core_init_role()
  USB: ldusb: fix read info leaks
  USB: serial: ti_usb_3410_5052: clean up serial data access
  USB: serial: ti_usb_3410_5052: fix port-close races
  USB: usblp: fix use-after-free on disconnect
  usb: udc: lpc32xx: fix bad bit shift operation
  usb: cdns3: Fix dequeue implementation.
  USB: legousbtower: fix a signedness bug in tower_probe()
  USB: legousbtower: fix memleak on disconnect
  USB: ldusb: fix memleak on disconnect
This commit is contained in:
Linus Torvalds 2019-10-26 15:14:55 -04:00
commit 0ecdd78c75
7 changed files with 47 additions and 44 deletions

View File

@ -166,7 +166,6 @@ static int cdns3_core_init_role(struct cdns3 *cdns)
goto err;
switch (cdns->dr_mode) {
case USB_DR_MODE_UNKNOWN:
case USB_DR_MODE_OTG:
ret = cdns3_hw_role_switch(cdns);
if (ret)
@ -182,6 +181,9 @@ static int cdns3_core_init_role(struct cdns3 *cdns)
if (ret)
goto err;
break;
default:
ret = -EINVAL;
goto err;
}
return ret;

View File

@ -1145,6 +1145,14 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev,
request = cdns3_next_request(&priv_ep->pending_req_list);
priv_req = to_cdns3_request(request);
trb = priv_ep->trb_pool + priv_ep->dequeue;
/* Request was dequeued and TRB was changed to TRB_LINK. */
if (TRB_FIELD_TO_TYPE(trb->control) == TRB_LINK) {
trace_cdns3_complete_trb(priv_ep, trb);
cdns3_move_deq_to_next_trb(priv_req);
}
/* Re-select endpoint. It could be changed by other CPU during
* handling usb_gadget_giveback_request.
*/
@ -2067,6 +2075,7 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
struct usb_request *req, *req_temp;
struct cdns3_request *priv_req;
struct cdns3_trb *link_trb;
u8 req_on_hw_ring = 0;
unsigned long flags;
int ret = 0;
@ -2083,8 +2092,10 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
list_for_each_entry_safe(req, req_temp, &priv_ep->pending_req_list,
list) {
if (request == req)
if (request == req) {
req_on_hw_ring = 1;
goto found;
}
}
list_for_each_entry_safe(req, req_temp, &priv_ep->deferred_req_list,
@ -2096,27 +2107,21 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
goto not_found;
found:
if (priv_ep->wa1_trb == priv_req->trb)
cdns3_wa1_restore_cycle_bit(priv_ep);
link_trb = priv_req->trb;
cdns3_move_deq_to_next_trb(priv_req);
cdns3_gadget_giveback(priv_ep, priv_req, -ECONNRESET);
/* Update ring */
request = cdns3_next_request(&priv_ep->deferred_req_list);
if (request) {
priv_req = to_cdns3_request(request);
/* Update ring only if removed request is on pending_req_list list */
if (req_on_hw_ring) {
link_trb->buffer = TRB_BUFFER(priv_ep->trb_pool_dma +
(priv_req->start_trb * TRB_SIZE));
link_trb->control = (link_trb->control & TRB_CYCLE) |
TRB_TYPE(TRB_LINK) | TRB_CHAIN | TRB_TOGGLE;
} else {
priv_ep->flags |= EP_UPDATE_EP_TRBADDR;
TRB_TYPE(TRB_LINK) | TRB_CHAIN;
if (priv_ep->wa1_trb == priv_req->trb)
cdns3_wa1_restore_cycle_bit(priv_ep);
}
cdns3_gadget_giveback(priv_ep, priv_req, -ECONNRESET);
not_found:
spin_unlock_irqrestore(&priv_dev->lock, flags);
return ret;

View File

@ -445,6 +445,7 @@ static void usblp_cleanup(struct usblp *usblp)
kfree(usblp->readbuf);
kfree(usblp->device_id_string);
kfree(usblp->statusbuf);
usb_put_intf(usblp->intf);
kfree(usblp);
}
@ -1113,7 +1114,7 @@ static int usblp_probe(struct usb_interface *intf,
init_waitqueue_head(&usblp->wwait);
init_usb_anchor(&usblp->urbs);
usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
usblp->intf = intf;
usblp->intf = usb_get_intf(intf);
/* Malloc device ID string buffer to the largest expected length,
* since we can re-query it on an ioctl and a dynamic string
@ -1198,6 +1199,7 @@ abort:
kfree(usblp->readbuf);
kfree(usblp->statusbuf);
kfree(usblp->device_id_string);
usb_put_intf(usblp->intf);
kfree(usblp);
abort_ret:
return retval;

View File

@ -1177,11 +1177,11 @@ static void udc_pop_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes)
tmp = readl(USBD_RXDATA(udc->udp_baseaddr));
bl = bytes - n;
if (bl > 3)
bl = 3;
if (bl > 4)
bl = 4;
for (i = 0; i < bl; i++)
data[n + i] = (u8) ((tmp >> (n * 8)) & 0xFF);
data[n + i] = (u8) ((tmp >> (i * 8)) & 0xFF);
}
break;

View File

@ -380,10 +380,7 @@ static int ld_usb_release(struct inode *inode, struct file *file)
goto exit;
}
if (mutex_lock_interruptible(&dev->mutex)) {
retval = -ERESTARTSYS;
goto exit;
}
mutex_lock(&dev->mutex);
if (dev->open_count != 1) {
retval = -ENODEV;
@ -467,7 +464,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
/* wait for data */
spin_lock_irq(&dev->rbsl);
if (dev->ring_head == dev->ring_tail) {
while (dev->ring_head == dev->ring_tail) {
dev->interrupt_in_done = 0;
spin_unlock_irq(&dev->rbsl);
if (file->f_flags & O_NONBLOCK) {
@ -477,12 +474,17 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
retval = wait_event_interruptible(dev->read_wait, dev->interrupt_in_done);
if (retval < 0)
goto unlock_exit;
} else {
spin_unlock_irq(&dev->rbsl);
spin_lock_irq(&dev->rbsl);
}
spin_unlock_irq(&dev->rbsl);
/* actual_buffer contains actual_length + interrupt_in_buffer */
actual_buffer = (size_t *)(dev->ring_buffer + dev->ring_tail * (sizeof(size_t)+dev->interrupt_in_endpoint_size));
if (*actual_buffer > dev->interrupt_in_endpoint_size) {
retval = -EIO;
goto unlock_exit;
}
bytes_to_read = min(count, *actual_buffer);
if (bytes_to_read < *actual_buffer)
dev_warn(&dev->intf->dev, "Read buffer overflow, %zd bytes dropped\n",
@ -693,10 +695,9 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *
dev_warn(&intf->dev, "Interrupt out endpoint not found (using control endpoint instead)\n");
dev->interrupt_in_endpoint_size = usb_endpoint_maxp(dev->interrupt_in_endpoint);
dev->ring_buffer =
kmalloc_array(ring_buffer_size,
sizeof(size_t) + dev->interrupt_in_endpoint_size,
GFP_KERNEL);
dev->ring_buffer = kcalloc(ring_buffer_size,
sizeof(size_t) + dev->interrupt_in_endpoint_size,
GFP_KERNEL);
if (!dev->ring_buffer)
goto error;
dev->interrupt_in_buffer = kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL);

View File

@ -419,10 +419,7 @@ static int tower_release (struct inode *inode, struct file *file)
goto exit;
}
if (mutex_lock_interruptible(&dev->lock)) {
retval = -ERESTARTSYS;
goto exit;
}
mutex_lock(&dev->lock);
if (dev->open_count != 1) {
dev_dbg(&dev->udev->dev, "%s: device not opened exactly once\n",
@ -881,7 +878,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
get_version_reply,
sizeof(*get_version_reply),
1000);
if (result < sizeof(*get_version_reply)) {
if (result != sizeof(*get_version_reply)) {
if (result >= 0)
result = -EIO;
dev_err(idev, "get version request failed: %d\n", result);

View File

@ -776,7 +776,6 @@ static void ti_close(struct usb_serial_port *port)
struct ti_port *tport;
int port_number;
int status;
int do_unlock;
unsigned long flags;
tdev = usb_get_serial_data(port->serial);
@ -800,16 +799,13 @@ static void ti_close(struct usb_serial_port *port)
"%s - cannot send close port command, %d\n"
, __func__, status);
/* if mutex_lock is interrupted, continue anyway */
do_unlock = !mutex_lock_interruptible(&tdev->td_open_close_lock);
--tport->tp_tdev->td_open_port_count;
if (tport->tp_tdev->td_open_port_count <= 0) {
mutex_lock(&tdev->td_open_close_lock);
--tdev->td_open_port_count;
if (tdev->td_open_port_count == 0) {
/* last port is closed, shut down interrupt urb */
usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
tport->tp_tdev->td_open_port_count = 0;
}
if (do_unlock)
mutex_unlock(&tdev->td_open_close_lock);
mutex_unlock(&tdev->td_open_close_lock);
}