USB: core: Change usb_get_device_descriptor() API
commit de28e469da75359a2bb8cd8778b78aa64b1be1f4 upstream. The usb_get_device_descriptor() routine reads the device descriptor from the udev device and stores it directly in udev->descriptor. This interface is error prone, because the USB subsystem expects in-memory copies of a device's descriptors to be immutable once the device has been initialized. The interface is changed so that the device descriptor is left in a kmalloc-ed buffer, not copied into the usb_device structure. A pointer to the buffer is returned to the caller, who is then responsible for kfree-ing it. The corresponding changes needed in the various callers are fairly small. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/d0111bb6-56c1-4f90-adf2-6cfe152f6561@rowland.harvard.edu Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
3cef18d13f
commit
6ceffc2ecf
@@ -982,6 +982,7 @@ static int register_root_hub(struct usb_hcd *hcd)
|
|||||||
{
|
{
|
||||||
struct device *parent_dev = hcd->self.controller;
|
struct device *parent_dev = hcd->self.controller;
|
||||||
struct usb_device *usb_dev = hcd->self.root_hub;
|
struct usb_device *usb_dev = hcd->self.root_hub;
|
||||||
|
struct usb_device_descriptor *descr;
|
||||||
const int devnum = 1;
|
const int devnum = 1;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
@@ -993,13 +994,16 @@ static int register_root_hub(struct usb_hcd *hcd)
|
|||||||
mutex_lock(&usb_bus_idr_lock);
|
mutex_lock(&usb_bus_idr_lock);
|
||||||
|
|
||||||
usb_dev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
|
usb_dev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
|
||||||
retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
|
descr = usb_get_device_descriptor(usb_dev);
|
||||||
if (retval != sizeof usb_dev->descriptor) {
|
if (IS_ERR(descr)) {
|
||||||
|
retval = PTR_ERR(descr);
|
||||||
mutex_unlock(&usb_bus_idr_lock);
|
mutex_unlock(&usb_bus_idr_lock);
|
||||||
dev_dbg (parent_dev, "can't read %s device descriptor %d\n",
|
dev_dbg (parent_dev, "can't read %s device descriptor %d\n",
|
||||||
dev_name(&usb_dev->dev), retval);
|
dev_name(&usb_dev->dev), retval);
|
||||||
return (retval < 0) ? retval : -EMSGSIZE;
|
return retval;
|
||||||
}
|
}
|
||||||
|
usb_dev->descriptor = *descr;
|
||||||
|
kfree(descr);
|
||||||
|
|
||||||
if (le16_to_cpu(usb_dev->descriptor.bcdUSB) >= 0x0201) {
|
if (le16_to_cpu(usb_dev->descriptor.bcdUSB) >= 0x0201) {
|
||||||
retval = usb_get_bos_descriptor(usb_dev);
|
retval = usb_get_bos_descriptor(usb_dev);
|
||||||
|
@@ -2646,12 +2646,17 @@ int usb_authorize_device(struct usb_device *usb_dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (usb_dev->wusb) {
|
if (usb_dev->wusb) {
|
||||||
result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor));
|
struct usb_device_descriptor *descr;
|
||||||
if (result < 0) {
|
|
||||||
|
descr = usb_get_device_descriptor(usb_dev);
|
||||||
|
if (IS_ERR(descr)) {
|
||||||
|
result = PTR_ERR(descr);
|
||||||
dev_err(&usb_dev->dev, "can't re-read device descriptor for "
|
dev_err(&usb_dev->dev, "can't re-read device descriptor for "
|
||||||
"authorization: %d\n", result);
|
"authorization: %d\n", result);
|
||||||
goto error_device_descriptor;
|
goto error_device_descriptor;
|
||||||
}
|
}
|
||||||
|
usb_dev->descriptor = *descr;
|
||||||
|
kfree(descr);
|
||||||
}
|
}
|
||||||
|
|
||||||
usb_dev->authorized = 1;
|
usb_dev->authorized = 1;
|
||||||
@@ -4680,7 +4685,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
|
|||||||
const char *driver_name;
|
const char *driver_name;
|
||||||
bool do_new_scheme;
|
bool do_new_scheme;
|
||||||
int maxp0;
|
int maxp0;
|
||||||
struct usb_device_descriptor *buf;
|
struct usb_device_descriptor *buf, *descr;
|
||||||
|
|
||||||
buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
|
buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
@@ -4913,15 +4918,16 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
|
|||||||
usb_ep0_reinit(udev);
|
usb_ep0_reinit(udev);
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);
|
descr = usb_get_device_descriptor(udev);
|
||||||
if (retval < (signed)sizeof(udev->descriptor)) {
|
if (IS_ERR(descr)) {
|
||||||
|
retval = PTR_ERR(descr);
|
||||||
if (retval != -ENODEV)
|
if (retval != -ENODEV)
|
||||||
dev_err(&udev->dev, "device descriptor read/all, error %d\n",
|
dev_err(&udev->dev, "device descriptor read/all, error %d\n",
|
||||||
retval);
|
retval);
|
||||||
if (retval >= 0)
|
|
||||||
retval = -ENOMSG;
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
udev->descriptor = *descr;
|
||||||
|
kfree(descr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some superspeed devices have finished the link training process
|
* Some superspeed devices have finished the link training process
|
||||||
@@ -5038,7 +5044,7 @@ hub_power_remaining(struct usb_hub *hub)
|
|||||||
|
|
||||||
|
|
||||||
static int descriptors_changed(struct usb_device *udev,
|
static int descriptors_changed(struct usb_device *udev,
|
||||||
struct usb_device_descriptor *old_device_descriptor,
|
struct usb_device_descriptor *new_device_descriptor,
|
||||||
struct usb_host_bos *old_bos)
|
struct usb_host_bos *old_bos)
|
||||||
{
|
{
|
||||||
int changed = 0;
|
int changed = 0;
|
||||||
@@ -5049,8 +5055,8 @@ static int descriptors_changed(struct usb_device *udev,
|
|||||||
int length;
|
int length;
|
||||||
char *buf;
|
char *buf;
|
||||||
|
|
||||||
if (memcmp(&udev->descriptor, old_device_descriptor,
|
if (memcmp(&udev->descriptor, new_device_descriptor,
|
||||||
sizeof(*old_device_descriptor)) != 0)
|
sizeof(*new_device_descriptor)) != 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if ((old_bos && !udev->bos) || (!old_bos && udev->bos))
|
if ((old_bos && !udev->bos) || (!old_bos && udev->bos))
|
||||||
@@ -5370,9 +5376,8 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
|||||||
{
|
{
|
||||||
struct usb_port *port_dev = hub->ports[port1 - 1];
|
struct usb_port *port_dev = hub->ports[port1 - 1];
|
||||||
struct usb_device *udev = port_dev->child;
|
struct usb_device *udev = port_dev->child;
|
||||||
struct usb_device_descriptor descriptor;
|
struct usb_device_descriptor *descr;
|
||||||
int status = -ENODEV;
|
int status = -ENODEV;
|
||||||
int retval;
|
|
||||||
|
|
||||||
dev_dbg(&port_dev->dev, "status %04x, change %04x, %s\n", portstatus,
|
dev_dbg(&port_dev->dev, "status %04x, change %04x, %s\n", portstatus,
|
||||||
portchange, portspeed(hub, portstatus));
|
portchange, portspeed(hub, portstatus));
|
||||||
@@ -5399,23 +5404,20 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
|||||||
* changed device descriptors before resuscitating the
|
* changed device descriptors before resuscitating the
|
||||||
* device.
|
* device.
|
||||||
*/
|
*/
|
||||||
descriptor = udev->descriptor;
|
descr = usb_get_device_descriptor(udev);
|
||||||
retval = usb_get_device_descriptor(udev,
|
if (IS_ERR(descr)) {
|
||||||
sizeof(udev->descriptor));
|
|
||||||
if (retval < 0) {
|
|
||||||
dev_dbg(&udev->dev,
|
dev_dbg(&udev->dev,
|
||||||
"can't read device descriptor %d\n",
|
"can't read device descriptor %ld\n",
|
||||||
retval);
|
PTR_ERR(descr));
|
||||||
} else {
|
} else {
|
||||||
if (descriptors_changed(udev, &descriptor,
|
if (descriptors_changed(udev, descr,
|
||||||
udev->bos)) {
|
udev->bos)) {
|
||||||
dev_dbg(&udev->dev,
|
dev_dbg(&udev->dev,
|
||||||
"device descriptor has changed\n");
|
"device descriptor has changed\n");
|
||||||
/* for disconnect() calls */
|
|
||||||
udev->descriptor = descriptor;
|
|
||||||
} else {
|
} else {
|
||||||
status = 0; /* Nothing to do */
|
status = 0; /* Nothing to do */
|
||||||
}
|
}
|
||||||
|
kfree(descr);
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
} else if (udev->state == USB_STATE_SUSPENDED &&
|
} else if (udev->state == USB_STATE_SUSPENDED &&
|
||||||
|
@@ -1039,39 +1039,34 @@ char *usb_cache_string(struct usb_device *udev, int index)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* usb_get_device_descriptor - (re)reads the device descriptor (usbcore)
|
* usb_get_device_descriptor - read the device descriptor
|
||||||
* @dev: the device whose device descriptor is being updated
|
* @udev: the device whose device descriptor should be read
|
||||||
* @size: how much of the descriptor to read
|
|
||||||
* Context: !in_interrupt ()
|
* Context: !in_interrupt ()
|
||||||
*
|
*
|
||||||
* Updates the copy of the device descriptor stored in the device structure,
|
|
||||||
* which dedicates space for this purpose.
|
|
||||||
*
|
|
||||||
* Not exported, only for use by the core. If drivers really want to read
|
* Not exported, only for use by the core. If drivers really want to read
|
||||||
* the device descriptor directly, they can call usb_get_descriptor() with
|
* the device descriptor directly, they can call usb_get_descriptor() with
|
||||||
* type = USB_DT_DEVICE and index = 0.
|
* type = USB_DT_DEVICE and index = 0.
|
||||||
*
|
*
|
||||||
* This call is synchronous, and may not be used in an interrupt context.
|
* Returns: a pointer to a dynamically allocated usb_device_descriptor
|
||||||
*
|
* structure (which the caller must deallocate), or an ERR_PTR value.
|
||||||
* Return: The number of bytes received on success, or else the status code
|
|
||||||
* returned by the underlying usb_control_msg() call.
|
|
||||||
*/
|
*/
|
||||||
int usb_get_device_descriptor(struct usb_device *dev, unsigned int size)
|
struct usb_device_descriptor *usb_get_device_descriptor(struct usb_device *udev)
|
||||||
{
|
{
|
||||||
struct usb_device_descriptor *desc;
|
struct usb_device_descriptor *desc;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (size > sizeof(*desc))
|
|
||||||
return -EINVAL;
|
|
||||||
desc = kmalloc(sizeof(*desc), GFP_NOIO);
|
desc = kmalloc(sizeof(*desc), GFP_NOIO);
|
||||||
if (!desc)
|
if (!desc)
|
||||||
return -ENOMEM;
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
ret = usb_get_descriptor(udev, USB_DT_DEVICE, 0, desc, sizeof(*desc));
|
||||||
|
if (ret == sizeof(*desc))
|
||||||
|
return desc;
|
||||||
|
|
||||||
ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, size);
|
|
||||||
if (ret >= 0)
|
if (ret >= 0)
|
||||||
memcpy(&dev->descriptor, desc, size);
|
ret = -EMSGSIZE;
|
||||||
kfree(desc);
|
kfree(desc);
|
||||||
return ret;
|
return ERR_PTR(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -42,8 +42,8 @@ extern bool usb_endpoint_is_ignored(struct usb_device *udev,
|
|||||||
struct usb_endpoint_descriptor *epd);
|
struct usb_endpoint_descriptor *epd);
|
||||||
extern int usb_remove_device(struct usb_device *udev);
|
extern int usb_remove_device(struct usb_device *udev);
|
||||||
|
|
||||||
extern int usb_get_device_descriptor(struct usb_device *dev,
|
extern struct usb_device_descriptor *usb_get_device_descriptor(
|
||||||
unsigned int size);
|
struct usb_device *udev);
|
||||||
extern int usb_set_isoch_delay(struct usb_device *dev);
|
extern int usb_set_isoch_delay(struct usb_device *dev);
|
||||||
extern int usb_get_bos_descriptor(struct usb_device *dev);
|
extern int usb_get_bos_descriptor(struct usb_device *dev);
|
||||||
extern void usb_release_bos_descriptor(struct usb_device *dev);
|
extern void usb_release_bos_descriptor(struct usb_device *dev);
|
||||||
|
Reference in New Issue
Block a user