From: Hyunjung Ko ns2_drd_phy_probe() schedules driver->wq_extcon (extcon_work), which is also queued from the ID/VBUS GPIO interrupt handler gpio_irq_handler(). The work handler dereferences the driver data via container_of(). struct ns2_phy_driver is allocated with devm_kzalloc() and the driver has no remove callback, so on unbind devres frees it after probe's resources are released. The GPIO interrupts are requested with devm_request_irq(), and so released by devres; free_irq() only stops further interrupts, it does not cancel a delayed work that is already queued. probe() queues wq_extcon with a debounce delay before returning, and the GPIO interrupt can queue it too, so on unbind the pending work can run after ns2_phy_driver has been freed, dereferencing freed memory (use-after-free). Register the work with devm_delayed_work_autocancel() instead of INIT_DELAYED_WORK(). It is set up before the GPIO interrupts are requested, so on unwind devres frees the interrupts first - after which the work can no longer be queued - and then cancels the work while the driver data is still valid. extcon_work() does not re-queue itself, so a single cancel drains it. Found by static analysis and code review; not runtime-reproduced (needs Broadcom Northstar2 USB DRD PHY hardware). Fixes: 787f24543c4a ("phy: phy-bcm-ns2-usbdrd: Broadcom USB DRD PHY driver for Northstar2") Cc: stable@vger.kernel.org Signed-off-by: Hyunjung Ko --- Changes in v2: - Reword the commit message: the GPIO interrupts are requested with devm_request_irq() and released by devres (not "released with devm_request_irq()") (Ray Jui). - Place the new #include in alphabetical order, after (Ray Jui). drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c b/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c index 171bf09..4b8930b 100644 --- a/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c +++ b/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c @@ -2,6 +2,7 @@ // Copyright (C) 2017 Broadcom #include +#include #include #include #include @@ -339,7 +340,9 @@ static int ns2_drd_phy_probe(struct platform_device *pdev) if (ret < 0) driver->debounce_jiffies = msecs_to_jiffies(GPIO_DELAY); - INIT_DELAYED_WORK(&driver->wq_extcon, extcon_work); + ret = devm_delayed_work_autocancel(dev, &driver->wq_extcon, extcon_work); + if (ret) + return ret; driver->id_irq = gpiod_to_irq(driver->id_gpiod); if (driver->id_irq < 0) { -- 2.43.0