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

Fan Wu posted 1 patch 1 month, 3 weeks ago
drivers/extcon/extcon-usb-gpio.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
[PATCH] extcon: usb-gpio: Use devm_delayed_work_autocancel() for detect work
Posted by Fan Wu 1 month, 3 weeks ago
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@vger.kernel.org
Assisted-by: Codex:gpt-5.6
Signed-off-by: Fan Wu <fanwu01@zju.edu.cn>
---
 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@ti.com>
  */
 
+#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