[PATCH] extcon: usb-gpio: Use devm_delayed_work_autocancel() for detect work

From: Fan Wu

Date: Wed Aug 05 2026 - 01:05:09 EST


The id/vbus threaded IRQ handler re-arms the detect delayed work on every
edge. cancel_delayed_work_sync() in ->remove() runs before the IRQs are
freed by devm, so an IRQ firing in between can re-arm the work and run it
after info is freed, leading to a use-after-free. The same window exists on
probe-error paths.

Use devm_delayed_work_autocancel() so devm LIFO order frees the IRQs before
the work is cancelled, on every path. Drop the now-redundant cancel from
->remove(). This matches the other extcon drivers.

This issue was found by an in-house static analysis tool.
Compile-tested only; runtime testing is appreciated.

Fixes: e52817faae35 ("extcon: usb-gpio: Introduce gpio usb extcon driver")
Cc: stable@xxxxxxxxxxxxxxx
Assisted-by: Codex:gpt-5.6
Signed-off-by: Fan Wu <fanwu01@xxxxxxxxxx>
---
drivers/extcon/extcon-usb-gpio.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c
index 5e8ad21ad206..4cc42f102098 100644
--- a/drivers/extcon/extcon-usb-gpio.c
+++ b/drivers/extcon/extcon-usb-gpio.c
@@ -6,6 +6,7 @@
* Author: Roger Quadros <rogerq@xxxxxx>
*/

+#include <linux/devm-helpers.h>
#include <linux/extcon-provider.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h>
@@ -146,7 +147,10 @@ static int usb_extcon_probe(struct platform_device *pdev)
if (ret < 0)
info->debounce_jiffies = msecs_to_jiffies(USB_GPIO_DEBOUNCE_MS);

- INIT_DELAYED_WORK(&info->wq_detcable, usb_extcon_detect_cable);
+ ret = devm_delayed_work_autocancel(dev, &info->wq_detcable,
+ usb_extcon_detect_cable);
+ if (ret)
+ return ret;

if (info->id_gpiod) {
info->id_irq = gpiod_to_irq(info->id_gpiod);
@@ -195,9 +199,6 @@ static int usb_extcon_probe(struct platform_device *pdev)

static void usb_extcon_remove(struct platform_device *pdev)
{
- struct usb_extcon_info *info = platform_get_drvdata(pdev);
-
- cancel_delayed_work_sync(&info->wq_detcable);
device_init_wakeup(&pdev->dev, false);
}

--
2.43.0