diff options
author | Mark Brown <broonie@kernel.org> | 2018-01-08 15:54:50 +0000 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2018-01-08 15:54:50 +0000 |
commit | 498495dba268b20e8eadd7fe93c140c68b6cc9d2 (patch) | |
tree | 00d1562049d8bc2194fddd9ba0cbbe0812ad6f68 /drivers/usb/core/message.c | |
parent | d5cc0a1fcbb5ddbef9fdd4c4a978da3254ddbf37 (diff) | |
parent | 5c256045b87b8aa8e5bc9d2e2fdc0802351c1f99 (diff) | |
download | linux-stable-498495dba268b20e8eadd7fe93c140c68b6cc9d2.tar.gz linux-stable-498495dba268b20e8eadd7fe93c140c68b6cc9d2.tar.bz2 linux-stable-498495dba268b20e8eadd7fe93c140c68b6cc9d2.zip |
Merge branch 'fix/intel' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into asoc-intel
Diffstat (limited to 'drivers/usb/core/message.c')
-rw-r--r-- | drivers/usb/core/message.c | 57 |
1 files changed, 48 insertions, 9 deletions
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 4c38ea41ae96..77001bcfc504 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1,8 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * message.c - synchronous message handling * * Released under the GPLv2 only. - * SPDX-License-Identifier: GPL-2.0 */ #include <linux/pci.h> /* for scatterlist macros */ @@ -918,7 +918,8 @@ int usb_get_device_descriptor(struct usb_device *dev, unsigned int size) /** * usb_get_status - issues a GET_STATUS call * @dev: the device whose status is being checked - * @type: USB_RECIP_*; for device, interface, or endpoint + * @recip: USB_RECIP_*; for device, interface, or endpoint + * @type: USB_STATUS_TYPE_*; for standard or PTM status types * @target: zero (for device), else interface or endpoint number * @data: pointer to two bytes of bitmap data * Context: !in_interrupt () @@ -937,24 +938,58 @@ int usb_get_device_descriptor(struct usb_device *dev, unsigned int size) * Returns 0 and the status value in *@data (in host byte order) on success, * or else the status code from the underlying usb_control_msg() call. */ -int usb_get_status(struct usb_device *dev, int type, int target, void *data) +int usb_get_status(struct usb_device *dev, int recip, int type, int target, + void *data) { int ret; - __le16 *status = kmalloc(sizeof(*status), GFP_KERNEL); + void *status; + int length; + + switch (type) { + case USB_STATUS_TYPE_STANDARD: + length = 2; + break; + case USB_STATUS_TYPE_PTM: + if (recip != USB_RECIP_DEVICE) + return -EINVAL; + + length = 4; + break; + default: + return -EINVAL; + } + status = kmalloc(length, GFP_KERNEL); if (!status) return -ENOMEM; ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, status, - sizeof(*status), USB_CTRL_GET_TIMEOUT); + USB_REQ_GET_STATUS, USB_DIR_IN | recip, USB_STATUS_TYPE_STANDARD, + target, status, length, USB_CTRL_GET_TIMEOUT); + + switch (ret) { + case 4: + if (type != USB_STATUS_TYPE_PTM) { + ret = -EIO; + break; + } - if (ret == 2) { - *(u16 *) data = le16_to_cpu(*status); + *(u32 *) data = le32_to_cpu(*(__le32 *) status); ret = 0; - } else if (ret >= 0) { + break; + case 2: + if (type != USB_STATUS_TYPE_STANDARD) { + ret = -EIO; + break; + } + + *(u16 *) data = le16_to_cpu(*(__le16 *) status); + ret = 0; + break; + default: ret = -EIO; } + kfree(status); return ret; } @@ -2069,6 +2104,10 @@ int cdc_parse_cdc_header(struct usb_cdc_parsed_header *hdr, elength = 1; goto next_desc; } + if ((buflen < elength) || (elength < 3)) { + dev_err(&intf->dev, "invalid descriptor buffer length\n"); + break; + } if (buffer[1] != USB_DT_CS_INTERFACE) { dev_err(&intf->dev, "skipping garbage\n"); goto next_desc; |