From: hyunjungg <hj351016@gmail.com>
To: Neill Kapron <nkapron@google.com>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
linux-usb@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, Hyunjung Ko <hj351016@gmail.com>,
stable@vger.kernel.org
Subject: [PATCH v2] usb: gadget: pch_udc: drain vbus GPIO works before freeing the device
Date: Sat, 7 Nov 2026 16:02:58 +0900 [thread overview]
Message-ID: <20261107070258.3413402-1-hj351016@gmail.com> (raw)
From: Hyunjung Ko <hj351016@gmail.com>
pch_vbus_gpio_irq() and pch_udc_dev_isr() schedule
dev->vbus_gpio.irq_work_fall / irq_work_rise (pch_vbus_gpio_work_fall /
pch_vbus_gpio_work_rise), whose handlers obtain the pch_udc_dev via
container_of() and dereference it (dev->driver, dev->pdev, and
pch_udc_init()/pch_udc_reconnect()). Nothing cancels these works on
teardown.
pch_udc_remove() -> pch_udc_exit() -> pch_vbus_gpio_free() previously
only called free_irq() for the VBUS GPIO interrupt; dev is allocated with
devm_kzalloc() and is freed by devres after removal. free_irq() only
waits for the interrupt handler to finish, it does not cancel a work the
handler has already queued, so a pending or running work then runs
against the freed pch_udc_dev (use-after-free). pch_vbus_gpio_work_fall()
polls for up to PCH_VBUS_PERIOD (3s), widening the window.
The two works are armed differently. pch_vbus_gpio_init() assigns
dev->vbus_gpio.port and INIT_WORK()s irq_work_fall *before* request_irq()
sets dev->vbus_gpio.intr, and pch_udc_dev_isr() schedules irq_work_fall
exactly when dev->vbus_gpio.intr is 0; irq_work_rise is only initialised
and scheduled once intr is non-zero. Cancelling both only under
"if (dev->vbus_gpio.intr)" therefore misses irq_work_fall whenever the
GPIO is present but the IRQ was not acquired (gpiod_to_irq()/request_irq()
failure, or a device interrupt racing removal before interrupts are
masked).
Drain each work according to how it is armed: cancel irq_work_fall
whenever a VBUS GPIO port exists, and cancel irq_work_rise next to
free_irq() under the intr guard. free_irq() runs first so the GPIO
interrupt can no longer schedule work before it is drained.
Found by static analysis and code review; not runtime-reproduced (needs
EG20T/ML7213 pch_udc hardware with a VBUS detection GPIO and an interrupt
racing device removal).
Fixes: 637b78eb31e0 ("usb: gadget: pch_udc: Detecting VBUS through GPIO with interrupt")
Cc: stable@vger.kernel.org
Signed-off-by: Hyunjung Ko <hj351016@gmail.com>
---
v2: drain irq_work_fall under the GPIO-port guard rather than the IRQ
guard. irq_work_fall is scheduled from pch_udc_dev_isr() when
dev->vbus_gpio.intr == 0, so the v1 "if (intr)" placement skipped it.
Spotted by Sashiko AI review. The separate pre-existing missing
cancellation in pch_udc_shutdown() that the review also flagged is
left for its own patch.
drivers/usb/gadget/udc/pch_udc.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c
index 99b3ce2..5351bd9 100644
--- a/drivers/usb/gadget/udc/pch_udc.c
+++ b/drivers/usb/gadget/udc/pch_udc.c
@@ -1406,8 +1406,12 @@ static int pch_vbus_gpio_init(struct pch_udc_dev *dev)
*/
static void pch_vbus_gpio_free(struct pch_udc_dev *dev)
{
- if (dev->vbus_gpio.intr)
+ if (dev->vbus_gpio.intr) {
free_irq(dev->vbus_gpio.intr, dev);
+ cancel_work_sync(&dev->vbus_gpio.irq_work_rise);
+ }
+ if (dev->vbus_gpio.port)
+ cancel_work_sync(&dev->vbus_gpio.irq_work_fall);
}
/**
--
2.43.0
next reply other threads:[~2026-11-07 7:03 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-07 7:02 hyunjungg [this message]
2026-11-07 7:14 ` [PATCH v2] usb: gadget: pch_udc: drain vbus GPIO works before freeing the device sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261107070258.3413402-1-hj351016@gmail.com \
--to=hj351016@gmail.com \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=nkapron@google.com \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.