From abd876b3b5fc80dc302183cd372067bab40efab5 Mon Sep 17 00:00:00 2001 From: Pratham Pratap Date: Tue, 8 May 2018 16:17:52 +0530 Subject: [PATCH] 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: Pratham Pratap --- drivers/usb/gadget/function/f_mtp.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c index 1363f0e89dcc..d432913f707e 100644 --- a/drivers/usb/gadget/function/f_mtp.c +++ b/drivers/usb/gadget/function/f_mtp.c @@ -575,7 +575,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); @@ -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); + 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; } @@ -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"); + 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); -- 2.20.1