usb: gadget: f_mtp: Avoid race between mtp_read and mtp_function_disable lineage-17.1
authorPratham Pratap <prathampratap@codeaurora.org>
Tue, 8 May 2018 10:47:52 +0000 (16:17 +0530)
committerStricted <info@stricted.net>
Tue, 28 Jan 2020 10:51:30 +0000 (10:51 +0000)
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: Pratham Pratap <prathampratap@codeaurora.org>
drivers/usb/gadget/function/f_mtp.c

index 1363f0e89dccf30a8a07561fa6cff5f264fd6612..d432913f707e29571edfa171f61b3bf02851d4f2 100644 (file)
@@ -575,7 +575,17 @@ static ssize_t mtp_read(struct file *fp, char __user *buf,
                goto done;
        }
        spin_lock_irq(&dev->lock);
                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 (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);
                len = usb_ep_align_maybe(cdev->gadget, dev->ep_out, count);
                if (len > MTP_BULK_BUFFER_SIZE) {
                        spin_unlock_irq(&dev->lock);
@@ -1288,7 +1298,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);
                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->state = STATE_OFFLINE;
+       dev->cdev = NULL;
+       spin_unlock_irq(&dev->lock);
        kfree(f->os_desc_table);
        f->os_desc_n = 0;
 }
        kfree(f->os_desc_table);
        f->os_desc_n = 0;
 }
@@ -1343,7 +1356,9 @@ static void mtp_function_disable(struct usb_function *f)
        struct usb_composite_dev        *cdev = dev->cdev;
 
        DBG(cdev, "mtp_function_disable\n");
        struct usb_composite_dev        *cdev = dev->cdev;
 
        DBG(cdev, "mtp_function_disable\n");
+       spin_lock_irq(&dev->lock);
        dev->state = STATE_OFFLINE;
        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);
        usb_ep_disable(dev->ep_in);
        usb_ep_disable(dev->ep_out);
        usb_ep_disable(dev->ep_intr);