* [PATCH AUTOSEL 6.18-5.15] dmaengine: dw-axi-dmac: fix __le32 on set of CH_CTL_H_LLI_VALID
[not found] <20261019135441.1420968-1-sashal@kernel.org>
@ 2026-10-19 13:52 ` Sasha Levin
2026-10-19 13:53 ` [PATCH AUTOSEL 6.18-5.10] dmaengine: pl330: remove debugfs file on teardown Sasha Levin
1 sibling, 0 replies; 2+ messages in thread
From: Sasha Levin @ 2026-10-19 13:52 UTC (permalink / raw)
To: patches, stable
Cc: Ben Dooks, Vinod Koul, Sasha Levin, Eugeniy.Paltsev, dmaengine,
linux-kernel
From: Ben Dooks <ben.dooks@codethink.co.uk>
[ Upstream commit 89aba9c39bdda8a973a6ffed7c9e93321edcfc16 ]
When writing the lli->ctl_hi, this is an __le32 type so the
value being orred should be convered to __le32 by cpu_to_le32.
Fixes 1deb96c0fa58a ("dmaegine: dw-axi-dmac: Support device_prep_dma_cyclic()")
--
Note, the call to axi_chan_irq_clear() is passing lli->status_lo
through which is also an __le32 but it does not seem to be set
anywhere. Is this also a bug?
Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
Link: https://patch.msgid.link/20260617084944.705266-1-ben.dooks@codethink.co.uk
Signed-off-by: Vinod Koul <vkoul@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable backport analysis: `89aba9c39bdda` (`dmaengine: dw-axi-dmac:
fix __le32 on set of CH_CTL_H_LLI_VALID`)
Local tree: **v7.3-rc4** (`7.3.0-rc4`, detached HEAD `f0100363d8c37`).
The cyclic DW AXI DMA path exists here (introduced in v5.12). Decision
is for this checkout only.
---
## PHASE 1: COMMIT MESSAGE FORENSICS
**Step 1.1: PARSE THE SUBJECT LINE**
Record: **[dmaengine / dw-axi-dmac] [fix] [endian-convert
`CH_CTL_H_LLI_VALID` before OR into `__le32` `lli->ctl_hi`]**
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Record:
- `Fixes 1deb96c0fa58a ("dmaegine: dw-axi-dmac: Support
device_prep_dma_cyclic()")` — malformed (`Fixes` missing the colon),
so it would not auto-route to stable. SHA is real:
`1deb96c0fa58afe0f5c4aa8e5916baa9454979d6`.
- `Link: https://patch.msgid.link/20260617084944.705266-1-
ben.dooks@codethink.co.uk`
- `Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>` (author)
- `Signed-off-by: Vinod Koul <vkoul@kernel.org>` (dmaengine maintainer)
- No `Reported-by`, `Tested-by`, `Reviewed-by`, `Acked-by`, `Cc:
stable`, syzbot, or CVE.
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- **Bug:** `lli->ctl_hi` is `__le32`; the cyclic completion path ORs in
host-endian `CH_CTL_H_LLI_VALID` (`BIT(31)`).
- **Symptom:** On a big-endian CPU the LLI_VALID bit is written as the
wrong byte, so the DMA engine does not see the descriptor as valid
when cyclic transfers re-arm. Little-endian is a no-op (`cpu_to_le32`
is identity).
- **Version:** Introduced with cyclic support (`1deb96c0fa58a`,
v5.12-rc1).
- **Side note in the message:** `axi_chan_irq_clear(chan,
lli->status_lo)` also passes `__le32` as `u32`; that is a separate
pre-existing issue, not changed here.
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: **Not hidden.** Subject and body say “fix”. Author later told
Frank Li this was a **sparse `__le32` cast warning**; that is still a
real endian/type bug in a hardware LLI, not style cleanup.
---
## PHASE 2: DIFF ANALYSIS
**Step 2.1: INVENTORY THE CHANGES**
Record:
- File: `drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c` (`1` insertion,
`1` deletion)
- Function: `axi_chan_block_xfer_complete()`
- Scope: **single-file, 1-line surgical fix**
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Record: Cyclic IRQ path only (`chan->cyclic`). After matching the
current LLP, the old code did `hw_desc->lli->ctl_hi |=
CH_CTL_H_LLI_VALID`. New code uses `|= cpu_to_le32(CH_CTL_H_LLI_VALID)`.
Non-cyclic completion is unchanged.
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record: **(f) Type / endianness.** `struct axi_dma_lli.ctl_hi` is
`__le32`; `CH_CTL_H_LLI_VALID` is `BIT(31)` in `dw-axi-dmac.h`.
Descriptor setup already stores `ctl_hi` with `cpu_to_le32()`
(`dw_axi_dma_set_hw_desc()` ~line 715, memcpy path ~line 985). This
cyclic re-arm was the missed conversion from `1deb96c0fa58a`.
On BE, `|= BIT(31)` stores `80 00 00 00`; the LE engine reads `BIT(7)`
instead of bit 31, so LLI_VALID is not set and the cyclic ring does not
restart.
**Step 2.4: ASSESS THE FIX QUALITY**
Record: **Obviously correct** and consistent with every other `ctl_hi`
store in the file. Minimal. LE codegen is unchanged. No
API/locking/refcount change. Does not fix the `status_lo` IRQ-clear
question; that does not make this line wrong.
---
## PHASE 3: GIT HISTORY INVESTIGATION
**Step 3.1: BLAME THE CHANGED LINES**
Record: Cyclic block and the original `|= CH_CTL_H_LLI_VALID` are from
**`1deb96c0fa58a` (Sia Jee Heng, 2021-01-25)**. First contained in
**v5.12-rc1**. Long-lived, not recent.
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: `1deb96c0fa58a` added `device_prep_dma_cyclic()` (ALSA-style
cyclic DMA). It is an ancestor of HEAD (`git merge-base --is-ancestor`
exit 0). No later LLI_VALID fix besides this commit.
**Step 3.3: CHECK FILE HISTORY**
Record: Recent work is PM, CV1800B, StarFive, per-channel IRQ — none of
it is a prerequisite for this one-line OR. **Standalone**, not `patch
X/Y`.
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: Ben Dooks has prior dw-axi-dmac fixes (`ignore interrupt if no
descriptor`, `do not print NULL LLI`). Not the subsystem maintainer;
Vinod Koul applied it.
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record: Needs cyclic support (`chan->cyclic`, `hw_desc->lli->ctl_hi`).
That is in this tree since v5.12. **Applies standalone.**
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- Lore / msgid: https://patch.msgid.link/20260617084944.705266-1-
ben.dooks@codethink.co.uk
- **v1 only** (`b4 dig -a`); committed version is that v1
(`89aba9c39bdda`).
- Frank Li: asked whether it would pass sparse.
- Ben Dooks: *“This was fixing a __le32 cast warning from sparse, forgot
to put the actual warning in the commit message.”*
- Vinod Koul: **Applied, thanks!** No NAK, no `Cc: stable` request.
- Sashiko bot flagged **pre-existing** issues (`status_lo`,
`descs_allocated` vs `nr_hw_descs`, cyclic period math) — not
introduced by this patch.
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record (`b4 dig -w`): Ben Dooks, Eugeniy Paltsev (Synopsys / binding
maintainer), Vinod Koul, Frank Li, `dmaengine@vger.kernel.org`, `linux-
kernel@vger.kernel.org`. Maintainer applied it. Frank commented; no
formal Reviewed-by.
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record: **No user bugzilla/syzbot report.** Trigger was sparse, not a
field crash. Direct lore fetch of the msgid returned 403; the full
thread was recovered via `b4 dig -m`.
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: Standalone. Author asked about `status_lo`; that was **not**
patched here and is not required for this conversion.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: Web search of lore stable for this subject did not turn up a
prior stable discussion or an explicit rejection. **UNVERIFIED** that
every stable archive was exhaustively scanned (lore HTML is 403 /
Anubis-protected).
---
## PHASE 5: CODE SEMANTIC ANALYSIS
**Step 5.1: KEY FUNCTIONS**
Record: `axi_chan_block_xfer_complete()` (modified). Related:
`dw_axi_dma_interrupt()`, `dw_axi_dma_chan_prep_cyclic()`,
`dw_axi_dma_set_hw_desc()`.
**Step 5.2: TRACE CALLERS**
Record: Only caller is `dw_axi_dma_interrupt()` when
`DWAXIDMAC_IRQ_DMA_TRF` is set. Same handler is registered from probe
(`devm_request_irq`). **IRQ context.** Userspace reaches it via
dmaengine cyclic prep (ALSA and other slave cyclic clients).
**Step 5.3: TRACE CALLEES**
Record: `axi_chan_irq_clear()`, `vchan_cyclic_callback()`,
`axi_chan_enable()`, `vchan_next_desc()`. The important store is into
the DMA-visible LLI.
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: userspace cyclic DMA → `dw_axi_dma_chan_prep_cyclic` (sets
LLI_VALID via `cpu_to_le32`, `set_desc_last`) → HW completes a block →
IRQ → re-set LLI_VALID → `axi_chan_enable`. **Reachable from userspace**
on boards that use this DMAC for cyclic audio/peripheral DMA.
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: Every other `ctl_hi` assignment already uses `cpu_to_le32()`.
This was the remaining `|=` of a host `BIT()` into `__le32`. No sibling
driver copy of this exact bug was searched beyond this file.
---
## PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record: **Yes, in this lineage.** Cyclic path is present; the bug was
the missing `cpu_to_le32` on the re-arm OR, from **v5.12**. Current HEAD
already has the fixed line (`ctl_hi |= cpu_to_le32(CH_CTL_H_LLI_VALID)`
at line 1129). Introduced after 5.12, long before 7.3.
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: Surrounding cyclic IRQ code is still the 2021 structure. **Clean
apply** on a tree that still has the unconverted `|=`. No conflicting
refactor in this function.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: This exact conversion is the only LLI_VALID endian fix. No
alternate fix. Presence of `89aba9c39bdda` on 7.3-rc4 is expected for a
mainline commit and is **not** treated as “already selected for stable.”
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
**Step 7.1: SUBSYSTEM AND CRITICALITY**
Record: **dmaengine / Synopsys DW AXI DMAC** (`CONFIG_DW_AXI_DMAC`).
**IMPORTANT** for those SoCs, not core mm/VFS. In-tree users: StarFive
JH7110/JH8100, Intel Keem Bay / Agilex5, Sophgo CV1800B/SG2044, T-Head
TH1520, Canaan K210, **ARC HSDK** (`CONFIG_DW_AXI_DMAC=y` in
`hsdk_defconfig`).
**Step 7.2: SUBSYSTEM ACTIVITY**
Record: Actively maintained (StarFive, Sophgo, PM, per-channel IRQ).
Cyclic completion itself has been stable since 2021.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
**Step 8.1: WHO IS AFFECTED**
Record: **Driver-specific**, plus **endian-specific**. Production DTs
are RISC-V/ARM64 (LE), where this is a no-op. ARC can be built
`CPU_BIG_ENDIAN`; HSDK defconfig is LE but BE ARC + this IP is a valid
config. Cyclic clients (ALSA) are the functional path.
**Step 8.2: TRIGGER CONDITIONS**
Record: Cyclic DMA block-complete IRQ. Common on audio; unused if the
channel is memcpy-only. Unprivileged users can trigger it if they have
the PCM/DMA device. Not a race.
**Step 8.3: FAILURE MODE SEVERITY**
Record: On BE, LLI_VALID is not set → cyclic DMA does not re-arm →
**audio/DMA stall or dropped periods**, not an oops. On LE, **no runtime
change**. Severity: **MEDIUM** on BE, **none** on LE. Not
UAF/panic/corruption.
**Step 8.4: RISK-BENEFIT RATIO**
Record:
- **Benefit:** Restores cyclic DMA descriptor validity on BE; matches
the rest of the driver; zero LE behavior change.
- **Risk:** Very low (1 line, standard conversion).
- **Ratio:** Favorable. The strict “crash/security/deadlock” bar is not
met; the recognized **endianness/type** class and zero regression risk
still make it appropriate.
---
## PHASE 9: FINAL SYNTHESIS
**Step 9.1: COMPILE THE EVIDENCE**
**FOR:**
- Real `__le32` vs host `BIT(31)` mismatch in a DMA-visible LLI.
- Same file already converts every other `ctl_hi` store.
- Bug present since v5.12 cyclic support; that commit is in this tree.
- 1 line, obviously correct, maintainer-applied.
- BE cyclic DMA would fail to re-validate descriptors.
- Standalone; no new API.
**AGAINST:**
- Author described it as a sparse warning; no user/syzbot report.
- In-tree boards are LE, so this is a no-op for typical 7.3 users of
JH7110/Keem Bay/Sophgo.
- Not a crash, UAF, deadlock, or security issue.
- `status_lo` concern left unfixed (out of scope).
**UNRESOLVED:** Exhaustive stable-list search (lore 403). Exact sparse
warning text was never pasted in the commit.
**Step 9.2: STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — matches existing stores;
applied by Vinod Koul. No extra Tested-by.
2. Fixes a real bug that affects users? **PASS** — wrong LLI bit on BE;
type-incorrect on all builds.
3. Important issue? **PASS (low end of the bar)** — functional cyclic
DMA failure on BE, not a panic. Endianness/type fixes of this shape
are accepted stable material; this is not a warning-only whitespace
change.
4. Small and contained? **PASS** — 1 line, one function.
5. No new features or APIs? **PASS**
6. Can apply to the local tree? **PASS** — cyclic path and `Fixes:`
target exist; context is unchanged.
**Step 9.3: EXCEPTION CATEGORIES**
Record: Not a device-ID/quirk/DT/docs exception. Closest: type-
correctness / sparse, but the runtime BE effect is a real hardware-
descriptor bug.
**Step 9.4: DECISION**
This tree has the driver and the v5.12 cyclic path the bug was
introduced in. The change is a one-line, obviously correct endian
conversion on a DMA linked-list field. Risk is negligible; on BE it is
the difference between a valid LLI_VALID bit and a silent cyclic stall.
That meets stable rules for this checkout.
---
### What the commit solves for this tree
Cyclic completion re-arms `CH_CTL_H_LLI_VALID` in an `__le32` LLI.
Without `cpu_to_le32()`, a big-endian CPU writes the wrong bit and the
DW AXI engine will not treat the descriptor as valid. Little-endian
machines (StarFive, Intel, Sophgo, default HSDK) generate the same code
as before.
### Risk vs benefit
Benefit is correctness of cyclic DMA on BE and type-safety of a hardware
descriptor. Risk is essentially zero. No dependencies beyond cyclic
support, which is already here.
---
## Verification
- **[Phase 1]** Parsed tags: malformed `Fixes 1deb96c0fa58a` (no colon);
Link msgid; SOBs Ben Dooks + Vinod Koul; no syzbot/Reported-by/Cc
stable.
- **[Phase 2]** Diff: 1 line in `axi_chan_block_xfer_complete()`;
`ctl_hi` is `__le32` (`dw-axi-dmac.h:85`); `CH_CTL_H_LLI_VALID` is
`BIT(31)` (line 256); other stores already use `cpu_to_le32` (lines
715, 985, 1129 after the fix).
- **[Phase 3]** `git blame`: cyclic OR from `1deb96c0fa58a`; `git
describe --contains 1deb96c0fa58a` → `v5.12-rc1~57^2~12`.
- **[Phase 3]** `git merge-base --is-ancestor 1deb96c0fa58a HEAD` → 0
(present). `git merge-base --is-ancestor 89aba9c39bdda HEAD` → 0
(commit is in this mainline checkout; not used as a circular “already
selected” NO).
- **[Phase 3]** `git show 1deb96c0fa58a`: added `hw_desc->lli->ctl_hi |=
CH_CTL_H_LLI_VALID` without conversion.
- **[Phase 4]** `b4 dig -c 89aba9c39bdda`: msgid
`20260617084944.705266-1-ben.dooks@codethink.co.uk`.
- **[Phase 4]** `b4 dig -a`: v1 only.
- **[Phase 4]** `b4 dig -w`: Vinod, Eugeniy Paltsev, Frank Li, dmaengine
list.
- **[Phase 4]** `b4 dig -m`: Frank Li sparse question; Ben confirmed
sparse `__le32` warning; Vinod applied; Sashiko pre-existing notes
only.
- **[Phase 4]** WebFetch lore URL: 403; thread recovered from mbox
instead.
- **[Phase 4]** Stable lore search: no hit for this patch (UNVERIFIED
exhaustive).
- **[Phase 5]** Callers: only `dw_axi_dma_interrupt()` on
`DWAXIDMAC_IRQ_DMA_TRF`; IRQ from probe.
- **[Phase 6]** `git describe HEAD` → `v7.3-rc4-27-gf0100363d8c37`;
`make kernelversion` → `7.3.0-rc4`.
- **[Phase 6]** Buggy cyclic path exists; `1deb96c0fa58a` is ancestor;
apply context still the 2021 function.
- **[Phase 7]** DTs: `snps,axi-dma-1.01a` / StarFive / Sophgo / Intel /
ARC HSDK; `hsdk_defconfig` has `CONFIG_DW_AXI_DMAC=y`, not
`CPU_BIG_ENDIAN`.
- **[Phase 8]** Failure mode: BE cyclic DMA fails to set LLI_VALID
(stall), not oops; LE no-op.
- **UNVERIFIED:** Exact sparse warning string; whether any production BE
board actually ships this IP.
**YES**
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
index ea4e47ee0d710..343d32eeaa29a 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
@@ -1128,7 +1128,7 @@ static void axi_chan_block_xfer_complete(struct axi_dma_chan *chan)
hw_desc = &desc->hw_desc[i];
if (hw_desc->llp == llp) {
axi_chan_irq_clear(chan, hw_desc->lli->status_lo);
- hw_desc->lli->ctl_hi |= CH_CTL_H_LLI_VALID;
+ hw_desc->lli->ctl_hi |= cpu_to_le32(CH_CTL_H_LLI_VALID);
desc->completed_blocks = i;
if (((hw_desc->len * (i + 1)) % desc->period_len) == 0)
--
2.53.0
^ permalink raw reply related [flat|nested] 2+ messages in thread* [PATCH AUTOSEL 6.18-5.10] dmaengine: pl330: remove debugfs file on teardown
[not found] <20261019135441.1420968-1-sashal@kernel.org>
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-5.15] dmaengine: dw-axi-dmac: fix __le32 on set of CH_CTL_H_LLI_VALID Sasha Levin
@ 2026-10-19 13:53 ` Sasha Levin
1 sibling, 0 replies; 2+ messages in thread
From: Sasha Levin @ 2026-10-19 13:53 UTC (permalink / raw)
To: patches, stable
Cc: Pengpeng Hou, Vinod Koul, Sasha Levin, dmaengine, linux-kernel
From: Pengpeng Hou <pengpeng@iscas.ac.cn>
[ Upstream commit 0d3e3376b289cdaff5b3b6c1581999926ff1000f ]
init_pl330_debugfs() creates a debugfs file with struct pl330_dmac as
private data. pl330_remove() then unregisters the DMA device and frees
the PL330 channel/thread state without removing that file.
Keep the debugfs dentry and remove it before tearing down the DMAC state
used by the debugfs show callback.
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
Link: https://patch.msgid.link/20260615091645.28878-1-pengpeng@iscas.ac.cn
Signed-off-by: Vinod Koul <vkoul@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit message forensics
**Step 1.1: PARSE THE SUBJECT LINE**
Record: **[dmaengine/pl330] [remove] [drop the leftover debugfs file
before DMAC teardown]**
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Record:
- `Fixes:` — absent (expected for this review)
- `Reported-by:` — absent
- `Tested-by:` — absent
- `Reviewed-by:` — absent
- `Acked-by:` — absent
- `Link:`
`https://patch.msgid.link/20260615091645.28878-1-pengpeng@iscas.ac.cn`
- `Cc: stable@vger.kernel.org` — absent (expected)
- `Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>` (author)
- `Signed-off-by: Vinod Koul <vkoul@kernel.org>` (dmaengine maintainer)
- Ignore any Sasha Levin SOB if present in candidate wrapping — none on
this commit object
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- **Bug:** `init_pl330_debugfs()` creates a debugfs file whose private
data is `struct pl330_dmac *`. `pl330_remove()` tears down DMA
registration and frees channel/thread state without removing that
file.
- **Symptom:** After unbind/`rmmod`, the debugfs file remains. A later
read runs `pl330_debugfs_show()` against freed `pl330` /
`pl330->channels` (use-after-free / oops).
- **Version info:** none in the message. The debugfs file was added in
`b45aef3aef636` (contained in v5.2-rc1).
- **Root cause:** missing `debugfs_remove()` before DMAC teardown.
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: Not disguised. It is an explicit lifetime/UAF fix (remove
debugfs before freeing the object the show callback uses).
---
## Phase 2: Diff analysis
**Step 2.1: INVENTORY THE CHANGES**
Record:
- File: `drivers/dma/pl330.c` only (`+16 / -3`)
- Functions: `struct pl330_dmac` (add `dbgfs`), `init_pl330_debugfs()`,
new `deinit_pl330_debugfs()`, `pl330_remove()`
- Scope: single-file surgical fix
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Record:
- **Hunk 1 (`struct pl330_dmac`):** store the dentry so it can be
removed later.
- **Hunk 2 (`init_pl330_debugfs`):** keep the return of
`debugfs_create_file()` in `pl330->dbgfs`. Add
`deinit_pl330_debugfs()` that calls `debugfs_remove()` and NULLs the
pointer. `#else` stub for `!CONFIG_DEBUG_FS`.
- **Hunk 3 (`pl330_remove`):** call `deinit_pl330_debugfs(pl330)`
**before** IRQ free, `dma_async_device_unregister()`, channel
teardown, and `pl330_del()`.
Probe still creates the file only on the success path after
`dma_async_device_register()`; nothing after `init_pl330_debugfs()` can
fail, so probe error paths do not need deinit.
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record: **Use-after-free / lifetime** (debugfs private data).
Before: file at debugfs root, private data = `pl330`. `pl330_remove()`
then:
1. unregisters the DMA device
2. `pl330_del()` → `dmac_free_threads()` → `kfree(pl330->channels)`
3. AMBA `devm` frees `pl330` itself (`devm_kzalloc` in `pl330_probe`)
`pl330_debugfs_show()` then does `s->private` → `pl330->channels[ch]` on
freed memory.
After: `debugfs_remove()` first. Core debugfs waits for `active_users`
to drain, so an in-flight `cat` finishes before teardown.
**Step 2.4: ASSESS THE FIX QUALITY**
Record: Obviously correct and minimal. `debugfs_remove()` already no-ops
on `IS_ERR_OR_NULL`. `pl330` is `devm_kzalloc`’d so `dbgfs` starts NULL.
Sibling DMA drivers (`pxa_dma`, `hidma`, `idxd`, `bcm-sba-raid`) already
remove debugfs on teardown.
Regression risk: very low. `debugfs_remove()` may wait for a reader;
that is intended. No API/locking/hot-path change.
---
## Phase 3: Git history
**Step 3.1: BLAME THE CHANGED LINES**
Record: Buggy create-without-remove came from `b45aef3aef636`
(“dmaengine: pl330: introduce debugfs interface”, 2019-03-25). `git
describe --contains` → `v5.2-rc1~115^2~30`. Present for years in this
lineage.
**Step 3.2: FOLLOW THE FIXES TAG**
Record: No `Fixes:` tag. Introducer is `b45aef3aef636`, ancestor of HEAD
(`git merge-base --is-ancestor` exit 0).
**Step 3.3: CHECK FILE HISTORY**
Record: Recent `pl330.c` history is unrelated (GFP helpers, runtime PM).
No prerequisite series. Standalone.
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: Pengpeng Hou has this one dmaengine commit here. Applied by
maintainer Vinod Koul. Not a series from this author.
**Step 3.5: DEPENDENT/PREREQUISITE COMMITS**
Record: None. Uses long-standing `debugfs_create_file` /
`debugfs_remove` / `DEFINE_SHOW_ATTRIBUTE`. Applies standalone.
---
## Phase 4: Mailing list / external research
**Step 4.1: ORIGINAL PATCH DISCUSSION**
Record:
- Lore URL from `b4 dig -c 0d3e3376b289c`:
`https://patch.msgid.link/20260615091645.28878-1-pengpeng@iscas.ac.cn`
- `b4 dig -a`: single **v1**, no later revision
- Thread (mbox): author submission; sashiko-bot comments on **pre-
existing** issues (desc_pool locking, IRQ vs `pl330_add`,
`pch->thread` TOCTOU in show); **Vinod: “Applied, thanks!”** as
`0d3e3376b289c`
- No NAK of this change. No reviewer `Cc: stable`. Direct lore HTTP
fetch returned 403; discussion taken from `b4 dig -m`.
**Step 4.2: WHO REVIEWED**
Record (`b4 dig -w`): To/Cc Vinod Koul, Frank Li,
`dmaengine@vger.kernel.org`, `linux-kernel@vger.kernel.org`. Maintainer
applied it. No human Reviewed-by.
**Step 4.3: BUG REPORT**
Record: No syzbot/bugzilla/`Reported-by`. Found by inspection. Failure
mode is still a concrete UAF on leftover debugfs.
**Step 4.4: RELATED PATCHES / SERIES**
Record: Standalone 1/1. Not part of a multi-patch series.
**Step 4.5: STABLE MAILING LIST**
Record: **UNVERIFIED** — `lore.kernel.org/stable` returned HTTP 403. No
stable discussion in the dmaengine mbox.
---
## Phase 5: Code semantic analysis
**Step 5.1: KEY FUNCTIONS**
Record: `init_pl330_debugfs`, `deinit_pl330_debugfs` (new),
`pl330_remove`, `pl330_debugfs_show` (user of private data), `pl330_del`
/ `dmac_free_threads` (free the memory the show callback uses).
**Step 5.2: CALLERS**
Record:
- `init_pl330_debugfs()` — `pl330_probe()` success path only
- `deinit_pl330_debugfs()` — `pl330_remove()` only
- `pl330_remove()` — AMBA `.remove`
- `pl330_debugfs_show()` — debugfs read (`DEFINE_SHOW_ATTRIBUTE`)
**Step 5.3: CALLEES**
Record: `debugfs_create_file`, `debugfs_remove`, then existing remove
path (`dma_async_device_unregister`, `pl330_del` → `kfree(channels)`).
**Step 5.4: CALL CHAIN / REACHABILITY**
Record: `echo … > unbind` or `rmmod dma-pl330` → `pl330_remove`. Then
`cat /sys/kernel/debug/<devname>` (file is created with parent `NULL` at
debugfs root). Reachable from userspace. debugfs is typically root-only
(0700), so not an unprivileged UAF, still a kernel UAF/oops.
**Step 5.5: SIMILAR PATTERNS**
Record: Other DMA drivers already `debugfs_remove[_recursive]` on
teardown (`pxa_dma.c`, `dmaengine.c`, `bcm-sba-raid.c`,
`idxd/debugfs.c`, `qcom/hidma_dbg.c`). pl330 was the outlier.
---
## Phase 6: Local tree
**Step 6.1: DOES THE BUGGY CODE EXIST HERE?**
Record: Local tree is **v7.3-rc4** (`VERSION=7 PATCHLEVEL=3 SUBLEVEL=0
EXTRAVERSION=-rc4`, `git describe` `v7.3-rc4-27-gf0100363d8c37`).
`drivers/dma/pl330.c` is present. Debugfs dates to v5.2. This commit
**is already an ancestor of HEAD** (`0d3e3376b289c`). The bug existed in
this lineage until that commit; current HEAD already has the fix. That
is the mainline landing, not a reason to reject it as a stable
candidate.
**Step 6.2: BACKPORT COMPLICATIONS**
Record: Clean apply on this file. Context (`quirks`, `rstc`,
`init_pl330_debugfs`, `pl330_remove`) has been stable. Expected **clean
apply** to trees that still have the v5.2 debugfs code.
**Step 6.3: RELATED FIXES ALREADY HERE**
Record: This commit is the fix. No earlier alternative fix on `pl330.c`.
---
## Phase 7: Subsystem context
**Step 7.1: SUBSYSTEM AND CRITICALITY**
Record: **dmaengine / ARM PL330** (`drivers/dma/pl330.c`). **IMPORTANT**
for ARM SoCs that use PrimeCell DMA (not core mm/net). Enabled as
`CONFIG_PL330_DMA=y` in `arm64/defconfig`, `multi_v7`, `exynos`,
`socfpga`, `hisi`, `axm55xx`.
**Step 7.2: SUBSYSTEM ACTIVITY**
Record: Mature driver (since ~2010). Recent commits are small fixes, not
a rewrite.
---
## Phase 8: Impact and risk
**Step 8.1: WHO IS AFFECTED**
Record: Driver-specific + `CONFIG_DEBUG_FS`. Population: ARM/ARM64
boards with PL330 (Exynos and others). Built-in in several defconfigs,
so unbind is less common than for a typical module, but sysfs unbind and
`rmmod` (tristate) still exist.
**Step 8.2: TRIGGER CONDITIONS**
Record: Bind PL330 with debugfs on → unbind or unload → read leftover
`/sys/kernel/debug/<devname>`. Not every boot. Root-oriented (debugfs).
Race-free UAF after teardown; concurrent read during remove is handled
by debugfs `active_users`.
**Step 8.3: FAILURE MODE SEVERITY**
Record: **Use-after-free → oops / KASAN / potential memory corruption.**
Severity **HIGH**. debugfs is usually root-only, so not a typical
unprivileged CVE path, still a real crash/UAF.
**Step 8.4: RISK-BENEFIT**
Record:
- **Benefit:** medium-high for PL330 + debugfs users (prevents UAF on
teardown).
- **Risk:** very low (~19 lines, one driver, standard `debugfs_remove`).
- **Ratio:** favorable.
---
## Phase 9: Synthesis
**Step 9.1: EVIDENCE**
**For:**
- Real UAF: debugfs private data outlives `pl330` / `channels`
- Show callback indexes `pl330->channels[ch]` after `kfree`
- Small, obviously correct, matches other DMA drivers
- Maintainer applied v1
- `debugfs_remove()` waits for active readers
- Bug present since v5.2; driver is in this tree
**Against:**
- No user/syzbot report (inspection-only)
- Needs `CONFIG_DEBUG_FS` and unbind/unload
- debugfs typically root-only
- No `Fixes:` / `Cc: stable` (not a negative per the review rules)
**Unresolved:** stable@ lore search (HTTP 403).
**Step 9.2: STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — standard debugfs lifetime;
maintainer applied.
2. Real bug affecting users? **PASS** — leftover file + UAF on read
after remove.
3. Important (crash/security/corruption/deadlock)? **PASS** — UAF/oops.
HIGH, not a hot-path panic.
4. Small and contained? **PASS** — one file, +16/-3.
5. No new features/APIs? **PASS**
6. Can apply to the local tree? **PASS** — same file/functions; already
landed here as the upstream commit.
**Step 9.3: EXCEPTION CATEGORIES**
Record: None (not an ID/quirk/DT/build/docs exception). Ordinary bug
fix.
**Step 9.4: DECISION**
This is a contained UAF fix in a long-shipped ARM DMA driver. The local
v7.3-rc4 tree has the PL330 debugfs code; the change is the right stable
material (crash/UAF, tiny, no new API). Missing reports and debugfs-only
trigger do not outweigh that.
---
### What the commit solves
`init_pl330_debugfs()` created `/sys/kernel/debug/<dev>` with `pl330` as
private data and never removed it. `pl330_remove()` then freed
`pl330->channels` and let `devm` free `pl330`. A later debugfs read is a
use-after-free. The patch stores the dentry and removes it first;
`debugfs_remove()` drains active readers.
### Stable rules
Meets them: real UAF, small, no new API, applies to this driver’s
existing debugfs code.
### Risk vs benefit
Benefit is preventing oops/UAF after PL330 teardown. Risk is very low.
### Concerns
No `Fixes:` tag (introducer is `b45aef3aef636` / v5.2). No mailing-list
stable nomination. Trigger is unbind/unload + debugfs. None of that
blocks backport.
---
Verification:
- [Phase 1] Parsed tags: Link to msgid
`20260615091645.28878-1-pengpeng@iscas.ac.cn`; SOBs Hou + Vinod Koul;
no Fixes/Reported-by/Cc stable
- [Phase 1] Body describes create-without-remove and show-callback
lifetime
- [Phase 2] Diff: `drivers/dma/pl330.c` +16/-3; `dbgfs` field;
`deinit_pl330_debugfs` in `pl330_remove` before teardown
- [Phase 2] Pre-patch `init_pl330_debugfs` discarded
`debugfs_create_file()`; `pl330_remove` had no remove
- [Phase 2] `pl330_probe`: `devm_kzalloc` for `pl330`; `pl330_del` →
`kfree(pl330->channels)`
- [Phase 2] `fs/debugfs/inode.c`: `debugfs_remove` handles
`IS_ERR_OR_NULL`; waits on `active_users`
- [Phase 3] `git blame` / `git log -S init_pl330_debugfs --
drivers/dma/pl330.c`: introducer `b45aef3aef636` (v5.2-rc1)
- [Phase 3] `git merge-base --is-ancestor b45aef3aef636 HEAD` and
`0d3e3376b289c HEAD`: both true
- [Phase 3] `git log --oneline -20 -- drivers/dma/pl330.c`: no
prerequisite series
- [Phase 3] Author log on `drivers/dma/`: only this commit
- [Phase 4] `b4 dig -c 0d3e3376b289c`: lore match at the msgid above
- [Phase 4] `b4 dig -a`: v1 only
- [Phase 4] `b4 dig -w`: Vinod Koul, Frank Li, dmaengine@, linux-kernel@
- [Phase 4] mbox: Vinod applied as `0d3e3376b289c`; sashiko comments
were pre-existing, not a NAK of this fix
- [Phase 4] lore HTTP 403; stable@ search 403 — UNVERIFIED via
WebFetch/curl
- [Phase 5] Callers: probe → init; remove → deinit; show via debugfs
- [Phase 5] Same debugfs-remove pattern in other `drivers/dma/*` files
- [Phase 6] `git describe HEAD` / Makefile: v7.3-rc4; `pl330.c` present;
fix already on HEAD
- [Phase 7] `CONFIG_PL330_DMA` in
arm64/multi_v7/exynos/socfpga/hisi/axm55xx defconfigs
- [Phase 8] Failure mode: UAF on leftover debugfs read after remove,
severity HIGH
- UNVERIFIED: whether stable@ ever discussed this patch (HTTP 403)
**YES**
drivers/dma/pl330.c | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 82a9fe88ad54c..fe4d266ee611c 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -502,6 +502,7 @@ struct pl330_dmac {
struct dma_pl330_chan *peripherals; /* keep at end */
int quirks;
+ struct dentry *dbgfs;
struct reset_control *rstc;
struct reset_control *rstc_ocp;
};
@@ -2958,14 +2959,24 @@ DEFINE_SHOW_ATTRIBUTE(pl330_debugfs);
static inline void init_pl330_debugfs(struct pl330_dmac *pl330)
{
- debugfs_create_file(dev_name(pl330->ddma.dev),
- S_IFREG | 0444, NULL, pl330,
- &pl330_debugfs_fops);
+ pl330->dbgfs = debugfs_create_file(dev_name(pl330->ddma.dev),
+ S_IFREG | 0444, NULL, pl330,
+ &pl330_debugfs_fops);
+}
+
+static inline void deinit_pl330_debugfs(struct pl330_dmac *pl330)
+{
+ debugfs_remove(pl330->dbgfs);
+ pl330->dbgfs = NULL;
}
#else
static inline void init_pl330_debugfs(struct pl330_dmac *pl330)
{
}
+
+static inline void deinit_pl330_debugfs(struct pl330_dmac *pl330)
+{
+}
#endif
/*
@@ -3211,6 +3222,8 @@ static void pl330_remove(struct amba_device *adev)
struct dma_pl330_chan *pch, *_p;
int i, irq;
+ deinit_pl330_debugfs(pl330);
+
pm_runtime_get_noresume(pl330->ddma.dev);
if (adev->dev.of_node)
--
2.53.0
^ permalink raw reply related [flat|nested] 2+ messages in thread