* [PATCH v2 0/4] usb: stop timers/works left armed on teardown
@ 2026-11-13 6:34 Chengyu Liu
2026-11-13 6:34 ` [PATCH v2 1/4] usb: musb: cancel the delayed works after quiescing the interrupt Chengyu Liu
` (4 more replies)
0 siblings, 5 replies; 10+ messages in thread
From: Chengyu Liu @ 2026-11-13 6:34 UTC (permalink / raw)
To: linux-usb
Cc: b-liu, gregkh, nkapron, tony, bigeasy, balbi, shimoda.yoshihiro,
robert.jarzmik, Chengyu Liu
The teardown paths in these four drivers do not quiesce every producer
of asynchronous work before draining it: an interrupt handler may still
queue or re-arm a timer or work item after the cancellation, while the
corresponding object is being torn down. In three of them the IRQ is
devm-managed and freed only at detach, after remove() returns; in musb
the plain free_irq() happens later in the same remove path. Either way
a late interrupt re-arms the callback, which then runs on freed memory:
[1/4] musb core: musb_stage0_irq() can schedule irq_work (and
finish_resume_work on remote wakeup) from interrupt context,
irq_work can also re-arm itself from the session recheck path,
and musb_hub_control() can arm finish_resume_work and
deassert_reset_work until the root hub is torn down;
musb_remove() cancelled all three too early.
[2/4] musb dsps glue: the devm VBUS interrupt outlives the child
teardown that deletes musb->dev_timer; its handler re-arms
the timer via dsps_mod_timer().
[3/4] r8a66597: r8a66597_remove() deletes the timer while the devm
IRQ can still re-arm it from the VBINT path.
[4/4] gpio-vbus: gpio_vbus_remove() cancels the work while the devm
GPIO interrupt can still re-arm it (100 ms debounce delay).
Two further instances of this defect class found in the same sweep -
pch_udc and lpc32xx_udc - are being handled in Hyunjung Ko's
"usb: gadget: pch_udc: drain vbus GPIO works before freeing the
device" and "usb: gadget: lpc32xx_udc: drain the pullup work on
removal" threads, so they are not part of this series.
Testing:
[1-3/4] build-tested on x86_64 (COMPILE_TEST where needed); they
require hardware we do not have, so no runtime reproducer.
[4/4] additionally confirmed with a KASAN reproducer: the driver
probed on a gpio-sim chip in QEMU, slab-use-after-free write
in __run_timer_base() after unregister (5/5 runs), clean with
the fix (0/5). The KASAN report and the reproducer kit follow
in this thread.
All found by static analysis. Fixes written with AI assistance.
Changelog:
v2:
- [1/4] also move the finish_resume_work and deassert_reset_work
cancels behind the interrupt quiesce, per Neill Kapron's
review; finish_resume_work is armed from interrupt context as
well (musb_handle_intr_resume()), and both it and
deassert_reset_work can additionally be re-armed via
musb_hub_control() until musb_host_cleanup() tears the host
down. Suggested-by added; Fixes tag corrected to
commit f730f205cc51 ("usb: musb: Split PM runtime between wrapper IP and musb core")
- [2-4/4] unchanged; collected Neill Kapron's Reviewed-by.
v1: https://lore.kernel.org/linux-usb/20261112160448.41566-1-lui2012qwq@gmail.com/
Chengyu Liu (4):
usb: musb: cancel the delayed works after quiescing the interrupt
usb: musb: dsps: free the VBUS interrupt before the child teardown
usb: gadget: r8a66597: free the IRQ before deleting the timer
usb: phy: gpio-vbus: free the interrupt before cancelling the work
drivers/usb/gadget/udc/r8a66597-udc.c | 8 ++++++++
drivers/usb/gadget/udc/r8a66597-udc.h | 1 +
drivers/usb/musb/musb_core.c | 15 ++++++++++++---
drivers/usb/musb/musb_dsps.c | 11 +++++++++++
drivers/usb/phy/phy-gpio-vbus-usb.c | 8 ++++++++
5 files changed, 40 insertions(+), 3 deletions(-)
Signed-off-by: Chengyu Liu <lui2012qwq@gmail.com>
--
2.25.1
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2 1/4] usb: musb: cancel the delayed works after quiescing the interrupt
2026-11-13 6:34 [PATCH v2 0/4] usb: stop timers/works left armed on teardown Chengyu Liu
@ 2026-11-13 6:34 ` Chengyu Liu
2026-11-13 6:56 ` sashiko-bot
2026-11-13 6:34 ` [PATCH v2 2/4] usb: musb: dsps: free the VBUS interrupt before the child teardown Chengyu Liu
` (3 subsequent siblings)
4 siblings, 1 reply; 10+ messages in thread
From: Chengyu Liu @ 2026-11-13 6:34 UTC (permalink / raw)
To: linux-usb
Cc: b-liu, gregkh, nkapron, tony, bigeasy, balbi, shimoda.yoshihiro,
robert.jarzmik, Chengyu Liu, stable
musb_remove() cancels finish_resume_work and deassert_reset_work up
front, while the interrupt is still enabled and the root hub is still
registered, and cancels irq_work only later. All three works can be
armed past their cancel:
- musb_handle_intr_resume() schedules finish_resume_work from
interrupt context (RESUME in OTG_STATE_A_SUSPEND, via
musb_stage0_irq());
- musb_hub_control() schedules finish_resume_work (ClearPortFeature
SUSPEND -> musb_port_suspend()) and deassert_reset_work
(SetPortFeature RESET -> musb_port_reset()) from process context,
and the root hub is only torn down by musb_host_cleanup();
- musb_stage0_irq() schedules irq_work, which can also re-arm itself
from the session recheck path (musb_pm_runtime_check_session()).
A work armed after its cancel runs musb_host_finish_resume(),
musb_deassert_reset() or musb_irq_work() after musb_free() has
released the struct.
Tear down the host and gadget sides first so no process-context
producer remains, mask the interrupts and synchronize the IRQ line so
no interrupt handler can be running, and only then cancel all three
works. This also restores the pre-f730f205cc51 ordering, which had
the cancels behind the interrupt masking.
Found by static analysis.
Suggested-by: Neill Kapron <nkapron@google.com>
Fixes: f730f205cc51 ("usb: musb: Split PM runtime between wrapper IP and musb core")
Cc: stable@vger.kernel.org
Signed-off-by: Chengyu Liu <lui2012qwq@gmail.com>
---
v1 -> v2:
- also move the finish_resume_work and deassert_reset_work cancels
behind the interrupt quiesce, per Neill Kapron's review:
finish_resume_work is armed from interrupt context as well
(musb_handle_intr_resume()), and both it and deassert_reset_work
can additionally be re-armed via musb_hub_control() until
musb_host_cleanup() tears the host down.
- correct the Fixes tag to f730f205cc51 (the 2016 PM-runtime split
moved the cancels ahead of the interrupt masking)
v1: https://lore.kernel.org/linux-usb/20261112160448.41566-2-lui2012qwq@gmail.com/
Build-tested on x86_64: musb_core.o compiles clean
(USB_MUSB_HDRC). No runtime reproducer: requires MUSB-based OTG
hardware. Fix written with AI assistance.
drivers/usb/musb/musb_core.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 9b63b56edc45..25115217e0af 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -2630,9 +2630,6 @@ static void musb_remove(struct platform_device *pdev)
*/
musb_exit_debugfs(musb);
- cancel_delayed_work_sync(&musb->irq_work);
- cancel_delayed_work_sync(&musb->finish_resume_work);
- cancel_delayed_work_sync(&musb->deassert_reset_work);
pm_runtime_get_sync(musb->controller);
musb_host_cleanup(musb);
musb_gadget_cleanup(musb);
@@ -2642,6 +2639,18 @@ static void musb_remove(struct platform_device *pdev)
musb_disable_interrupts(musb);
musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
spin_unlock_irqrestore(&musb->lock, flags);
+
+ /*
+ * musb_stage0_irq() arms irq_work (and finish_resume_work on
+ * remote wakeup) from interrupt context, so the works can only be
+ * cancelled for good once interrupts are masked and any in-flight
+ * handler has completed.
+ */
+ synchronize_irq(musb->nIrq);
+ cancel_delayed_work_sync(&musb->irq_work);
+ cancel_delayed_work_sync(&musb->finish_resume_work);
+ cancel_delayed_work_sync(&musb->deassert_reset_work);
+
musb_platform_exit(musb);
pm_runtime_dont_use_autosuspend(musb->controller);
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 2/4] usb: musb: dsps: free the VBUS interrupt before the child teardown
2026-11-13 6:34 [PATCH v2 0/4] usb: stop timers/works left armed on teardown Chengyu Liu
2026-11-13 6:34 ` [PATCH v2 1/4] usb: musb: cancel the delayed works after quiescing the interrupt Chengyu Liu
@ 2026-11-13 6:34 ` Chengyu Liu
2026-11-13 6:48 ` sashiko-bot
2026-11-13 6:34 ` [PATCH v2 3/4] usb: gadget: r8a66597: free the IRQ before deleting the timer Chengyu Liu
` (2 subsequent siblings)
4 siblings, 1 reply; 10+ messages in thread
From: Chengyu Liu @ 2026-11-13 6:34 UTC (permalink / raw)
To: linux-usb
Cc: b-liu, gregkh, nkapron, tony, bigeasy, balbi, shimoda.yoshihiro,
robert.jarzmik, Chengyu Liu, stable
dsps_remove() unregisters the musb child, which deletes
musb->dev_timer and frees the structure, while the glue's VBUS
interrupt is devm-managed and only freed after dsps_remove() returns.
dsps_vbus_threaded_irq() re-arms the timer via dsps_mod_timer(), so
a VBUS event in between re-arms dev_timer past its deletion and
otg_timer() runs on freed memory.
Free the VBUS interrupt first, which also waits for any in-flight
handler, so nothing can re-arm the timer once the child teardown
runs.
Found by static analysis.
Fixes: 369469a92393 ("usb: musb: Add support for optional VBUS irq to dsps glue layer")
Cc: stable@vger.kernel.org
Reviewed-by: Neill Kapron <nkapron@google.com>
Signed-off-by: Chengyu Liu <lui2012qwq@gmail.com>
---
v1 -> v2: no code change; collected Neill Kapron's Reviewed-by.
Build-tested on x86_64: musb_dsps.o compiles clean
(USB_MUSB_DSPS). No runtime reproducer: requires AM33xx/DSPS
hardware. Fix written with AI assistance.
drivers/usb/musb/musb_dsps.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 91d8712efa41..69c8b4b3ffa7 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -942,6 +942,17 @@ static void dsps_remove(struct platform_device *pdev)
{
struct dsps_glue *glue = platform_get_drvdata(pdev);
+ /*
+ * The VBUS interrupt handler re-arms musb->dev_timer via
+ * dsps_mod_timer(); the IRQ is devm-managed and would only be
+ * freed after this function returns, while the child teardown
+ * below deletes the timer and frees the musb structure. Free
+ * the interrupt first so no VBUS event can re-arm the timer
+ * past that point.
+ */
+ if (glue->vbus_irq)
+ devm_free_irq(glue->dev, glue->vbus_irq, glue);
+
platform_device_unregister(glue->musb);
pm_runtime_disable(&pdev->dev);
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 3/4] usb: gadget: r8a66597: free the IRQ before deleting the timer
2026-11-13 6:34 [PATCH v2 0/4] usb: stop timers/works left armed on teardown Chengyu Liu
2026-11-13 6:34 ` [PATCH v2 1/4] usb: musb: cancel the delayed works after quiescing the interrupt Chengyu Liu
2026-11-13 6:34 ` [PATCH v2 2/4] usb: musb: dsps: free the VBUS interrupt before the child teardown Chengyu Liu
@ 2026-11-13 6:34 ` Chengyu Liu
2026-11-13 6:48 ` sashiko-bot
2026-11-13 6:34 ` [PATCH v2 4/4] usb: phy: gpio-vbus: free the interrupt before cancelling the work Chengyu Liu
2026-11-13 6:36 ` [PATCH v2 0/4] usb: stop timers/works left armed on teardown Chengyu Liu
4 siblings, 1 reply; 10+ messages in thread
From: Chengyu Liu @ 2026-11-13 6:34 UTC (permalink / raw)
To: linux-usb
Cc: b-liu, gregkh, nkapron, tony, bigeasy, balbi, shimoda.yoshihiro,
robert.jarzmik, Chengyu Liu, stable
r8a66597_remove() deletes r8a66597->timer while the interrupt is
still live: the IRQ is devm-managed and only freed at detach, and
r8a66597_irq() re-arms the timer when sampling VBUS (VBINT). An
interrupt landing after timer_delete_sync() re-arms the timer, and
r8a66597_timer() then runs on freed memory.
Store the requested IRQ number at probe time and free it before
deleting the timer; freeing also waits for any running handler, so
nothing can re-arm the timer past the delete.
Found by static analysis.
Fixes: c41442474a26 ("usb: gadget: R8A66597 peripheral controller support.")
Cc: stable@vger.kernel.org
Reviewed-by: Neill Kapron <nkapron@google.com>
Signed-off-by: Chengyu Liu <lui2012qwq@gmail.com>
---
v1 -> v2: no code change; collected Neill Kapron's Reviewed-by.
Build-tested on x86_64: r8a66597-udc.o compiles clean
(USB_R8A66597 + COMPILE_TEST). No runtime reproducer: requires
R8A66597 hardware. Fix written with AI assistance.
drivers/usb/gadget/udc/r8a66597-udc.c | 8 ++++++++
drivers/usb/gadget/udc/r8a66597-udc.h | 1 +
2 files changed, 9 insertions(+)
diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c
index 469075b064ba..bfccc6565e0a 100644
--- a/drivers/usb/gadget/udc/r8a66597-udc.c
+++ b/drivers/usb/gadget/udc/r8a66597-udc.c
@@ -1810,6 +1810,13 @@ static void r8a66597_remove(struct platform_device *pdev)
struct r8a66597 *r8a66597 = platform_get_drvdata(pdev);
usb_del_gadget_udc(&r8a66597->gadget);
+
+ /*
+ * The interrupt handler re-arms the timer on VBUS changes; the
+ * IRQ is devm-managed and freed only at detach, so free it
+ * before deleting the timer.
+ */
+ devm_free_irq(&pdev->dev, r8a66597->irq, r8a66597);
timer_delete_sync(&r8a66597->timer);
r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req);
@@ -1896,6 +1903,7 @@ static int r8a66597_probe(struct platform_device *pdev)
udc_name, r8a66597);
if (ret < 0)
goto clean_up2;
+ r8a66597->irq = irq;
INIT_LIST_HEAD(&r8a66597->gadget.ep_list);
r8a66597->gadget.ep0 = &r8a66597->ep[0].ep;
diff --git a/drivers/usb/gadget/udc/r8a66597-udc.h b/drivers/usb/gadget/udc/r8a66597-udc.h
index 9a115caba661..08acabe02421 100644
--- a/drivers/usb/gadget/udc/r8a66597-udc.h
+++ b/drivers/usb/gadget/udc/r8a66597-udc.h
@@ -110,6 +110,7 @@ struct r8a66597 {
unsigned char interrupt;
unsigned char isochronous;
unsigned char num_dma;
+ int irq;
unsigned irq_sense_low:1;
};
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 4/4] usb: phy: gpio-vbus: free the interrupt before cancelling the work
2026-11-13 6:34 [PATCH v2 0/4] usb: stop timers/works left armed on teardown Chengyu Liu
` (2 preceding siblings ...)
2026-11-13 6:34 ` [PATCH v2 3/4] usb: gadget: r8a66597: free the IRQ before deleting the timer Chengyu Liu
@ 2026-11-13 6:34 ` Chengyu Liu
2026-11-13 6:40 ` sashiko-bot
2026-11-13 6:36 ` [PATCH v2 0/4] usb: stop timers/works left armed on teardown Chengyu Liu
4 siblings, 1 reply; 10+ messages in thread
From: Chengyu Liu @ 2026-11-13 6:34 UTC (permalink / raw)
To: linux-usb
Cc: b-liu, gregkh, nkapron, tony, bigeasy, balbi, shimoda.yoshihiro,
robert.jarzmik, Chengyu Liu, stable
gpio_vbus_remove() cancels gpio_vbus->work while the VBUS sensing GPIO
interrupt is still live: it is devm-managed and freed only at detach,
and gpio_vbus_irq() schedules the work with a 100 ms debounce delay.
A plug event landing after the cancel re-arms the work, and its timer
then fires on the freed gpio_vbus_data.
Free the interrupt first, which also waits for any running handler,
so nothing can re-arm the work past the cancel.
Found by static analysis and confirmed with a KASAN reproducer:
slab-use-after-free write in __run_timer_base() within one debounce
interval of unregistering the device while its VBUS GPIO is toggled
(object allocated by gpio_vbus_probe() via devm_kmalloc(), freed by
devres_release_all() at unbind).
Fixes: c2344f13b59e ("USB: gpio_vbus: add delayed vbus_session calls")
Cc: stable@vger.kernel.org
Reviewed-by: Neill Kapron <nkapron@google.com>
Signed-off-by: Chengyu Liu <lui2012qwq@gmail.com>
---
v1 -> v2: no code change; collected Neill Kapron's Reviewed-by.
The reproducer instantiates the unmodified driver on a gpio-sim
chip in QEMU and toggles the line while the device is unregistered;
it widens the remove()-to-detach window with a 500 ms sleep, logic
otherwise unmodified. Repeated runs: 5/5 KASAN splats without the
fix, 0/5 with it. The KASAN report and the reproducer kit follow
in this thread. Also build-tested on x86_64 (USB_GPIO_VBUS).
Fix written with AI assistance.
drivers/usb/phy/phy-gpio-vbus-usb.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/usb/phy/phy-gpio-vbus-usb.c b/drivers/usb/phy/phy-gpio-vbus-usb.c
index 60b7c1219dd2..82d2301c3804 100644
--- a/drivers/usb/phy/phy-gpio-vbus-usb.c
+++ b/drivers/usb/phy/phy-gpio-vbus-usb.c
@@ -325,6 +325,14 @@ static void gpio_vbus_remove(struct platform_device *pdev)
struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
device_init_wakeup(&pdev->dev, 0);
+
+ /*
+ * The VBUS sensing GPIO interrupt is devm-managed and freed only
+ * at detach, and its handler schedules the work with a 100ms
+ * delay; free the interrupt before cancelling the work so a
+ * late plug event cannot re-arm it past the cancel.
+ */
+ devm_free_irq(&pdev->dev, gpio_vbus->irq, pdev);
cancel_delayed_work_sync(&gpio_vbus->work);
usb_remove_phy(&gpio_vbus->phy);
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v2 0/4] usb: stop timers/works left armed on teardown
2026-11-13 6:34 [PATCH v2 0/4] usb: stop timers/works left armed on teardown Chengyu Liu
` (3 preceding siblings ...)
2026-11-13 6:34 ` [PATCH v2 4/4] usb: phy: gpio-vbus: free the interrupt before cancelling the work Chengyu Liu
@ 2026-11-13 6:36 ` Chengyu Liu
4 siblings, 0 replies; 10+ messages in thread
From: Chengyu Liu @ 2026-11-13 6:36 UTC (permalink / raw)
To: linux-usb
Cc: b-liu, gregkh, nkapron, tony, bigeasy, balbi, shimoda.yoshihiro,
robert.jarzmik, Chengyu Liu
The KASAN report and the reproducer kit for the gpio-vbus instance
[4/4], as promised in the cover letter. [4/4] is unchanged in v2,
so this is the same report and kit as posted in the v1 thread.
Environment: QEMU x86_64, generic KASAN kernel (v7.3-rc7 plus unrelated
local commits; config: KASAN/KASAN_GENERIC=y, GPIOLIB=y, GPIO_SIM=y,
CONFIGFS_FS=y, USB_GADGET=m, USB_GPIO_VBUS=m),
phy-gpio-vbus-usb built as a module. The driver under test is
unmodified except for the disclosed 500 ms sleep widening the
remove()-to-detach window.
Setup: a one-line gpio-sim chip labelled "vbus-sim" stands in for the
VBUS sense GPIO; writing its "pull" sysfs attribute generates real GPIO
edge interrupts. The vbus_rig module registers a gpiod lookup table and
the "gpio-vbus" platform device, so the real driver probes it, and
attaches a dummy usb_gadget to phy->otg->gadget so gpio_vbus_irq() takes
its normal schedule_delayed_work() path (a UDC provides this on real
hardware); the module fails to load if the phy cannot be attached, so a
clean run cannot be a setup artifact. rmmod vbus_rig runs the real
gpio_vbus_remove() while the line is being toggled.
Results over repeated runs of the same script:
vulnerable kernel: 5/5 runs, KASAN slab-use-after-free each time
patched kernel: 5/5 runs, clean
Representative vulnerable splat (VBUS edges toggle at max rate while the
device is unregistered; an interrupt lands after the
cancel_delayed_work_sync(), re-arms the 100 ms debounce work, and the
work's timer fires after the devm release has freed gpio_vbus_data):
[ 3.571772] BUG: KASAN: slab-use-after-free in __run_timer_base.part.0+0x80c/0x900
[ 3.571779] Write of size 8 at addr ffff8880033291d8 by task sh/89
[ 3.571781]
[ 3.571784] CPU: 0 UID: 0 PID: 89 Comm: sh Tainted: G W O 7.3.0-rc7-00036-gf9532d351e12-dirty #29 PREEMPT(lazy)
[ 3.571788] Tainted: [W]=WARN, [O]=OOT_MODULE
[ 3.571788] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1ubuntu1.1 04/01/2014
[ 3.571790] Call Trace:
[ 3.571791] <IRQ>
[ 3.571792] dump_stack_lvl+0x55/0x70
[ 3.571808] print_report+0x10d/0x5d0
[ 3.571811] ? __run_timer_base.part.0+0x80c/0x900
[ 3.571813] kasan_report+0x96/0xd0
[ 3.571815] ? __run_timer_base.part.0+0x80c/0x900
[ 3.571817] __run_timer_base.part.0+0x80c/0x900
[ 3.571819] ? __pfx___run_timer_base.part.0+0x10/0x10
[ 3.571821] ? __pfx___hrtimer_get_next_event+0x10/0x10
[ 3.571825] ? kvm_clock_read+0x15/0x30
[ 3.571827] ? __hrtimer_run_queues+0x2aa/0x580
[ 3.571829] ? clockevents_program_event+0x2b0/0x7c0
[ 3.571833] ? hrtimer_update_next_event+0x8a/0x100
[ 3.571835] run_timer_softirq+0xd6/0x190
[ 3.571837] handle_softirqs+0x184/0x5c0
[ 3.571840] ? __hrtimer_rearm_deferred+0x15d/0x460
[ 3.571841] irq_exit_rcu+0x6e/0x150
[ 3.571843] sysvec_apic_timer_interrupt+0x70/0x80
[ 3.571845] </IRQ>
[ 3.571846] <TASK>
[ 3.571846] asm_sysvec_apic_timer_interrupt+0x1a/0x20
[ 3.571849] RIP: 0010:stack_depot_save_flags+0x61/0x830
[ 3.571852] Code: 70 05 05 00 74 16 48 83 c4 30 44 89 e8 5b 5d 41 5c 41 5d 41 5e 41 5f c3 cc cc cc cc 89 c1 48 01 c9 89 cf 8d 04 8d 7b 71 f5 75 <83> f9 03 0f 86 36 01 00 00 89 c3 89 c1 4c 89 fe 03 5e 08 03 06 83
[ 3.571854] RSP: 0018:ffff888002207a08 EFLAGS: 00000216
[ 3.571856] RAX: 0000000075f571cb RBX: ffff888003880988 RCX: 0000000000000014
[ 3.571858] RDX: ffffffffb3000130 RSI: 000000000000000a RDI: 0000000000000014
[ 3.571859] RBP: ffff888001041640 R08: 0000000000000000 R09: ffffffffb87baec6
[ 3.571859] R10: ffff888002207978 R11: ffff888002207f50 R12: 0000000000000001
[ 3.571860] R13: 0000000000000000 R14: 000000000000000a R15: ffff888002207a70
[ 3.571862] ? entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 3.571864] ? stack_depot_save_flags+0x2d/0x830
[ 3.571866] ? kernfs_fop_write_iter+0x168/0x480
[ 3.571868] kasan_save_stack+0x34/0x50
[ 3.571870] ? kasan_save_stack+0x24/0x50
[ 3.571871] ? kasan_save_track+0x14/0x30
[ 3.571872] ? kasan_save_free_info+0x3a/0x60
[ 3.571874] ? __kasan_slab_free+0x43/0x70
[ 3.571875] ? kfree+0x18e/0x3c0
[ 3.571877] ? kernfs_fop_write_iter+0x168/0x480
[ 3.571878] ? vfs_write+0x87a/0xd40
[ 3.571880] ? ksys_write+0xf3/0x1c0
[ 3.571881] ? do_syscall_64+0xee/0x500
[ 3.571883] ? entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 3.571885] ? do_sys_openat2+0x308/0x450
[ 3.571886] ? kasan_save_stack+0x34/0x50
[ 3.571888] ? kasan_save_stack+0x24/0x50
[ 3.571889] ? kasan_save_track+0x14/0x30
[ 3.571890] ? kasan_save_free_info+0x3a/0x60
[ 3.571892] ? __kasan_slab_free+0x43/0x70
[ 3.571893] ? kmem_cache_free+0x1d4/0x3c0
[ 3.571895] ? do_sys_openat2+0x308/0x450
[ 3.571896] ? do_sys_open+0x8d/0xe0
[ 3.571898] ? __x64_sys_openat+0x9d/0x110
[ 3.571899] ? do_syscall_64+0xee/0x500
[ 3.571901] ? entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 3.571902] ? __pfx_path_openat+0x10/0x10
[ 3.571905] ? kasan_save_stack+0x34/0x50
[ 3.571906] ? kasan_save_stack+0x24/0x50
[ 3.571907] ? mutex_unlock+0x82/0xd0
[ 3.571909] ? __pfx_mutex_unlock+0x10/0x10
[ 3.571911] ? _raw_spin_lock_irqsave+0x8b/0xf0
[ 3.571913] ? gpio_sim_apply_pull+0x1c8/0x4e0
[ 3.571915] ? __pfx_gpio_sim_apply_pull+0x10/0x10
[ 3.571917] ? kasan_save_track+0x14/0x30
[ 3.571918] kasan_save_track+0x14/0x30
[ 3.571920] kasan_save_free_info+0x3a/0x60
[ 3.571921] __kasan_slab_free+0x43/0x70
[ 3.571923] kfree+0x18e/0x3c0
[ 3.571925] ? __pfx_sysfs_kf_write+0x10/0x10
[ 3.571926] kernfs_fop_write_iter+0x168/0x480
[ 3.571928] vfs_write+0x87a/0xd40
[ 3.571929] ? alloc_fd+0x2c6/0x5d0
[ 3.571932] ? __pfx_vfs_write+0x10/0x10
[ 3.571933] ? __do_sys_wait4+0xf2/0x100
[ 3.571935] ? fdget_pos+0x1cd/0x4c0
[ 3.571937] ksys_write+0xf3/0x1c0
[ 3.571939] ? __pfx_ksys_write+0x10/0x10
[ 3.571940] do_syscall_64+0xee/0x500
[ 3.571942] entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 3.571944] RIP: 0033:0x49a227
[ 3.571945] Code: 64 89 02 48 c7 c0 ff ff ff ff eb bb 0f 1f 80 00 00 00 00 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 10 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 51 c3 48 83 ec 28 48 89 54 24 18 48 89 74 24
[ 3.571947] RSP: 002b:00007ffd89cad1e8 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
[ 3.571948] RAX: ffffffffffffffda RBX: 0000000000000001 RCX: 000000000049a227
[ 3.571949] RDX: 000000000000000a RSI: 000000003e0afe50 RDI: 0000000000000001
[ 3.571951] RBP: 000000003e0afe50 R08: 000000003e0afe50 R09: 006e776f642d6c6c
[ 3.571952] R10: 0000000000000000 R11: 0000000000000246 R12: 000000000000000a
[ 3.571953] R13: 000000003e0ad8a0 R14: 0000000000609c01 R15: 00007ffd89cad250
[ 3.571955] </TASK>
[ 3.571955]
[ 3.571956] Allocated by task 86:
[ 3.571957] kasan_save_stack+0x24/0x50
[ 3.571959] kasan_save_track+0x14/0x30
[ 3.571960] __kasan_kmalloc+0x7f/0x90
[ 3.571961] __kmalloc_node_track_caller_noprof+0x1d4/0x4a0
[ 3.571963] devm_kmalloc+0x81/0x240
[ 3.571965] gpio_vbus_probe+0x30/0x670 [phy_gpio_vbus_usb]
[ 3.571968] platform_probe+0x9e/0x140
[ 3.571970] really_probe+0x1cf/0x5c0
[ 3.571972] __driver_probe_device+0x1a1/0x3b0
[ 3.571974] driver_probe_device+0x49/0xd0
[ 3.571975] __device_attach_driver+0x183/0x200
[ 3.571977] bus_for_each_drv+0x105/0x190
[ 3.571979] __device_attach+0x20b/0x380
[ 3.571981] device_initial_probe+0x7d/0xa0
[ 3.571982] bus_probe_device+0x5a/0x130
[ 3.571983] device_add+0xd6f/0x14c0
[ 3.571984] platform_device_add+0x253/0x5a0
[ 3.571986] platform_device_register_full+0x3c3/0x560
[ 3.571988] 0xffffffffc02250aa
[ 3.571989] do_one_initcall+0x89/0x350
[ 3.571990] do_init_module+0x2a1/0x890
[ 3.571992] load_module+0x5166/0x6750
[ 3.571994] init_module_from_file+0x162/0x190
[ 3.571996] idempotent_init_module+0x325/0x680
[ 3.571997] __x64_sys_finit_module+0xc2/0x130
[ 3.571999] do_syscall_64+0xee/0x500
[ 3.572001] entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 3.572002]
[ 3.572002] Freed by task 91:
[ 3.572003] kasan_save_stack+0x24/0x50
[ 3.572004] kasan_save_track+0x14/0x30
[ 3.572005] kasan_save_free_info+0x3a/0x60
[ 3.572007] __kasan_slab_free+0x43/0x70
[ 3.572008] kfree+0x18e/0x3c0
[ 3.572009] release_nodes+0xbe/0x120
[ 3.572011] devres_release_all+0x127/0x1a0
[ 3.572012] device_unbind_cleanup+0x76/0x260
[ 3.572014] device_release_driver_internal+0x163/0x210
[ 3.572015] bus_remove_device+0x256/0x3e0
[ 3.572017] device_del+0x3a8/0x960
[ 3.572019] platform_device_del.part.0+0x1f/0x1e0
[ 3.572020] platform_device_unregister+0x20/0x40
[ 3.572022] 0xffffffffc022008c
[ 3.572023] __x64_sys_delete_module+0x32c/0x4a0
[ 3.572025] do_syscall_64+0xee/0x500
[ 3.572026] entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 3.572027]
[ 3.572028] Last potentially related work creation:
[ 3.572028] kasan_save_stack+0x24/0x50
[ 3.572029] kasan_record_aux_stack+0x89/0xa0
[ 3.572031] insert_work+0x2d/0x240
[ 3.572033] __queue_work+0x44e/0xd70
[ 3.572034] call_timer_fn+0x27/0x210
[ 3.572035] __run_timer_base.part.0+0x3cc/0x900
[ 3.572037] run_timer_softirq+0xd6/0x190
[ 3.572039] handle_softirqs+0x184/0x5c0
[ 3.572040] irq_exit_rcu+0x6e/0x150
[ 3.572041] sysvec_apic_timer_interrupt+0x70/0x80
[ 3.572042] asm_sysvec_apic_timer_interrupt+0x1a/0x20
[ 3.572044]
[ 3.572044] Second to last potentially related work creation:
[ 3.572045] kasan_save_stack+0x24/0x50
[ 3.572046] kasan_record_aux_stack+0x89/0xa0
[ 3.572047] insert_work+0x2d/0x240
[ 3.572048] __queue_work+0x44e/0xd70
[ 3.572050] call_timer_fn+0x27/0x210
[ 3.572051] __run_timer_base.part.0+0x3cc/0x900
[ 3.572052] run_timer_softirq+0xd6/0x190
[ 3.572054] handle_softirqs+0x184/0x5c0
[ 3.572055] irq_exit_rcu+0x6e/0x150
[ 3.572056] sysvec_apic_timer_interrupt+0x39/0x80
[ 3.572058] asm_sysvec_apic_timer_interrupt+0x1a/0x20
[ 3.572059]
[ 3.572059] The buggy address belongs to the object at ffff888003329000
[ 3.572059] which belongs to the cache kmalloc-1k of size 1024
[ 3.572061] The buggy address is located 472 bytes inside of
[ 3.572061] freed 1024-byte region [ffff888003329000, ffff888003329400)
[ 3.572062]
[ 3.572063] The buggy address belongs to the physical page:
[ 3.572064] page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff888003328000 pfn:0x3328
[ 3.572066] head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
[ 3.572067] flags: 0x100000000000240(workingset|head|node=0|zone=1)
[ 3.572069] page_type: f5(slab)
[ 3.572071] raw: 0100000000000240 ffff888001041dc0 ffff888001040590 ffffea0000110610
[ 3.572073] raw: ffff888003328000 000000000010000f 00000000f5000000 0000000000000000
[ 3.572075] head: 0100000000000240 ffff888001041dc0 ffff888001040590 ffffea0000110610
[ 3.572076] head: ffff888003328000 000000000010000f 00000000f5000000 0000000000000000
[ 3.572077] head: 0100000000000003 fffffffffffffe01 00000000ffffffff 00000000ffffffff
[ 3.572078] head: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000000
[ 3.572078] page dumped because: kasan: bad access detected
[ 3.572079]
[ 3.572079] Memory state around the buggy address:
[ 3.572080] ffff888003329080: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[ 3.572081] ffff888003329100: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[ 3.572082] >ffff888003329180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[ 3.572083] ^
[ 3.572084] ffff888003329200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[ 3.572084] ffff888003329280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[ 3.572085] ==================================================================
(The "gpiod_get_value can_sleep" WARNINGs earlier in the boot are a
gpio-sim artifact - simulated chips set can_sleep - and are unrelated
to the bug. One of the five runs faulted in gpio_vbus_work() itself
instead of __run_timer_base(); same object, same free site.)
Reproducer kit (against the KASAN kernel tree above):
vbus_rig.c:
// SPDX-License-Identifier: GPL-2.0
/*
* vbus_rig - PoC rig for the gpio-vbus teardown UAF (F-138).
*
* Instantiates a "gpio-vbus" platform device wired via a gpiod lookup
* table to line 0 of a gpio-sim chip labelled "vbus-sim", so the real
* phy-gpio-vbus-usb platform driver probes it. Attaches a dummy
* usb_gadget to phy->otg->gadget so the driver's IRQ handler takes its
* normal schedule_delayed_work() path (it skips scheduling when no
* gadget is attached - on real hardware a UDC provides the gadget).
* rmmod vbus_rig runs the real gpio_vbus_remove() path. Contains no
* vulnerable logic itself.
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/gpio/machine.h>
#include <linux/usb/phy.h>
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
static struct gpiod_lookup_table vbus_lookup = {
.dev_id = "gpio-vbus.0",
.table = {
GPIO_LOOKUP("vbus-sim", 0, "vbus", GPIO_ACTIVE_HIGH),
{ }
},
};
static const struct usb_gadget_ops vbus_rig_gadget_ops; /* all NULL */
static struct usb_gadget vbus_rig_gadget = {
.ops = (struct usb_gadget_ops *)&vbus_rig_gadget_ops,
.name = "vbus_rig",
};
static struct platform_device *vbus_pdev;
static struct usb_phy *rig_phy;
static int __init vbus_rig_init(void)
{
gpiod_add_lookup_table(&vbus_lookup);
vbus_pdev = platform_device_register_simple("gpio-vbus", 0, NULL, 0);
if (IS_ERR(vbus_pdev)) {
gpiod_remove_lookup_table(&vbus_lookup);
return PTR_ERR(vbus_pdev);
}
rig_phy = usb_get_phy(USB_PHY_TYPE_USB2);
if (IS_ERR(rig_phy)) {
pr_err("vbus_rig: no phy found (%ld) - setup broken\n",
PTR_ERR(rig_phy));
goto fail;
}
if (!rig_phy->otg) {
pr_err("vbus_rig: phy has no otg - setup broken\n");
usb_put_phy(rig_phy);
goto fail;
}
rig_phy->otg->gadget = &vbus_rig_gadget;
pr_info("vbus_rig: gpio-vbus.0 registered, phy attached\n");
return 0;
fail:
platform_device_unregister(vbus_pdev);
gpiod_remove_lookup_table(&vbus_lookup);
return -ENODEV;
}
static void __exit vbus_rig_exit(void)
{
/*
* Drop our phy reference first; the driver module stays put via
* the bound device. Keep the gadget attached across the
* unregister: the driver's IRQ handler must keep taking its
* normal schedule_delayed_work() path all the way through
* remove().
*/
usb_put_phy(rig_phy);
platform_device_unregister(vbus_pdev);
gpiod_remove_lookup_table(&vbus_lookup);
pr_info("vbus_rig: gpio-vbus.0 unregistered\n");
}
module_init(vbus_rig_init);
module_exit(vbus_rig_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("gpio-vbus teardown UAF PoC rig");
Makefile:
obj-m += vbus_rig.o
guest init script (packed into a busybox initramfs with udc-core.ko,
phy-gpio-vbus-usb.ko and vbus_rig.ko):
#!/bin/sh
# PoC init: gpio-vbus teardown re-arm UAF (F-138)
#
# mode=vuln : kernel has the unpatched gpio_vbus_remove() + a 500ms
# POC-WITNESS msleep() after cancel_delayed_work_sync().
# mode=fixed : kernel has the fix (devm_free_irq before the cancel)
# plus the same witness sleep.
#
# A busy toggler flips the gpio-sim line pull (= VBUS edges) while
# rmmod runs the real remove path. In vuln mode an edge lands after
# the cancel, re-arms the 100ms debounce work, and the work fires on
# the freed gpio_vbus_data -> KASAN slab-use-after-free.
#
# The toggler prints nothing; the console between "rmmod starts" and
# the verdict carries only kernel output. If a run comes out clean,
# just run it again (IRQ delivery timing varies).
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs dev /dev
mount -t configfs none /sys/kernel/config
# 1. one-line gpio-sim chip labelled "vbus-sim"
SIM=/sys/kernel/config/gpio-sim/sim0
mkdir -p $SIM/bank0
echo vbus-sim > $SIM/bank0/label
echo 1 > $SIM/bank0/num_lines
echo 1 > $SIM/live
PULL=$(echo /sys/devices/platform/gpio-sim.0/gpiochip*/sim_gpio0/pull)
# 2. load the gadget core, the real driver + rig (probe runs now)
insmod /udc-core.ko || { echo "SETUP FAIL: udc-core"; poweroff -f; }
insmod /phy-gpio-vbus-usb.ko || { echo "SETUP FAIL: phy module"; poweroff -f; }
insmod /vbus_rig.ko || { echo "SETUP FAIL: rig (phy attach broken)"; poweroff -f; }
ls /sys/bus/platform/drivers/gpio-vbus/
grep -i vbus /proc/interrupts || { echo "SETUP FAIL: no vbus irq"; poweroff -f; }
# 3. toggle VBUS edges at max rate, then run the real remove path
( while :; do echo pull-up > $PULL; echo pull-down > $PULL; done ) &
T=$!
sleep 1
echo "=== rmmod vbus_rig: remove path ==="
rmmod vbus_rig
sleep 2
kill $T
# 4. verdict
if dmesg | grep -q 'BUG: KASAN'; then
echo "=== RESULT: KASAN SPLAT (vuln confirmed) ==="
else
echo "=== RESULT: clean (no KASAN splat) ==="
fi
poweroff -f
run.sh (QEMU wrapper; its first argument is only a log label, the
vulnerable/fixed state comes from which witness diff was applied at
build time):
#!/bin/bash
# run.sh -- boot the PoC in QEMU. usage: run.sh <label> [logfile]
#
# NOTE: <label> is only a name for the log; it does NOT switch kernel
# state. The vulnerable/fixed state comes from which witness diff is
# applied to the kernel tree when the modules and initramfs were last
# built (see README.md: vuln = witness-vuln.diff, fixed =
# witness-fixed.diff).
set -o pipefail
cd "$(dirname "$0")"
K=${KDIR:-$HOME/patternmine/worktrees/vm-hdlc}
MODE=${1:-vuln}
LOG=${2:-/tmp/f138-$MODE.log}
timeout 120 qemu-system-x86_64 -enable-kvm -cpu host -smp 2 -m 1024 \
-kernel "$K/arch/x86/boot/bzImage" \
-initrd initramfs.cpio \
-append "console=ttyS0 loglevel=8 panic_on_oops=0" \
-nographic -no-reboot 2>&1 | tee "$LOG"
matrix.sh (repeated runs):
#!/bin/bash
# matrix.sh -- run N VMs with the current build, print the tally.
# usage: matrix.sh <N> <label> (label is only for log naming; the
# vulnerable/fixed state comes from which witness diff was applied at
# build time -- see README.md)
cd "$(dirname "$0")"
N=${1:-5}
MODE=${2:-vuln}
HIT=0
for i in $(seq 1 "$N"); do
./run.sh "$MODE" "/tmp/f138-matrix-$MODE-$i.log" >/dev/null 2>&1
if grep -q 'BUG: KASAN' "/tmp/f138-matrix-$MODE-$i.log"; then
HIT=$((HIT+1))
elif grep -q 'SETUP FAIL' "/tmp/f138-matrix-$MODE-$i.log"; then
echo "run $i: SETUP FAIL - do not count"; continue
fi
echo "run $i: $(grep -m1 'RESULT' "/tmp/f138-matrix-$MODE-$i.log" | sed 's/.*=== //;s/ ===//')"
done
echo "== $MODE: $HIT/$N KASAN splats =="
witness diff applied to the vulnerable kernel (window widening only,
logic unchanged):
diff --git a/drivers/usb/phy/phy-gpio-vbus-usb.c b/drivers/usb/phy/phy-gpio-vbus-usb.c
index ce09e789afd8..f3e1c3f3b125 100644
--- a/drivers/usb/phy/phy-gpio-vbus-usb.c
+++ b/drivers/usb/phy/phy-gpio-vbus-usb.c
@@ -332,6 +332,12 @@ static void gpio_vbus_remove(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 0);
cancel_delayed_work_sync(&gpio_vbus->work);
+ /* POC-WITNESS: widen the re-arm window so the reproducer's
+ * interrupt lands reliably between the cancel and the devm
+ * release. Not part of the bug; logic unchanged.
+ */
+ msleep(500);
+
usb_remove_phy(&gpio_vbus->phy);
}
and for the patched control run, the fix plus the same window:
diff --git a/drivers/usb/phy/phy-gpio-vbus-usb.c b/drivers/usb/phy/phy-gpio-vbus-usb.c
index ce09e789afd8..25e0dcd36b34 100644
--- a/drivers/usb/phy/phy-gpio-vbus-usb.c
+++ b/drivers/usb/phy/phy-gpio-vbus-usb.c
@@ -330,8 +330,15 @@ static void gpio_vbus_remove(struct platform_device *pdev)
struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
device_init_wakeup(&pdev->dev, 0);
+
+ devm_free_irq(&pdev->dev, gpio_vbus->irq, pdev);
cancel_delayed_work_sync(&gpio_vbus->work);
+ /* POC-WITNESS: same artificial window as the vuln run, to show
+ * the fix closes it.
+ */
+ msleep(500);
+
usb_remove_phy(&gpio_vbus->phy);
}
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v2 4/4] usb: phy: gpio-vbus: free the interrupt before cancelling the work
2026-11-13 6:34 ` [PATCH v2 4/4] usb: phy: gpio-vbus: free the interrupt before cancelling the work Chengyu Liu
@ 2026-11-13 6:40 ` sashiko-bot
0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-11-13 6:40 UTC (permalink / raw)
To: Chengyu Liu, linux-usb
> gpio_vbus_remove() cancels gpio_vbus->work while the VBUS sensing GPIO
> interrupt is still live: it is devm-managed and freed only at detach,
> and gpio_vbus_irq() schedules the work with a 100 ms debounce delay.
> A plug event landing after the cancel re-arms the work, and its timer
> then fires on the freed gpio_vbus_data.
>
> Free the interrupt first, which also waits for any running handler,
> so nothing can re-arm the work past the cancel.
>
> Found by static analysis and confirmed with a KASAN reproducer:
> slab-use-after-free write in __run_timer_base() within one debounce
> interval of unregistering the device while its VBUS GPIO is toggled
> (object allocated by gpio_vbus_probe() via devm_kmalloc(), freed by
> devres_release_all() at unbind).
>
> Fixes: c2344f13b59e ("USB: gpio_vbus: add delayed vbus_session calls")
> Cc: stable@vger.kernel.org
> Reviewed-by: Neill Kapron <nkapron@google.com>
> Signed-off-by: Chengyu Liu <lui2012qwq@gmail.com>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261113063409.47485-1-lui2012qwq@gmail.com?part=4
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 3/4] usb: gadget: r8a66597: free the IRQ before deleting the timer
2026-11-13 6:34 ` [PATCH v2 3/4] usb: gadget: r8a66597: free the IRQ before deleting the timer Chengyu Liu
@ 2026-11-13 6:48 ` sashiko-bot
0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-11-13 6:48 UTC (permalink / raw)
To: Chengyu Liu, linux-usb
> r8a66597_remove() deletes r8a66597->timer while the interrupt is
> still live: the IRQ is devm-managed and only freed at detach, and
> r8a66597_irq() re-arms the timer when sampling VBUS (VBINT). An
> interrupt landing after timer_delete_sync() re-arms the timer, and
> r8a66597_timer() then runs on freed memory.
>
> Store the requested IRQ number at probe time and free it before
> deleting the timer; freeing also waits for any running handler, so
> nothing can re-arm the timer past the delete.
>
> Found by static analysis.
>
> Fixes: c41442474a26 ("usb: gadget: R8A66597 peripheral controller support.")
> Cc: stable@vger.kernel.org
> Reviewed-by: Neill Kapron <nkapron@google.com>
> Signed-off-by: Chengyu Liu <lui2012qwq@gmail.com>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261113063409.47485-1-lui2012qwq@gmail.com?part=3
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 2/4] usb: musb: dsps: free the VBUS interrupt before the child teardown
2026-11-13 6:34 ` [PATCH v2 2/4] usb: musb: dsps: free the VBUS interrupt before the child teardown Chengyu Liu
@ 2026-11-13 6:48 ` sashiko-bot
0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-11-13 6:48 UTC (permalink / raw)
To: Chengyu Liu, linux-usb
> dsps_remove() unregisters the musb child, which deletes
> musb->dev_timer and frees the structure, while the glue's VBUS
> interrupt is devm-managed and only freed after dsps_remove() returns.
> dsps_vbus_threaded_irq() re-arms the timer via dsps_mod_timer(), so
> a VBUS event in between re-arms dev_timer past its deletion and
> otg_timer() runs on freed memory.
>
> Free the VBUS interrupt first, which also waits for any in-flight
> handler, so nothing can re-arm the timer once the child teardown
> runs.
>
> Found by static analysis.
>
> Fixes: 369469a92393 ("usb: musb: Add support for optional VBUS irq to dsps glue layer")
> Cc: stable@vger.kernel.org
> Reviewed-by: Neill Kapron <nkapron@google.com>
> Signed-off-by: Chengyu Liu <lui2012qwq@gmail.com>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261113063409.47485-1-lui2012qwq@gmail.com?part=2
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 1/4] usb: musb: cancel the delayed works after quiescing the interrupt
2026-11-13 6:34 ` [PATCH v2 1/4] usb: musb: cancel the delayed works after quiescing the interrupt Chengyu Liu
@ 2026-11-13 6:56 ` sashiko-bot
0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-11-13 6:56 UTC (permalink / raw)
To: Chengyu Liu, linux-usb
> musb_remove() cancels finish_resume_work and deassert_reset_work up
> front, while the interrupt is still enabled and the root hub is still
> registered, and cancels irq_work only later. All three works can be
> armed past their cancel:
>
> - musb_handle_intr_resume() schedules finish_resume_work from
> interrupt context (RESUME in OTG_STATE_A_SUSPEND, via
> musb_stage0_irq());
> - musb_hub_control() schedules finish_resume_work (ClearPortFeature
> SUSPEND -> musb_port_suspend()) and deassert_reset_work
> (SetPortFeature RESET -> musb_port_reset()) from process context,
> and the root hub is only torn down by musb_host_cleanup();
> - musb_stage0_irq() schedules irq_work, which can also re-arm itself
> from the session recheck path (musb_pm_runtime_check_session()).
>
> [ ... ]
>
> Suggested-by: Neill Kapron <nkapron@google.com>
> Fixes: f730f205cc51 ("usb: musb: Split PM runtime between wrapper IP and musb core")
> Cc: stable@vger.kernel.org
> Signed-off-by: Chengyu Liu <lui2012qwq@gmail.com>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261113063409.47485-1-lui2012qwq@gmail.com?part=1
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-11-13 6:56 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-13 6:34 [PATCH v2 0/4] usb: stop timers/works left armed on teardown Chengyu Liu
2026-11-13 6:34 ` [PATCH v2 1/4] usb: musb: cancel the delayed works after quiescing the interrupt Chengyu Liu
2026-11-13 6:56 ` sashiko-bot
2026-11-13 6:34 ` [PATCH v2 2/4] usb: musb: dsps: free the VBUS interrupt before the child teardown Chengyu Liu
2026-11-13 6:48 ` sashiko-bot
2026-11-13 6:34 ` [PATCH v2 3/4] usb: gadget: r8a66597: free the IRQ before deleting the timer Chengyu Liu
2026-11-13 6:48 ` sashiko-bot
2026-11-13 6:34 ` [PATCH v2 4/4] usb: phy: gpio-vbus: free the interrupt before cancelling the work Chengyu Liu
2026-11-13 6:40 ` sashiko-bot
2026-11-13 6:36 ` [PATCH v2 0/4] usb: stop timers/works left armed on teardown Chengyu Liu
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.