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

Commit bb4380d3 authored by Pratham Pratap's avatar Pratham Pratap Committed by Mayank Rana
Browse files

usb: gadget: f_mtp: Avoid race between mtp_read and mtp_function_disable



While mtp_read is being executed and mtp_function_disable
is called then all the eps will be disabled which will
lead to NULL pointer dereference in usb_ep_align_maybe
function which will subsequently try to access endpoint
descriptors.
Add spinlock protection in mtp_function_disable to
avoid race between mtp_read and mtp_function_disable.

Change-Id: If7f00ff2a98f75d2782e6bb35ad5fe59e4db6734
Signed-off-by: default avatarPratham Pratap <prathampratap@codeaurora.org>
Signed-off-by: default avatarMayank Rana <mrana@codeaurora.org>
parent 9e5a39a7
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -556,7 +556,17 @@ static ssize_t mtp_read(struct file *fp, char __user *buf,
		goto done;
	}
	spin_lock_irq(&dev->lock);
	if (dev->state == STATE_OFFLINE) {
		spin_unlock_irq(&dev->lock);
		return -ENODEV;
	}

	if (dev->ep_out->desc) {
		if (!cdev) {
			spin_unlock_irq(&dev->lock);
			return -ENODEV;
		}

		len = usb_ep_align_maybe(cdev->gadget, dev->ep_out, count);
		if (len > MTP_BULK_BUFFER_SIZE) {
			spin_unlock_irq(&dev->lock);
@@ -1267,7 +1277,10 @@ mtp_function_unbind(struct usb_configuration *c, struct usb_function *f)
		mtp_request_free(dev->rx_req[i], dev->ep_out);
	while ((req = mtp_req_get(dev, &dev->intr_idle)))
		mtp_request_free(req, dev->ep_intr);
	spin_lock_irq(&dev->lock);
	dev->state = STATE_OFFLINE;
	dev->cdev = NULL;
	spin_unlock_irq(&dev->lock);
	kfree(f->os_desc_table);
	f->os_desc_n = 0;
	fi_mtp->func_inst.f = NULL;
@@ -1323,7 +1336,9 @@ static void mtp_function_disable(struct usb_function *f)
	struct usb_composite_dev	*cdev = dev->cdev;

	DBG(cdev, "mtp_function_disable\n");
	spin_lock_irq(&dev->lock);
	dev->state = STATE_OFFLINE;
	spin_unlock_irq(&dev->lock);
	usb_ep_disable(dev->ep_in);
	usb_ep_disable(dev->ep_out);
	usb_ep_disable(dev->ep_intr);