[PATCH] usb: renesas_usbhs: fix race between device remove and ISR
From: UAF Researcher
Date: Mon Mar 02 2026 - 19:47:25 EST
From: Fan Wu <fanwu01@xxxxxxxxxx>
In usbhs_remove(), the pipe array info->pipe is freed by calling
usbhs_pipe_remove(priv). However, the interrupt handler usbhs_interrupt()
is registered using devm_request_irq(). The devres cleanup, which
includes freeing the IRQ, happens after usbhs_remove() returns.
If a hardware interrupt fires or a pending ISR executes after
usbhs_pipe_remove() but before devres cleanup, the ISR will access the
freed info->pipe array via the usbhs_for_each_pipe_with_dcp() macro,
leading to a slab-use-after-free.
The race window can be illustrated as:
CPU 0 (remove path) CPU 1 (ISR context)
--------------------- ---------------------
usbhs_remove()
usbhs_pipe_remove()
kfree(info->pipe) <--+
|
| usbhs_interrupt()
| usbhsf_irq_empty()
| usbhs_for_each_pipe_with_dcp()
| access pipe->pipe_type <-- UAF!
...
return
(devres cleanup frees IRQ too late)
Fix this by explicitly calling disable_irq() before freeing the pipe
array in usbhs_remove(), ensuring that no ISR can run and access the
freed memory.
KASAN report:
BUG: KASAN: slab-use-after-free in usbhsf_irq_empty+0x1c4/0x210 [renesas_usbhs]
Read of size 4 at addr ffff88800d3d3d00 by task swapper/0/0
Call Trace:
<IRQ>
dump_stack_lvl+0x68/0xa0
kasan_report+0xca/0x100
usbhs_for_each_pipe_with_dcp+... [renesas_usbhs]
usbhsf_irq_empty+... [renesas_usbhs]
usbhs_interrupt+... [renesas_usbhs]
</IRQ>
Allocated by task 70:
kcalloc+0x52/0xb0
usbhs_pipe_probe+0xed/0x4f0 [renesas_usbhs]
usbhs_probe+0xa3e/0xf40 [renesas_usbhs]
...
Freed by task 70:
kfree+0x12c/0x350
usbhs_pipe_remove+0x41/0x60 [renesas_usbhs]
usbhs_remove+0x1a1/0x1f0 [renesas_usbhs]
device_release_driver_internal+0x371/0x540
...
Fixes: f1407d5c6624 ("usb: renesas_usbhs: Add Renesas USBHS common code")
Signed-off-by: Fan Wu <fanwu01@xxxxxxxxxx>
---
Note for reviewers:
Due to the difficulty of precisely controlling hardware interrupt timing
for physical hot-unplug, I verified this race condition dynamically.
I wrote a software harness that injects a delay in usbhs_remove() and
simulates the ISR accessing the pipe array via a high-frequency timer
in QEMU. This reliably triggers the KASAN Use-After-Free trace shown
in the commit message, confirming the vulnerability.
drivers/usb/renesas_usbhs/common.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index cf4a0367d..404220ceb 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -815,6 +815,10 @@ static void usbhs_remove(struct platform_device *pdev)
usbhs_platform_call(priv, hardware_exit, pdev);
reset_control_assert(priv->rsts);
+
+ /* Disable IRQ before freeing resources to prevent UAF in ISR */
+ disable_irq(priv->irq);
+
usbhs_mod_remove(priv);
usbhs_fifo_remove(priv);
usbhs_pipe_remove(priv);
--
2.34.1