usb: gadget: udc: fix possible sleep-in-atomic-context bugs in gr_probe()
authorJia-Ju Bai <baijiaju1990@gmail.com>
Wed, 18 Dec 2019 03:43:49 +0000 (11:43 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 15 Jan 2020 09:39:22 +0000 (10:39 +0100)
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: Jia-Ju Bai <baijiaju1990@gmail.com>
Signed-off-by: Felipe Balbi <balbi@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/gadget/udc/gr_udc.c

index 64d80c6..aaf975c 100644 (file)
@@ -2175,8 +2175,6 @@ static int gr_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
-       spin_lock(&dev->lock);
-
        /* Inside lock so that no gadget can use this udc until probe is done */
        retval = usb_add_gadget_udc(dev->dev, &dev->gadget);
        if (retval) {
@@ -2185,15 +2183,21 @@ static int gr_probe(struct platform_device *pdev)
        }
        dev->added = 1;
 
+       spin_lock(&dev->lock);
+
        retval = gr_udc_init(dev);
-       if (retval)
+       if (retval) {
+               spin_unlock(&dev->lock);
                goto out;
-
-       gr_dfs_create(dev);
+       }
 
        /* Clear all interrupt enables that might be left on since last boot */
        gr_disable_interrupts_and_pullup(dev);
 
+       spin_unlock(&dev->lock);
+
+       gr_dfs_create(dev);
+
        retval = gr_request_irq(dev, dev->irq);
        if (retval) {
                dev_err(dev->dev, "Failed to request irq %d\n", dev->irq);
@@ -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);
 
 out:
-       spin_unlock(&dev->lock);
-
        if (retval)
                gr_remove(pdev);