Commit 01ff3a0a authored by Maximilain Schneider's avatar Maximilain Schneider Committed by Sasha Levin

can: gs_usb: fixed disconnect bug by removing erroneous use of kfree()

[ Upstream commit e9a2d81b ]

gs_destroy_candev() erroneously calls kfree() on a struct gs_can *, which is
allocated through alloc_candev() and should instead be freed using
free_candev() alone.

The inappropriate use of kfree() causes the kernel to hang when
gs_destroy_candev() is called.

Only the struct gs_usb * which is allocated through kzalloc() should be freed
using kfree() when the device is disconnected.
Signed-off-by: default avatarMaximilian Schneider <max@schneidersoft.net>
Cc: linux-stable <stable@vger.kernel.org>
Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: default avatarSasha Levin <sasha.levin@oracle.com>
parent 870be7d2
...@@ -826,9 +826,8 @@ static struct gs_can *gs_make_candev(unsigned int channel, struct usb_interface ...@@ -826,9 +826,8 @@ static struct gs_can *gs_make_candev(unsigned int channel, struct usb_interface
static void gs_destroy_candev(struct gs_can *dev) static void gs_destroy_candev(struct gs_can *dev)
{ {
unregister_candev(dev->netdev); unregister_candev(dev->netdev);
free_candev(dev->netdev);
usb_kill_anchored_urbs(&dev->tx_submitted); usb_kill_anchored_urbs(&dev->tx_submitted);
kfree(dev); free_candev(dev->netdev);
} }
static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
...@@ -913,12 +912,15 @@ static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id * ...@@ -913,12 +912,15 @@ static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *
for (i = 0; i < icount; i++) { for (i = 0; i < icount; i++) {
dev->canch[i] = gs_make_candev(i, intf); dev->canch[i] = gs_make_candev(i, intf);
if (IS_ERR_OR_NULL(dev->canch[i])) { if (IS_ERR_OR_NULL(dev->canch[i])) {
/* save error code to return later */
rc = PTR_ERR(dev->canch[i]);
/* on failure destroy previously created candevs */ /* on failure destroy previously created candevs */
icount = i; icount = i;
for (i = 0; i < icount; i++) { for (i = 0; i < icount; i++)
gs_destroy_candev(dev->canch[i]); gs_destroy_candev(dev->canch[i]);
dev->canch[i] = NULL;
} usb_kill_anchored_urbs(&dev->rx_submitted);
kfree(dev); kfree(dev);
return rc; return rc;
} }
...@@ -939,16 +941,12 @@ static void gs_usb_disconnect(struct usb_interface *intf) ...@@ -939,16 +941,12 @@ static void gs_usb_disconnect(struct usb_interface *intf)
return; return;
} }
for (i = 0; i < GS_MAX_INTF; i++) { for (i = 0; i < GS_MAX_INTF; i++)
struct gs_can *can = dev->canch[i]; if (dev->canch[i])
gs_destroy_candev(dev->canch[i]);
if (!can)
continue;
gs_destroy_candev(can);
}
usb_kill_anchored_urbs(&dev->rx_submitted); usb_kill_anchored_urbs(&dev->rx_submitted);
kfree(dev);
} }
static const struct usb_device_id gs_usb_table[] = { static const struct usb_device_id gs_usb_table[] = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment