aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorXenia Ragiadakou <burzalodowa@gmail.com>2013-08-29 14:45:48 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-08-30 15:02:08 -0400
commite3376d6c87eea09bd65ece6073f6e5d47aa560a3 (patch)
tree0d44a8f7a1f48d61534fec9cdaa0d4b3bbe29cd0 /drivers/usb
parenteb5ea7300d48c52b028966a6e59f9244faa930d0 (diff)
usbcore: compare and release one bos descriptor in usb_reset_and_verify_device()
In usb_reset_and_verify_device(), hub_port_init() allocates a new bos descriptor to hold the value read by the device. The new bos descriptor has to be compared with the old one in order to figure out if device 's firmware has changed in which case the device has to be reenumerated. In the original code, none of the two descriptors was deallocated leading to memory leaks. This patch compares the old bos descriptor with the new one to detect change in firmware and releases the newly allocated bos descriptor to prevent memory leak. Signed-off-by: Xenia Ragiadakou <burzalodowa@gmail.com> Reported-by: Martin MOKREJS <mmokrejs@gmail.com> Tested-by: Martin MOKREJS <mmokrejs@gmail.com> Suggested-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/core/hub.c23
1 files changed, 21 insertions, 2 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 5d859fc07610..3b7ca181cd72 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -4944,7 +4944,8 @@ void usb_hub_cleanup(void)
4944} /* usb_hub_cleanup() */ 4944} /* usb_hub_cleanup() */
4945 4945
4946static int descriptors_changed(struct usb_device *udev, 4946static int descriptors_changed(struct usb_device *udev,
4947 struct usb_device_descriptor *old_device_descriptor) 4947 struct usb_device_descriptor *old_device_descriptor,
4948 struct usb_host_bos *old_bos)
4948{ 4949{
4949 int changed = 0; 4950 int changed = 0;
4950 unsigned index; 4951 unsigned index;
@@ -4958,6 +4959,16 @@ static int descriptors_changed(struct usb_device *udev,
4958 sizeof(*old_device_descriptor)) != 0) 4959 sizeof(*old_device_descriptor)) != 0)
4959 return 1; 4960 return 1;
4960 4961
4962 if ((old_bos && !udev->bos) || (!old_bos && udev->bos))
4963 return 1;
4964 if (udev->bos) {
4965 len = udev->bos->desc->wTotalLength;
4966 if (len != old_bos->desc->wTotalLength)
4967 return 1;
4968 if (memcmp(udev->bos->desc, old_bos->desc, le16_to_cpu(len)))
4969 return 1;
4970 }
4971
4961 /* Since the idVendor, idProduct, and bcdDevice values in the 4972 /* Since the idVendor, idProduct, and bcdDevice values in the
4962 * device descriptor haven't changed, we will assume the 4973 * device descriptor haven't changed, we will assume the
4963 * Manufacturer and Product strings haven't changed either. 4974 * Manufacturer and Product strings haven't changed either.
@@ -5054,6 +5065,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
5054 struct usb_hub *parent_hub; 5065 struct usb_hub *parent_hub;
5055 struct usb_hcd *hcd = bus_to_hcd(udev->bus); 5066 struct usb_hcd *hcd = bus_to_hcd(udev->bus);
5056 struct usb_device_descriptor descriptor = udev->descriptor; 5067 struct usb_device_descriptor descriptor = udev->descriptor;
5068 struct usb_host_bos *bos;
5057 int i, ret = 0; 5069 int i, ret = 0;
5058 int port1 = udev->portnum; 5070 int port1 = udev->portnum;
5059 5071
@@ -5071,6 +5083,9 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
5071 } 5083 }
5072 parent_hub = usb_hub_to_struct_hub(parent_hdev); 5084 parent_hub = usb_hub_to_struct_hub(parent_hdev);
5073 5085
5086 bos = udev->bos;
5087 udev->bos = NULL;
5088
5074 /* Disable LPM and LTM while we reset the device and reinstall the alt 5089 /* Disable LPM and LTM while we reset the device and reinstall the alt
5075 * settings. Device-initiated LPM settings, and system exit latency 5090 * settings. Device-initiated LPM settings, and system exit latency
5076 * settings are cleared when the device is reset, so we have to set 5091 * settings are cleared when the device is reset, so we have to set
@@ -5104,7 +5119,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
5104 goto re_enumerate; 5119 goto re_enumerate;
5105 5120
5106 /* Device might have changed firmware (DFU or similar) */ 5121 /* Device might have changed firmware (DFU or similar) */
5107 if (descriptors_changed(udev, &descriptor)) { 5122 if (descriptors_changed(udev, &descriptor, bos)) {
5108 dev_info(&udev->dev, "device firmware changed\n"); 5123 dev_info(&udev->dev, "device firmware changed\n");
5109 udev->descriptor = descriptor; /* for disconnect() calls */ 5124 udev->descriptor = descriptor; /* for disconnect() calls */
5110 goto re_enumerate; 5125 goto re_enumerate;
@@ -5177,11 +5192,15 @@ done:
5177 /* Now that the alt settings are re-installed, enable LTM and LPM. */ 5192 /* Now that the alt settings are re-installed, enable LTM and LPM. */
5178 usb_unlocked_enable_lpm(udev); 5193 usb_unlocked_enable_lpm(udev);
5179 usb_enable_ltm(udev); 5194 usb_enable_ltm(udev);
5195 usb_release_bos_descriptor(udev);
5196 udev->bos = bos;
5180 return 0; 5197 return 0;
5181 5198
5182re_enumerate: 5199re_enumerate:
5183 /* LPM state doesn't matter when we're about to destroy the device. */ 5200 /* LPM state doesn't matter when we're about to destroy the device. */
5184 hub_port_logical_disconnect(parent_hub, port1); 5201 hub_port_logical_disconnect(parent_hub, port1);
5202 usb_release_bos_descriptor(udev);
5203 udev->bos = bos;
5185 return -ENODEV; 5204 return -ENODEV;
5186} 5205}
5187 5206