Commit 9c1ed62a authored by Jia-Ju Bai's avatar Jia-Ju Bai Committed by Greg Kroah-Hartman

usb: gadget: udc: fix possible sleep-in-atomic-context bugs in gr_probe()

The driver may sleep while holding a spinlock.
The function call path (from bottom to top) in Linux 4.19 is:

drivers/usb/gadget/udc/core.c, 1175:
	kzalloc(GFP_KERNEL) in usb_add_gadget_udc_release
drivers/usb/gadget/udc/core.c, 1272:
	usb_add_gadget_udc_release in usb_add_gadget_udc
drivers/usb/gadget/udc/gr_udc.c, 2186:
	usb_add_gadget_udc in gr_probe
drivers/usb/gadget/udc/gr_udc.c, 2183:
	spin_lock in gr_probe

drivers/usb/gadget/udc/core.c, 1195:
	mutex_lock in usb_add_gadget_udc_release
drivers/usb/gadget/udc/core.c, 1272:
	usb_add_gadget_udc_release in usb_add_gadget_udc
drivers/usb/gadget/udc/gr_udc.c, 2186:
	usb_add_gadget_udc in gr_probe
drivers/usb/gadget/udc/gr_udc.c, 2183:
	spin_lock in gr_probe

drivers/usb/gadget/udc/gr_udc.c, 212:
	debugfs_create_file in gr_probe
drivers/usb/gadget/udc/gr_udc.c, 2197:
	gr_dfs_create in gr_probe
drivers/usb/gadget/udc/gr_udc.c, 2183:
    spin_lock in gr_probe

drivers/usb/gadget/udc/gr_udc.c, 2114:
	devm_request_threaded_irq in gr_request_irq
drivers/usb/gadget/udc/gr_udc.c, 2202:
	gr_request_irq in gr_probe
drivers/usb/gadget/udc/gr_udc.c, 2183:
    spin_lock in gr_probe

kzalloc(GFP_KERNEL), mutex_lock(), debugfs_create_file() and
devm_request_threaded_irq() can sleep at runtime.

To fix these possible bugs, usb_add_gadget_udc(), gr_dfs_create() and
gr_request_irq() are called without handling the spinlock.

These bugs are found by a static analysis tool STCheck written by myself.
Signed-off-by: default avatarJia-Ju Bai <baijiaju1990@gmail.com>
Signed-off-by: default avatarFelipe Balbi <balbi@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d2450c69
...@@ -2175,8 +2175,6 @@ static int gr_probe(struct platform_device *pdev) ...@@ -2175,8 +2175,6 @@ static int gr_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
} }
spin_lock(&dev->lock);
/* Inside lock so that no gadget can use this udc until probe is done */ /* Inside lock so that no gadget can use this udc until probe is done */
retval = usb_add_gadget_udc(dev->dev, &dev->gadget); retval = usb_add_gadget_udc(dev->dev, &dev->gadget);
if (retval) { if (retval) {
...@@ -2185,15 +2183,21 @@ static int gr_probe(struct platform_device *pdev) ...@@ -2185,15 +2183,21 @@ static int gr_probe(struct platform_device *pdev)
} }
dev->added = 1; dev->added = 1;
spin_lock(&dev->lock);
retval = gr_udc_init(dev); retval = gr_udc_init(dev);
if (retval) if (retval) {
spin_unlock(&dev->lock);
goto out; goto out;
}
gr_dfs_create(dev);
/* Clear all interrupt enables that might be left on since last boot */ /* Clear all interrupt enables that might be left on since last boot */
gr_disable_interrupts_and_pullup(dev); gr_disable_interrupts_and_pullup(dev);
spin_unlock(&dev->lock);
gr_dfs_create(dev);
retval = gr_request_irq(dev, dev->irq); retval = gr_request_irq(dev, dev->irq);
if (retval) { if (retval) {
dev_err(dev->dev, "Failed to request irq %d\n", dev->irq); dev_err(dev->dev, "Failed to request irq %d\n", dev->irq);
...@@ -2222,8 +2226,6 @@ static int gr_probe(struct platform_device *pdev) ...@@ -2222,8 +2226,6 @@ static int gr_probe(struct platform_device *pdev)
dev_info(dev->dev, "regs: %p, irq %d\n", dev->regs, dev->irq); dev_info(dev->dev, "regs: %p, irq %d\n", dev->regs, dev->irq);
out: out:
spin_unlock(&dev->lock);
if (retval) if (retval)
gr_remove(pdev); gr_remove(pdev);
......
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