[PATCH AUTOSEL 6.18] PCI: dwc: Protect root bus removal with rescan lock
From: Sasha Levin
Date: Mon Aug 31 2026 - 14:20:26 EST
From: Hans Zhang <18255117159@xxxxxxx>
[ Upstream commit 26335696498ab502e907a556e97c7039bc80a87e ]
Hold the pci_rescan_remove_lock lock while stopping and removing a root bus
to avoid racing with concurrent rescan or hotplug operations triggered via
sysfs. Such races may lead to use-after-free issues or system crashes.
Signed-off-by: Hans Zhang <18255117159@xxxxxxx>
Signed-off-by: Manivannan Sadhasivam <mani@xxxxxxxxxx>
[bhelgaas: commit log]
Signed-off-by: Bjorn Helgaas <bhelgaas@xxxxxxxxxx>
Link: https://patch.msgid.link/20260521161822.132996-3-18255117159@xxxxxxx
Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>
---
LLM Generated explanations, may be completely bogus:
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: PARSE THE SUBJECT LINE
**Record:** `[PCI: dwc]` `[Protect]` — Add synchronization around root
bus teardown in the DesignWare PCIe host controller to prevent races
with concurrent PCI rescan/hotplug.
### Step 1.2: PARSE ALL COMMIT MESSAGE TAGS
**Record:**
- **Link:**
`https://patch.msgid.link/20260521161822.132996-3-18255117159@xxxxxxx`
- **Signed-off-by:** Hans Zhang `<18255117159@xxxxxxx>`
- **Signed-off-by:** Manivannan Sadhasivam `<mani@xxxxxxxxxx>`
- **Signed-off-by:** Bjorn Helgaas `<bhelgaas@xxxxxxxxxx>` (with
`[bhelgaas: commit log]`)
- No `Fixes:`, `Reported-by:`, `Tested-by:`, `Reviewed-by:`, `Acked-
by:`, or `Cc: stable@xxxxxxxxxxxxxxx`
- Notable: PCI maintainer (Bjorn Helgaas) committed; DWC maintainer
(Mani) signed off. No syzbot or user crash report in the message
itself.
### Step 1.3: ANALYZE THE COMMIT BODY TEXT
**Record:**
- **Bug:** `dw_pcie_host_deinit()` stops and removes the root bus
without holding `pci_rescan_remove_lock`.
- **Symptom:** Race with concurrent sysfs-triggered PCI rescan or
hotplug; may cause use-after-free or system crashes.
- **Root cause:** `pci_stop_root_bus()` / `pci_remove_root_bus()` are
not serialized against sysfs paths that already take
`pci_lock_rescan_remove()`.
- **Version info:** None in the message.
### Step 1.4: DETECT HIDDEN BUG FIXES
**Record:** Not hidden — this is an explicit synchronization bug fix.
The “protect” wording and UAF/crash description clearly indicate a real
concurrency defect, not cleanup.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: INVENTORY THE CHANGES
**Record:**
- **Files:** `drivers/pci/controller/dwc/pcie-designware-host.c` (+2
lines)
- **Function:** `dw_pcie_host_deinit()`
- **Scope:** Single-file, surgical fix (2 insertions around existing
calls)
### Step 2.2: UNDERSTAND THE CODE FLOW CHANGE
**Record:**
- **Hunk (deinit path):**
- **Before:** `pci_stop_root_bus()` and `pci_remove_root_bus()` run
unlocked during driver teardown.
- **After:** Same operations run under `pci_lock_rescan_remove()` /
`pci_unlock_rescan_remove()`.
- **Path affected:** Platform driver remove / module unload / probe
error cleanup via `dw_pcie_host_deinit()`.
### Step 2.3: IDENTIFY THE BUG MECHANISM
**Record:**
- **Category:** Race condition / synchronization bug (can manifest as
UAF or crash).
- **Mechanism:** Sysfs rescan/remove (`rescan_store`, `remove_store`,
`bus_rescan_store` in `pci-sysfs.c`) holds `pci_rescan_remove_lock`.
DWC host teardown did not, so two threads could concurrently mutate
the same PCI bus/device tree.
### Step 2.4: ASSESS THE FIX QUALITY
**Record:**
- **Quality:** Obviously correct; matches the established pattern in
`pci_host_common_remove()`, `pci-aardvark.c`, `pci-mvebu.c`, `pci-
hyperv.c`, etc.
- **Regression risk:** Very low. The lock is a global PCI mutex already
used widely; holding it only around bus stop/remove is the intended
usage documented in `probe.c`.
- **Red flags:** None.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: BLAME THE CHANGED LINES
**Record:**
- `pci_stop_root_bus()` / `pci_remove_root_bus()` in
`dw_pcie_host_deinit()` introduced in commit `5808d43e7c91b2` (Rob
Herring, Aug 2020).
- `dw_pcie_host_deinit()` itself dates to 2019.
- **Bug present since:** ~2020 in this function; DWC host code never had
the rescan lock (`git log -S 'pci_lock_rescan_remove' -- pcie-
designware-host.c` returned empty).
### Step 3.2: FOLLOW THE FIXES: TAG
**Record:** No `Fixes:` tag. N/A.
### Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES
**Record:**
- Related fix in-tree: `1d59d474e1cb7` — “PCI: Hold rescan lock while
adding devices during host probe” (Oct 2024), with a documented NULL
deref crash from concurrent probe vs. sysfs remove.
- This commit is patch **2/9** in series “PCI: controller: Add missing
rescan lock around root bus removal”; cover letter states **each patch
is independent**.
- Fix is **not yet merged** in this tree (current `pcie-designware-
host.c` still lacks the lock).
### Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS
**Record:** Hans Zhang is an active PCI contributor (capability-search
refactors, cadence/dwc work). This series is a targeted locking fix, not
part of a larger refactor.
### Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS
**Record:**
- **Dependency:** `pci_lock_rescan_remove()` API from `9d16947b75831`
(Jan 2014) — **present in this tree**.
- **Standalone:** Yes; no structural/API prerequisites beyond the
existing lock helpers.
- Buggy code (`5808d43e7c91b2`) is also an ancestor of HEAD.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION
**Record:**
- `b4 dig -c` failed (commit not in local history yet).
- Local mbox/cover files found: `20260522_18255117159_pci_controller_add
_missing_rescan_lock_around_root_bus_removal.{cover,mbx}`.
- **Series:** 9 independent patches; this is patch 2/9 (DWC).
- **Cover letter context:** Bot review on a separate cadence patch
flagged the same missing-lock pattern; author submitted this series to
fix all affected controllers.
- **Lore URL fetch:** Blocked by Anubis anti-bot on lore.kernel.org.
### Step 4.2: CHECK WHO REVIEWED THE PATCH
**Record:** From commit message: Manivannan Sadhasivam (DWC maintainer)
SOB; Bjorn Helgaas (PCI maintainer) committed. `b4 dig -w` not available
for this unreleased commit.
### Step 4.3: SEARCH FOR THE BUG REPORT
**Record:** No `Reported-by:` or crash trace in this specific patch.
Precedent crash documented in `1d59d474e1cb7` for the **probe/add** side
of the same locking gap. This fix addresses the symmetric **remove**
side.
### Step 4.4: CHECK FOR RELATED PATCHES AND SERIES
**Record:** 8 sibling patches fix the same pattern in cadence, altera,
brcmstb, iproc, mediatek, rockchip, vmd, plda. Each is independently
backportable.
### Step 4.5: CHECK STABLE MAILING LIST HISTORY
**Record:** Not searched (lore blocked). No stable-list discussion found
in local mbox files.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF
**Record:** `dw_pcie_host_deinit()` — only function modified.
### Step 5.2: TRACE CALLERS
**Record:** `dw_pcie_host_deinit()` is called from multiple DWC-based
platform drivers:
- `pcie-tegra194.c` (`tegra_pcie_deinit_controller()` → platform
`.remove` and probe error path)
- `pcie-stm32.c`, `pcie-rcar-gen4.c`, `pci-meson.c`, `pci-dra7xx.c`,
`pcie-bt1.c`, `pci-exynos.c`, `pcie-kirin.c`, `pcie-intel-gw.c`
- **Context:** Driver remove, module unload, and probe failure cleanup
on embedded/SoC platforms using Synopsys DWC PCIe.
### Step 5.3: TRACE CALLEES
**Record:** Key callees in the critical section:
- `pci_stop_root_bus()` — stops child devices, releases host bridge
driver
- `pci_remove_root_bus()` — removes child devices, deletes host bridge
from device model
- Both documented to require the rescan/remove lock when racing with
sysfs operations.
### Step 5.4: FOLLOW THE CALL CHAIN
**Record:**
- **Trigger A:** Platform device remove / module rmmod →
`dw_pcie_host_deinit()` → unlocked bus teardown.
- **Trigger B (concurrent):** Root/admin writes to
`/sys/bus/pci/rescan`, `/sys/bus/pci/devices/.../remove`, or per-bus
rescan sysfs → `pci_lock_rescan_remove()` → bus mutation.
- **Userspace reachability:** Sysfs PCI operations require privileges;
race is realistic during driver unbind/rebind, hotplug, or admin
tooling — not merely theoretical.
### Step 5.5: SEARCH FOR SIMILAR PATTERNS
**Record:** In this tree, several controllers already protect removal
with the lock (`pci-host-common.c`, `pci-aardvark.c`, `pci-mvebu.c`,
`pcie-mediatek-gen3.c`, `pci-hyperv.c`). DWC and others listed in the
series do **not** — inconsistent, known-bad pattern.
---
## PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
### Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?
**Record:**
- **Tree:** `v6.18.44` (`stable/linux-6.18.y`, detached HEAD at
`2736c32da98b9`)
- **Buggy code:** **YES** — `pcie-designware-host.c:709-710` calls
`pci_stop_root_bus()` / `pci_remove_root_bus()` without locking.
- **Bug age:** Present since ~2020; not a post-6.18 regression.
### Step 6.2: CHECK FOR BACKPORT COMPLICATIONS
**Record:** **Clean apply expected** — 2-line addition with no context
conflicts. File has recent churn but the `dw_pcie_host_deinit()`
teardown block is stable and matches the patch hunk.
### Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE
**Record:** Probe-side rescan lock fix (`1d59d474e1cb7`) is in-tree.
Remove-side DWC fix is **not** present. No duplicate fix found.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
### Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY
**Record:** **PCI / DWC host controller drivers** — **IMPORTANT**.
Affects many ARM/embedded SoC platforms (Tegra, STM32, Kirin, Meson,
Exynos, R-Car, etc.), not universal but widely deployed.
### Step 7.2: ASSESS SUBSYSTEM ACTIVITY
**Record:** PCI controller code is actively maintained; recent related
stable-worthy fix (`1d59d474e1cb7`) shows the subsystem maintainers
treat rescan-lock gaps as real crash bugs.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: DETERMINE WHO IS AFFECTED
**Record:** Users of DWC-based PCIe host controllers on platforms using
`dw_pcie_host_deinit()` — embedded ARM servers/devices, Tegra, various
SoCs. Config-dependent on `CONFIG_PCIE_DW_HOST` and specific platform
drivers.
### Step 8.2: DETERMINE THE TRIGGER CONDITIONS
**Record:**
- **Trigger:** Concurrent root bus removal (driver unload/remove) with
sysfs PCI rescan/remove/hotplug.
- **Likelihood:** Uncommon but realistic during driver rebinding,
development, or admin maintenance.
- **Unprivileged trigger:** No direct unprivileged sysfs access; race
still matters for system stability under privileged operations.
### Step 8.3: DETERMINE THE FAILURE MODE SEVERITY
**Record:**
- **Failure mode:** Use-after-free, NULL pointer dereference, kernel
oops/crash during concurrent bus teardown.
- **Severity:** **CRITICAL** (system crash; potential memory
corruption).
### Step 8.4: CALCULATE RISK-BENEFIT RATIO
**Record:**
- **Benefit:** **High** — prevents crashes on a common PCIe IP block
across many platforms; aligns DWC with already-fixed controllers.
- **Risk:** **Very low** — 2-line, established locking pattern, no
API/behavior change beyond proper serialization.
- **Ratio:** Strong benefit, minimal risk.
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: COMPILE THE EVIDENCE
**FOR backporting:**
- Real race between bus removal and sysfs rescan/remove paths.
- Documented failure modes (UAF/crash) in commit message; strong
precedent in `1d59d474e1cb7`.
- Tiny, obviously correct fix matching multiple in-tree controllers.
- Buggy code present in v6.18.44; prerequisites
(`pci_lock_rescan_remove`) present.
- Standalone patch; maintainer-reviewed.
- Affects widely used DWC PCIe host path on many embedded platforms.
**AGAINST backporting:**
- No explicit user crash report or syzbot entry for this specific patch.
- Race requires concurrent privileged sysfs activity (somewhat
uncommon).
- Part of a 9-patch series (though each patch is independent).
**UNRESOLVED:**
- Full lore.kernel.org review thread (blocked by anti-bot).
- No independent `Tested-by:` on this specific DWC patch.
### Step 9.2: STABLE RULES CHECKLIST
1. Obviously correct and tested? **PASS** — pattern is standard;
maintainer SOBs; no test report but fix is trivial and well-
precedented.
2. Fixes a real bug? **PASS** — missing lock on a documented race path.
3. Important issue? **PASS** — UAF/kernel crash potential
(**CRITICAL**).
4. Small and contained? **PASS** — 2 lines, one function.
5. No new features or APIs? **PASS** — uses existing lock API only.
6. Can apply to the local tree? **PASS** — buggy code and API both
present; clean apply expected.
### Step 9.3: EXCEPTION CATEGORIES
**Record:** None (not a quirk/DT/build/docs fix). This is a core
synchronization bug fix.
### Step 9.4: DECISION RATIONALE
For **linux-6.18.y** (`v6.18.44`), `dw_pcie_host_deinit()` removes the
root PCI bus without the global rescan/remove lock that sysfs PCI
operations already use. That is the same class of defect already fixed
on the probe/add path (`1d59d474e1cb7`) and already handled correctly in
several other PCI host controller drivers in this tree. The fix is
minimal, self-contained, and prevents realistic kernel crashes during
driver teardown on DWC-based platforms.
---
## Verification
- **[Phase 1]** Parsed subject, tags, body; no Fixes/Reported-by;
maintainer SOBs present.
- **[Phase 2]** Confirmed diff: +2 lines wrapping
`pci_stop/remove_root_bus` in `dw_pcie_host_deinit()`.
- **[Phase 3]** `git blame`: buggy calls from `5808d43e7c91b2` (2020);
`git log -S`: DWC never had rescan lock.
- **[Phase 3]** `git merge-base --is-ancestor`: `9d16947b75831` YES,
`5808d43e7c91b2` YES.
- **[Phase 3]** Related fix `1d59d474e1cb7` confirmed in tree with crash
stack trace.
- **[Phase 3]** `git log --grep`: fix not merged in this tree.
- **[Phase 4]** Read local mbox/cover for series context; patch 2/9,
independent patches stated.
- **[Phase 4]** `b4 dig -c`: failed (commit not in tree); lore fetch
blocked.
- **[Phase 5]** `grep dw_pcie_host_deinit(`: 9 platform driver call
sites verified.
- **[Phase 5]** Read `pci-sysfs.c`: rescan/remove paths use
`pci_lock_rescan_remove()`.
- **[Phase 5]** Read `pci-host-common.c`, `probe.c`: lock pattern and
API confirmed.
- **[Phase 5]** `grep pci_lock_rescan_remove` in
`drivers/pci/controller/`: multiple drivers already protected; DWC
not.
- **[Phase 6]** `git describe HEAD`: `v6.18.44-1-g2736c32da98b9`;
`Makefile`: 6.18.44.
- **[Phase 6]** Read `pcie-designware-host.c:703-724`: buggy code
confirmed present.
- **[Phase 8]** Traced `tegra_pcie_dw_remove` →
`tegra_pcie_deinit_controller` → `dw_pcie_host_deinit`.
**YES**The analysis is complete: **backport this commit to
linux-6.18.y**.
`dw_pcie_host_deinit()` in `pcie-designware-host.c` removes the root PCI
bus without `pci_lock_rescan_remove()`, which can race with sysfs
rescan/remove and cause UAF or kernel crashes. The fix is two lines,
matches patterns already used in other PCI host drivers in this tree,
and applies cleanly to v6.18.44 where the bug is still present.
**YES**
drivers/pci/controller/dwc/pcie-designware-host.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 48e4a887bb1bb..d5c24098c3dd3 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -706,8 +706,10 @@ void dw_pcie_host_deinit(struct dw_pcie_rp *pp)
dwc_pcie_debugfs_deinit(pci);
+ pci_lock_rescan_remove();
pci_stop_root_bus(pp->bridge->bus);
pci_remove_root_bus(pp->bridge->bus);
+ pci_unlock_rescan_remove();
dw_pcie_stop_link(pci);
--
2.53.0