From: Sasha Levin <sashal@kernel.org>
To: patches@lists.linux.dev, stable@vger.kernel.org
Cc: Mario Peter <mario.peter@leica-geosystems.com>,
Xu Yang <xu.yang_2@nxp.com>, Peter Chen <peter.chen@kernel.org>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Sasha Levin <sashal@kernel.org>,
linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH AUTOSEL 6.19-6.12] usb: chipidea: udc: fix DMA and SG cleanup in _ep_nuke()
Date: Wed, 18 Feb 2026 21:03:38 -0500 [thread overview]
Message-ID: <20260219020422.1539798-2-sashal@kernel.org> (raw)
In-Reply-To: <20260219020422.1539798-1-sashal@kernel.org>
From: Mario Peter <mario.peter@leica-geosystems.com>
[ Upstream commit cea2a1257a3b5ea3e769a445b34af13e6aa5a123 ]
The ChipIdea UDC driver can encounter "not page aligned sg buffer"
errors when a USB device is reconnected after being disconnected
during an active transfer. This occurs because _ep_nuke() returns
requests to the gadget layer without properly unmapping DMA buffers
or cleaning up scatter-gather bounce buffers.
Root cause:
When a disconnect happens during a multi-segment DMA transfer, the
request's num_mapped_sgs field and sgt.sgl pointer remain set with
stale values. The request is returned to the gadget driver with status
-ESHUTDOWN but still has active DMA state. If the gadget driver reuses
this request on reconnect without reinitializing it, the stale DMA
state causes _hardware_enqueue() to skip DMA mapping (seeing non-zero
num_mapped_sgs) and attempt to use freed/invalid DMA addresses,
leading to alignment errors and potential memory corruption.
The normal completion path via _hardware_dequeue() properly calls
usb_gadget_unmap_request_by_dev() and sglist_do_debounce() before
returning the request. The _ep_nuke() path must do the same cleanup
to ensure requests are returned in a clean, reusable state.
Fix:
Add DMA unmapping and bounce buffer cleanup to _ep_nuke() to mirror
the cleanup sequence in _hardware_dequeue():
- Call usb_gadget_unmap_request_by_dev() if num_mapped_sgs is set
- Call sglist_do_debounce() with copy=false if bounce buffer exists
This ensures that when requests are returned due to endpoint shutdown,
they don't retain stale DMA mappings. The 'false' parameter to
sglist_do_debounce() prevents copying data back (appropriate for
shutdown path where transfer was aborted).
Signed-off-by: Mario Peter <mario.peter@leica-geosystems.com>
Reviewed-by: Xu Yang <xu.yang_2@nxp.com>
Acked-by: Peter Chen <peter.chen@kernel.org>
Link: https://patch.msgid.link/20260108165902.795354-1-mario.peter@leica-geosystems.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
This confirms:
1. `usb_gadget_unmap_request_by_dev()` at line 966 sets
`req->num_mapped_sgs = 0` - this is exactly what's needed to clear
the stale state
2. It also does `dma_unmap_sg()` at line 963 to properly unmap the DMA
buffers
3. Without this call in `_ep_nuke()`, the request is given back with
active DMA mappings and stale `num_mapped_sgs`
## 3. Assessment
### What the commit fixes:
- **DMA resource leak**: Requests returned via `_ep_nuke()` during
disconnect have active DMA mappings that are never unmapped, leaking
DMA resources
- **Stale state causing corruption**: The `num_mapped_sgs` field remains
non-zero, causing `_hardware_enqueue()` to skip DMA mapping on reuse
and instead use freed/invalid DMA addresses
- **Memory corruption**: Invalid DMA addresses lead to "not page aligned
sg buffer" errors and potential memory corruption
- **Bounce buffer leak**: SG bounce buffers (`sgt.sgl`) allocated via
`sglist_do_bounce()` are never freed, leaking memory
### Stable kernel criteria:
1. **Obviously correct**: The fix mirrors exactly what
`_hardware_dequeue()` (line 886-891) and `ep_dequeue()` (line
1738-1741) already do. It's a well-established pattern within the
same file.
2. **Fixes a real bug**: DMA corruption and resource leaks on USB
disconnect during active transfer.
3. **Important issue**: Memory corruption, stale DMA addresses,
potential data corruption.
4. **Small and contained**: Only 6 lines added, all within a single
function in a single file.
5. **No new features**: Pure bug fix.
### Risk assessment:
- **Very low risk**: The added code calls well-known cleanup functions
that are already called in the two other completion paths
(`_hardware_dequeue` and `ep_dequeue`). The `false` parameter to
`sglist_do_debounce` is appropriate as no data needs to be copied back
during shutdown.
- The `usb_gadget_unmap_request_by_dev()` call is safe even if no DMA
was mapped (it checks `req->length == 0`, `sg_was_mapped`, and
`num_mapped_sgs` before doing anything).
### Dependency consideration:
- The `sglist_do_debounce()` function was introduced in v6.13 (commit
edfcc455c85cc). For stable trees older than 6.13, only the
`usb_gadget_unmap_request_by_dev()` line would apply (the
`sglist_do_debounce` part would need to be dropped). However, the DMA
unmap portion is independently valuable.
- The `usb_gadget_unmap_request_by_dev()` function has existed for a
long time and is available in all active stable trees.
### Reviews/Acks:
- Reviewed-by: Xu Yang (NXP engineer, author of the bounce buffer code)
- Acked-by: Peter Chen (ChipIdea UDC subsystem maintainer)
- Applied by: Greg Kroah-Hartman (USB maintainer)
## Verification
- **Verified** `_hardware_dequeue()` at lines 886-891 performs the same
cleanup (DMA unmap + sglist debounce) - confirmed by reading the file
- **Verified** `ep_dequeue()` at lines 1738-1741 also performs the same
cleanup pattern - confirmed by reading the file
- **Verified** `usb_gadget_unmap_request_by_dev()` in
`drivers/usb/gadget/udc/core.c:956-972` clears `num_mapped_sgs` to 0
(line 966) and unmaps DMA - confirmed by reading the source
- **Verified** `_ep_nuke()` is called from multiple paths: disconnect
(line 1108), endpoint reset (lines 1326-1327), endpoint disable (line
1615) - confirmed by grep
- **Verified** `sglist_do_debounce()` was introduced in commit
`edfcc455c85cc` which first appeared in v6.13 - confirmed via `git tag
--contains`
- **Verified** the commit is self-contained: no other patches needed for
the fix to work in trees with v6.13+
- **Verified** commit has proper review: Reviewed-by (Xu Yang, bounce
buffer author), Acked-by (Peter Chen, subsystem maintainer)
- **Verified** `_hardware_enqueue()` at line 708 checks `num_mapped_sgs`
to decide whether to skip DMA mapping - this is the code path that
breaks when stale state remains
## Conclusion
This is a textbook stable backport candidate:
- Fixes a real, user-triggerable bug (USB disconnect during active
transfer)
- Causes memory corruption and DMA errors
- Small, surgical fix (6 lines added)
- Mirrors existing cleanup patterns already in the same file
- Reviewed and acked by subsystem experts
- Very low regression risk
- Affects real hardware users (ChipIdea UDC is used in NXP i.MX SoCs,
common in embedded/IoT)
**YES**
drivers/usb/chipidea/udc.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 64a421ae0f05b..c8d931d9d4330 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -931,6 +931,13 @@ __acquires(hwep->lock)
list_del_init(&hwreq->queue);
hwreq->req.status = -ESHUTDOWN;
+ /* Unmap DMA and clean up bounce buffers before giving back */
+ usb_gadget_unmap_request_by_dev(hwep->ci->dev->parent,
+ &hwreq->req, hwep->dir);
+
+ if (hwreq->sgt.sgl)
+ sglist_do_debounce(hwreq, false);
+
if (hwreq->req.complete != NULL) {
spin_unlock(hwep->lock);
usb_gadget_giveback_request(&hwep->ep, &hwreq->req);
--
2.51.0
next prev parent reply other threads:[~2026-02-19 2:04 UTC|newest]
Thread overview: 45+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-19 2:03 [PATCH AUTOSEL 6.19] rust_binder: Fix build failure if !CONFIG_COMPAT Sasha Levin
2026-02-19 2:03 ` Sasha Levin [this message]
2026-02-19 2:03 ` [PATCH AUTOSEL 6.19-5.15] staging: rtl8723bs: fix memory leak on failure path Sasha Levin
2026-02-19 2:03 ` [PATCH AUTOSEL 6.19] tty: vt/keyboard: Split apart vt_do_diacrit() Sasha Levin
2026-02-19 2:03 ` [PATCH AUTOSEL 6.19-5.10] fix it87_wdt early reboot by reporting running timer Sasha Levin
2026-02-19 2:03 ` [PATCH AUTOSEL 6.19-5.15] misc: eeprom: Fix EWEN/EWDS/ERAL commands for 93xx56 and 93xx66 Sasha Levin
2026-02-19 2:03 ` [PATCH AUTOSEL 6.19-5.15] mmc: rtsx_pci: add quirk to disable MMC_CAP_AGGRESSIVE_PM for RTS525A Sasha Levin
2026-02-19 10:29 ` Ulf Hansson
2026-02-26 13:23 ` Sasha Levin
2026-02-19 2:03 ` [PATCH AUTOSEL 6.19-6.1] fpga: of-fpga-region: Fail if any bridge is missing Sasha Levin
2026-02-19 2:03 ` [PATCH AUTOSEL 6.19-6.12] soundwire: intel_auxdevice: add cs42l45 codec to wake_capable_list Sasha Levin
2026-02-19 2:03 ` [PATCH AUTOSEL 6.19-5.10] iio: magnetometer: Remove IRQF_ONESHOT Sasha Levin
2026-02-19 2:03 ` [PATCH AUTOSEL 6.19-6.1] watchdog: imx7ulp_wdt: handle the nowayout option Sasha Levin
2026-02-19 2:03 ` [PATCH AUTOSEL 6.19-5.10] serial: 8250_dw: handle clock enable errors in runtime_resume Sasha Levin
2026-02-19 2:03 ` [PATCH AUTOSEL 6.19-6.12] most: core: fix resource leak in most_register_interface error paths Sasha Levin
2026-02-19 2:03 ` [PATCH AUTOSEL 6.19] block: fix partial IOVA mapping cleanup in blk_rq_dma_map_iova Sasha Levin
2026-02-19 2:03 ` [PATCH AUTOSEL 6.19-6.1] misc: bcm_vk: Fix possible null-pointer dereferences in bcm_vk_read() Sasha Levin
2026-02-19 2:03 ` [PATCH AUTOSEL 6.19-6.1] dmaengine: sun6i: Choose appropriate burst length under maxburst Sasha Levin
2026-02-19 2:03 ` [PATCH AUTOSEL 6.19-6.1] mmc: rtsx: reset power state on suspend Sasha Levin
2026-02-19 10:27 ` Ulf Hansson
2026-02-26 13:24 ` Sasha Levin
2026-02-19 2:03 ` [PATCH AUTOSEL 6.19] serial: rsci: Add set_rtrg() callback Sasha Levin
2026-02-19 2:03 ` [PATCH AUTOSEL 6.19-5.10] Revert "mfd: da9052-spi: Change read-mask to write-mask" Sasha Levin
2026-02-19 2:03 ` [PATCH AUTOSEL 6.19-6.18] pinctrl: mediatek: make devm allocations safer and clearer in mtk_eint_do_init() Sasha Levin
2026-02-19 2:03 ` [PATCH AUTOSEL 6.19-6.12] serial: 8250: 8250_omap.c: Add support for handling UART error conditions Sasha Levin
2026-02-19 2:03 ` [PATCH AUTOSEL 6.19-6.12] usb: gadget: f_fs: Fix ioctl error handling Sasha Levin
2026-02-19 2:03 ` [PATCH AUTOSEL 6.19-6.12] phy: cadence-torrent: restore parent clock for refclk during resume Sasha Levin
2026-02-19 2:04 ` [PATCH AUTOSEL 6.19-5.10] binder: don't use %pK through printk Sasha Levin
2026-02-19 2:04 ` [PATCH AUTOSEL 6.19-6.18] iio: bmi270_i2c: Add MODULE_DEVICE_TABLE for BMI260/270 Sasha Levin
2026-02-19 2:04 ` [PATCH AUTOSEL 6.19-5.15] iio: Use IRQF_NO_THREAD Sasha Levin
2026-02-19 2:04 ` [PATCH AUTOSEL 6.19-6.12] mfd: intel-lpss: Add Intel Nova Lake-S PCI IDs Sasha Levin
2026-02-19 2:04 ` [PATCH AUTOSEL 6.19-6.12] phy: ti: phy-j721e-wiz: restore mux selection during resume Sasha Levin
2026-02-19 2:04 ` [PATCH AUTOSEL 6.19-5.10] MIPS: Loongson: Make cpumask_of_node() robust against NUMA_NO_NODE Sasha Levin
2026-02-19 2:04 ` [PATCH AUTOSEL 6.19-6.12] usb: gadget: f_fs: fix DMA-BUF OUT queues Sasha Levin
2026-02-19 2:04 ` [PATCH AUTOSEL 6.19-5.10] phy: fsl-imx8mq-usb: disable bind/unbind platform driver feature Sasha Levin
2026-02-19 2:04 ` [PATCH AUTOSEL 6.19-6.18] watchdog: rzv2h_wdt: Discard pm_runtime_put() return value Sasha Levin
2026-02-19 2:04 ` [PATCH AUTOSEL 6.19-6.1] soundwire: dmi-quirks: add mapping for Avell B.ON (OEM rebranded of NUC15) Sasha Levin
2026-02-19 2:04 ` [PATCH AUTOSEL 6.19-6.18] pinctrl: renesas: rzt2h: Allow .get_direction() for IRQ function GPIOs Sasha Levin
2026-02-19 2:04 ` [PATCH AUTOSEL 6.19-6.12] dmaengine: stm32-dma3: use module_platform_driver Sasha Levin
2026-02-19 2:04 ` [PATCH AUTOSEL 6.19-5.15] staging: rtl8723bs: fix missing status update on sdio_alloc_irq() failure Sasha Levin
2026-02-19 2:04 ` [PATCH AUTOSEL 6.19-5.15] phy: mvebu-cp110-utmi: fix dr_mode property read from dts Sasha Levin
2026-02-19 2:04 ` [PATCH AUTOSEL 6.19-6.1] usb: typec: ucsi: psy: Fix voltage and current max for non-Fixed PDOs Sasha Levin
2026-02-19 2:04 ` [PATCH AUTOSEL 6.19-5.10] serial: 8250: 8250_omap.c: Clear DMA RX running status only after DMA termination is done Sasha Levin
2026-02-19 2:04 ` [PATCH AUTOSEL 6.19-6.1] dmaengine: stm32-mdma: initialize m2m_hw_period and ccr to fix warnings Sasha Levin
2026-02-19 2:04 ` [PATCH AUTOSEL 6.19-6.18] misc: ti_fpc202: fix a potential memory leak in probe function Sasha Levin
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=20260219020422.1539798-2-sashal@kernel.org \
--to=sashal@kernel.org \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=mario.peter@leica-geosystems.com \
--cc=patches@lists.linux.dev \
--cc=peter.chen@kernel.org \
--cc=stable@vger.kernel.org \
--cc=xu.yang_2@nxp.com \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox