Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 427a8c5d authored by Ajay Agarwal's avatar Ajay Agarwal Committed by Gerrit - the friendly Code Review server
Browse files

usb: misc: diag_bridge: Move dev->ifc cleanup to delete function



Since the close function can be called after disconnect, it can
lead to null pointer dereference from dev->ifc since it is being
assigned null in disconnect. Also, there can be a use-after-free
if the interface structure is used after disconnect function has
been called and core has freed the intf.
Fix this by moving the dev->ifc cleanup from disconnect to the
delete function. This will ensure that dev->ifc exists when the
diag core can still queue read/write and call close. Also do a
get and put of interface from probe and delete respectively to
prevent the use-after-free issue. While at it, also mark ENODEV
error to dev->err to prevent further read/write after disconnect.

Change-Id: I1a1fa4440560b0c0b77880fb3f5a37c3c24c7e67
Signed-off-by: default avatarAjay Agarwal <ajaya@codeaurora.org>
parent 727e7069
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -102,9 +102,12 @@ EXPORT_SYMBOL(diag_bridge_open);
static void diag_bridge_delete(struct kref *kref)
{
	struct diag_bridge *dev = container_of(kref, struct diag_bridge, kref);
	struct usb_interface *ifc = dev->ifc;
	int id = dev->id;

	dev_dbg(&dev->ifc->dev, "%s\n", __func__);
	usb_set_intfdata(ifc, NULL);
	usb_put_intf(ifc);
	usb_put_dev(dev->udev);
	__dev[id] = 0;
	kfree(dev);
@@ -500,7 +503,7 @@ diag_bridge_probe(struct usb_interface *ifc, const struct usb_device_id *id)
	dev->id = devid;

	dev->udev = usb_get_dev(interface_to_usbdev(ifc));
	dev->ifc = ifc;
	dev->ifc = usb_get_intf(ifc);
	kref_init(&dev->kref);
	mutex_init(&dev->ifc_mutex);
	init_usb_anchor(&dev->submitted);
@@ -556,12 +559,9 @@ static void diag_bridge_disconnect(struct usb_interface *ifc)
	dev_dbg(&dev->ifc->dev, "%s\n", __func__);

	platform_device_unregister(dev->pdev);
	mutex_lock(&dev->ifc_mutex);
	dev->ifc = NULL;
	mutex_unlock(&dev->ifc_mutex);
	diag_bridge_debugfs_cleanup();
	dev->err = -ENODEV;
	kref_put(&dev->kref, diag_bridge_delete);
	usb_set_intfdata(ifc, NULL);
}

static int diag_bridge_suspend(struct usb_interface *ifc, pm_message_t message)