* [PATCH AUTOSEL 6.18-5.15] perf/x86/intel/uncore: Fix PCI PMU cleanup on setup failure
[not found] <20261019135441.1420968-1-sashal@kernel.org>
@ 2026-10-19 13:45 ` Sasha Levin
2026-10-19 14:02 ` sashiko-bot
2026-10-19 13:45 ` [PATCH AUTOSEL 6.18-6.1] perf/x86: Free hybrid state on PMU init failure Sasha Levin
` (6 subsequent siblings)
7 siblings, 1 reply; 15+ messages in thread
From: Sasha Levin @ 2026-10-19 13:45 UTC (permalink / raw)
To: patches, stable
Cc: Zide Chen, Peter Zijlstra (Intel), Dapeng Mi, Sasha Levin, mingo,
acme, namhyung, tglx, bp, dave.hansen, x86, linux-perf-users,
linux-kernel
From: Zide Chen <zide.chen@intel.com>
[ Upstream commit 003267cb94e21d762eb72d6977d84f44f1705bb7 ]
When uncore_pci_pmu_register() fails, pmu->boxes[die] is set to NULL
before returning. In the uncore_pci_remove() path, this causes
uncore_pci_pmu_unregister() to be skipped entirely, leaking
pmu->activeboxes. In the uncore_bus_notify() path,
uncore_pci_pmu_unregister() may still be called and must exit early
when pmu->boxes[die] is NULL to avoid a NULL pointer dereference, and
to ensure activeboxes is only decremented for a previously active box.
Additionally, since pci_get_drvdata() returns NULL on registration
failure, uncore_pci_remove() can no longer treat NULL drvdata as an
indicator of an auxiliary PCI device. Remove the associated
WARN_ON_ONCE().
Signed-off-by: Zide Chen <zide.chen@intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Link: https://sashiko.dev/#/patchset/20260512233048.9577-1-zide.chen@intel.com?part=1
Link: https://patch.msgid.link/20260611160033.66760-2-zide.chen@intel.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The 6.18.53 file matches the pre-fix code exactly, so this is a clean,
self-contained error-path leak and NULL-deref fix. Full phase
walkthrough follows.
===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================
Step 1.1: PARSE THE SUBJECT LINE
Record: [perf/x86/intel/uncore] [fix] [PCI PMU cleanup on setup failure]
Step 1.2: PARSE ALL COMMIT MESSAGE TAGS
Record:
- Signed-off-by: Zide Chen (author)
- Signed-off-by: Peter Zijlstra (Intel) (perf/x86 maintainer)
- Reviewed-by: Dapeng Mi (Intel uncore reviewer)
- Link: https://sashiko.dev/#/patchset/20260512233048.9577-1-
zide.chen@intel.com?part=1
- Link:
https://patch.msgid.link/20260611160033.66760-2-zide.chen@intel.com
- No Fixes: tag (expected)
- No Reported-by / Tested-by / syzbot
- No Cc: stable (expected)
- Ignore: [Upstream commit 003267cb94e21d762eb72d6977d84f44f1705bb7] and
Sasha Levin SOB (pipeline)
Step 1.3: ANALYZE THE COMMIT BODY TEXT
Record:
- Bug: when `uncore_pci_pmu_register()` fails, `pmu->boxes[die]` is
NULLed and the box is freed, but `pmu->activeboxes` stays incremented.
- Symptoms: (1) `uncore_pci_remove()` skips unregister because drvdata
is NULL → `activeboxes` leak; (2) `uncore_bus_notify()` still calls
unregister → NULL deref of `box`; (3) false `WARN_ON_ONCE()` because
NULL drvdata is no longer uniquely “extra PCI device”.
- Version info: none in the message. Code dates to 2020.
- Root cause: incomplete error-path rollback in
`uncore_pci_pmu_register()`, and unregister not tolerating a NULL box.
Step 1.4: DETECT HIDDEN BUG FIXES
Record: Not hidden. Explicit leak + NULL-deref + false-WARN fix. The
“remove WARN_ON” piece is diagnostic, not a new feature.
===============================================================
PHASE 2: DIFF ANALYSIS - LINE BY LINE
===============================================================
Step 2.1: INVENTORY THE CHANGES
Record:
- File: `arch/x86/events/intel/uncore.c` (+4 / −1)
- Functions: `uncore_pci_pmu_register()`, `uncore_pci_pmu_unregister()`,
`uncore_pci_remove()`
- Scope: single-file surgical fix (5 lines)
Step 2.2: UNDERSTAND THE CODE FLOW CHANGE
Record:
- Hunk 1 (`uncore_pci_pmu_register`): first-box `uncore_pmu_register()`
failure already NULLed `boxes[die]`, exited and freed the box, but
left `activeboxes` incremented. After: `atomic_dec(&pmu->activeboxes)`
on that path.
- Hunk 2 (`uncore_pci_pmu_unregister`): previously always used `box` and
decremented `activeboxes`. After: return immediately if `box` is NULL
(no deref, no bogus decrement).
- Hunk 3 (`uncore_pci_remove`): drop `WARN_ON_ONCE(i >=
UNCORE_EXTRA_PCI_DEV_MAX)` when drvdata is NULL.
Step 2.3: IDENTIFY THE BUG MECHANISM
Record:
- Category: error-path resource leak + NULL pointer dereference (and a
false WARN).
- Mechanism: `atomic_inc_return(&pmu->activeboxes)` runs before
`uncore_pmu_register()`. On failure the box is torn down but the
counter is not. Discovery/`bus_notify` still looks up the PMU by PCI
identity and calls unregister, which does `uncore_box_exit(box)` on
NULL (`box->flags`).
- Leak consequence: the next box of the same PMU sees `activeboxes > 1`
and skips `uncore_pmu_register()`, so the PMU never appears in perf.
Step 2.4: ASSESS THE FIX QUALITY
Record:
- Quality: obviously correct. Decrement matches the increment; NULL
guard is the standard pattern; no API/data-structure change.
- Regression risk: very low. Sashiko noted that PCI probe failure does
not call `remove()`, so the WARN removal is not strictly required for
that path. That only drops a diagnostic; it does not create a crash.
The NULL check is required for `uncore_bus_notify()`, which is
independent of `remove()`.
===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================
Step 3.1: BLAME THE CHANGED LINES
Record:
- Buggy register error path: `16fa64315c1bd` (“Factor out
uncore_pci_pmu_register()”), Kan Liang, 2020-09-14. First mainline:
v5.10-rc1.
- Unregister without NULL check: `cdcce92a3a03bc` (2020).
- WARN_ON_ONCE: `899396cf7b4b31` (Yan Zheng, 2013).
- Long-lived code, present in this 6.18 tree.
Step 3.2: FOLLOW THE FIXES: TAG
Record: No Fixes: tag. Introducer is `16fa64315c1bd`, which **is** an
ancestor of v6.18.53.
Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES
Record:
- This is v3 1/8 of “PMU setup robustness fixes”.
- Series: 1/8 this fix; 2/8 refcnt cleanup; 3/8 init_box errors; 4/8
keep PCI PMUs if MMIO/MSR alloc fails; 5/8 factor box setup; 6–8
flags/lazy setup.
- 4/8 (`d623e292c6a4c`) is already in v6.18.53. 2/8 and 5/8 are not.
- This patch does not depend on 2/8+; later patches build on it.
Standalone.
Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS
Record: Zide Chen is an active Intel uncore contributor on this tree
(die-id, discovery, IMC events, etc.). Maintainer path: Peter Zijlstra
SOB. Dapeng Mi Reviewed-by.
Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS
Record: No missing helpers or types. Parent of the candidate and
`v6.18.53:arch/x86/events/intel/uncore.c` are byte-identical (same
sha256). Applies standalone. Dry-run `patch -p1` against the v6.18.53
file succeeded.
===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================
Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION
Record:
- `b4 dig -c 540120722e9bf`: `[PATCH V3 1/8] perf/x86/intel/uncore: Fix
PCI PMU cleanup on setup failure`
- URL:
https://patch.msgid.link/20260611160033.66760-2-zide.chen@intel.com
- lore.kernel.org WebFetch returned 403; full thread saved via `b4 dig
-m` (26 messages).
- V1/V2 existed; this patch was **new in v2** after Sashiko review of
v1. v3 only added Reviewed-by. Applied version is latest.
- Cover letter: “PCI PMU cleanup on setup failure has activeboxes leaks
and potential NULL pointer dereference in error paths.”
- No NAK. tip-bot applied it to perf/core (2026-06-30).
- Sashiko on v3: questioned WARN_ON removal (Medium); two High notes
were pre-existing UAF/races, not introduced by this patch. No stable
NAK.
Step 4.2: CHECK WHO REVIEWED THE PATCH
Record: `b4 dig -w` recipients: Peter Zijlstra, Ingo Molnar, Arnaldo,
Namhyung Kim, Ian Rogers, Adrian Hunter, Alexander Shishkin, Andi Kleen,
Stephane Eranian, linux-kernel, linux-perf-users, Dapeng Mi. Dapeng
Reviewed-by on the committed patch; Peter Zijlstra SOB.
Step 4.3: SEARCH FOR THE BUG REPORT
Record: No syzbot/bugzilla. Found by code review (Sashiko on v1 → new
patch 1 in v2). Still a real, reachable error path, not a theoretical
rewrite.
Step 4.4: CHECK FOR RELATED PATCHES AND SERIES
Record: 8-patch robustness series. This 1/8 is self-contained. 4/8
already landed in this 6.18.53 tree. Later patches are larger (broken-
state, lazy MSR/MMIO) and are not required for this leak/NULL-deref fix.
Step 4.5: CHECK STABLE MAILING LIST HISTORY
Record: lore.kernel.org/stable WebFetch returned 403. UNVERIFIED whether
stable@ discussed it. Not used as a NO signal (absence of Cc: stable is
expected).
===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================
Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF
Record: `uncore_pci_pmu_register`, `uncore_pci_pmu_unregister`,
`uncore_pci_remove`. Related: `uncore_pci_probe`, `uncore_bus_notify`,
`uncore_pci_pmus_register`, `uncore_pci_sub_driver_init`.
Step 5.2: TRACE CALLERS
Record:
- `uncore_pci_pmu_register`: `uncore_pci_probe` (legacy
`uncore_pci_driver`), `uncore_pci_sub_driver_init` (PCI sub-devices),
`uncore_pci_pmus_register` (discovery; return value ignored).
- `uncore_pci_pmu_unregister`: `uncore_pci_remove`, `uncore_bus_notify`.
- `uncore_bus_notify`: PCI `BUS_NOTIFY_DEL_DEVICE`. Discovery always
registers this notifier.
- Context: driver init / PCI probe / PCI device deletion. Not a syscall
hot path, but boot and hot-unplug on Intel systems with uncore
(default `y`).
Step 5.3: TRACE CALLEES
Record:
- `uncore_pmu_register()` → `perf_pmu_register()` (can fail: ENOMEM,
sysfs/device_add, name collision).
- `uncore_box_exit()` at v6.18.53: `test_and_clear_bit(...,
&box->flags)` — NULL `box` is a hard oops.
- `kfree(NULL)` is safe; the crash is `uncore_box_exit`.
Step 5.4: FOLLOW THE CALL CHAIN
Record:
- Modern Intel (no `uncore_pci_driver`): `uncore_pci_init` →
`uncore_pci_pmus_register` → register (retval ignored) →
`bus_register_notifier`. Failed first-box `perf_pmu_register` + later
`BUS_NOTIFY_DEL_DEVICE` → `uncore_pci_find_dev_pmu_from_types` still
finds the PMU → unregister(NULL) → oops.
- Same PMU, later boxes: `activeboxes > 1` skips `uncore_pmu_register` →
uncore PMU missing from perf.
- Reachable without a special debug option.
`CONFIG_PERF_EVENTS_INTEL_UNCORE` defaults to y on Intel+PCI.
Step 5.5: SEARCH FOR SIMILAR PATTERNS
Record: MSR/MMIO setup is a different model; this series later factors
PCI lazy registration for those paths. No duplicate of this exact PCI
error-path bug in-tree. 2/8 adds refcnt decrement in unregister and is a
follow-up cleanup, not a prerequisite.
===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================
Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?
Record:
- Local tree: `v6.18.53-5049-g0f0bdc2b0dffb`, `make kernelversion`
6.18.53.
- At v6.18.53, `uncore_pci_pmu_register` still omits `atomic_dec` on
`uncore_pmu_register()` failure; unregister has no NULL check;
`WARN_ON_ONCE` is present. Bug exists here.
- Introduced v5.10-rc1; not after 6.18 branched.
- `git merge-base --is-ancestor 16fa64315c1bd v6.18.53` → yes.
Step 6.2: CHECK FOR BACKPORT COMPLICATIONS
Record: Expected apply: **clean**. Candidate parent `uncore.c` sha256
equals v6.18.53 `uncore.c`. Dry-run apply succeeded.
Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE
Record: No other “PCI PMU cleanup” fix in v6.18.53. 4/8 of the same
series is already in 6.18.53 (`d623e292c6a4c`). That does not fix this
leak/NULL deref.
===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================
Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY
Record: [arch/x86/events/intel uncore PMU] [IMPORTANT — default-on Intel
server/workstation perf, not core mm/sched, but widely enabled]
Step 7.2: ASSESS SUBSYSTEM ACTIVITY
Record: Mature (2012+) with ongoing platform adds (PTL, WCL, etc.). This
bug is old incomplete error handling, not a brand-new driver.
===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================
Step 8.1: DETERMINE WHO IS AFFECTED
Record: Intel x86 with `CONFIG_PERF_EVENTS_INTEL_UNCORE` (default y).
Driver-specific / config-default-on. Discovery platforms (newer Xeon)
hit the bus-notify NULL deref path.
Step 8.2: DETERMINE THE TRIGGER CONDITIONS
Record:
- Trigger: first box of a PCI uncore PMU fails `perf_pmu_register()`
(ENOMEM, sysfs failure, name clash).
- Not every boot, but a real error path. Discovery ignores register
failure and still installs the notifier.
- Unprivileged users do not trigger it directly; PCI unbind/hotplug and
boot setup do. Missing PMU is user-visible to perf.
Step 8.3: DETERMINE THE FAILURE MODE SEVERITY
Record:
- NULL deref in `uncore_box_exit(NULL)` on device delete → oops.
**HIGH** (crash on error + unplug).
- `activeboxes` leak → later boxes skip PMU registration → uncore events
absent. **MEDIUM–HIGH**.
- False WARN_ON. **LOW**.
- Overall: **HIGH** (crash on a reachable error path).
Step 8.4: CALCULATE RISK-BENEFIT RATIO
Record:
- Benefit: high — prevents oops and silently missing uncore PMUs after a
failed first-box register.
- Risk: very low — 5 lines, no locking/API change, WARN removal is the
only nit.
- Ratio: strongly favorable.
===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================
Step 9.1: COMPILE THE EVIDENCE
FOR backporting:
- Real leak of `pmu->activeboxes` on `uncore_pmu_register()` failure
(code at v6.18.53 matches).
- Real NULL deref: discovery `uncore_pci_pmus_register()` ignores
failure, `uncore_bus_notify` still unregisters,
`uncore_box_exit(NULL)` oopses.
- Same leak causes later boxes to skip `uncore_pmu_register()`, so the
PMU never shows up in perf.
- 5-line, obviously correct, no new API.
- Applies cleanly; file is identical to the pre-fix version.
- Bug present since v5.10; this 6.18 tree has it.
- Reviewed by Dapeng Mi; SOB Peter Zijlstra.
- Patch 1/8 is standalone; later series members not required.
- Same series 4/8 already in this 6.18.53 tree.
AGAINST:
- Trigger is an error path (`perf_pmu_register` failure), not a always-
on boot crash.
- No user/syzbot report.
- Sashiko: WARN_ON removal is weakly justified for the `pci_driver`
probe/remove model (probe failure does not call remove). Diagnostic-
only concern.
- Later 2/8 refcnt cleanup is related but separate; not a blocker.
UNRESOLVED:
- Stable mailing list search via lore HTTP was 403 (mbox/review still
obtained via b4).
- How often `perf_pmu_register` actually fails in production:
unverified, but ENOMEM/sysfs failure is a standard, reachable errno
path.
Step 9.2: APPLY THE STABLE RULES CHECKLIST
1. Obviously correct and tested? **PASS** — counter rollback + NULL
guard; maintainer SOB; Dapeng review; in mainline perf/core.
2. Fixes a real bug that affects users? **PASS** — leak, skipped PMU
registration, oops on device delete.
3. Important issue? **PASS** — NULL deref oops; missing uncore PMU.
Severity HIGH.
4. Small and contained? **PASS** — 5 lines, one file.
5. No new features or APIs? **PASS**.
6. Can apply to the local tree? **PASS** — clean apply to v6.18.53
`uncore.c`.
Step 9.3: CHECK FOR EXCEPTION CATEGORIES
Record: Not a device-ID/quirk/DT/build/docs exception. Ordinary small
bugfix; does not need an exception.
Step 9.4: MAKE YOUR DECISION
This belongs in 6.18.y: the buggy rollback is in this tree, the fix is
surgical, and the failure mode is a kernel oops plus a stuck/missing PCI
uncore PMU. WARN_ON removal is a minor diagnostic tradeoff, not a reason
to reject the leak and NULL-deref fix.
What the commit solves for stable users: Intel uncore PCI PMU setup
failure currently leaks `activeboxes` and can oops in
`uncore_bus_notify` when the device goes away. Backporting restores
counter balance, skips unregister when there is no box, and avoids a
false WARN.
Risk vs benefit: benefit is crash/functional correctness on a default-on
Intel perf driver; risk is a 5-line error-path change that applies with
no prerequisites.
Verification:
- [Phase 1] Parsed tags: SOB Zide Chen, SOB Peter Zijlstra, Reviewed-by
Dapeng Mi; Links to sashiko and patch.msgid.link; no Fixes/syzbot.
- [Phase 2] Diff: +`atomic_dec` on register failure; +`if (!box) return`
in unregister; −`WARN_ON_ONCE` in remove. 4+/1− in `uncore.c`.
- [Phase 2] `uncore_box_exit` at v6.18.53 dereferences `box->flags` —
NULL box is an oops.
- [Phase 3] blame: register failure path from `16fa64315c1bd`
(v5.10-rc1); present in v6.18.53.
- [Phase 3] `git merge-base --is-ancestor 16fa64315c1bd v6.18.53` → yes.
Candidate itself is not an ancestor of v6.18.53.
- [Phase 3] Parent `uncore.c` sha256 == v6.18.53 `uncore.c`; `patch -p1
--dry-run` succeeded.
- [Phase 3] Series 1/8 standalone; 4/8 `d623e292c6a4c` already in
v6.18.53; 2/8 and 5/8 not in v6.18.53 and not required.
- [Phase 4] `b4 dig -c 540120722e9bf`: V3 1/8,
https://patch.msgid.link/20260611160033.66760-2-zide.chen@intel.com
- [Phase 4] `b4 dig -a`: v1→v3; this patch added in v2 after Sashiko; v3
is what landed.
- [Phase 4] `b4 dig -w`: perf maintainers CC’d; Dapeng Reviewed-by; no
NAK.
- [Phase 4] mbox cover letter explicitly calls out activeboxes leak and
NULL deref.
- [Phase 4] lore HTTP 403; discussion recovered from b4 mbox. Stable-
list search UNVERIFIED (403).
- [Phase 5] Callers: probe, sub-driver init, discovery
`uncore_pci_pmus_register` (ignores retval, always registers bus
notifier).
- [Phase 5] `uncore_pmu_register` → `perf_pmu_register` can fail.
- [Phase 6] `git describe HEAD` = v6.18.53-5049-g0f0bdc2b0dffb;
`Makefile` 6.18.53; buggy code at v6.18.53 lines 1166–1172 / 1229–1238
/ 1257.
- [Phase 7] `CONFIG_PERF_EVENTS_INTEL_UNCORE` default y.
- [Phase 8] Failure mode: NULL deref oops + skipped PMU registration;
severity HIGH.
- UNVERIFIED: production frequency of `perf_pmu_register` failure;
stable@ lore thread (HTTP 403).
**YES**
arch/x86/events/intel/uncore.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/arch/x86/events/intel/uncore.c b/arch/x86/events/intel/uncore.c
index a5793847ed5a9..3d9973c416ecf 100644
--- a/arch/x86/events/intel/uncore.c
+++ b/arch/x86/events/intel/uncore.c
@@ -1165,6 +1165,7 @@ static int uncore_pci_pmu_register(struct pci_dev *pdev,
/* First active box registers the pmu */
ret = uncore_pmu_register(pmu);
if (ret) {
+ atomic_dec(&pmu->activeboxes);
pmu->boxes[die] = NULL;
uncore_box_exit(box);
kfree(box);
@@ -1230,6 +1231,9 @@ static void uncore_pci_pmu_unregister(struct intel_uncore_pmu *pmu, int die)
{
struct intel_uncore_box *box = pmu->boxes[die];
+ if (!box)
+ return;
+
pmu->boxes[die] = NULL;
if (atomic_dec_return(&pmu->activeboxes) == 0)
uncore_pmu_unregister(pmu);
@@ -1254,7 +1258,6 @@ static void uncore_pci_remove(struct pci_dev *pdev)
break;
}
}
- WARN_ON_ONCE(i >= UNCORE_EXTRA_PCI_DEV_MAX);
return;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH AUTOSEL 6.18-6.1] perf/x86: Free hybrid state on PMU init failure
[not found] <20261019135441.1420968-1-sashal@kernel.org>
2026-10-19 13:45 ` [PATCH AUTOSEL 6.18-5.15] perf/x86/intel/uncore: Fix PCI PMU cleanup on setup failure Sasha Levin
@ 2026-10-19 13:45 ` Sasha Levin
2026-10-19 13:47 ` [PATCH AUTOSEL 6.18] perf/arm-cmn: Add workarounds for CMN-S3 on Graviton5 Sasha Levin
` (5 subsequent siblings)
7 siblings, 0 replies; 15+ messages in thread
From: Sasha Levin @ 2026-10-19 13:45 UTC (permalink / raw)
To: patches, stable
Cc: Dapeng Mi, Peter Zijlstra (Intel), Thomas Falcon, Zide Chen,
Sasha Levin, mingo, acme, namhyung, tglx, bp, dave.hansen, x86,
linux-perf-users, linux-kernel
From: Dapeng Mi <dapeng1.mi@linux.intel.com>
[ Upstream commit 96746e731e1626545e343974ca4673739dceb31b ]
If PMU initialization fails, for example in check_hw_exists(), hybrid
state can be left partially initialized: x86_pmu.hybrid_pmu is not freed
and perf_is_hybrid remains set. This can leak memory and leave stale
hybrid state reachable after a failed init path.
Add x86_pmu_free_hybrid() and use it on PMU init failure paths so all
hybrid-related state is consistently reset.
Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Thomas Falcon <thomas.falcon@intel.com>
Reviewed-by: Zide Chen <zide.chen@intel.com>
Link: https://patch.msgid.link/20260717080342.1879573-3-dapeng1.mi@linux.intel.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The local tree is **6.12.111** (`pending-6.12`). The hybrid PMU
init/error path exists here, and this commit is a real error-path
UAF/leak fix that belongs in this tree.
===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================
**Step 1.1: PARSE THE SUBJECT LINE**
Record: **[perf/x86] [Free] [release hybrid PMU state when PMU init
fails]**
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Record:
- No `Fixes:` tag (expected for this review pipeline)
- No `Reported-by:` / syzbot
- No `Tested-by:`
- `Reviewed-by: Thomas Falcon <thomas.falcon@intel.com>`
- `Reviewed-by: Zide Chen <zide.chen@intel.com>`
- `Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>` (author)
- `Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>` (perf
maintainer)
- `Link: https://patch.msgid.link/20260717080342.1879573-3-
dapeng1.mi@linux.intel.com`
- No `Cc: stable` (not a negative signal)
SHA on `origin/master`: `96746e731e1626545e343974ca4673739dceb31b` (not
an ancestor of HEAD).
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- **Bug:** On hybrid Intel PMU init failure (example:
`check_hw_exists()`), `x86_pmu.hybrid_pmu` is not freed and
`perf_is_hybrid` stays enabled.
- **Symptom:** Memory leak plus leftover hybrid state after a failed
init.
- **Root cause:** `intel_pmu_init_hybrid()` allocates `hybrid_pmu` and
enables the static key; `init_hw_perf_events()` error paths
`memset(&x86_pmu, 0, ...)` without freeing or disabling that key. The
hybrid `perf_pmu_register` fail path kfree's too early and still
leaves the static key set.
- **Version:** Hybrid PMUs exist since 2021; this tree has them.
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: Not disguised. It is an explicit error-path leak/stale-state
fix. The delayed `kfree` also removes a use-after-free on the hybrid
register-fail path (see Phase 2/5).
===============================================================
PHASE 2: DIFF ANALYSIS - LINE BY LINE
===============================================================
**Step 2.1: INVENTORY THE CHANGES**
Record:
- File: `arch/x86/events/core.c` (+12 / −3)
- New helper: `x86_pmu_free_hybrid()`
- Modified: `init_hw_perf_events()` (hybrid register-fail block and
`out_bad_pmu`)
- Scope: single-file surgical error-path fix
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Record:
- **Hunk 1:** Add `x86_pmu_free_hybrid()`: if `hybrid_pmu` is set,
disable `perf_is_hybrid`, `kfree` the array, NULL it, set
`num_hybrid_pmus = 0`.
- **Hunk 2 (before):** Hybrid `perf_pmu_register` failure kfree's the
array, NULLs it, zeros the count, then `goto out2` (cpuhp teardown,
then `memset`).
- **Hunk 2 (after):** Only unregister already-registered PMUs and `goto
out2`; free/reset happens later in `out_bad_pmu`.
- **Hunk 3:** `out_bad_pmu` calls `x86_pmu_free_hybrid()` **before**
`memset(&x86_pmu, 0, ...)`.
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record: **Error-path resource leak + UAF + stale static key**
Verified in this tree (`init_hw_perf_events`, `intel_pmu_init_hybrid`,
`intel_pmu_cpu_dead`):
1. **Leak on early failure:** `intel_pmu_init_hybrid()` does `kcalloc` +
`static_branch_enable(&perf_is_hybrid)`. If `check_hw_exists()` then
fails, 6.12 jumps to `out_bad_pmu` and only `memset`s `x86_pmu`,
dropping the pointer without `kfree`. `perf_is_hybrid` stays enabled.
2. **UAF on hybrid register failure:** By the time `perf_pmu_register`
runs, `CPUHP_AP_PERF_X86_STARTING` has already run
`intel_pmu_cpu_starting()` → `init_hybrid_pmu()`, which sets
`cpuc->pmu` into the `hybrid_pmu` array. Current 6.12 code `kfree`s
that array **then** `goto out2` →
`cpuhp_remove_state(CPUHP_PERF_X86_PREPARE)` → `x86_pmu_dead_cpu()` →
`intel_pmu_cpu_dead()`:
```5209:5210:arch/x86/events/intel/core.c
if (is_hybrid() && cpuc->pmu)
cpumask_clear_cpu(cpu,
&hybrid_pmu(cpuc->pmu)->supported_cpus);
```
`is_hybrid()` is still true and `cpuc->pmu` still points at freed
memory. That is a use-after-free. Moving the free to after cpuhp
teardown fixes it.
3. **Stale static key:** The old register-fail path never called
`static_branch_disable(&perf_is_hybrid)`.
**Step 2.4: ASSESS THE FIX QUALITY**
Record: Obviously correct and minimal. `static_branch_disable` + `kfree`
+ NULL during `__init` teardown is low risk. Free-after-cpuhp is the
right order. No API change. Regression risk is low.
===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================
**Step 3.1: BLAME THE CHANGED LINES**
Record:
- Hybrid register/kfree block: `d9977c43bff89` (“perf/x86: Register
hybrid PMUs”, 2021-04-19) — present in 6.12.
- `intel_pmu_init_hybrid()` alloc/static key: `97588df87b56e2` (Kan
Liang, 2023-08-29) — present in 6.12.
- `out_bad_pmu` memset: `916e3a4f950eac` (Paolo Bonzini, 2022) — present
in 6.12.
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: No `Fixes:` tag. Bug was introduced with hybrid PMU support
(2021/2023), well before 6.12.
**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
Record: This is v3 **2/8** of Dapeng Mi’s “Miscellaneous PMU bug fixes
and optimizations”.
- Parent: `91787047b1dc5` “Unregister PMI handler on PMU init failure”
(adds `pmi_unregister:`) — **not** in this tree.
- Next: `278a3731c9d08` “Guard intel_pmu_cpu_dead() against invalid
hybrid PMU casts” — separate OOB/`container_of` bug; not required for
this leak/UAF fix.
This patch is standalone: the helper only needs to run before `memset`
at `out_bad_pmu`.
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: Dapeng Mi is an Intel perf contributor. Same series has several
hybrid/error-path fixes. Applied by Peter Zijlstra.
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record: Patch 1 is **not** a functional prerequisite. It only changes
nearby labels (`pmi_unregister`, `goto pmi_unregister` instead of
`return err`). `x86_pmu_free_hybrid()` can be added to 6.12’s existing
`out_bad_pmu`. No new helpers or structs.
===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- `b4 dig -c 96746e731e162` → https://patch.msgid.link/20260717080342.18
79573-3-dapeng1.mi@linux.intel.com
- Revisions: v1 (2026-07-10, 2/7), v2 (2026-07-13, 2/7), v3 (2026-07-17,
2/8). This hunk did not change across revisions.
- Cover letter: bugs found in review (Sashiko) of a later SIMD/eGPR
sampling series, not from a production crash.
- Zide Chen: `Reviewed-by` for the whole series. Author called the
series “low risky”. No NAKs found.
- Merged to tip perf/core 2026-08-12, then Linus.
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record (`b4 dig -w`): Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de
Melo, Namhyung Kim, Ian Rogers, Adrian Hunter, Alexander Shishkin, Andi
Kleen, Stephane Eranian, linux-kernel, linux-perf-users, Zide Chen,
Thomas Falcon. Maintainer applied it.
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record: No syzbot/bugzilla. Found by code review of hybrid init error
paths.
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: Standalone among 8 patches. Patch 1 (NMI unregister) and patch 3
(cpu_dead hybrid cast) are related but independent.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: No stable-list discussion found for this subject. Not a reason
to skip it.
===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================
**Step 5.1: KEY FUNCTIONS**
Record: `x86_pmu_free_hybrid()` (new), `init_hw_perf_events()`
(modified). Related existing: `intel_pmu_init_hybrid()`,
`intel_pmu_cpu_dead()`, `x86_pmu_dead_cpu()`.
**Step 5.2: TRACE CALLERS**
Record:
- `init_hw_perf_events()`: `early_initcall`, once at boot.
- `x86_pmu_free_hybrid()`: only `out_bad_pmu`.
- `intel_pmu_cpu_dead()`: `x86_pmu.cpu_dead` from `x86_pmu_dead_cpu` on
CPUHP_PERF_X86_PREPARE teardown (init rollback and later CPU down).
- `is_hybrid()` used in `get_possible_counter_mask()`, `is_x86_event()`,
`allocate_fake_cpuc()`, `x86_pmu_event_init()`,
`intel_pmu_cpu_starting()`, `intel_pmu_cpu_dead()`, and `hybrid()`
macros.
**Step 5.3: TRACE CALLEES**
Record: `static_branch_disable()`, `kfree()`. No locks, no I/O.
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: Boot-time hybrid Intel PMU init (Alder/Raptor/Meteor/Lunar/Arrow
Lake in this tree). Triggered by `check_hw_exists()` failure (broken
PMU, hypervisor without PMU) or `perf_pmu_register()` failure. Not a
normal syscall path; it is a boot/error path. Register-fail UAF runs in
cpuhp teardown while the array is already freed.
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: Same series cleans other hybrid error paths (NMI leak, invalid
`hybrid_pmu()` cast). `01c153956b443` (“Validate the return value of
intel_pmu_init_hybrid()”) is a related NULL-deref fix and is **not** in
this tree; not required here.
===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record: **Yes.**
- Tree: `p-6.12-3-gc504cf0baa3d8`, `VERSION=6 PATCHLEVEL=12
SUBLEVEL=111`
- `git merge-base --is-ancestor 96746e731e162 HEAD` → not an ancestor
- 6.12 `init_hw_perf_events()` still kfree's on register fail, then
`memset`s at `out_bad_pmu` with no `x86_pmu_free_hybrid()` and no
`static_branch_disable`
- `intel_pmu_init_hybrid()` still allocates and enables `perf_is_hybrid`
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: **Minor conflicts, easy backport.**
- `git apply --check` of the raw diff fails: `x86_pmu_show_pmu_cap()`
log strings differ, and mainline has `pmi_unregister:` from patch 1.
- The real change is still: add the helper after
`x86_pmu_show_pmu_cap()`, drop the three-line kfree in the register-
fail block, call the helper just before `memset` at `out_bad_pmu`.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: No `x86_pmu_free_hybrid`, no “Free hybrid state” commit.
Register-fail still does the early `kfree`.
===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================
**Step 7.1: SUBSYSTEM AND CRITICALITY**
Record: **arch/x86/events (x86 perf PMU)** — **IMPORTANT**. Hybrid Intel
CPUs are common (ADL/RPL/MTL/LNL/ARL). Not core mm/VFS, but production
x86 hardware.
**Step 7.2: SUBSYSTEM ACTIVITY**
Record: Mature PMU core with ongoing hybrid work. Bug has been in hybrid
support since it landed, not a last-month feature.
===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================
**Step 8.1: WHO IS AFFECTED**
Record: Intel hybrid x86 systems where PMU init fails (VMs without a
usable PMU, broken BIOS/MSRs, or `perf_pmu_register` failure). Not
universal; config `PERF_EVENTS` + hybrid CPU models.
**Step 8.2: TRIGGER CONDITIONS**
Record:
- `check_hw_exists()` false after `intel_pmu_init_hybrid()` — leak +
leftover `perf_is_hybrid`. Common-ish in hypervisors; uncommon on
healthy bare metal.
- Hybrid `perf_pmu_register` failure after cpuhp STARTING — **UAF** in
`intel_pmu_cpu_dead()`. Rare (ENOMEM/name clash) but a real error
path.
Not unprivileged-syscall triggered.
**Step 8.3: FAILURE MODE SEVERITY**
Record:
- Register-fail + early kfree: **UAF** → crash/KASAN — **HIGH**
- Early `check_hw_exists` fail: small one-time leak of `num_hybrid_pmus
* sizeof(struct x86_hybrid_pmu)` plus leftover `is_hybrid()` —
**MEDIUM** (leak) / **MEDIUM-HIGH** if later `hybrid()` users run with
a NULL/zeroed `x86_pmu`
Overall: **HIGH** because of the UAF, not only the leak.
**Step 8.4: RISK-BENEFIT RATIO**
Record:
- Benefit: closes UAF + leak + stale static key on hybrid init failure.
High for those systems, zero for others.
- Risk: ~12 lines, `__init` error path only, no locking/API change.
**Low**.
- Ratio: **favor backport**.
===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================
**Step 9.1: COMPILE THE EVIDENCE**
FOR:
- Buggy code is in this 6.12 tree (hybrid since 2021).
- Fixes a real leak (`memset` drops `hybrid_pmu` without `kfree`).
- Fixes a real UAF: kfree of `hybrid_pmu` before `cpuhp_remove_state` →
`intel_pmu_cpu_dead()` → `hybrid_pmu(cpuc->pmu)`.
- Also clears `perf_is_hybrid`, which the register-fail path never did.
- Small (12/−3), obviously correct, reviewed by Intel and applied by
Peter Zijlstra.
- Standalone; patch 1 is only context.
AGAINST:
- No production/syzbot report; found in review.
- Register-fail UAF is a rare path.
- Raw mainline diff does not apply cleanly (log text +
`pmi_unregister`).
- One-time init leak alone would be weak; the UAF is what makes it
important.
UNRESOLVED:
- Could not fetch lore HTML (403); used `b4 dig` + Patchew instead.
Reviews/NAKs still verified.
- Exact `sizeof(struct x86_hybrid_pmu)` not measured; leak is still a
bounded boot-time allocation.
**Step 9.2: STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — reviewed, tested (`perf
test` on Diamond Rapids/Nova Lake), merged via tip.
2. Fixes a real bug that affects users? **PASS** — leak + UAF + stale
hybrid key on hybrid init failure.
3. Important (crash/security/corruption/deadlock)? **PASS** — UAF on
cpuhp rollback after hybrid register failure; leftover hybrid key
after failed init.
4. Small and contained? **PASS** — one file, ~15 lines.
5. No new features or APIs? **PASS** — static helper on the existing
error path.
6. Can apply to the local tree? **PASS** — needs a trivial backport
(insert helper, drop 3 lines, call before `memset`); no missing APIs.
**Step 9.3: EXCEPTION CATEGORIES**
Record: Not a device-ID/quirk/DT/docs exception. Ordinary error-path
memory-safety fix.
**Step 9.4: DECISION**
This tree has the hybrid init bug. The patch is small, correct, and
fixes UAF plus leak on failure. Context from later mainline
(`pmi_unregister`) is not required. It should be backported to this 6.12
tree.
Verification:
- [Phase 1] Tags: Reviewed-by Falcon/Chen; SOB Zijlstra; Link msgid
`...-3-dapeng1.mi@linux.intel.com`; no Fixes/syzbot
- [Phase 1] SHA `96746e731e162` on origin/master; `merge-base --is-
ancestor` vs HEAD = not present
- [Phase 2] Diff: +12/−3 in `arch/x86/events/core.c`; helper + delayed
free + `out_bad_pmu` call
- [Phase 2] 6.12 `init_hw_perf_events` still early-kfrees at lines
2184–2186, then memset at 2200 with no static-key disable
- [Phase 2/5] `intel_pmu_cpu_dead()` uses `hybrid_pmu(cpuc->pmu)` when
`is_hybrid()`; `x86_pmu_dead_cpu` is the PREPARE teardown
- [Phase 3] Hybrid register path blamed to `d9977c43bff89` (2021);
alloc/key to `97588df87b56e2` (2023)
- [Phase 3] Parent `91787047b1dc5` (NMI unregister) not in HEAD; not
required
- [Phase 4] `b4 dig -c 96746e731e162` matched v3 2/8; v1→v3 hunk
unchanged; no NAK
- [Phase 4] Cover letter: review-found bugs; Zide Chen Reviewed-by for
series
- [Phase 4] lore.kernel.org HTTP 403; Patchew used instead
- [Phase 5] `intel_pmu_init_hybrid()` enables `perf_is_hybrid` after
`kcalloc` (this tree, ~6360)
- [Phase 6] `git describe HEAD` = p-6.12-3-gc504cf0baa3d8; `make
kernelversion` = 6.12.111
- [Phase 6] `git apply --check` of raw commit fails on
`x86_pmu_show_pmu_cap` context; logic still maps onto 6.12
`out_bad_pmu`
- [Phase 8] Failure mode: UAF in `intel_pmu_cpu_dead` after hybrid
register fail; leak on `check_hw_exists` fail
- UNVERIFIED: live reproduction of `perf_pmu_register` failure; exact
leaked byte count
The fix is small, matches this tree’s hybrid init code, and closes a
real UAF/leak on PMU init failure.
**YES**
arch/x86/events/core.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index 2aa9270446634..7c37c228a88a4 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -2087,6 +2087,17 @@ void x86_pmu_show_pmu_cap(struct pmu *pmu)
pr_info("... global_ctrl mask: %016llx\n", hybrid(pmu, intel_ctrl));
}
+static void x86_pmu_free_hybrid(void)
+{
+ if (!x86_pmu.hybrid_pmu)
+ return;
+
+ static_branch_disable(&perf_is_hybrid);
+ kfree(x86_pmu.hybrid_pmu);
+ x86_pmu.hybrid_pmu = NULL;
+ x86_pmu.num_hybrid_pmus = 0;
+}
+
static int __init init_hw_perf_events(void)
{
struct x86_pmu_quirk *quirk;
@@ -2214,9 +2225,6 @@ static int __init init_hw_perf_events(void)
for (j = 0; j < i; j++)
perf_pmu_unregister(&x86_pmu.hybrid_pmu[j].pmu);
pr_warn("Failed to register hybrid PMUs\n");
- kfree(x86_pmu.hybrid_pmu);
- x86_pmu.hybrid_pmu = NULL;
- x86_pmu.num_hybrid_pmus = 0;
goto out2;
}
}
@@ -2232,6 +2240,7 @@ static int __init init_hw_perf_events(void)
pmi_unregister:
unregister_nmi_handler(NMI_LOCAL, "PMI");
out_bad_pmu:
+ x86_pmu_free_hybrid();
memset(&x86_pmu, 0, sizeof(x86_pmu));
return err;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH AUTOSEL 6.18] perf/arm-cmn: Add workarounds for CMN-S3 on Graviton5
[not found] <20261019135441.1420968-1-sashal@kernel.org>
2026-10-19 13:45 ` [PATCH AUTOSEL 6.18-5.15] perf/x86/intel/uncore: Fix PCI PMU cleanup on setup failure Sasha Levin
2026-10-19 13:45 ` [PATCH AUTOSEL 6.18-6.1] perf/x86: Free hybrid state on PMU init failure Sasha Levin
@ 2026-10-19 13:47 ` Sasha Levin
2026-10-19 14:35 ` sashiko-bot
2026-10-19 13:47 ` [PATCH AUTOSEL 6.18-6.1] perf: marvell: Cancel CN10K DDR PMU hrtimer on device remove Sasha Levin
` (4 subsequent siblings)
7 siblings, 1 reply; 15+ messages in thread
From: Sasha Levin @ 2026-10-19 13:47 UTC (permalink / raw)
To: patches, stable
Cc: Aviv Bakal, Robin Murphy, Ilkka Koskinen, Will Deacon,
Sasha Levin, mark.rutland, linux-arm-kernel, linux-perf-users,
linux-kernel
From: Aviv Bakal <avivb@amazon.com>
[ Upstream commit 9d0b1714e1af16622a2d0f7317ddaa9a4b27f353 ]
Graviton5 uses a customised CMN-S3 implementation where certain
discovery registers report zeroed fields. Add the following workarounds:
- Introduce a dedicated ACPI HID to identify the Graviton5 CMN variant.
- Derive the DTC domain from the XP node ID, since the unit info
register reports it as zero.
- Set the DTC logical ID from the XP's logical ID, since the node info
register's logical ID field is also zeroed.
Signed-off-by: Aviv Bakal <avivb@amazon.com>
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
Reviewed-by: Ilkka Koskinen <ilkka@os.amperecomputing.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Will Deacon <will@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The local tree is **v7.3-rc4** (kernel 7.3.0-rc4). The question is
whether `9d0b1714e1af1` (`perf/arm-cmn: Add workarounds for CMN-S3 on
Graviton5`) belongs in **this** tree on technical merit.
---
## PHASE 1: COMMIT MESSAGE FORENSICS
**Step 1.1: PARSE THE SUBJECT LINE**
Record: `[perf/arm-cmn] [Add] [workarounds for a customised CMN-S3 on
Graviton5]`
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Record:
- `Fixes:` — none (expected)
- `Reported-by:` — none
- `Tested-by:` — none
- `Reviewed-by: Robin Murphy <robin.murphy@arm.com>` (arm-cmn
maintainer)
- `Reviewed-by: Ilkka Koskinen <ilkka@os.amperecomputing.com>`
- `Link:` — none in the commit
- `Cc: stable@vger.kernel.org` — none (expected)
- `Signed-off-by: Aviv Bakal <avivb@amazon.com>` (author)
- `Signed-off-by: Robin Murphy <robin.murphy@arm.com>`
- `Signed-off-by: Will Deacon <will@kernel.org>`
- Ignored: any Sasha Levin SOB / Upstream-commit markers
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- **Bug:** Graviton5’s CMN-S3 zeros some discovery fields (DTC domain in
unit info, logical ID in node info).
- **Symptom:** Standard discovery cannot identify DTC domains or DTC
logical IDs; a 10×14 mesh also exceeds `CMN_MAX_DIMENSION` 12.
- **Version info:** none in the message.
- **Root cause:** custom silicon, not a kernel logic regression.
Identified via ACPI HID `AMZN0070`.
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: Not a disguised cleanup. It is an explicit hardware workaround
plus ACPI ID. Cover letter language is “adds support”; the mechanism is
a quirk for broken discovery registers.
---
## PHASE 2: DIFF ANALYSIS
**Step 2.1: INVENTORY THE CHANGES**
Record:
- File: `drivers/perf/arm-cmn.c` (+31 / −1)
- Functions: `arm_cmn_graviton5_dtc_domain` (new), `arm_cmn_discover`
(workaround + DTC logid), `arm_cmn_acpi_match[]` (HID)
- Also: `CMN_MAX_DIMENSION` 12→14, `PART_GRAVITON5`
- Scope: single-file, surgical, driver-local
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Record:
- Dimension cap 12→14 so a 10×14 mesh is not rejected.
- ACPI `AMZN0070` → synthetic `PART_GRAVITON5`, then treated as
`PART_CMN_S3`.
- DTC domain: from unit-info register → from XP node ID `(x/5)+(y/7)*2`
on the 10×14 mesh (domains 0–3).
- DTC `logid`: from node info → XP `logid` so sort order matches
firmware IRQ order.
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record: **Hardware workaround + ACPI device ID.** Zeroed discovery
fields would map every XP to DTC domain 0 and every DTC logid to 0. Mesh
10×14 fails `max(mesh_x,mesh_y) > CMN_MAX_DIMENSION` (`36c0de02575ce`,
already in this tree).
**Step 2.4: ASSESS THE FIX QUALITY**
Record:
- Quality: small, gated on `AMZN0070` except the dimension bump.
Maintainer R-b’d after review (v1 used `xp->logid`; v2 used `xp->dtc`;
Robin required `xp->logid` because `cmn->dtc[]` is sorted by logid to
match firmware IRQ order). Committed code matches that.
- Regression risk: low. Workaround is HID-gated. `CMN_MAX_DIMENSION` 14
only grows per-event bitmaps (`CMN_MAX_XPS` 144→196). Domain formula
is Graviton5-specific; x,y are 4-bit so theoretical max domain is 7,
but 10×14 yields 0–3 (`CMN_MAX_DTCS` is 4).
---
## PHASE 3: GIT HISTORY INVESTIGATION
**Step 3.1: BLAME THE CHANGED LINES**
Record:
- Workaround and dimension bump introduced by `9d0b1714e1af1` itself
(Aviv Bakal, 2026-06-30; merged 2026-07-21).
- Driver: long-standing. CMN-S3: `0dc2f4963f7ef` (2024-09-04). ACPI
`ARMHC003`: `8c138a189f6db` (2025-05-19). Mesh reject: `36c0de02575ce`
(2026-02-03, `Cc: stable`).
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: No `Fixes:` tag. Not a regression from a specific kernel commit;
hardware does not implement discovery as the driver expects.
**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
Record:
- This is **v6 2/2**. Patch 1 is `56603c28d9169` (`Move DTM index data
out of hw_perf_event`) — **already an ancestor of HEAD**. Needed
because embedded `dtm_idx`/`wp_idx` in `hw_perf_event` were size-
capped; growing `CMN_MAX_DIMENSION` without that move would fail
`static_assert(sizeof(struct arm_cmn_hw_event) <= offsetof(struct
hw_perf_event, target))`.
- Later 7.3 work (filter refactor, CMN S3 r2) does not revert the
workaround. No graviton-specific follow-up.
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: Aviv Bakal (Amazon) — this is their only arm-cmn commit here.
Robin Murphy is the driver author/maintainer and both reviewed and re-
posted v6.
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record: Needs CMN-S3, ACPI table, mesh-size check, and the DTM-index
move. **All are in this 7.3-rc4 tree.** Standalone on this tree.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- `b4 dig -c 9d0b1714e1af1` → https://patch.msgid.link/e9340d3a4385e6f1a
6e80bda944a3ba6435472b6.1782824005.git.robin.murphy@arm.com
- Revisions: v1 (2026-05-03) → v2 → v3 (added DTM move) → v4 → v5 → **v6
applied** (Robin re-post, 2026-06-30)
- Robin on v2: use `xp->logid` not `xp->dtc`; “surprisingly pleasant and
unobtrusive given that it's a pretty horrible hardware issue”
- No NAK. Applied version is latest.
- A sashiko-bot note about unbounded DTC domain / sort order is the
opposite of Robin’s requested `xp->logid` behaviour; not a NAK from
maintainers.
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record (`b4 dig -w`): Robin Murphy, Will Deacon, Mark Rutland, linux-
arm-kernel, linux-perf-users, Amazon (zeev, blakgeof), Ilkka Koskinen.
Right maintainers.
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record: No syzbot/bugzilla. Amazon submitted from silicon bring-up.
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: Series is DTM-index move + this workaround. Patch 1 is in this
tree. No extra ACPI docs/HID patch required (`AMZN0070` is only in `arm-
cmn.c`).
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: lore.kernel.org/stable search returned 403. **UNVERIFIED:** no
confirmed stable-list nomination or rejection.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
**Step 5.1: IDENTIFY KEY FUNCTIONS**
Record: `arm_cmn_graviton5_dtc_domain`, `arm_cmn_discover`,
`arm_cmn_acpi_match`, `arm_cmn_init_node_info` (unchanged, still source
of zeroed logid).
**Step 5.2: TRACE CALLERS**
Record: `arm_cmn_discover()` ← `arm_cmn_probe()` only. Probe runs when
ACPI matches (including `AMZN0070`). Not IRQ/syscall hot path;
boot/device-init.
**Step 5.3: TRACE CALLEES**
Record: `arm_cmn_init_node_info`, `arm_cmn_dtc_domain` / graviton5
variant, `arm_cmn_init_dtm`, then `arm_cmn_init_dtcs` (sort by
type+logid, `platform_get_irq` by sort index).
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: ACPI `AMZN0070` → probe → discover (workaround) → init DTCs/IRQs
→ register PMU. Userspace `perf` then uses the interconnect PMU.
Reachable on Graviton5 with `CONFIG_ARM_CMN`.
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: Same file already has AmpereOneX bogus-child-pointer handling
and CMN-600AE aliasing. Same “quirks for broken discovery” pattern.
---
## PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record: Yes. `drivers/perf/arm-cmn.c` has CMN-S3, ACPI match, mesh-size
reject. Without this commit, `AMZN0070` would not bind; a 10×14 mesh
would `-ENODEV`; zeroed DTC fields would mis-program the PMU. Introduced
as hardware behaviour, not a post-7.3 commit.
`git describe HEAD` = `v7.3-rc4-27-gf0100363d8c37`. Commit is in
v7.3-rc1 (not in v7.2). That is **not** used as “already selected”; it
only shows 7.3 has the prerequisites.
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: Clean on this tree. Context still matches (graviton5 flag, ACPI
HID, dimension 14). Later S3 r2/filter refactors left the workaround in
place.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: No alternate Graviton5 fix. No later graviton-specific patch in
`9d0b1714e1af1..HEAD`.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
**Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY**
Record: `drivers/perf/` — Arm CMN uncore PMU. **PERIPHERAL/IMPORTANT:**
ARM64 servers with CMN; Graviton5-specific for the HID path. Not
mm/sched/VFS.
**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**
Record: Active in 7.3 (S3 r2, filters, DTM layout). Driver itself is
mature (~CMN-600 era).
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
**Step 8.1: DETERMINE WHO IS AFFECTED**
Record: ACPI `AMZN0070` / Graviton5 only, plus a small extra bitmap size
for all `CONFIG_ARM_CMN` users.
**Step 8.2: DETERMINE THE TRIGGER CONDITIONS**
Record: Probe on Graviton5. Not unprivileged-triggerable beyond normal
perf. Not a race. Common on that platform at boot.
**Step 8.3: DETERMINE THE FAILURE MODE SEVERITY**
Record: Missing/wrong CMN PMU (no bind, `-ENODEV`, or events on the
wrong DTC). Not panic/corruption/deadlock. **MEDIUM** for that hardware;
still the documented quirk/ID exception.
**Step 8.4: CALCULATE RISK-BENEFIT RATIO**
Record:
- Benefit: Graviton5 CMN perf actually works (HID + discovery + 10×14
mesh).
- Risk: low (~31 lines, HID-gated, maintainer-reviewed). Dimension bump
is small and already paired with the DTM-index move in this tree.
- Ratio: favorable.
---
## PHASE 9: FINAL SYNTHESIS
**Step 9.1: COMPILE THE EVIDENCE**
**FOR:**
- ACPI ID + hardware quirk on an existing driver (stable exception).
- Real silicon: zeroed CMN-S3 discovery, 10×14 mesh.
- Small, single-file, obviously correct after maintainer review.
- Prerequisites present in 7.3-rc4.
- Robin Murphy: use `xp->logid`; workaround is unobtrusive.
**AGAINST:**
- Enablement/quirk, not a crash/security/corruption fix.
- Cover letter is “add support”.
- `CMN_MAX_DIMENSION` affects all CMN bitmap sizes (small).
- Series 2/2 (patch 1 already here).
- No `Reported-by` from production crashes.
**UNRESOLVED:**
- Stable list discussion (lore 403).
- No public Tested-by (author is Amazon; hardware access is plausible
but unverified).
**Step 9.2: APPLY THE STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — maintainer R-b after v1–v6;
IRQ/logid issue addressed as Robin specified.
2. Fixes a real bug that affects users? **PASS** — Graviton5 CMN PMU
cannot enumerate correctly without it.
3. Important issue? **PASS** via quirk/ID exception (severity MEDIUM as
a PMU, not a panic).
4. Small and contained? **PASS** — +31/−1, one file.
5. No new features or APIs? **PASS** — no new uAPI; HID + discovery
workaround on existing PMU.
6. Can apply to the local tree? **PASS** — driver, CMN-S3, DTM-index
move, mesh check all present.
**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**
Record: **ACPI device ID** (`AMZN0070`) **and hardware quirk** for
customised CMN-S3.
**Step 9.4: MAKE YOUR DECISION**
This tree is 7.3-rc4, which already contains CMN-S3 and the series
prerequisite. The patch is the standard stable shape: ID + quirk so
existing `arm-cmn` works on shipping Graviton5. Benefit is real for that
platform; risk is low and mostly HID-gated.
---
## What the commit solves and why it matters here
Graviton5 implements CMN-S3 with discovery registers that read as zero
and a 10×14 mesh. In this tree, `arm_cmn_discover()` would then put
every XP in DTC domain 0, leave DTC logids at 0 (breaking IRQ sort
order), and reject the mesh as larger than 12. Adding `AMZN0070` and the
three workarounds makes the existing CMN PMU usable on that hardware
without new APIs.
It meets stable rules as a quirk/ID exception: small, reviewed, no uAPI,
applies cleanly here because `56603c28d9169` already moved DTM arrays
out of `hw_perf_event`.
Risk vs benefit: extra bitmap bytes for all CMN users vs a working
interconnect PMU on Graviton5. Favorable.
Concerns: not a panic-class bug; depends on the DTM-index move (already
in this tree). No stable-list confirmation (fetch failed).
---
## Verification
- [Phase 1] Parsed tags: R-b Robin Murphy + Ilkka Koskinen; SOB Aviv
Bakal, Robin Murphy, Will Deacon; no Fixes/Reported-by/Cc:stable
- [Phase 2] Diff: `drivers/perf/arm-cmn.c` +31/−1; HID `AMZN0070`,
`CMN_MAX_DIMENSION` 14, DTC domain/logid workarounds
- [Phase 2] Current tree still has graviton5 paths at `arm_cmn_discover`
/ `arm_cmn_graviton5_dtc_domain` / ACPI table
- [Phase 3] `git describe HEAD` = v7.3-rc4-27-gf0100363d8c37; `make
kernelversion` = 7.3.0-rc4
- [Phase 3] `git merge-base --is-ancestor 9d0b1714e1af1 HEAD` — yes; in
v7.3-rc1, not v7.2
- [Phase 3] CMN-S3 `0dc2f4963f7ef` (2024-09-04) in tree; ACPI S3
`8c138a189f6db` in tree
- [Phase 3] Mesh reject `36c0de02575ce` in tree; DTM move
`56603c28d9169` in tree (series 1/2)
- [Phase 3] `git blame` on workaround lines → `9d0b1714e1af1`
- [Phase 3] No graviton follow-ups in `9d0b1714e1af1..HEAD`
- [Phase 4] `b4 dig -c 9d0b1714e1af1` → v6 2/2 msgid `e9340d3a4385e6f1a6
e80bda944a3ba6435472b6.1782824005.git.robin.murphy@arm.com`
- [Phase 4] `b4 dig -a`: v1–v6; applied is v6
- [Phase 4] `b4 dig -w`: Will/Mark/Robin, linux-arm-kernel, linux-perf-
users
- [Phase 4] Robin v2 review: must use `xp->logid` for firmware IRQ order
(committed code does)
- [Phase 4] UNVERIFIED: lore.kernel.org/stable (403)
- [Phase 5] `arm_cmn_discover` only from `arm_cmn_probe`; ACPI match
includes `AMZN0070`
- [Phase 6] Buggy discovery path and mesh check exist in this checkout;
apply is clean
- [Phase 7] `CONFIG_ARM_CMN` depends on ARM64 || COMPILE_TEST
- [Phase 8] Failure: missing/wrong CMN PMU on Graviton5, not
oops/deadlock; severity MEDIUM + quirk exception
- UNVERIFIED: Amazon Tested-by on silicon (not in tags)
**YES**
drivers/perf/arm-cmn.c | 32 +++++++++++++++++++++++++++++++-
1 file changed, 31 insertions(+), 1 deletion(-)
diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c
index 527a953bf4744..688a94ef81c22 100644
--- a/drivers/perf/arm-cmn.c
+++ b/drivers/perf/arm-cmn.c
@@ -31,7 +31,8 @@
#define CMN_CHILD_NODE_ADDR GENMASK(29, 0)
#define CMN_CHILD_NODE_EXTERNAL BIT(31)
-#define CMN_MAX_DIMENSION 12
+/* Some implementations use a mesh larger than the architectural max of 12 */
+#define CMN_MAX_DIMENSION 14
#define CMN_MAX_XPS (CMN_MAX_DIMENSION * CMN_MAX_DIMENSION)
#define CMN_MAX_DTMS (CMN_MAX_XPS + (CMN_MAX_DIMENSION - 1) * 4)
@@ -215,6 +216,8 @@ enum cmn_part {
PART_CMN700 = 0x43c,
PART_CI700 = 0x43a,
PART_CMN_S3 = 0x43e,
+ /* Synthetic part number, overridden to PART_CMN_S3 during discovery */
+ PART_GRAVITON5 = 0xa5,
};
/* CMN-600 r0px shouldn't exist in silicon, thankfully */
@@ -2217,6 +2220,18 @@ static unsigned int arm_cmn_dtc_domain(struct arm_cmn *cmn, void __iomem *xp_reg
return FIELD_GET(CMN_DTM_UNIT_INFO_DTC_DOMAIN, readl_relaxed(xp_region + offset));
}
+static unsigned int arm_cmn_graviton5_dtc_domain(u16 xp_id)
+{
+ unsigned int x = (xp_id >> 7) & 0xf;
+ unsigned int y = (xp_id >> 3) & 0xf;
+
+ /*
+ * The unit info register reads as zero; derive the DTC domain from
+ * the XP's mesh coordinates over the 10x14 mesh.
+ */
+ return (x / 5) + (y / 7) * 2;
+}
+
static void arm_cmn_init_node_info(struct arm_cmn *cmn, u32 offset, struct arm_cmn_node *node)
{
int level;
@@ -2262,6 +2277,7 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
u64 reg;
int i, j;
size_t sz;
+ bool graviton5_workaround = false;
arm_cmn_init_node_info(cmn, rgn_offset, &cfg);
if (cfg.type != CMN_TYPE_CFG)
@@ -2272,6 +2288,13 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
reg = readq_relaxed(cfg_region + CMN_CFGM_PERIPH_ID_01);
part = FIELD_GET(CMN_CFGM_PID0_PART_0, reg);
part |= FIELD_GET(CMN_CFGM_PID1_PART_1, reg) << 8;
+
+ /* Graviton5 has a customised CMN-S3 which needs some fixups */
+ if (cmn->part == PART_GRAVITON5) {
+ cmn->part = PART_CMN_S3;
+ graviton5_workaround = true;
+ }
+
/* 600AE is close enough that it's not really worth more complexity */
if (part == PART_CMN600AE)
part = PART_CMN600;
@@ -2361,6 +2384,8 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
if (cmn->part == PART_CMN600)
xp->dtc = -1;
+ else if (graviton5_workaround)
+ xp->dtc = arm_cmn_graviton5_dtc_domain(xp->id);
else
xp->dtc = arm_cmn_dtc_domain(cmn, xp_region);
@@ -2439,6 +2464,10 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
switch (dn->type) {
case CMN_TYPE_DTC:
+ if (graviton5_workaround) {
+ /* Node info logical ID is zeroed; use the XP's */
+ dn->logid = xp->logid;
+ }
cmn->num_dtcs++;
dn++;
break;
@@ -2671,6 +2700,7 @@ static const struct acpi_device_id arm_cmn_acpi_match[] = {
{ "ARMHC650" },
{ "ARMHC700" },
{ "ARMHC003" },
+ { "AMZN0070", PART_GRAVITON5 },
{}
};
MODULE_DEVICE_TABLE(acpi, arm_cmn_acpi_match);
--
2.53.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH AUTOSEL 6.18-6.1] perf: marvell: Cancel CN10K DDR PMU hrtimer on device remove
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (2 preceding siblings ...)
2026-10-19 13:47 ` [PATCH AUTOSEL 6.18] perf/arm-cmn: Add workarounds for CMN-S3 on Graviton5 Sasha Levin
@ 2026-10-19 13:47 ` Sasha Levin
2026-10-19 14:44 ` sashiko-bot
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18] perf/core: Fix kernel register info leak via hardware skid Sasha Levin
` (3 subsequent siblings)
7 siblings, 1 reply; 15+ messages in thread
From: Sasha Levin @ 2026-10-19 13:47 UTC (permalink / raw)
To: patches, stable
Cc: Geetha sowjanya, Will Deacon, Sasha Levin, mark.rutland,
linux-arm-kernel, linux-perf-users, linux-kernel
From: Geetha sowjanya <gakula@marvell.com>
[ Upstream commit 7dbcb0268d1e2a1d3badb0c6e77ee70e550b1787 ]
cn10k_ddr_perf_remove() did not cancel the poll hrtimer before returning.
If the device was unbound while perf events were still active the timer
callback could run post-free.
To fix the issue by adding hrtimer_cancel() in remove().
Signed-off-by: Geetha sowjanya <gakula@marvell.com>
Signed-off-by: Will Deacon <will@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
I have enough to decide: the UAF is in this 6.1 tree, the cancel is a
standalone 6-line fix, and it does not need the CN20K series.
===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================
**Step 1.1: PARSE THE SUBJECT LINE**
Record: `[perf/marvell] [Cancel] Cancel CN10K DDR PMU hrtimer on device
remove`
Subsystem `perf: marvell:` is the Marvell CN10K DDR uncore PMU driver.
Verb `Cancel` is a stop-the-timer safety action. Claimed intent: stop
the poll hrtimer in the platform `remove()` path so it cannot fire after
the device is torn down.
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Record: tags present in the candidate message:
- `Signed-off-by: Geetha sowjanya <gakula@marvell.com>` (author)
- `Signed-off-by: Will Deacon <will@kernel.org>` (ARM perf maintainer
merge; pipeline `Signed-off-by: Sasha Levin` ignored per instructions)
Tags **not** present (expected for this review queue, not treated as a
negative):
- No `Fixes:`
- No `Reported-by:` / `Tested-by:` / `Reviewed-by:` / `Acked-by:`
- No `Link:`
- No `Cc: stable@vger.kernel.org`
From mailing-list forensics (Phase 4): original submission was `[PATCH
v8 3/3]` of a CN20K feature series, Message-ID
`20260601073318.7098-4-gakula@marvell.com`. Will Deacon applied it to
`arm64 (for-next/perf)` as `7dbcb0268d1e`. Krzysztof’s `Reviewed-by` is
on patch 1/3 (dt-bindings) only, not on this UAF patch.
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- **Bug:** `cn10k_ddr_perf_remove()` returned without cancelling the
overflow-poll hrtimer.
- **Symptom / failure mode:** if the device is unbound while events (and
therefore the timer) are still active, `cn10k_ddr_pmu_timer_handler()`
can run after `devm` frees `struct cn10k_ddr_pmu` and unmaps MMIO —
use-after-free / MMIO-after-unmap.
- **Version info:** cover letter for v8 says this is **pre-existing for
CN10K/Odyssey**, not a CN20K-only issue.
- **Root cause (author):** missing `hrtimer_cancel()` in `remove()`.
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: Not a disguised cleanup. The message names a post-free timer
callback. This is an explicit UAF fix. The series is mostly a CN20K
feature add; **this patch was split out in v8 specifically as a pre-
existing bug fix**.
===============================================================
PHASE 2: DIFF ANALYSIS - LINE BY LINE
===============================================================
**Step 2.1: INVENTORY THE CHANGES**
Record:
- File: `drivers/perf/marvell_cn10k_ddr_pmu.c`
- Scope: **+6 / -0**, single function `cn10k_ddr_perf_remove()`
- Classification: **single-file surgical fix** (comment +
`hrtimer_cancel()`)
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Record:
- **Before:** `remove()` got drvdata, dropped the cpuhp instance,
unregistered the PMU, returned. Timer left live if it had been
started.
- **After:** `hrtimer_cancel(&ddr_pmu->hrtimer)` **first**, then the
same teardown. `hrtimer_cancel()` also waits for a running callback,
so the handler cannot continue after `remove()` returns.
- Path: **driver teardown / unbind / module unload**, not the normal
event add/del path (that already cancels on last `event_del`).
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record: **Use-after-free / lifetime bug (memory safety)**
Mechanism verified in this tree:
- `ddr_pmu` is `devm_kzalloc()`’d; MMIO is
`devm_platform_get_and_ioremap_resource()`. Both are released after
`remove()` returns.
- Timer is started on first `event_add` (`hrtimer_start`,
`HRTIMER_MODE_REL_PINNED`) and cancelled only when `active_events ==
0` in `event_del`.
- Handler always `return HRTIMER_RESTART` after
`cn10k_ddr_pmu_overflow_handler(pmu)`, which dereferences
`pmu->events[]` and `pmu->base`.
- `perf_pmu_unregister()` in this tree (`kernel/events/core.c`) does
**not** stop events or cancel driver timers; it only unlists the PMU,
syncs RCU, and frees PMU context.
**Step 2.4: ASSESS THE FIX QUALITY**
Record:
- **Quality:** obviously correct. `hrtimer_cancel()` on an already-idle
timer is a no-op; cancelling before cpuhp/PMU teardown is the right
order.
- **Regression risk:** very low. Callback only does `local_irq_save` +
MMIO reads; it does not take locks `remove()` holds. No API/data-
structure change.
- **Red flags:** none in the hunk itself. Series context (3/3 of CN20K)
is a packaging concern, not a correctness concern — this hunk does not
use CN20K code.
===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================
**Step 3.1: BLAME THE CHANGED LINES**
Record:
- Buggy `cn10k_ddr_perf_remove()` (no timer cancel) introduced in
`7cf83e222bce0` (`perf/marvell: CN10k DDR performance monitor
support`, Bharat Bhushan, 2022-03-08).
- `git merge-base --is-ancestor 7cf83e222bce0 HEAD` succeeded; `git
merge-base --is-ancestor 7cf83e222bce0 v6.1` succeeded.
- Present in this tree from the 6.1 baseline (driver landed in v5.18).
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: No `Fixes:` tag. The introducing commit is `7cf83e222bce0`,
which **is** in this tree.
**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
Record: only four commits on this file in this tree:
- `7cf83e222bce0` CN10k DDR perfmon support
- `35a43326a9e3c` overflow handling
- `68fa55f0e05ce` core ownership
- `6676a42f1e4f1` `!CONFIG_OF` build fix
No later refactor of `remove()`. **Standalone** relative to this tree.
Does **not** need patches 1–2 of the CN20K series.
Related but **separate** bug (v7 of the same series, in patch 2/3):
`event_add` can `hrtimer_start()` then return `-EINVAL` from
`ddr_perf_get_event_bitmap()` without rolling back. That leak is **not**
this commit. This commit still stands alone.
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: `git log --author=Geetha -- drivers/perf/` is empty in this 6.1
tree. Author is a Marvell engineer extending a Marvell driver originally
by Bharat Bhushan. Will Deacon (ARM perf maintainer) merged it. That is
sufficient maintainer vetting.
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record: **No functional prerequisites.** The only apply wrinkle is 6.1
still has `static int cn10k_ddr_perf_remove(...)` returning `0`; later
kernels converted platform `.remove` to `void`. The added
`hrtimer_cancel()` line and comment apply unchanged.
===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- `b4 dig -c HEAD` was the wrong SHA (this commit is not in the 6.1
checkout). Direct lore fetch returned 403.
- `b4 am` on Message-ID `20260601073318.7098-4-gakula@marvell.com`
succeeded: v8 series, 3 patches, DKIM-signed, no newer revision
flagged.
- Lore/mirrors:
https://patch.msgid.link/20260601073318.7098-1-gakula@marvell.com ,
openwall, lkml.iu.edu, patchew, ratatoskr.
- Cover letter v8: “Cancel the poll hrtimer in `cn10k_ddr_perf_remove()`
before `devm` frees `struct cn10k_ddr_pmu` (pre-existing for
CN10K/Odyssey).”
- **No NAK.** Will Deacon: “Applied to arm64 (for-next/perf)” with git
id `7dbcb0268d1e` for this patch.
- **No reviewer `Cc: stable` found** (not treated as a negative).
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record: To/Cc on the original mail: `linux-perf-users`, `linux-kernel`,
`linux-arm-kernel`, `devicetree`, Mark Rutland, Will Deacon, Krzysztof
Kozlowski. Will Deacon merged. No NAK on 3/3.
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record: No syzbot, bugzilla, or external user report. Bug was found
during CN20K series review/development (added in v8). Still a concrete
UAF, just not fuzzer-reported.
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: Series is:
1. dt-bindings CN20K — feature, not this decision
2. CN20K driver support (+ event_add rollback) — feature / separate leak
fix
3. **this UAF cancel** — independent 6-line fix
Do **not** pull 1/3 or 2/3 into 6.1. This commit does not call CN20K
pdata/helpers.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: lore.kernel.org/stable search returned 403. No evidence on the
public v8 thread that stable rejected this. UNVERIFIED: whether
`-stable` ever discussed this hash by name.
===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================
**Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF**
Record: `cn10k_ddr_perf_remove()` only. Related existing functions:
`cn10k_ddr_perf_event_add`, `cn10k_ddr_perf_event_del`,
`cn10k_ddr_pmu_timer_handler`, `cn10k_ddr_pmu_overflow_handler`.
**Step 5.2: TRACE CALLERS**
Record:
- `cn10k_ddr_perf_remove` is the platform driver’s `.remove`
(`cn10k_ddr_pmu_driver`). Callers: device unbind, parent device
teardown, `platform_driver_unregister()` from `cn10k_ddr_pmu_exit()`.
- Timer handler is the hrtimer softirq/callback path, not a syscall.
**Step 5.3: TRACE CALLEES**
Record: `remove()` calls `platform_get_drvdata`, `hrtimer_cancel` (new),
`cpuhp_state_remove_instance_nocalls`, `perf_pmu_unregister`. Handler
calls overflow path which does MMIO `readq_relaxed` on `pmu->base`.
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: Userspace can start the timer via `perf_event_open` on this
uncore PMU (`event_add` when `active_events == 1`). Unbind/unload is
admin-triggered (module unload, device teardown), not an unprivileged
syscall by itself. `event_init` does **not** validate `attr.config`;
`event_add` can start the timer then fail `ddr_perf_get_event_bitmap()`.
`event_sched_in()` on add failure does **not** call `pmu->del()`
(verified at `kernel/events/core.c:2591-2595`). That can leave a running
timer even after a failed `perf_event_open`, after which `rmmod` can run
`remove()` with the timer still live. Reachable from userspace + admin
unload.
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: In this tree, this driver only cancels the timer in `event_del`.
`drivers/perf/thunderx2_pmu.c` also cancels on CPU offline. Sibling DDR
PMU `fsl_imx8_ddr_perf.c` also does not cancel in `remove()` here —
pattern exists, but that does not make this UAF fictional.
===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record: **Yes.** Local tree is **6.1.188** (`pending-6.1`, `git
describe` `p-6.1-10-g80966a5b14be4`).
```700:710:drivers/perf/marvell_cn10k_ddr_pmu.c
static int cn10k_ddr_perf_remove(struct platform_device *pdev)
{
struct cn10k_ddr_pmu *ddr_pmu = platform_get_drvdata(pdev);
cpuhp_state_remove_instance_nocalls(
CPUHP_AP_PERF_ARM_MARVELL_CN10K_DDR_ONLINE,
&ddr_pmu->node);
perf_pmu_unregister(&ddr_pmu->pmu);
return 0;
}
```
No `hrtimer_cancel()`. Introduced with the driver in `7cf83e222bce0`
(v5.18), present for the whole 6.1 lifetime.
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: **Minor context only.** 6.1 `remove` is `int` and returns `0`;
later kernels use `void`. OF match table in 6.1 has no `.data` / CN20K
entries. The added call does not depend on those. Expected apply:
**minor conflict, trivial rework**.
This tree still has `suppress_bind_attrs = true`, so **sysfs**
bind/unbind is hidden. That does **not** skip `.remove` on parent
teardown or `platform_driver_unregister()`.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: No `hrtimer_cancel` in `remove()`. No event_add rollback (`goto
err_free_counter`). Nothing already fixes this UAF.
===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================
**Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY**
Record: `drivers/perf/` Marvell CN10K DDR PMU. **PERIPHERAL** (SoC-
specific uncore PMU). Config `MARVELL_CN10K_DDR_PMU` depends on
`ARCH_THUNDER || (COMPILE_TEST && 64BIT)` — Octeon 10 / Thunder-class
ARM64.
**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**
Record: File is mature and quiet in 6.1 (four commits total). Bug is
old, not a last-month regression.
===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================
**Step 8.1: DETERMINE WHO IS AFFECTED**
Record: **Driver-specific / config-specific:**
`CONFIG_MARVELL_CN10K_DDR_PMU` on Marvell CN10K (`ARCH_THUNDER`). Not
universal.
**Step 8.2: DETERMINE THE TRIGGER CONDITIONS**
Record:
- Timer starts when the first perf event is added; period default
**100s** (`poll_period_sec`).
- Classic trigger: device `remove()` while the timer is queued (unbind /
parent removal / module exit).
- Mitigations in **this** tree: `suppress_bind_attrs = true` (no sysfs
unbind); successful events `try_module_get` the module so `rmmod`
waits for last close, and last `event_del` already cancels the timer.
- Remaining realistic triggers: platform device teardown with events
still open; **failed `event_add` after `hrtimer_start`** leaving a
live timer so `rmmod` can hit `remove()` without `event_del`.
- Unprivileged user can start/leak the timer via `perf_event_open`;
teardown is typically admin. Failure mode is still kernel UAF.
**Step 8.3: DETERMINE THE FAILURE MODE SEVERITY**
Record: Timer callback uses freed `cn10k_ddr_pmu` and unmapped MMIO →
**use-after-free / oops / memory corruption**. Severity: **HIGH** (UAF).
Not a guaranteed panic on every boot; when it hits, it is a hard kernel
memory-safety failure.
**Step 8.4: CALCULATE RISK-BENEFIT RATIO**
Record:
- **Benefit:** HIGH for CN10K users who unload/unbind with a live poll
timer; prevents UAF. Population is small but the bug class is serious.
- **Risk:** VERY LOW (6 lines, no-op if timer idle, no locking change).
- **Ratio:** strongly in favor of backporting.
===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================
**Step 9.1: COMPILE THE EVIDENCE**
**FOR:**
- Real UAF: poll hrtimer can run after `devm` free of the PMU struct.
- Bug exists in this 6.1 tree since the driver was added
(`7cf83e222bce0`).
- Surgical, obviously correct (`hrtimer_cancel` before teardown).
- Maintainer-merged (Will Deacon).
- Author/cover letter call it a **pre-existing CN10K** bug, not
CN20K-only.
- Independent of CN20K patches 1–2.
- Failed `event_add` in this tree can leave the timer running;
`pmu->add` failure does not call `del()`.
- `hrtimer_cancel` on idle timer is safe.
**AGAINST:**
- Peripheral SoC PMU, not a core path.
- No syzbot/user report.
- `suppress_bind_attrs` hides sysfs unbind; happy-path `rmmod` after
clean event_del already cancels the timer.
- Packaged as 3/3 of a feature series (but this hunk is independent).
- Trivial `int` vs `void` `remove` context mismatch.
**UNRESOLVED:**
- Could not fetch lore.kernel.org (403) or git.kernel.org (Anubis);
discussion reconstructed via `b4 am`, patchew, and mirrors.
- No `-stable` thread found (403).
- Exact mainline SHA in Linus’s tree not in this checkout; arm64
application id `7dbcb0268d1e` from Will’s mail.
**Step 9.2: APPLY THE STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — one `hrtimer_cancel()`,
merged by Will Deacon, idle-timer cancel is a no-op.
2. Fixes a real bug that affects users? **PASS** — UAF on remove with a
live poll timer; code present here.
3. Important issue? **PASS** — use-after-free / crash / memory
corruption (HIGH). Trigger is not every boot, but severity matches
stable’s crash/UAF bar.
4. Small and contained? **PASS** — 6 lines, one function, one file.
5. No new features or APIs? **PASS**.
6. Can apply to the local tree? **PASS** — buggy `remove()` is here;
only `int` vs `void` `remove` needs a one-line context tweak.
**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**
Record: Not a device-ID / quirk / DT / build / docs exception. It is a
normal small UAF fix.
**Step 9.4: MAKE YOUR DECISION**
This should be backported to **this** 6.1 tree. The CN20K feature
patches must stay out; this cancel is self-contained and matches the
code that has been in 6.1 from day one.
===============================================================
What the commit solves, and why it matters here
===============================================================
`cn10k_ddr_perf_remove()` tears down cpuhp and unregisters the PMU but
never stops the overflow-poll hrtimer. The PMU object and MMIO are
`devm`-managed, so they are freed as soon as `remove()` returns. If the
timer is still queued, `cn10k_ddr_pmu_timer_handler()` can run on freed
memory. That is a real UAF on Marvell CN10K systems that use this driver
— exactly the hardware this 6.1 tree already supports.
It meets stable rules: obviously correct, small, no new API, and the
buggy function is in this checkout. Risk is negligible. Benefit is
preventing a kernel UAF. The only backport edit is matching 6.1’s `int`
`remove` callback.
===============================================================
Verification
===============================================================
- [Phase 1] Parsed subject/body/tags: UAF-on-remove; SOBs Geetha
sowjanya + Will Deacon; no Fixes/Reported-by/Cc-stable.
- [Phase 2] Diff: +6 in `cn10k_ddr_perf_remove()` only; adds
`hrtimer_cancel()` before cpuhp/PMU teardown.
- [Phase 2] `perf_pmu_unregister()` at `kernel/events/core.c:11587` does
not cancel driver timers or wait for `event_del`.
- [Phase 2] Handler at lines 600–612 always `HRTIMER_RESTART` and uses
`pmu->base` / `pmu->events[]`.
- [Phase 3] `git describe HEAD` → `p-6.1-10-g80966a5b14be4`; `make
kernelversion` → 6.1.188.
- [Phase 3] `git merge-base --is-ancestor 7cf83e222bce0 HEAD` →
introducing driver commit is in this tree.
- [Phase 3] `git blame` on `remove()` → `7cf83e222bce0` (no cancel) and
`68fa55f0e05ce` (cpuhp).
- [Phase 3] File history: 4 commits; no existing remove-path timer fix.
- [Phase 4] `b4 am` msgid `20260601073318.7098-4-gakula@marvell.com` →
v8 3/3; cover letter “pre-existing for CN10K/Odyssey”.
- [Phase 4] Patchew: Will Deacon applied 3/3 as `7dbcb0268d1e`; no NAK.
- [Phase 4] lore.kernel.org and git.kernel.org fetches: 403 / Anubis —
used b4/patchew/mirrors instead.
- [Phase 5] `event_sched_in` add-failure path (`core.c:2591`) does not
call `pmu->del()`.
- [Phase 5] Local `event_init` does not validate `attr.config`;
`event_add` can start the timer then return `-EINVAL`.
- [Phase 6] Read local `cn10k_ddr_perf_remove()`: no `hrtimer_cancel`;
`devm_kzalloc` + `suppress_bind_attrs = true` confirmed.
- [Phase 7] Kconfig `MARVELL_CN10K_DDR_PMU` depends on `ARCH_THUNDER`.
- [Phase 8] Failure mode: UAF in hrtimer callback after `devm` free —
HIGH.
- UNVERIFIED: `-stable` list discussion of this exact commit
(lore/stable 403).
- UNVERIFIED: Linus-tree SHA beyond Will’s arm64 id `7dbcb0268d1e`.
**YES**
drivers/perf/marvell_cn10k_ddr_pmu.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/perf/marvell_cn10k_ddr_pmu.c b/drivers/perf/marvell_cn10k_ddr_pmu.c
index 72ac17efd846a..9974b62541f0d 100644
--- a/drivers/perf/marvell_cn10k_ddr_pmu.c
+++ b/drivers/perf/marvell_cn10k_ddr_pmu.c
@@ -1088,6 +1088,12 @@ static void cn10k_ddr_perf_remove(struct platform_device *pdev)
{
struct cn10k_ddr_pmu *ddr_pmu = platform_get_drvdata(pdev);
+ /*
+ * Cancel the poll timer before further teardown so the handler
+ * cannot run after this function returns.
+ */
+ hrtimer_cancel(&ddr_pmu->hrtimer);
+
cpuhp_state_remove_instance_nocalls(
CPUHP_AP_PERF_ARM_MARVELL_CN10K_DDR_ONLINE,
&ddr_pmu->node);
--
2.53.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH AUTOSEL 6.18] perf/core: Fix kernel register info leak via hardware skid
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (3 preceding siblings ...)
2026-10-19 13:47 ` [PATCH AUTOSEL 6.18-6.1] perf: marvell: Cancel CN10K DDR PMU hrtimer on device remove Sasha Levin
@ 2026-10-19 13:48 ` Sasha Levin
2026-10-19 14:42 ` sashiko-bot
2026-10-19 13:51 ` [PATCH AUTOSEL 6.18-6.1] perf/x86: Unregister PMI handler on PMU init failure Sasha Levin
` (2 subsequent siblings)
7 siblings, 1 reply; 15+ messages in thread
From: Sasha Levin @ 2026-10-19 13:48 UTC (permalink / raw)
To: patches, stable
Cc: Dapeng Mi, Peter Zijlstra (Intel), Sasha Levin, mingo, acme,
namhyung, linux-perf-users, linux-kernel
From: Dapeng Mi <dapeng1.mi@linux.intel.com>
[ Upstream commit 166f10836a653dfa280d4335603b52f685b8b1ef ]
An unprivileged hardware perf event using exclude_kernel=1 can leak kernel
register data to user space via PERF_SAMPLE_REGS_INTR or PERF_SAMPLE_IP.
Due to hardware skid, a PMI may trigger after the CPU has already entered
kernel space (Ring 0), bypassing the perf_allow_kernel() privilege
barrier.
This security vulnerability is severely exacerbated by upcoming support
for SIMD register sampling via XSAVES, which could expose sensitive kernel
FPU states (such as active cryptographic keys).
Fix this by ensuring that sampled register data is dropped if the event's
exclude_kernel attribute is set but the PMI catches the CPU in kernel mode.
Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/all/20260529085613.CCAFB1F00893@smtp.kernel.org/
Link: https://patch.msgid.link/20260616044654.3468742-8-dapeng1.mi@linux.intel.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
I have enough to decide: this is a real unprivileged kernel-register
leak on 6.18.53, and the fix is small enough to backport.
===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================
Step 1.1: PARSE THE SUBJECT LINE
Record: [perf/core] [Fix] [Stop unprivileged hardware sampling from
leaking kernel IP/register state when PMI skid lands in Ring 0]
Step 1.2: PARSE ALL COMMIT MESSAGE TAGS
Record:
- Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com> (author)
- Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
(perf/core maintainer; merged into tip perf/core)
- Link: https://lore.kernel.org/all/20260529085613.CCAFB1F00893@smtp.ker
nel.org/ (earlier discussion; lore fetch returned 403)
- Link: https://patch.msgid.link/20260616044654.3468742-8-
dapeng1.mi@linux.intel.com (v4 series, this patch)
- No Fixes: tag (expected)
- No Cc: stable (expected)
- No Reported-by / Tested-by / Reviewed-by / Acked-by besides SOBs
- Ignore: Signed-off-by: Sasha Levin and "[Upstream commit
166f10836a653dfa280d4335603b52f685b8b1ef]" (pipeline markers)
Step 1.3: ANALYZE THE COMMIT BODY TEXT
Record:
- Bug: An unprivileged hardware perf event with `exclude_kernel=1` can
still observe kernel register data through `PERF_SAMPLE_REGS_INTR` or
`PERF_SAMPLE_IP`.
- Symptom/failure mode: Kernel IP and interrupt-time register state
(GPRs; on some Intel platforms PEBS XMM too) are copied into the
userspace mmap buffer. That is a KASLR / kernel-state info leak. The
message also warns that later XSAVES SIMD sampling would make this
worse (crypto-key material in FPU/SIMD state).
- Trigger: Hardware PMI skid: the overflow interrupt is delivered after
the CPU has already entered kernel mode, so `perf_allow_kernel()` at
`perf_event_open()` time is bypassed.
- Root cause: Sample preparation always dumps `regs` / IP from the PMI
frame, with no check that `exclude_kernel` is consistent with
`user_mode(regs)`.
- Versions: No kernel-version range in the message. The REGS_INTR dump
path dates to 2014; guest IP helper to 2024.
Step 1.4: DETECT HIDDEN BUG FIXES
Record: Not a disguised cleanup. Subject and body state a security leak
and a surgical filter. Not a hidden bug.
===============================================================
PHASE 2: DIFF ANALYSIS - LINE BY LINE
===============================================================
Step 2.1: INVENTORY THE CHANGES
Record:
- File: `kernel/events/core.c` (+30 / -7)
- Functions: `perf_instruction_pointer()`, `perf_sample_regs_intr()`,
call site in `perf_prepare_sample()`
- Scope: single-file surgical fix
Step 2.2: UNDERSTAND THE CODE FLOW CHANGE
Record:
- Hunk 1 (`perf_instruction_pointer`): Before, guest and host always
returned the captured IP. After, if `exclude_kernel` and the captured
context is not userspace (host `!user_mode(regs)`, or guest without
`PERF_GUEST_USER`), IP is replaced with 0.
- Hunk 2 (`perf_sample_regs_intr`): Before, always `regs_intr->regs =
regs` and a real ABI. After, if `exclude_kernel && !user_mode(regs)`,
ABI is `PERF_SAMPLE_REGS_ABI_NONE` and `regs` is NULL so
`perf_output_sample()` writes a zero ABI and skips register payload.
- Hunk 3 (`perf_prepare_sample`): Passes `event->attr.exclude_kernel`
into the new parameter. Sample header size already accounts for a NULL
`regs` pointer (`if (data->regs_intr.regs)`), so dyn_size stays
consistent.
Step 2.3: IDENTIFY THE BUG MECHANISM
Record: Memory-safety / info-leak (unprivileged kernel-state
disclosure), not UAF/leak-of-heap.
- Mechanism: PMI skid + `exclude_kernel=1` still presents kernel
`pt_regs` to userspace.
- Fix: Drop register payload and zero IP when the sample is kernel-mode
but the event asked to exclude the kernel.
- Analogous to the 2017 attempt `cc1582c231ea0` ("Drop kernel samples
even though :u is specified"), which was reverted in `6a8a75f323572`
because dropping the whole sample broke rr overflow signals. This
patch keeps the sample/signal and only redacts contents.
Step 2.4: ASSESS THE FIX QUALITY
Record:
- Obviously correct: the predicate matches the existing
`sample_is_allowed()` / `perf_exclude_event()` tests (`exclude_kernel
&& !user_mode(regs)`).
- Minimal: three related sites, no API/UAPI change (ABI_NONE is the
documented empty-regs encoding).
- Regression risk: low for kernel correctness. Userspace profilers can
see IP=0 on skid samples; kernel test robot reported `perf-sanity-
tests.Object_code_reading.fail` for that. Author said the kernel
behavior is intended and the test should skip IP 0. rr is not broken
because overflow still fires. Privileged `exclude_kernel=0` events are
unchanged.
===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================
Step 3.1: BLAME THE CHANGED LINES
Record:
- `perf_sample_regs_intr()` introduced by `60e2364e60e86e` (Stephane
Eranian, 2014-11-16) "perf: Add ability to sample machine state on
interrupt".
- `perf_instruction_pointer(event, regs)` guest split from
`2c47e7a74f4454` / `04782e63917dbc` (Colton Lewis, 2024-11-13)
"perf/core: Correct perf sampling with guest VMs".
- The leak of kernel IP on `:u` sampling has been a known class since at
least 2017.
Step 3.2: FOLLOW THE FIXES: TAG
Record: No Fixes: tag. Historical related commits:
- `cc1582c231ea0` (2017): dropped entire skid kernel samples; Cc:
stable.
- `6a8a75f323572` (2017): reverted that because rr depends on overflow
signals, not sample contents.
- `030a976efae83` (2022): reintroduced `sample_is_allowed()` only for
sigtrap, not for sample output. In this tree it is used solely at
`kernel/events/core.c:10445`.
Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES
Record: Sibling security patches in the same Dapeng series (self-
contained, not prerequisites of this hunk):
- `perf/core: Check kernel access when kernel callchains are requested`
(callchain permission hole)
- `perf/x86/intel: Fix kernel address leakages in LBR stack`
This patch does not need those to compile or to close the IP/REGS_INTR
hole.
Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS
Record: Dapeng Mi is an Intel PMU/perf contributor. Peter Zijlstra
(subsystem maintainer) signed off and queued it on tip perf/core (commit
166f10836a653dfa280d4335603b52f685b8b1ef, 2026-06-30). Author's other
`kernel/events` work in this clone is unrelated cpu-clock fixes.
Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS
Record: Standalone. All symbols used (`user_mode`,
`PERF_SAMPLE_REGS_ABI_NONE`, `should_sample_guest`, `perf_guest_state`,
`PERF_GUEST_USER`, `perf_guest_get_ip`) exist in v6.18.53. Signature
change of static `perf_sample_regs_intr()` has a single call site in
`core.c`.
===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================
Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION
Record:
- b4 dig matched patch-id to lore; msgid
`20260616044654.3468742-8-dapeng1.mi@linux.intel.com`
- Evolved from the v8 SIMD/XSAVES sampling series (2026-05-29) into a
standalone "miscellaneous PMU bug fixes" series:
- v1 2026-06-05: only `perf_sample_regs_intr` (no IP redaction)
- v2–v4: added `perf_instruction_pointer` host+guest IP redaction
(committed form)
- Merged to tip perf/core 2026-06-30 by Peter Zijlstra; no NAK found.
- Later (2026-09-15) kernel test robot: userspace `Object code reading`
test fails on IP 0. Dapeng: expected; test should filter IP 0. That is
not a kernel functional/security regression.
Step 4.2: CHECK WHO REVIEWED THE PATCH
Record: Recipients (b4 dig -w): Peter Zijlstra, Ingo Molnar, Arnaldo
Carvalho de Melo, Namhyung Kim, Ian Rogers, Adrian Hunter, Alexander
Shishkin, Andi Kleen, Stephane Eranian, Mark Rutland, linux-kernel,
linux-perf-users. Maintainer SOB is the strongest review signal found.
Lore HTML itself returned 403; discussion reconstructed from
openwall/lkml mirrors.
Step 4.3: SEARCH FOR THE BUG REPORT
Record: No syzbot/bugzilla. Motivated by analysis around SIMD register
sampling. The IP leak is independently real: unprivileged `perf record
-e cycles:u` is a common path, and 2017 already treated skid kernel
samples as a security issue.
Step 4.4: CHECK FOR RELATED PATCHES AND SERIES
Record: Same series also has callchain permission and LBR address-leak
fixes. Those are separate holes. This commit does not depend on
SIMD/XSAVES patches; v6.18.53 has no XSAVES SIMD sampling (`git grep` of
XSAVES SIMD sample paths on v6.18.53 was empty). XMM-via-PEBS already
exists on Ice Lake+ (`PERF_REG_EXTENDED_MASK` in
`arch/x86/events/core.c`).
Step 4.5: CHECK STABLE MAILING LIST HISTORY
Record: lore.kernel.org/stable search returned 403. No evidence this was
rejected for stable. Absence of Cc: stable is expected for this review
pipeline.
===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================
Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF
Record: `perf_instruction_pointer`, `perf_sample_regs_intr`,
`perf_prepare_sample`. Related existing helpers: `sample_is_allowed`,
`perf_allow_kernel`, `perf_output_sample`.
Step 5.2: TRACE CALLERS
Record:
- `perf_instruction_pointer()`: only used from `perf_prepare_sample()`
(`data->ip = ...`) when `PERF_SAMPLE_IP` (or dependent
`PERF_SAMPLE_CODE_PAGE_SIZE`) is set.
- `perf_sample_regs_intr()`: only called from `perf_prepare_sample()`
for `PERF_SAMPLE_REGS_INTR`.
- `perf_prepare_sample()`: `__perf_event_output()` (normal mmap
samples), `bpf_overflow_handler()`, PEBS/BTS/s390 sampling paths.
Hardware PMI → `perf_event_overflow()` → overflow handler → output.
Confirmed `__perf_event_overflow()` does **not** drop skid kernel
samples today; `sample_is_allowed()` is sigtrap-only.
Step 5.3: TRACE CALLEES
Record: `user_mode(regs)`, `perf_arch_instruction_pointer()`,
`perf_guest_get_ip()`, `perf_guest_state()`, `perf_reg_abi()`. Output
path: `perf_output_sample()` already treats ABI 0 as "no regs".
Step 5.4: FOLLOW THE CALL CHAIN
Record: Reachable from unprivileged `perf_event_open()`:
- `sysctl_perf_event_paranoid > 1` requires `exclude_kernel=1`
(`perf_allow_kernel()` at `kernel/events/core.c:13553`).
- `PERF_SAMPLE_IP` has no extra privilege check (default sample type).
- `PERF_SAMPLE_REGS_INTR` is gated only by
`security_locked_down(LOCKDOWN_PERF)`, not paranoid. Without lockdown
(typical without Secure Boot), unprivileged REGS_INTR is allowed.
Trigger is common: non-precise `cycles:u` around syscalls/page faults.
Step 5.5: SEARCH FOR SIMILAR PATTERNS
Record: Same `exclude_kernel && !user_mode(regs)` already used in
`sample_is_allowed()`, `perf_exclude_event()`, and tracepoint matching.
This patch extends that policy to sample payload. Remaining sibling
holes (callchain, LBR) are other commits.
===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================
Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?
Record: Yes. Local tree is **6.18.53** (`git describe HEAD` =
`v6.18.53-5049-g0f0bdc2b0dffb`, Makefile VERSION=6 PATCHLEVEL=18
SUBLEVEL=53). At tag `v6.18.53`:
- `perf_instruction_pointer` returns guest/host IP unconditionally.
- `perf_sample_regs_intr(regs)` always assigns `regs`.
- Call site is `perf_sample_regs_intr(&data->regs_intr, regs);`
- `git merge-base --is-ancestor 166f10836a653dfa280d4335603b52f685b8b1ef
v6.18.53` is false.
Step 6.2: CHECK FOR BACKPORT COMPLICATIONS
Record: Clean apply expected. Pre-image of both functions and the call
site on v6.18.53 matches the patch. `PERF_GUEST_USER` is in
`include/linux/perf_event.h`. No conflicting refactor of these functions
on 6.18.y.
Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE
Record: The 2017 full-sample drop is **not** present (reverted).
`sample_is_allowed()` does not redact IP/REGS_INTR. No other in-tree
substitute for this leak on 6.18.53.
===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================
Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY
Record: [perf/core, `kernel/events/core.c`] [CORE for
observability/security: `perf_event_open` is a common unprivileged
syscall; leak is kernel-wide, not driver-specific]
Step 7.2: ASSESS SUBSYSTEM ACTIVITY
Record: Actively maintained (Peter Zijlstra). File still receives
UAF/deadlock fixes on 6.18.y; these two functions have been stable for
years.
===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================
Step 8.1: DETERMINE WHO IS AFFECTED
Record: Any unprivileged user who can open a hardware sampling event
with `exclude_kernel=1` (default paranoid). Universal on systems with a
hardware PMU. REGS_INTR extra impact depends on lockdown; IP leak does
not.
Step 8.2: DETERMINE THE TRIGGER CONDITIONS
Record: Common. Non-precise userspace-only sampling (`cycles:u`) plus
kernel entry/exit. Unprivileged-triggerable. Timing-dependent (skid) but
well documented and previously reproduced in 2017.
Step 8.3: DETERMINE THE FAILURE MODE SEVERITY
Record: [Kernel address / register info leak, KASLR bypass; on PEBS XMM
also SIMD state] [Severity: HIGH / security. Not a panic. XSAVES full-
SIMD crypto-key leak is **not** in 6.18; XMM PEBS already is.]
Step 8.4: CALCULATE RISK-BENEFIT RATIO
Record:
- Benefit: HIGH — closes an unprivileged kernel-IP leak on a default
sampling path; also covers REGS_INTR.
- Risk: LOW — ~30 lines, static helper, keeps overflow (rr-safe),
existing ABI_NONE encoding.
- Residual: userspace tools may see IP=0 (test already did). That is the
security behavior, not a kernel crash.
- Ratio: strongly favors backport.
===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================
Step 9.1: COMPILE THE EVIDENCE
FOR:
- Real unprivileged info leak via PMI skid; same class previously sent
to stable in 2017.
- Current code on 6.18.53 still emits kernel IP/regs;
`sample_is_allowed()` no longer drops samples.
- Surgical, obviously correct, maintainer-signed, applies cleanly.
- Avoids the rr regression by redacting payload instead of dropping the
event.
AGAINST:
- Userspace perf "object code reading" test can fail on IP 0 (author:
fix the test).
- No Fixes:/Cc:stable (not a negative per rules).
- XSAVES SIMD exacerbation is not in 6.18; the IP/GPR (and PEBS XMM)
leak still is.
UNRESOLVED:
- Full lore HTML was 403; review reconstructed from mirrors and b4.
Peter Zijlstra SOB still verified.
- Whether a userspace-only test fix later landed is unverified in this
clone; it does not block the kernel fix.
Step 9.2: APPLY THE STABLE RULES CHECKLIST
1. Obviously correct and tested? PASS — maintainer merged; robot only
hit expected IP=0.
2. Fixes a real bug that affects users? PASS — unprivileged
`perf_event_open` + hardware sampling.
3. Important issue (crash, security, corruption, deadlock)? PASS —
security info leak / KASLR.
4. Small and contained? PASS — one file, +30/-7.
5. No new features or APIs? PASS.
6. Can apply to the local tree? PASS — v6.18.53 pre-image matches.
Step 9.3: CHECK FOR EXCEPTION CATEGORIES
Record: Not a device-ID/quirk/DT/build/docs exception. Ordinary security
bugfix.
Step 9.4: MAKE YOUR DECISION
This tree is 6.18.53. The buggy dump path is present. The patch is a
small, rr-safe security fix with no missing prerequisites. It should be
backported.
------------------------------------------------
What the commit solves for stable users
Unprivileged hardware sampling with `exclude_kernel=1` can still capture
kernel IP and interrupt registers when the PMI skids into Ring 0. On
6.18 that includes default `PERF_SAMPLE_IP` and, unless lockdown,
`PERF_SAMPLE_REGS_INTR` (including PEBS XMM on capable Intel CPUs). The
fix redacts that payload without dropping the sample, so overflow-based
tools keep working.
Risk vs benefit
Benefit is a real KASLR/register leak on a common syscall path. Risk is
low: tiny core.c change, existing empty-regs ABI, no locking/API change.
The only observed fallout is userspace seeing IP 0, which is intended.
Concerns
No series dependencies for this hunk. XSAVES SIMD is not in 6.18; that
does not reduce the IP leak. A follow-up is only needed for the perf
selftest, not for kernel correctness.
Verification:
- [Phase 1] Parsed tags: Dapeng Mi author, Peter Zijlstra SOB, two
lore/msgid links; no Fixes/Reported-by
- [Phase 2] Diff: `perf_instruction_pointer` zeros IP;
`perf_sample_regs_intr` uses ABI_NONE; `perf_prepare_sample` passes
`exclude_kernel`
- [Phase 3] `git blame v6.18.53`: REGS_INTR dump from `60e2364e60e86e`
(2014); guest IP from `2c47e7a74f4454` (2024)
- [Phase 3] `git log -S sample_is_allowed -- kernel/events/core.c`: 2017
drop reverted; current use is sigtrap-only
- [Phase 3] `git show 6a8a75f323572`: revert because rr needs overflow
signals
- [Phase 4] `b4 dig -c 7db4d13613f57`: matched v4 msgid
20260616044654.3468742-8; recipients include Peter Zijlstra et al.
- [Phase 4] `b4 dig -a`: originated in SIMD series v8, then standalone
bugfix series v1–v4; IP redaction added after v1
- [Phase 4] openwall 2026-09-15: author confirms IP=0 is the leak fix;
test should skip it
- [Phase 5] grep: `perf_instruction_pointer` / `perf_sample_regs_intr`
only used from `perf_prepare_sample`; overflow path does not drop skid
samples
- [Phase 5] `perf_allow_kernel()` at open requires `exclude_kernel` for
unprivileged users; REGS_INTR only checks lockdown
- [Phase 6] `git describe HEAD` / Makefile: 6.18.53; v6.18.53 still has
the unfiltered dump; ancestor check of 166f10836a65 vs v6.18.53 is
false
- [Phase 6] `PERF_GUEST_USER` present; function pre-image matches patch
- [Phase 6] no XSAVES SIMD sampling in v6.18.53; XMM PEBS already
present
- [Phase 8] Failure mode: unprivileged kernel IP/register disclosure,
HIGH security
- UNVERIFIED: full lore.kernel.org thread body (HTTP 403); stable@ list
search (403)
**YES**
kernel/events/core.c | 37 ++++++++++++++++++++++++++++++-------
1 file changed, 30 insertions(+), 7 deletions(-)
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 018a1e4ef5b0d..3b01c2853d681 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -7499,10 +7499,20 @@ unsigned long perf_misc_flags(struct perf_event *event,
unsigned long perf_instruction_pointer(struct perf_event *event,
struct pt_regs *regs)
{
- if (should_sample_guest(event))
- return perf_guest_get_ip();
+ /*
+ * Hardware skid can lead to a scenario where a PMI is
+ * delivered after the CPU has already entered kernel mode.
+ * In that case, user-space sampling must not expose kernel
+ * register state.
+ */
+ if (should_sample_guest(event)) {
+ return event->attr.exclude_kernel &&
+ !(perf_guest_state() & PERF_GUEST_USER) ?
+ 0 : perf_guest_get_ip();
+ }
- return perf_arch_instruction_pointer(regs);
+ return event->attr.exclude_kernel && !user_mode(regs) ?
+ 0 : perf_arch_instruction_pointer(regs);
}
static void
@@ -7536,10 +7546,22 @@ static void perf_sample_regs_user(struct perf_regs *regs_user,
}
static void perf_sample_regs_intr(struct perf_regs *regs_intr,
- struct pt_regs *regs)
+ struct pt_regs *regs,
+ bool exclude_kernel)
{
- regs_intr->regs = regs;
- regs_intr->abi = perf_reg_abi(current);
+ /*
+ * Hardware skid can lead to a scenario where a PMI is
+ * delivered after the CPU has already entered kernel mode.
+ * In that case, user-space sampling must not expose kernel
+ * register state.
+ */
+ if (exclude_kernel && !user_mode(regs)) {
+ regs_intr->abi = PERF_SAMPLE_REGS_ABI_NONE;
+ regs_intr->regs = NULL;
+ } else {
+ regs_intr->regs = regs;
+ regs_intr->abi = perf_reg_abi(current);
+ }
}
@@ -8427,7 +8449,8 @@ void perf_prepare_sample(struct perf_sample_data *data,
/* regs dump ABI info */
int size = sizeof(u64);
- perf_sample_regs_intr(&data->regs_intr, regs);
+ perf_sample_regs_intr(&data->regs_intr, regs,
+ event->attr.exclude_kernel);
if (data->regs_intr.regs) {
u64 mask = event->attr.sample_regs_intr;
--
2.53.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH AUTOSEL 6.18-6.1] perf/x86: Unregister PMI handler on PMU init failure
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (4 preceding siblings ...)
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18] perf/core: Fix kernel register info leak via hardware skid Sasha Levin
@ 2026-10-19 13:51 ` Sasha Levin
2026-10-19 15:17 ` sashiko-bot
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-6.12] RISC-V: perf: fix resource cleanup on driver probe failure Sasha Levin
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-6.1] perf/x86/intel: Fallback to sw branch type decoding if no hw decoding Sasha Levin
7 siblings, 1 reply; 15+ messages in thread
From: Sasha Levin @ 2026-10-19 13:51 UTC (permalink / raw)
To: patches, stable
Cc: Dapeng Mi, Peter Zijlstra (Intel), Thomas Falcon, Zide Chen,
Sasha Levin, mingo, acme, namhyung, tglx, bp, dave.hansen, x86,
linux-perf-users, linux-kernel
From: Dapeng Mi <dapeng1.mi@linux.intel.com>
[ Upstream commit 91787047b1dc52b1fee68b07f79af70aae5fce47 ]
Fix an NMI handler leak in init_hw_perf_events(). When PMU
initialization fails after register_nmi_handler(), the error path
exits without calling unregister_nmi_handler(), leaving a stale
NMI_LOCAL "PMI" handler registered. Add the missing call before
clearing x86_pmu state.
Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Thomas Falcon <thomas.falcon@intel.com>
Reviewed-by: Zide Chen <zide.chen@intel.com>
Link: https://patch.msgid.link/20260717080342.1879573-2-dapeng1.mi@linux.intel.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The local tree is **6.12.111** (`pending-6.12`). The NMI-handler leak is
in this checkout, and the four-line cleanup applies cleanly.
===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================
**Step 1.1: PARSE THE SUBJECT LINE**
Record: **[perf/x86] [Unregister] Unregister PMI NMI handler when PMU
init fails after `register_nmi_handler()`**
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Record:
- Signed-off-by: Dapeng Mi (author)
- Signed-off-by: Peter Zijlstra (Intel) (perf/x86 maintainer; merged to
tip/perf/core)
- Reviewed-by: Thomas Falcon (Intel)
- Reviewed-by: Zide Chen (Intel)
- Link: https://patch.msgid.link/20260717080342.1879573-2-
dapeng1.mi@linux.intel.com
- No Fixes:, Reported-by:, Tested-by:, Cc: stable, or syzbot tags
(absence is expected)
- Pipeline markers ignored per instructions
- Tip merge SHA: `91787047b1dc52b1fee68b07f79af70aae5fce47` (not an
ancestor of this tree)
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- **Bug:** `init_hw_perf_events()` registers NMI_LOCAL handler `"PMI"`
then can fail in cpuhp / `perf_pmu_register` without unregistering it.
- **Symptom:** stale NMI handler remains for the life of the kernel;
first cpuhp failure also skips `memset(&x86_pmu)`.
- **Version info:** none in the message. Code has been this way since
the 2016 cpuhp conversion.
- **Root cause:** missing `unregister_nmi_handler(NMI_LOCAL, "PMI")` on
post-register error paths.
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: Not disguised. Explicit error-path resource-leak fix (NMI
handler leak). Also completes the incomplete `memset(&x86_pmu)` on the
first `cpuhp_setup_state()` failure, which today still `return err`.
===============================================================
PHASE 2: DIFF ANALYSIS
===============================================================
**Step 2.1: INVENTORY THE CHANGES**
Record:
- File: `arch/x86/events/core.c` only (+3 / −1; net +2)
- Function: `init_hw_perf_events()`
- Scope: single-file surgical error-path fix
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Record:
- Hunk 1: `cpuhp_setup_state(CPUHP_PERF_X86_PREPARE)` failure currently
`return err` (no NMI unregister, no `memset`). After: `goto
pmi_unregister`.
- Hunk 2: new `pmi_unregister:` label after cpuhp teardown, before
`out_bad_pmu:`. All later error paths (`out`/`out1`/`out2`) now
unregister the PMI handler, then still `memset(&x86_pmu, 0, ...)`.
- Early `goto out_bad_pmu` (no PMU driver / `check_hw_exists()` fail)
stays before `register_nmi_handler()` and still skips unregister —
correct.
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record: **Error-path resource leak.** `register_nmi_handler()` has no
matching `unregister_nmi_handler()` if later init fails. Category (a)
error-path leak; also incomplete cleanup of `x86_pmu` on the first cpuhp
failure.
**Step 2.4: ASSESS THE FIX QUALITY**
Record: Obviously correct. Success path still `return 0` before the
labels. First cpuhp failure still skips `cpuhp_remove_state()` (setup
rolls back on failure). Early `out_bad_pmu` still does not unregister.
Regression risk is very low; no API/locking/hot-path change.
===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================
**Step 3.1: BLAME THE CHANGED LINES**
Record:
- `register_nmi_handler(..., "PMI")`: `9c48f1c629ecfa` (Don Zickus,
2011)
- cpuhp error paths including `return err`: `95ca792c7582fd` (Thomas
Gleixner, 2016; in v4.8-rc1)
- `out_bad_pmu` / `memset(&x86_pmu)`: `916e3a4f950eac` (Paolo Bonzini,
2022) — in this tree; message said hotplug install failure should
clear `x86_pmu`, but the first `return err` was left uncleared
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: No Fixes: tag. Introducer of the leaky error path is
`95ca792c7582fd`, present in this tree (`git merge-base --is-ancestor`
exit 0).
**Step 3.3: CHECK FILE HISTORY**
Record: Recent `arch/x86/events/core.c` changes are unrelated
(callchain, hybrid, counters). No equivalent `pmi_unregister` commit.
`git log -S pmi_unregister -- arch/x86/events/core.c` is empty here.
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: Dapeng Mi is a regular Intel perf/x86 contributor in this tree
(PEBS, LBR, KASAN). Patch signed off by Peter Zijlstra.
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record: Standalone. It is v3 1/8 of “Miscellaneous PMU bug fixes and
optimizations”. Patch 2 (`Free hybrid state on PMU init failure`) *uses*
the new `pmi_unregister` label but is a follow-up, not a prerequisite.
`unregister_nmi_handler()` already exists (`arch/x86/kernel/nmi.c`). No
new helpers required.
===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- `b4 dig -c 91787047b1dc52b1fee68b07f79af70aae5fce47` matched the
series (patch-id 48e634d2936fd149d8d36fbf100fd51c3fa0e39b)
- Lore/msgid: https://patch.msgid.link/20260717080342.1879573-2-
dapeng1.mi@linux.intel.com
- v1→v3: this hunk is unchanged across revisions; later-series comments
(hybrid cast, drain_pebs) do not affect this patch
- Merged to tip/perf/core 2026-08-10; no NAK found
- Cover letter: bugs found by Sashiko review of another series; tested
on Diamonds/Novalake (`perf test` 119/155/156)
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record: `b4 dig -w` recipients included Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Namhyung Kim, linux-kernel, linux-perf-users,
plus Intel reviewers. Reviewed-by Thomas Falcon and Zide Chen;
maintainer SOB from Peter Zijlstra.
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record: No syzbot/bugzilla/user crash report. Found by static review
(Sashiko), then coded as an explicit leak fix.
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: Series of 8; this patch is independent. Patch 2 is a related
hybrid-state leak on the same function and can land later.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: No useful stable-list hit that this was rejected or already
queued. UNVERIFIED beyond search noise: lore.kernel.org returned 403 for
direct thread fetch.
===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================
**Step 5.1: IDENTIFY KEY FUNCTIONS**
Record: `init_hw_perf_events` (modified). Related:
`perf_event_nmi_handler`, `unregister_nmi_handler`,
`x86_pmu_prepare_cpu`.
**Step 5.2: TRACE CALLERS**
Record: `init_hw_perf_events` is `early_initcall` — once at boot.
`x86_pmu_prepare_cpu` is the PREPARE cpuhp callback; Intel/AMD
`cpu_prepare` can return `-ENOMEM` (`intel_cpuc_prepare` kzallocs;
`amd_pmu_cpu_prepare` kzallocs `lbr_sel` / `amd_nb`).
**Step 5.3: TRACE CALLEES**
Record: After register: cpuhp setup, `perf_pmu_register`. Handler
`perf_event_nmi_handler` returns `NMI_DONE` if `active_events==0`, else
`static_call(x86_pmu_handle_irq)`.
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: Not a syscall hot path. Reachable at boot if hardware PMU exists
and later setup fails (ENOMEM in prepare, cpuhp failure,
`perf_pmu_register` / hybrid register failure). Unprivileged users do
not trigger it directly. If the handler is left registered after
`memset(&x86_pmu)`, a later NMI still walks it.
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: Other x86 NMI users (kgdb, IBS, nmi_selftest) pair
register/unregister. This init path did not.
===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record: Yes. `arch/x86/events/core.c`: `register_nmi_handler` at 2108;
`if (err) return err;` at 2144–2145; `out`/`out1`/`out2` then
`out_bad_pmu` memset with no unregister.
`91787047b1dc52b1fee68b07f79af70aae5fce47` is **not** an ancestor
(`merge-base --is-ancestor` exit 1). Bug introduced with cpuhp
conversion in v4.8 era.
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: `git apply --check` of the two hunks against this tree: **clean
apply** (rc 0). Surrounding `init_hw_perf_events` matches the patch.
Difficulty: clean apply.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: `916e3a4f950eac` is present (clears `x86_pmu` on some fail
paths) but still misses NMI unregister and the first `return err`. No
later equivalent fix.
===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================
**Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY**
Record: **perf/x86** (`arch/x86/events/`). **IMPORTANT** — x86 hardware
performance monitoring, used by `perf`, KVM PMU
(`perf_get_x86_pmu_capability`), and profiling. Not core mm/scheduler,
not staging.
**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**
Record: Actively maintained (frequent intel/amd PMU commits). This leak
is old (2016), not a brand-new subsystem.
===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================
**Step 8.1: DETERMINE WHO IS AFFECTED**
Record: x86 systems with a hardware PMU whose **init fails after** NMI
registration (ENOMEM in prepare, cpuhp setup fail, PMU register fail).
Not every boot; not non-x86.
**Step 8.2: DETERMINE THE TRIGGER CONDITIONS**
Record: Boot-time only. Common “no/broken PMU” path (`intel_pmu_init`
fail / `check_hw_exists` false) is **before** register, so it does not
leak. The leak needs a later failure. `intel_cpuc_prepare` /
`amd_pmu_cpu_prepare` returning `-ENOMEM` is a concrete trigger. Not
unprivileged-triggerable.
**Step 8.3: DETERMINE THE FAILURE MODE SEVERITY**
Record: Stale NMI_LOCAL handler remains; extra NMI-chain walk for the
life of the system. If later paths `memset` `x86_pmu` while the handler
is still registered, `perf_event_nmi_handler` can still run. If
`active_events==0` it returns `NMI_DONE` (typical after failed
register). First cpuhp failure today also leaves `x86_pmu` populated, so
`perf_get_x86_pmu_capability()` can report a live PMU after failed init
— the case `916e3a4f950eac` tried to close. Severity: **MEDIUM**
(resource leak in NMI context; rare trigger; latent inconsistency more
than a guaranteed oops).
**Step 8.4: CALCULATE RISK-BENEFIT RATIO**
Record:
- Benefit: medium for affected boots (correct NMI teardown + complete
`x86_pmu` clear); modest globally because the path is rare
- Risk: very low (4-line error-path-only change, applies cleanly)
- Ratio: favorable — cheap correctness fix for a real leak
===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================
**Step 9.1: COMPILE THE EVIDENCE**
FOR:
- Real NMI handler leak on verified error paths in this 6.12 tree
- Also closes the leftover `return err` that skips `memset(&x86_pmu)`
after PREPARE cpuhp failure
- Tiny, obviously correct, maintainer-acked, applies cleanly
- `unregister_nmi_handler` already exists; no new API
- Concrete `-ENOMEM` failure in Intel/AMD `cpu_prepare`
- Error-path leak cleanup is standard stable material
AGAINST:
- Rare one-time init path, not a hot-path leak
- No user/syzbot report; found by review
- Not a guaranteed panic/corruption on typical boots (`active_events`
usually 0)
UNRESOLVED:
- Direct lore.kernel.org fetch returned 403; discussion reconstructed
via b4, patchew, lkml.iu.edu
- No evidence this was rejected for stable
**Step 9.2: APPLY THE STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — mechanical unregister;
series tested; Peter Zijlstra merged it
2. Fixes a real bug that affects users? **PASS** — leaked NMI handler
after failed x86 PMU init
3. Important issue? **PASS** — NMI-context resource leak plus incomplete
PMU-state teardown; not a guaranteed panic, but more than cosmetic
4. Small and contained? **PASS** — +3/−1, one function
5. No new features or APIs? **PASS**
6. Can apply to the local tree? **PASS** — `git apply --check` clean;
buggy code present; fix not already here
**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**
Record: Not a device-ID/quirk/DT/docs exception. Ordinary small bugfix.
**Step 9.4: MAKE YOUR DECISION**
The leak exists in 6.12.111, the fix is surgical, and leaving an NMI
handler registered after tearing down `x86_pmu` is a real stability
defect even if the trigger is uncommon. Benefit/risk supports backport.
===============================================================
What the commit solves and why it matters here
===============================================================
On this tree, `init_hw_perf_events()` registers the `"PMI"` NMI handler,
then sets up cpuhp states and registers the PMU. If any of those later
steps fail, cpuhp is unwound (except the first PREPARE failure, which
just returns) and `x86_pmu` is zeroed — but the NMI handler is left
installed. That handler stays on the NMI_LOCAL list for the rest of the
boot. The patch adds the missing `unregister_nmi_handler()` on those
paths and routes the PREPARE failure through the same cleanup so
`x86_pmu` is cleared consistently.
That matches stable rules: real bug, small, no new API, applies here
without dependencies.
===============================================================
Verification
===============================================================
- [Phase 1] Parsed subject/tags: unregister PMI on init failure; SOB
Dapeng Mi + Peter Zijlstra; R-b Falcon/Chen; Link msgid
20260717080342.1879573-2; no Fixes/syzbot
- [Phase 2] Diff: +3/−1 in `init_hw_perf_events`; `return err` → `goto
pmi_unregister`; add `unregister_nmi_handler(NMI_LOCAL, "PMI")` before
`out_bad_pmu`
- [Phase 3] Blame: leaky cpuhp errors from `95ca792c7582fd` (v4.8); NMI
register from `9c48f1c629ecfa` (2011); memset from `916e3a4f950eac`
(2022), in this tree
- [Phase 3] `git merge-base --is-ancestor
91787047b1dc52b1fee68b07f79af70aae5fce47 HEAD` → not ancestor (fix
absent)
- [Phase 3] `git log -S pmi_unregister -- arch/x86/events/core.c` →
empty
- [Phase 4] `b4 dig -c 91787047...`: matched series; v1–v3 hunk
unchanged; merged tip/perf/core 2026-08-10
- [Phase 4] Cover letter (lkml.iu.edu / patchew): Sashiko-found PMU
bugs; this patch is 1/8 and standalone
- [Phase 4] `b4 dig -w`: Peter Zijlstra, Ingo, linux-perf-users CC’d; no
NAK found
- [Phase 4] lore.kernel.org WebFetch 403; stable-list search did not
show a rejection
- [Phase 5] `intel_cpuc_prepare` / `amd_pmu_cpu_prepare` return
`-ENOMEM` — verified trigger for PREPARE cpuhp failure
- [Phase 5] `perf_event_nmi_handler` still callable if handler leaked;
early-out if `!active_events`
- [Phase 6] `git describe HEAD` → `p-6.12-3-gc504cf0baa3d8`; `make
kernelversion` → 6.12.111
- [Phase 6] Local code at `arch/x86/events/core.c:2108` and `:2144-2201`
matches the buggy pattern
- [Phase 6] `git apply --check` of the two hunks → rc 0 (clean apply)
- [Phase 8] Failure mode: leaked NMI handler + incomplete `x86_pmu`
clear; severity MEDIUM; trigger rare (init error)
- UNVERIFIED: full lore mbox body (403); whether linus.git mainline SHA
differs from tip SHA 91787047 (tip merge confirmed)
The fix is small, surgical, present as a real bug in this 6.12 tree, and
meets the stable criteria.
**YES**
arch/x86/events/core.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index 330c2ba41f076..2aa9270446634 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -2175,7 +2175,7 @@ static int __init init_hw_perf_events(void)
err = cpuhp_setup_state(CPUHP_PERF_X86_PREPARE, "perf/x86:prepare",
x86_pmu_prepare_cpu, x86_pmu_dead_cpu);
if (err)
- return err;
+ goto pmi_unregister;
err = cpuhp_setup_state(CPUHP_AP_PERF_X86_STARTING,
"perf/x86:starting", x86_pmu_starting_cpu,
@@ -2229,6 +2229,8 @@ static int __init init_hw_perf_events(void)
cpuhp_remove_state(CPUHP_AP_PERF_X86_STARTING);
out:
cpuhp_remove_state(CPUHP_PERF_X86_PREPARE);
+pmi_unregister:
+ unregister_nmi_handler(NMI_LOCAL, "PMI");
out_bad_pmu:
memset(&x86_pmu, 0, sizeof(x86_pmu));
return err;
--
2.53.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH AUTOSEL 6.18-6.12] RISC-V: perf: fix resource cleanup on driver probe failure
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (5 preceding siblings ...)
2026-10-19 13:51 ` [PATCH AUTOSEL 6.18-6.1] perf/x86: Unregister PMI handler on PMU init failure Sasha Levin
@ 2026-10-19 13:52 ` Sasha Levin
2026-10-19 15:33 ` sashiko-bot
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-6.1] perf/x86/intel: Fallback to sw branch type decoding if no hw decoding Sasha Levin
7 siblings, 1 reply; 15+ messages in thread
From: Sasha Levin @ 2026-10-19 13:52 UTC (permalink / raw)
To: patches, stable
Cc: Atish Patra, Sashiko AI, Charlie Jenkins, Paul Walmsley,
Sasha Levin, atish.patra, will, mark.rutland, palmer, aou,
linux-riscv, linux-arm-kernel, linux-perf-users, linux-kernel
From: Atish Patra <atishp@meta.com>
[ Upstream commit e24a1418e90beac2ef4384bc9b0b5a10f19b806e ]
Sashiko pointed out various UAF and memory leak issues around
pmu_sbi_device_probe() error paths.
If the probe fails, here are list of cleanups needed.
a. Already registered pmu must be freed
b. per cpu IRQ must be released
c. pmu_ctr_list data structure must be freed
d. cpu hotplug state must be cleaned up only if added.
Fix the resource cleanup by reorganizing the code around probe failure.
Reported-by: Sashiko AI <sashiko-bot@kernel.org>
Reviewed-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
Signed-off-by: Atish Patra <atishp@meta.com>
Link: https://patch.msgid.link/20260807-counter_delegation-v9-1-58658104e487@meta.com
Signed-off-by: Paul Walmsley <pjw@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
This tree is **6.12.111** (`pending-6.12`). The buggy probe cleanup is
present here, the patch applies, and it is a real UAF/leak/crash fix — a
YES for this tree.
---
## PHASE 1: COMMIT MESSAGE FORENSICS
**Step 1.1: PARSE THE SUBJECT LINE**
Record: `[RISC-V perf / SBI PMU] [fix] [resource cleanup on driver probe
failure]`
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Record:
- `Reported-by: Sashiko AI <sashiko-bot@kernel.org>` — static-analysis
bot, not a user oops, but it named concrete UAF/leak paths
- `Reviewed-by: Charlie Jenkins <thecharlesjenkins@gmail.com>` — RISC-V
reviewer
- `Signed-off-by: Atish Patra <atishp@meta.com>` — original SBI PMU
driver author
- `Link: https://patch.msgid.link/20260807-counter_delegation-v9-1-
58658104e487@meta.com` — **v9 01/20** of the counter-delegation series
- `Signed-off-by: Paul Walmsley <pjw@kernel.org>` — RISC-V maintainer
- No `Fixes:` tag (expected)
- Ignore pipeline `Signed-off-by: Sasha Levin` / `[Upstream commit ...]`
— none on the real commit `e24a1418e90be`
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- **Bug:** `pmu_sbi_device_probe()` error paths leak and leave live
references to freed objects
- **Needed cleanups:** (a) unregister an already-registered PMU, (b)
release the per-CPU IRQ, (c) free `pmu_ctr_list`, (d) remove the CPU-
hotplug instance only if it was added
- **Symptom:** UAF and memory leaks if probe fails after partial setup
- **Root cause:** probe does `goto out_unregister` / `out_free` without
matching teardown
- **Version info:** none in the message; code dates to 2022–2024
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: Not disguised. It is an explicit error-path UAF/leak fix.
“Reorganizing probe failure” is the usual `goto` cleanup pattern, not a
refactor-for-its-own-sake.
---
## PHASE 2: DIFF ANALYSIS
**Step 2.1: INVENTORY THE CHANGES**
Record:
- File: `drivers/perf/riscv_pmu_sbi.c` — **+27 / −6** (33 insertions, 6
deletions)
- Functions: `pmu_sbi_setup_irqs()`, `riscv_pmu_destroy()`,
`pmu_sbi_device_probe()`
- Scope: single-file surgical error-path fix
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Record:
1. **`pmu_sbi_setup_irqs()`**
- Before: domain/mapping/request failures return immediately.
`riscv_pmu_use_irq` can stay **true** even though no IRQ was
installed. Mapping leaked if `request_percpu_irq()` failed.
- After: those paths `goto err`, dispose a created mapping, set
`riscv_pmu_use_irq = false`.
2. **`riscv_pmu_destroy()`**
- Before: always `cpuhp_state_remove_instance()` even when the
instance was never added.
- After: only if `!hlist_unhashed(&pmu->node)`.
3. **`pmu_sbi_device_probe()`**
- Before: `riscv_pm_pmu_register` / `perf_pmu_register` failures jump
to `out_unregister` (destroy + `kfree(pmu)` only). Snapshot-alloc
and cpuhp-add failures also skip `perf_pmu_unregister`. IRQ,
`hw_events`, and `pmu_ctr_list` never freed.
- After: `irq_requested` tracks a successful IRQ request. Failures
before PMU register go to `out_destroy`. Failures after register go
to `out_unregister` which now calls `perf_pmu_unregister`. Then
IRQ/percpu/`pmu_ctr_list`/`pmu` are freed.
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record: **Error-path resource leak + UAF + NULL deref**, with a logic
fix on the IRQ fallback path.
Verified mechanisms in **this** tree:
| Bug | Mechanism |
|---|---|
| **UAF of registered PMU** | `perf_pmu_register()` then
`pmu_sbi_snapshot_alloc()` or `cpuhp_state_add_instance()` fails →
`kfree(pmu)` while the PMU stays in perf core |
| **NULL deref / list corruption** | `riscv_pmu_destroy()` →
`cpuhp_state_remove_instance()` → `hlist_del()` → `WRITE_ONCE(*pprev,
next)` with `pprev == NULL` on a `kzalloc`’d node |
| **IRQ + cookie UAF** | successful `request_percpu_irq(..., hw_events)`
then later probe fail frees `pmu`/`hw_events` without `free_percpu_irq`
|
| **Leaks** | `alloc_percpu` `hw_events` and `kcalloc` `pmu_ctr_list`
only freed on the new `out_free` |
| **Wrong IRQ flag on success path** | IRQ setup failure is **non-
fatal**; probe continues with `PERF_PMU_CAP_NO_INTERRUPT` but
`riscv_pmu_use_irq` stayed true, so `pmu_sbi_starting_cpu()` can
`enable_percpu_irq(0)` |
**Step 2.4: ASSESS THE FIX QUALITY**
Record: Obviously correct and minimal. `out_unregister` is only reached
after a successful `perf_pmu_register`. `out_destroy` does not
unregister. `hlist_unhashed` matches `cpuhp` (node is hashed only after
successful add). IRQ free happens before `free_percpu(hw_events)`.
Regression risk: **low**. Remaining gaps (sysctl not unregistered;
`sbi_pmu_snapshot_available` static key not disabled) are pre-existing
and not introduced here. They do not make this patch unsafe.
---
## PHASE 3: GIT HISTORY INVESTIGATION
**Step 3.1: BLAME THE CHANGED LINES**
Record:
- IRQ error returns: `4905ec2fb7e642` (Atish Patra, 2022-02-18) —
sscofpmf
- Destroy / `out_unregister`: `e9a023f2b73ac3` (Eric Lin, 2022-07-05) —
PM notifier
- Snapshot + moving `cpuhp_state_add_instance` **after** register:
`a8625217a054ca` (Atish Patra, 2024-04-20) — **this is when the
registered-PMU UAF became real**
- Original `kfree(pmu)`-only `out_free`: `e9991434596f53` (2022-02-18) —
driver introduction
All of these are ancestors of this 6.12 tree.
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: No `Fixes:` tag. Buggy code is still in this checkout (see Phase
6).
**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
Record (this tree, `git log --oneline -20 --
drivers/perf/riscv_pmu_sbi.c`): overflow-IRQ NULL check, bitmap cmask,
errno/firmware-event fixes. None of those replace this cleanup. `git log
--oneline e24a1418e90be..origin/master -- drivers/perf/riscv_pmu_sbi.c`
only shows later overflow-mask/bitmap work; they do not revert or redo
this cleanup.
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: Atish Patra wrote the SBI PMU driver (`e9991434596f53`) and the
snapshot code. This is a maintainer-area fix, not drive-by.
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record: Msgid is `counter_delegation-v9-1`. Patches 2–20 add
Smcsrind/Ssccfg/Smcdeleg and a new PMU path. They are **features**, not
prerequisites. This hunk only uses `hlist_unhashed`,
`perf_pmu_unregister`, `free_percpu_irq`, `irq_dispose_mapping`,
`free_percpu`, `pmu_ctr_list` — all already in 6.12. **Standalone.**
`git show e24a1418e90be | git apply --check` succeeded (offsets only).
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- `b4 dig -c e24a1418e90be`: matched patch-id; lore URL `https://patch.m
sgid.link/20260807-counter_delegation-v9-1-58658104e487@meta.com`
- `b4 dig -a`: cleanup first appeared as **v7 01/22** (2026-06-22), then
**v9 01/20** (committed)
- WebFetch of lore returned **403** (Anubis). Thread was recovered via
`b4 dig -m /tmp/riscv-pmu-cleanup.mbox`
- No NAK on this patch. Paul Walmsley queued the first ten patches
(including this one) for `riscv/for-next`
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record: Charlie Jenkins `Reviewed-by`. Paul Walmsley applied it.
Recipients are the RISC-V list / maintainers (from msgid and SOBs). No
`Cc: stable` in review.
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record: Reporter is Sashiko, not syzbot. v9 review of **this** patch
restates remaining **pre-existing** issues (snapshot disable without CPU
pin, static key, sysctl leak, init-time cpuhp leak). It does **not** NAK
the cleanup. The UAF it describes of a registered-then-freed PMU is
exactly what `perf_pmu_unregister` addresses.
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: Rest of v9 is new ISA / delegation code. Not needed for this
cleanup. Later origin/master commits on this file do not change these
error labels.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: lore.kernel.org/stable WebFetch also 403. **UNVERIFIED** whether
stable@ already discussed this. Absence of `Cc: stable` is expected for
this review queue.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
**Step 5.1: KEY FUNCTIONS**
Record: `pmu_sbi_setup_irqs`, `riscv_pmu_destroy`,
`pmu_sbi_device_probe`. Related: `pmu_sbi_starting_cpu`,
`riscv_pmu_alloc`, `pmu_sbi_get_ctrinfo`.
**Step 5.2: TRACE CALLERS**
Record:
- `pmu_sbi_device_probe` — `.probe` of `pmu_sbi_driver`
- Called from `pmu_sbi_devinit()` (`device_initcall`) via
`platform_device_register_simple(RISCV_PMU_SBI_PDEV_NAME, ...)`
- `pmu_sbi_starting_cpu` / `pmu_sbi_dying_cpu` read `riscv_pmu_use_irq`
(the flag this patch clears on IRQ setup failure)
**Step 5.3: TRACE CALLEES**
Record: `riscv_pmu_alloc()` does `kzalloc` + `alloc_percpu_gfp` (this
tree, `drivers/perf/riscv_pmu.c`). `pmu_sbi_get_ctrinfo()` `kcalloc`s
`pmu_ctr_list`. `cpuhp_state_remove_instance()` always `hlist_del()`s.
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: Boot/init on RISC-V with SBI PMU (`CONFIG_RISCV_PMU_SBI`
**default y**). Trigger is probe failure after partial success:
`snapshot_alloc` ENOMEM, `perf_pmu_register` failure,
`cpuhp_state_add_instance` failure, or `cpu_pm_register_notifier`
failure. After a successful `perf_pmu_register` and a later fail,
userspace `perf` can touch a PMU whose `struct riscv_pmu` is already
`kfree`d — **userspace-reachable UAF**.
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: Same file’s `pmu_sbi_devinit()` still leaks
`cpuhp_setup_state_multi` if `platform_driver_register` fails. Pre-
existing, out of this patch’s scope.
---
## PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record: **Yes.** This checkout is 6.12.111; `e24a1418e90be` is **not**
an ancestor (`git merge-base --is-ancestor` exit 1).
Current probe error path (`drivers/perf/riscv_pmu_sbi.c`):
```1462:1468:drivers/perf/riscv_pmu_sbi.c
out_unregister:
riscv_pmu_destroy(pmu);
out_free:
kfree(pmu);
return ret;
```
`riscv_pmu_destroy()` still unconditionally removes the cpuhp instance.
`pmu_sbi_setup_irqs()` still returns without clearing
`riscv_pmu_use_irq` or disposing a mapping.
Bug introduced: leaks since v5.17-era driver; UAF of registered PMU
since snapshot/cpuhp reorder in `a8625217a054ca` (in this tree).
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: **Clean apply** (`git apply --check` — all 6 hunks succeeded
with −54 line offset). Context differs (`bitmap_copy` vs mainline
`pmu->cmask = cmask`) because 6.12 already has `143668c424772` (counter
mask as bitmap). No rework required.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: No equivalent cleanup. Bitmap and overflow-IRQ fixes in this
tree are independent.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
**Step 7.1: SUBSYSTEM AND CRITICALITY**
Record: `drivers/perf` / RISC-V SBI PMU. **IMPORTANT** for RISC-V
(default-on perf), not core-mm/VFS. Not staging.
**Step 7.2: SUBSYSTEM ACTIVITY**
Record: Mature driver (2022) with ongoing RISC-V perf fixes. This is a
long-standing error-path hole, not churn in brand-new code.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
**Step 8.1: WHO IS AFFECTED**
Record: RISC-V systems with `CONFIG_RISCV_PMU_SBI` (default y) and SBI
PMU (QEMU virt, most recent boards). Driver-specific, not universal.
**Step 8.2: TRIGGER CONDITIONS**
Record:
- Common path: probe succeeds — no crash
- Realistic fail: `pmu_sbi_snapshot_alloc()` ENOMEM (page alloc
GFP_ATOMIC per CPU) **after** `perf_pmu_register`
- IRQ mapping fail with SSCOF/T-Head/Andes: probe **continues**,
`riscv_pmu_use_irq` wrongly stays true
- Unprivileged user cannot force probe, but **can** open the registered
`"cpu"` PMU in the failure window
**Step 8.3: FAILURE MODE SEVERITY**
Record:
- Registered PMU then `kfree(pmu)` → **UAF** → HIGH
- `hlist_del` on unhashed node → **oops** → HIGH
- IRQ cookie UAF → HIGH
- One-time leaks if probe dies before register → MEDIUM
- `enable_percpu_irq(0)` on fallback success path → MEDIUM–HIGH
**Step 8.4: RISK-BENEFIT RATIO**
Record:
- **Benefit:** high for RISC-V 6.12 — prevents oops/UAF on probe fail
and a wrong IRQ flag on a continued probe
- **Risk:** low — ~27 net lines, error path + one flag clear, applies
cleanly
- **Ratio:** favor backport
---
## PHASE 9: FINAL SYNTHESIS
**Step 9.1: EVIDENCE**
**FOR:**
- Real UAF: perf-registered PMU freed without unregister (snapshot/cpuhp
fail after `perf_pmu_register`)
- Real oops: `cpuhp_state_remove_instance` → `hlist_del` with NULL
`pprev`
- Real IRQ leak/UAF and `pmu_ctr_list`/`hw_events` leaks
- `riscv_pmu_use_irq` left true on non-fatal IRQ setup failure (success-
path bug)
- Small, obviously correct, reviewed by Charlie Jenkins, authored by the
driver owner
- Buggy code and helpers exist in 6.12; patch applies cleanly
- Standalone despite being 01/20 of a feature series
**AGAINST:**
- Probe-fail is uncommon (except IRQ-setup fallback, which is not fatal
and is common on some platforms)
- Incomplete: sysctl, snapshot static key, init-time cpuhp still leak
(pre-existing)
- RISC-V only
- Reported by an AI bot, not a production oops
**UNRESOLVED:** stable@ thread (lore 403); whether Sashiko had a
concrete reproducer beyond code review.
**Step 9.2: STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — reviewed, applied by RISC-V
maintainer, logic matches the four listed holes
2. Fixes a real bug that affects users? **PASS** — UAF/oops/leaks in the
default RISC-V PMU driver
3. Important issue? **PASS** — UAF and NULL deref are HIGH; not a style
cleanup
4. Small and contained? **PASS** — one file, +27/−6
5. No new features or APIs? **PASS**
6. Can apply to the local tree? **PASS** — `git apply --check` clean
**Step 9.3: EXCEPTION CATEGORIES**
Record: None. Ordinary bugfix.
**Step 9.4: DECISION**
This 6.12 tree has the buggy probe path. The fix is small, applies, and
closes UAF/oops/leak holes in a default-on RISC-V driver. Remaining
cleanup gaps are not a reason to withhold the part that is correct.
---
## What this means for 6.12 users
On RISC-V with SBI PMU, a failed probe after `perf_pmu_register()`
currently frees `struct riscv_pmu` while perf still holds it, and
`riscv_pmu_destroy()` oopses by deleting an unhashed cpuhp node. The
same path leaks the per-CPU IRQ cookie, `hw_events`, and `pmu_ctr_list`.
IRQ setup failure is treated as non-fatal but leaves `riscv_pmu_use_irq`
set, so hotplug can enable IRQ 0. The patch only rewires those gotos and
frees; it does not pull in counter-delegation.
Risk is low relative to leaving a registered-PMU UAF in a long-term
tree.
---
## Verification
- **[Phase 1]** Parsed tags: Sashiko Reported-by, Charlie Jenkins
Reviewed-by, Atish Patra + Paul Walmsley SOBs, msgid v9 01/20; no
Fixes
- **[Phase 2]** Diff: +27/−6 in `riscv_pmu_sbi.c`; IRQ err goto,
`hlist_unhashed` guard, `perf_pmu_unregister`,
`free_percpu_irq`/`free_percpu`/`kfree(pmu_ctr_list)`
- **[Phase 2]** Read 6.12 `pmu_sbi_device_probe` lines 1367–1468:
destroy + `kfree(pmu)` only
- **[Phase 2]** Read `kernel/cpu.c` `__cpuhp_state_remove_instance`:
always `hlist_del(node)`
- **[Phase 2]** Read `include/linux/list.h` `__hlist_del`:
`WRITE_ONCE(*pprev, next)` NULL-derefs if never hashed
- **[Phase 2]** Read `__cpuhp_state_add_instance_cpuslocked`:
`hlist_add_head` only on success
- **[Phase 3]** `git blame` IRQ path `4905ec2fb7e642` (2022); destroy
`e9a023f2b73ac3` (2022); snapshot/cpuhp order `a8625217a054ca` (2024,
in this tree)
- **[Phase 3]** `git merge-base --is-ancestor e24a1418e90be HEAD` → not
in this tree; `e9a023f2b73ac3` / `a8625217a054ca` / `e9991434596f53` →
in this tree
- **[Phase 3]** Follow-ups on origin/master do not redo this cleanup
- **[Phase 4]** `b4 dig -c e24a1418e90be` → patch.msgid.link v9-1; `-a`
shows v7 first, v9 applied
- **[Phase 4]** `b4 dig -m`: 31-message mbox; Sashiko comments are pre-
existing leftovers; Paul queued first ten patches; no NAK
- **[Phase 4]** WebFetch lore/stable: 403 — UNVERIFIED stable-list
discussion
- **[Phase 5]** Probe from `device_initcall(pmu_sbi_devinit)`;
`riscv_pmu_alloc` allocates `hw_events`; `pmu_sbi_get_ctrinfo`
allocates `pmu_ctr_list`
- **[Phase 5]** `pmu_sbi_starting_cpu` uses `riscv_pmu_use_irq` /
`riscv_pmu_irq`
- **[Phase 6]** `git describe HEAD` → `p-6.12-4-gbf6fcdf761abd`; `make
kernelversion` → **6.12.111**
- **[Phase 6]** `git apply --check` of `e24a1418e90be`: all hunks OK
- **[Phase 7]** `CONFIG_RISCV_PMU_SBI` default y in
`drivers/perf/Kconfig`
- **[Phase 8]** Failure mode: UAF of registered PMU + cpuhp oops → HIGH
- **UNVERIFIED:** live user oops; stable@ nomination history
**YES**
drivers/perf/riscv_pmu_sbi.c | 33 +++++++++++++++++++++++++++------
1 file changed, 27 insertions(+), 6 deletions(-)
diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
index 25f3a45dd7869..10f64b7b60c53 100644
--- a/drivers/perf/riscv_pmu_sbi.c
+++ b/drivers/perf/riscv_pmu_sbi.c
@@ -1258,22 +1258,29 @@ static int pmu_sbi_setup_irqs(struct riscv_pmu *pmu, struct platform_device *pde
DOMAIN_BUS_ANY);
if (!domain) {
pr_err("Failed to find INTC IRQ root domain\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto err;
}
riscv_pmu_irq = irq_create_mapping(domain, riscv_pmu_irq_num);
if (!riscv_pmu_irq) {
pr_err("Failed to map PMU interrupt for node\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto err;
}
ret = request_percpu_irq(riscv_pmu_irq, pmu_sbi_ovf_handler, "riscv-pmu", hw_events);
if (ret) {
pr_err("registering percpu irq failed [%d]\n", ret);
- return ret;
+ irq_dispose_mapping(riscv_pmu_irq);
+ riscv_pmu_irq = 0;
+ goto err;
}
return 0;
+err:
+ riscv_pmu_use_irq = false;
+ return ret;
}
#ifdef CONFIG_CPU_PM
@@ -1340,7 +1347,8 @@ static void riscv_pmu_destroy(struct riscv_pmu *pmu)
}
}
riscv_pm_pmu_unregister(pmu);
- cpuhp_state_remove_instance(CPUHP_AP_PERF_RISCV_STARTING, &pmu->node);
+ if (!hlist_unhashed(&pmu->node))
+ cpuhp_state_remove_instance(CPUHP_AP_PERF_RISCV_STARTING, &pmu->node);
}
static void pmu_sbi_event_init(struct perf_event *event)
@@ -1462,6 +1470,7 @@ static int pmu_sbi_device_probe(struct platform_device *pdev)
struct riscv_pmu *pmu = NULL;
int ret = -ENODEV;
int num_counters;
+ bool irq_requested = false;
pr_info("SBI PMU extension is available\n");
pmu = riscv_pmu_alloc();
@@ -1490,6 +1499,7 @@ static int pmu_sbi_device_probe(struct platform_device *pdev)
pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT;
pmu->pmu.capabilities |= PERF_PMU_CAP_NO_EXCLUDE;
}
+ irq_requested = (ret == 0);
pmu->pmu.attr_groups = riscv_pmu_attr_groups;
pmu->pmu.parent = &pdev->dev;
@@ -1508,11 +1518,11 @@ static int pmu_sbi_device_probe(struct platform_device *pdev)
ret = riscv_pm_pmu_register(pmu);
if (ret)
- goto out_unregister;
+ goto out_destroy;
ret = perf_pmu_register(&pmu->pmu, "cpu", PERF_TYPE_RAW);
if (ret)
- goto out_unregister;
+ goto out_destroy;
/* SBI PMU Snapsphot is only available in SBI v2.0 */
if (sbi_v2_available) {
@@ -1553,9 +1563,20 @@ static int pmu_sbi_device_probe(struct platform_device *pdev)
return 0;
out_unregister:
+ perf_pmu_unregister(&pmu->pmu);
+
+out_destroy:
riscv_pmu_destroy(pmu);
+ if (irq_requested) {
+ free_percpu_irq(riscv_pmu_irq, pmu->hw_events);
+ irq_dispose_mapping(riscv_pmu_irq);
+ riscv_pmu_irq = 0;
+ }
out_free:
+ free_percpu(pmu->hw_events);
+ kfree(pmu_ctr_list);
+ pmu_ctr_list = NULL;
kfree(pmu);
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH AUTOSEL 6.18-6.1] perf/x86/intel: Fallback to sw branch type decoding if no hw decoding
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (6 preceding siblings ...)
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-6.12] RISC-V: perf: fix resource cleanup on driver probe failure Sasha Levin
@ 2026-10-19 13:52 ` Sasha Levin
2026-10-19 15:25 ` sashiko-bot
7 siblings, 1 reply; 15+ messages in thread
From: Sasha Levin @ 2026-10-19 13:52 UTC (permalink / raw)
To: patches, stable
Cc: Dapeng Mi, Peter Zijlstra (Intel), Sasha Levin, mingo, acme,
namhyung, tglx, bp, dave.hansen, x86, linux-perf-users,
linux-kernel
From: Dapeng Mi <dapeng1.mi@linux.intel.com>
[ Upstream commit 170cc6b02e3d5203ccaa49ffea1ee5a7ab08c885 ]
intel_pmu_lbr_filter() currently assumes arch-LBR provides hardware
branch-type decoding and skips software decoding on that path.
However, arch-LBR may not always expose branch-type information. In
that case, treating entries as hardware-decoded can misclassify sampled
branches (for example, defaulting to JCC), which breaks branch-type
filtering results.
Fix this by using software branch-type decoding when hardware
branch-type decoding is unavailable (that is, when x86_lbr_type is not
enabled). This keeps branch classification and filtering behavior
correct across arch-LBR configurations.
Since x86_lbr_type is only set to true when arch-LBR is supported,
it's unnecessary to check if the CPU has the arch-LBR feature.
Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20260616044654.3468742-4-dapeng1.mi@linux.intel.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
I have enough to decide: the 6.18.53 tree still has the JCC
misclassification, and this is a one-line, already-reviewed correction
of that path.
===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================
Step 1.1: PARSE THE SUBJECT LINE
Record: [perf/x86/intel] [Fallback] [Use software branch-type decoding
when Arch LBR does not provide hardware type]
Step 1.2: PARSE ALL COMMIT MESSAGE TAGS
Record:
- Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com> (author, Intel)
- Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> (perf/x86
maintainer; applied to tip)
- Link: https://patch.msgid.link/20260616044654.3468742-4-
dapeng1.mi@linux.intel.com
- No Fixes: tag (expected)
- No Reported-by / Tested-by / Reviewed-by / Acked-by / Cc: stable
- Ignore pipeline tags: [Upstream commit
170cc6b02e3d5203ccaa49ffea1ee5a7ab08c885], Signed-off-by: Sasha Levin
Notable: msgid `-4` is patch 3/8 of “perf/x86: Miscellaneous PMU bug
fixes” (cover letter is `-1`). Independent patches grouped for
review/backport, not a tightly coupled series.
Step 1.3: ANALYZE THE COMMIT BODY TEXT
Record:
- Bug: `intel_pmu_lbr_filter()` treats Arch LBR as always having
hardware branch-type decode and skips software decode.
- Reality: Arch LBR CPUID leaf 28H ECX bit 2 (`lbr_br_type`) is
optional. If it is clear, `get_lbr_br_type()` returns 0.
- Symptom: type 0 is `ARCH_LBR_BR_TYPE_JCC`, so sampled branches are
classified as JCC. Branch-type filters (`PERF_SAMPLE_BRANCH_*`) and
saved types are wrong (calls/returns dropped or shown as
conditionals).
- Root cause: gate is `static_cpu_has(X86_FEATURE_ARCH_LBR)` instead of
“hardware type actually present”.
- Fix: gate on `static_branch_likely(&x86_lbr_type)`, which is enabled
only when `x86_pmu.lbr_br_type` is set in `intel_pmu_arch_lbr_init()`.
- Version info in message: none.
Step 1.4: DETECT HIDDEN BUG FIXES
Record: Not hidden. Explicit correctness fix for misclassification. Not
style/cleanup.
===============================================================
PHASE 2: DIFF ANALYSIS - LINE BY LINE
===============================================================
Step 2.1: INVENTORY THE CHANGES
Record:
- File: `arch/x86/events/intel/lbr.c` — 1 insertion, 1 deletion
- Function: `intel_pmu_lbr_filter()`
- Scope: single-file, one-line surgical change
Step 2.2: UNDERSTAND THE CODE FLOW CHANGE
Record:
- Before: if CPU has Arch LBR and `type <= ARCH_LBR_BR_TYPE_KNOWN_MAX`
(0–5), map via `arch_lbr_br_type_map[]`. Else `branch_type()` software
decode.
- After: same hardware map only if `x86_lbr_type` is enabled (HW type
field present). Otherwise software decode.
- Path: LBR sample filtering after PMI / branch-stack snapshot, not
probe/init-only.
Step 2.3: IDENTIFY THE BUG MECHANISM
Record:
- Category: logic/correctness (wrong classifier when optional HW field
is absent)
- Mechanism: `get_lbr_br_type()` is:
```866:873:arch/x86/events/intel/lbr.c
static __always_inline int get_lbr_br_type(u64 info)
{
int type = 0;
if (static_branch_likely(&x86_lbr_type))
type = (info & LBR_INFO_BR_TYPE) >>
LBR_INFO_BR_TYPE_OFFSET;
return type;
}
```
When `x86_lbr_type` is off, stored type is 0. Old filter still took the
Arch LBR map because `0 <= ARCH_LBR_BR_TYPE_KNOWN_MAX`, so every entry
became JCC. Fix uses the same static key as the reader.
Step 2.4: ASSESS THE FIX QUALITY
Record:
- Obviously correct: one condition aligned with how type is populated.
- Minimal; no unrelated edits.
- Regression risk: low on CPUs with `lbr_br_type` (common Arch LBR) —
same HW path.
- On Arch LBR without HW type: software decode in NMI (existing
`branch_type()` path). Sashiko flagged extra NMI cost because
`intel_pmu_setup_hw_lbr_filter()` always sets `X86_BR_TYPE_SAVE` for
Arch LBR, so the filter never early-returns. That is the cost of
correct types, not a change to already-correct behavior. Peter merged
this form anyway.
- No public API / data-structure change.
===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================
Step 3.1: BLAME THE CHANGED LINES
Record:
- Buggy `if (static_cpu_has(X86_FEATURE_ARCH_LBR) &&` introduced in
`47125db27e47e9` (“perf/x86/intel/lbr: Support Architectural LBR”, Kan
Liang, 2020-07-08). Contained in `perf-core-2020-08-03` (~v5.9).
Present in this tree.
- `x86_lbr_type` added in `6b19788ddc593` (“perf/x86/intel/lbr: Add
static_branch for LBR INFO flags”, 2022-01-18, ~v5.17). Present here.
- `X86_BR_TYPE_SAVE` forced for Arch LBR in `32ba156df1b1c` (2022, Cc:
stable). Present here.
Step 3.2: FOLLOW THE FIXES: TAG
Record: No Fixes: tag. Functionally this is a late correction of
`47125db27e47e9`, which is in v6.18.53.
Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES
Record:
- `3c492c8eba026` “Fix kernel address leakages in LBR stack” is already
in v6.18.53 (same series, patch 4/8). Surrounding filter already has
`from_plm` kernel-from dropping.
- Candidate `906dbeecfa0ff` is this patch on autosel; **not** in
`v6.18.53` (`git merge-base --is-ancestor 906dbeecfa0ff v6.18.53`
failed).
- v6.18.53 still has `static_cpu_has(X86_FEATURE_ARCH_LBR)` at the
filter. Bug is live on the baseline.
- Standalone vs series: cover letter: “several independent PMU fixes to
simplify review and backporting.” This hunk does not need 1/8, 2/8,
5–8. 4/8 is already here.
Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS
Record: Dapeng Mi is a regular Intel perf/x86 contributor. Peter
Zijlstra applied it. Nearby same-series work: leakage fix already in
this stable tree.
Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS
Record:
- Needs `x86_lbr_type` — in this tree since ~v5.17.
- Does not need other v4 patches.
- Applies standalone: v6.18.53 already has the exact one-line context
(candidate applied as 1 line).
===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================
Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION
Record:
- `b4 dig -c 170cc6b02e3d5203ccaa49ffea1ee5a7ab08c885` → https://patch.m
sgid.link/20260616044654.3468742-4-dapeng1.mi@linux.intel.com
- Subject: `[Patch v4 3/8] perf/x86/intel: Fallback to sw branch type
decoding if no hw decoding`
- Series: v1 2026-06-05, v2 2026-06-09, v3 2026-06-12, v4 2026-06-16;
tip-bot2 applied 2026-06-30.
- v3→v4: unrelated patches; Peter asked to drop markdown in changelogs.
- v2→v3: “Patch 3/8: Only keep x86_lbr_type check … (Peter).” Committed
form is what the maintainer asked for.
- v1→v2: software fallback added after Sashiko review of v1.
- Cover: “independent PMU fixes to simplify review and backporting.”
- Human NAKs: none in the saved thread.
- Sashiko AI on v4: High — always-on `X86_BR_TYPE_SAVE` plus software
decode can add NMI cost if HW type is missing. Not addressed in the
merged patch; maintainer still took it.
- WebFetch to lore.kernel.org: 403. Thread recovered via `b4 dig -m`.
Step 4.2: CHECK WHO REVIEWED THE PATCH
Record (`b4 dig -w`): To/Cc included Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Namhyung Kim, Ian Rogers, Adrian Hunter,
Alexander Shishkin, Andi Kleen, Stephane Eranian, linux-perf-users, Zide
Chen, Thomas Falcon, Xudong Hao. Peter signed off. No extra Reviewed-by
on the commit.
Step 4.3: SEARCH FOR THE BUG REPORT
Record: No Reported-by, bugzilla, or syzbot. Looks Intel-internal / code
review. Unverified which SKU has Arch LBR without `lbr_br_type`; CPUID
documents it as optional (`union cpuid28_ecx.lbr_br_type`).
Step 4.4: CHECK FOR RELATED PATCHES AND SERIES
Record: v4 8 independent fixes. 4/8 (kernel LBR address leak) already in
this tree. This 3/8 is self-contained.
Step 4.5: CHECK STABLE MAILING LIST HISTORY
Record: lore.kernel.org/stable search returned 403. Cover letter still
states the series was meant to be easy to backport. UNVERIFIED: no
stable-list NAK found (could not query the list).
===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================
Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF
Record: `intel_pmu_lbr_filter()` only. Uses `x86_lbr_type`,
`arch_lbr_br_type_map`, `branch_type()`, `common_branch_type()`.
Step 5.2: TRACE CALLERS
Record:
- `intel_pmu_lbr_read()` → `intel_pmu_lbr_filter()`
- `__intel_pmu_snapshot_branch_stack()` (irq-off snapshot)
- Intel PMI handler in `intel/core.c` (~line 3375, NMI)
- `intel_pmu_store_pebs_lbrs()` → store then filter (PEBS LBR)
Step 5.3: TRACE CALLEES
Record: `kernel_ip()`, `arch_lbr_br_type_map[]`, `branch_type()` (insn
decode in `arch/x86/events/utils.c`), `common_branch_type()`.
`branch_type()` already used for non-Arch LBR and OTHER_BRANCH.
Step 5.4: FOLLOW THE CALL CHAIN
Record: Userspace `perf_event_open` with `PERF_SAMPLE_BRANCH_STACK` →
PMI/PEBS → LBR read → filter. Reachable from perf. Needs Intel PMU +
Arch LBR without HW type to hit the bug; with HW type the new check
matches old behavior.
Step 5.5: SEARCH FOR SIMILAR PATTERNS
Record: AMD `arch/x86/events/amd/lbr.c` has its own filter; not this
bug. Same file already uses `x86_lbr_type` in `get_lbr_br_type()`; the
filter was the inconsistent check.
===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================
Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?
Record:
- `git describe HEAD` → `v6.18.53-5049-g0f0bdc2b0dffb`; `make
kernelversion` → 6.18.53; branch `autosel`.
- v6.18.53 `intel_pmu_lbr_filter()` still uses
`static_cpu_has(X86_FEATURE_ARCH_LBR)`.
- Bug introduced ~v5.9; still present on this 6.18 baseline.
Step 6.2: CHECK FOR BACKPORT COMPLICATIONS
Record: Clean apply. Candidate is a 1-line replace on the v6.18.53 line.
Leakage extra checks around it do not conflict.
Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE
Record: No other fallback to `x86_lbr_type` in the filter on v6.18.53.
Leakage fix is separate and already present.
===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================
Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY
Record: perf/x86 Intel LBR (`arch/x86/events/intel/lbr.c`). IMPORTANT:
Intel PMU branch recording, not core mm/VFS. Widely used on x86 via
perf.
Step 7.2: ASSESS SUBSYSTEM ACTIVITY
Record: Actively maintained (Kan Liang, Dapeng Mi, Peter Zijlstra). Arch
LBR path is mature (since 2020), not brand-new.
===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================
Step 8.1: DETERMINE WHO IS AFFECTED
Record: Intel x86 with Arch LBR (Ice Lake+) when CPUID leaf 28H does not
set branch-type. Users of `perf record -j` / `PERF_SAMPLE_BRANCH_STACK`
with type filters or type save. Not universal; driver/PMU-specific.
Step 8.2: DETERMINE THE TRIGGER CONDITIONS
Record: Normal LBR sampling when HW type is absent. Unprivileged users
can open perf events if `perf_event_paranoid` allows; typically needs
profiling access. Not a rare error-path-only bug.
Step 8.3: DETERMINE THE FAILURE MODE SEVERITY
Record:
- Failure: wrong branch types; type filters drop real calls/returns or
keep everything as JCC; saved types lie.
- Not oops, deadlock, or filesystem corruption.
- Severity: MEDIUM (silent wrong samples). Important for perf
correctness; same class as other LBR type fixes that already went to
stable (e.g. `32ba156df1b1c`).
Step 8.4: CALCULATE RISK-BENEFIT RATIO
Record:
- Benefit: correct LBR classification/filtering on Arch LBR without HW
type; no-op where HW type exists.
- Risk: very low (1 line). Extra software decode only on the previously
wrong config; `branch_type()` is already used in NMI.
- Ratio: favorable.
===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================
Step 9.1: COMPILE THE EVIDENCE
FOR:
- Real misclassification (all branches as JCC) when Arch LBR lacks HW
type.
- Bug exists on this 6.18.53 baseline.
- One-line, obviously correct, matches `get_lbr_br_type()`.
- Maintainer (Peter Zijlstra) requested this check and signed off.
- Independent of the rest of the series; cover letter aimed at
backporting.
- Prerequisites (`x86_lbr_type`, Arch LBR filter) are in this tree.
- Applies cleanly; sibling 4/8 already in 6.18.53.
AGAINST:
- Not a crash, UAF, or security hole (leak is a different commit already
here).
- No user Reported-by / syzbot.
- Sashiko NMI-overhead note not addressed; only matters if HW type is
missing.
- Which production SKUs omit `lbr_br_type` is unverified.
UNRESOLVED:
- Exact CPU/VMM configs with Arch LBR and `lbr_br_type=0`.
- Stable-list discussion (lore 403).
Step 9.2: APPLY THE STABLE RULES CHECKLIST
1. Obviously correct and tested? PASS — one-line, maintainer-shaped, in
tip/mainline.
2. Fixes a real bug that affects users? PASS — wrong LBR types/filters.
3. Important issue? PASS (MEDIUM) — silent wrong branch samples on Intel
LBR; not a panic, but user-visible PMU corruption.
4. Small and contained? PASS — 1 line, one function.
5. No new features or APIs? PASS.
6. Can apply to the local tree? PASS — v6.18.53 has the buggy line and
`x86_lbr_type`.
Step 9.3: CHECK FOR EXCEPTION CATEGORIES
Record: None (not a device ID, quirk, DT, build, or doc fix). Qualifies
as a normal small correctness fix.
Step 9.4: MAKE YOUR DECISION
This 6.18.53 tree still has the Arch LBR filter assuming hardware types
whenever `X86_FEATURE_ARCH_LBR` is set. That is wrong when CPUID does
not advertise the type field: types collapse to JCC and filters lie. The
fix is the same static key already used to read the field, applies
cleanly, and does not change the common HW-type path. That is
appropriate for this stable tree.
What it solves for stable users: Intel perf LBR branch-type
filtering/classification on Arch LBR configs without hardware type,
instead of silently tagging everything as conditional jumps.
Risk vs benefit: one line vs wrong samples; remaining risk is extra
software decode only on the previously broken config.
Verification:
- [Phase 1] Parsed tags: SOB Dapeng Mi + Peter Zijlstra; Link msgid
3468742-4; no Fixes/Reported-by/Cc stable
- [Phase 1] Cover letter (mbox): independent PMU fixes “to simplify
review and backporting”; this is v4 3/8
- [Phase 2] Diff: 1 line in `intel_pmu_lbr_filter()`,
`static_cpu_has(X86_FEATURE_ARCH_LBR)` →
`static_branch_likely(&x86_lbr_type)`
- [Phase 2] Confirmed `get_lbr_br_type()` returns 0 when `x86_lbr_type`
is off; 0 maps to JCC
- [Phase 3] `git blame` on parent: buggy check from `47125db27e47e9`
(2020 Arch LBR)
- [Phase 3] `git merge-base --is-ancestor 47125db27e47e9 v6.18.53` →
yes; `6b19788ddc593` (x86_lbr_type) → yes
- [Phase 3] `git merge-base --is-ancestor 906dbeecfa0ff v6.18.53` → no
(not in baseline)
- [Phase 3] `git show v6.18.53:arch/x86/events/intel/lbr.c` still has
`static_cpu_has(X86_FEATURE_ARCH_LBR)` in the filter
- [Phase 3] Leakage fix `3c492c8eba026` is already in v6.18.53
- [Phase 4] `b4 dig -c 170cc6b02e3d5`: lore thread
20260616044654.3468742-4; v1–v4; Peter asked for x86_lbr_type-only
check in v3
- [Phase 4] `b4 dig -w`: Peter, Ingo, acme, Namhyung, Eranian, linux-
perf-users CC’d
- [Phase 4] Sashiko v4: NMI software-decode cost if TYPE_SAVE always
set; unverified product impact
- [Phase 4] WebFetch lore/stable: 403; UNVERIFIED stable-list discussion
- [Phase 5] Callers: `intel_pmu_lbr_read()` from PMI and snapshot;
`intel_pmu_store_pebs_lbrs()` from PEBS
- [Phase 6] `git describe HEAD`: v6.18.53-5049-g0f0bdc2b0dffb; `make
kernelversion`: 6.18.53
- [Phase 8] Failure: misclassified LBR samples, severity MEDIUM
- UNVERIFIED: concrete CPUID dumps with Arch LBR and `lbr_br_type=0`
**YES**
arch/x86/events/intel/lbr.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c
index 44f5556440223..bbfd6ffbdd68a 100644
--- a/arch/x86/events/intel/lbr.c
+++ b/arch/x86/events/intel/lbr.c
@@ -1230,7 +1230,7 @@ intel_pmu_lbr_filter(struct cpu_hw_events *cpuc)
* Doesn't support OTHER_BRANCH decoding for now.
* OTHER_BRANCH branch type still rely on software decoding.
*/
- if (static_cpu_has(X86_FEATURE_ARCH_LBR) &&
+ if (static_branch_likely(&x86_lbr_type) &&
type <= ARCH_LBR_BR_TYPE_KNOWN_MAX) {
to_plm = kernel_ip(to) ? X86_BR_KERNEL : X86_BR_USER;
type = arch_lbr_br_type_map[type] | to_plm;
--
2.53.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH AUTOSEL 6.18-5.15] perf/x86/intel/uncore: Fix PCI PMU cleanup on setup failure
2026-10-19 13:45 ` [PATCH AUTOSEL 6.18-5.15] perf/x86/intel/uncore: Fix PCI PMU cleanup on setup failure Sasha Levin
@ 2026-10-19 14:02 ` sashiko-bot
0 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-10-19 14:02 UTC (permalink / raw)
To: Sasha Levin; +Cc: linux-perf-users
> From: Zide Chen <zide.chen@intel.com>
>
> [ Upstream commit 003267cb94e21d762eb72d6977d84f44f1705bb7 ]
>
> When uncore_pci_pmu_register() fails, pmu->boxes[die] is set to NULL
> before returning. In the uncore_pci_remove() path, this causes
> uncore_pci_pmu_unregister() to be skipped entirely, leaking
> pmu->activeboxes. In the uncore_bus_notify() path,
> uncore_pci_pmu_unregister() may still be called and must exit early
> when pmu->boxes[die] is NULL to avoid a NULL pointer dereference, and
> to ensure activeboxes is only decremented for a previously active box.
>
> Additionally, since pci_get_drvdata() returns NULL on registration
> failure, uncore_pci_remove() can no longer treat NULL drvdata as an
> indicator of an auxiliary PCI device. Remove the associated
> WARN_ON_ONCE().
>
> Signed-off-by: Zide Chen <zide.chen@intel.com>
> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
> Reviewed-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
> Link: https://sashiko.dev/#/patchset/20260512233048.9577-1-zide.chen@intel.com?part=1
> Link: https://patch.msgid.link/20260611160033.66760-2-zide.chen@intel.com
> Signed-off-by: Sasha Levin <sashal@kernel.org>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261019135441.1420968-19-sashal@kernel.org?part=1
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH AUTOSEL 6.18] perf/arm-cmn: Add workarounds for CMN-S3 on Graviton5
2026-10-19 13:47 ` [PATCH AUTOSEL 6.18] perf/arm-cmn: Add workarounds for CMN-S3 on Graviton5 Sasha Levin
@ 2026-10-19 14:35 ` sashiko-bot
0 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-10-19 14:35 UTC (permalink / raw)
To: Sasha Levin; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] perf/arm-cmn: CMN_MAX_DIMENSION bump breaks 32-bit COMPILE_TEST static_assert
--
commit 27fbc22fac85b996ea007fe76c639085d36b43ec
Author: Aviv Bakal <avivb@amazon.com>
perf/arm-cmn: Add workarounds for CMN-S3 on Graviton5
This commit adds an ACPI HID and discovery workarounds for the customised
CMN-S3 implementation on Graviton5, and raises CMN_MAX_DIMENSION from 12
to 14 to support its 10x14 mesh.
> diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c
> index 527a953bf4744..688a94ef81c22 100644
> --- a/drivers/perf/arm-cmn.c
> +++ b/drivers/perf/arm-cmn.c
> @@ -31,7 +31,8 @@
> #define CMN_CHILD_NODE_ADDR GENMASK(29, 0)
> #define CMN_CHILD_NODE_EXTERNAL BIT(31)
>
> -#define CMN_MAX_DIMENSION 12
> +/* Some implementations use a mesh larger than the architectural max of 12 */
> +#define CMN_MAX_DIMENSION 14
> #define CMN_MAX_XPS (CMN_MAX_DIMENSION * CMN_MAX_DIMENSION)
> #define CMN_MAX_DTMS (CMN_MAX_XPS + (CMN_MAX_DIMENSION - 1) * 4)
[Severity: Medium]
Does raising CMN_MAX_DIMENSION to 14 break 32-bit builds when
CONFIG_ARM_CMN is enabled under CONFIG_COMPILE_TEST?
Upstream commit 9d0b1714e1af1 ("perf/arm-cmn: Add workarounds for CMN-S3 on
Graviton5") was patch 2/2 of a series depending on upstream commit
56603c28d9169 ("perf/arm-cmn: Move DTM index data out of hw_perf_event"),
which moved dtm_idx and wp_idx out of struct arm_cmn_hw_event.
Without that prerequisite commit in this tree, struct arm_cmn_hw_event in
drivers/perf/arm-cmn.c still embeds both arrays:
struct arm_cmn_hw_event {
struct arm_cmn_node *dn;
u64 dtm_idx[DIV_ROUND_UP(CMN_MAX_NODES_PER_EVENT * 2, 64)];
s8 dtc_idx[CMN_MAX_DTCS];
u8 num_dns;
u8 dtm_offset;
/*
* WP config registers are divided to UP and DOWN events. We need to
* keep to track only one of them.
*/
DECLARE_BITMAP(wp_idx, CMN_MAX_XPS);
bool wide_sel;
enum cmn_filter_select filter_sel;
};
static_assert(sizeof(struct arm_cmn_hw_event) <= offsetof(struct hw_perf_event, target));
Increasing CMN_MAX_DIMENSION from 12 to 14 grows CMN_MAX_XPS and
CMN_MAX_NODES_PER_EVENT from 144 to 196. That expands dtm_idx from 5 to 7
u64 elements (+16 bytes) and wp_idx on 32-bit architectures from 5 to 7
unsigned longs (+8 bytes), increasing sizeof(struct arm_cmn_hw_event) from
88 to 112 bytes (or from 80 to 104 bytes on i386).
On 32-bit architectures, unsigned long in struct hw_perf_event
(include/linux/perf_event.h) is 4 bytes, so offsetof(struct hw_perf_event,
target) is only 104 bytes (or 96 bytes on i386), causing the static_assert
to fail at compile time.
Should upstream commit 56603c28d9169 ("perf/arm-cmn: Move DTM index data
out of hw_perf_event") also be included as a prerequisite?
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261019135441.1420968-145-sashal@kernel.org?part=1
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH AUTOSEL 6.18] perf/core: Fix kernel register info leak via hardware skid
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18] perf/core: Fix kernel register info leak via hardware skid Sasha Levin
@ 2026-10-19 14:42 ` sashiko-bot
0 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-10-19 14:42 UTC (permalink / raw)
To: Sasha Levin; +Cc: linux-perf-users
> From: Dapeng Mi <dapeng1.mi@linux.intel.com>
>
> [ Upstream commit 166f10836a653dfa280d4335603b52f685b8b1ef ]
>
> An unprivileged hardware perf event using exclude_kernel=1 can leak kernel
> register data to user space via PERF_SAMPLE_REGS_INTR or PERF_SAMPLE_IP.
> Due to hardware skid, a PMI may trigger after the CPU has already entered
> kernel space (Ring 0), bypassing the perf_allow_kernel() privilege
> barrier.
>
> This security vulnerability is severely exacerbated by upcoming support
> for SIMD register sampling via XSAVES, which could expose sensitive kernel
> FPU states (such as active cryptographic keys).
>
> Fix this by ensuring that sampled register data is dropped if the event's
> exclude_kernel attribute is set but the PMI catches the CPU in kernel mode.
>
> Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
> Link: https://lore.kernel.org/all/20260529085613.CCAFB1F00893@smtp.kernel.org/
> Link: https://patch.msgid.link/20260616044654.3468742-8-dapeng1.mi@linux.intel.com
> Signed-off-by: Sasha Levin <sashal@kernel.org>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261019135441.1420968-208-sashal@kernel.org?part=1
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH AUTOSEL 6.18-6.1] perf: marvell: Cancel CN10K DDR PMU hrtimer on device remove
2026-10-19 13:47 ` [PATCH AUTOSEL 6.18-6.1] perf: marvell: Cancel CN10K DDR PMU hrtimer on device remove Sasha Levin
@ 2026-10-19 14:44 ` sashiko-bot
0 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-10-19 14:44 UTC (permalink / raw)
To: Sasha Levin; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] perf: marvell: premature hrtimer_cancel() in cn10k_ddr_perf_remove()
--
commit ee388a976febdb25de30edee55cec9fcf0a7184a
Author: Geetha sowjanya <gakula@marvell.com>
perf: marvell: Cancel CN10K DDR PMU hrtimer on device remove
This commit cancels the poll hrtimer in cn10k_ddr_perf_remove() so the
timer callback cannot run after the device is unbound and its resources
are freed.
> diff --git a/drivers/perf/marvell_cn10k_ddr_pmu.c b/drivers/perf/marvell_cn10k_ddr_pmu.c
> index 72ac17efd846a..9974b62541f0d 100644
> --- a/drivers/perf/marvell_cn10k_ddr_pmu.c
> +++ b/drivers/perf/marvell_cn10k_ddr_pmu.c
> @@ -1088,6 +1088,12 @@ static void cn10k_ddr_perf_remove(struct platform_device *pdev)
> {
> struct cn10k_ddr_pmu *ddr_pmu = platform_get_drvdata(pdev);
>
> + /*
> + * Cancel the poll timer before further teardown so the handler
> + * cannot run after this function returns.
> + */
> + hrtimer_cancel(&ddr_pmu->hrtimer);
> +
> cpuhp_state_remove_instance_nocalls(
> CPUHP_AP_PERF_ARM_MARVELL_CN10K_DDR_ONLINE,
> &ddr_pmu->node);
[Severity: High]
Can ddr_pmu->hrtimer be re-armed after hrtimer_cancel() returns here?
In cn10k_ddr_perf_remove(), hrtimer_cancel(&ddr_pmu->hrtimer) is called
before cpuhp_state_remove_instance_nocalls() and perf_pmu_unregister():
drivers/perf/marvell_cn10k_ddr_pmu.c:cn10k_ddr_perf_remove() {
hrtimer_cancel(&ddr_pmu->hrtimer);
cpuhp_state_remove_instance_nocalls(
CPUHP_AP_PERF_ARM_MARVELL_CN10K_DDR_ONLINE,
&ddr_pmu->node);
perf_pmu_unregister(&ddr_pmu->pmu);
}
Until cpuhp_state_remove_instance_nocalls() removes the hotplug instance
and perf_pmu_unregister() finishes synchronize_srcu() / synchronize_rcu()
and detaches events via pmu_detach_events(), PMU and CPU hotplug callbacks
remain active:
kernel/events/core.c:perf_pmu_unregister() {
...
synchronize_srcu(&pmus_srcu);
synchronize_rcu();
...
pmu_detach_events(pmu);
...
}
During that window, cn10k_ddr_perf_event_add() can still run on another
CPU (via an in-flight perf_event_open(), ioctl(PERF_EVENT_IOC_ENABLE),
perf_rotate_context(), or cn10k_ddr_pmu_offline_cpu() ->
perf_pmu_migrate_context()) and call hrtimer_start() when
pmu->active_events becomes 1:
drivers/perf/marvell_cn10k_ddr_pmu.c:cn10k_ddr_perf_event_add() {
...
pmu->active_events++;
hwc->idx = counter;
if (pmu->active_events == 1)
hrtimer_start(&pmu->hrtimer, cn10k_ddr_pmu_timer_period(),
HRTIMER_MODE_REL_PINNED);
if (counter < DDRC_PERF_NUM_GEN_COUNTERS) {
/* Generic counters, configure event id */
reg_offset = DDRC_PERF_CFG(p_data->cfg_base, counter);
ret = ddr_perf_get_event_bitmap(config, &val, pmu);
if (ret)
return ret;
...
}
If ddr_perf_get_event_bitmap() then returns -EINVAL (or if
pmu->active_events was previously skewed by a failed add),
cn10k_ddr_perf_event_add() returns without decrementing pmu->active_events
or stopping pmu->hrtimer. Because event_sched_in() leaves the event in
PERF_EVENT_STATE_INACTIVE on add failure, pmu_detach_events() ->
event_sched_out() never calls cn10k_ddr_perf_event_del() for that event
(and even if other active events are detached, pmu->active_events never
reaches 0 in cn10k_ddr_perf_event_del()).
This leaves ddr_pmu->hrtimer armed when cn10k_ddr_perf_remove() returns,
allowing cn10k_ddr_pmu_timer_handler() to run after devm frees struct
cn10k_ddr_pmu and unmaps ddr_pmu->base.
Should hrtimer_cancel(&ddr_pmu->hrtimer) be called after
perf_pmu_unregister() and cpuhp_state_remove_instance_nocalls() have
completed (matching the reverse of the setup order in
cn10k_ddr_perf_probe())?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261019135441.1420968-185-sashal@kernel.org?part=1
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH AUTOSEL 6.18-6.1] perf/x86: Unregister PMI handler on PMU init failure
2026-10-19 13:51 ` [PATCH AUTOSEL 6.18-6.1] perf/x86: Unregister PMI handler on PMU init failure Sasha Levin
@ 2026-10-19 15:17 ` sashiko-bot
0 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-10-19 15:17 UTC (permalink / raw)
To: Sasha Levin; +Cc: linux-perf-users
> From: Dapeng Mi <dapeng1.mi@linux.intel.com>
>
> [ Upstream commit 91787047b1dc52b1fee68b07f79af70aae5fce47 ]
>
> Fix an NMI handler leak in init_hw_perf_events(). When PMU
> initialization fails after register_nmi_handler(), the error path
> exits without calling unregister_nmi_handler(), leaving a stale
> NMI_LOCAL "PMI" handler registered. Add the missing call before
> clearing x86_pmu state.
>
> Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
> Reviewed-by: Thomas Falcon <thomas.falcon@intel.com>
> Reviewed-by: Zide Chen <zide.chen@intel.com>
> Link: https://patch.msgid.link/20260717080342.1879573-2-dapeng1.mi@linux.intel.com
> Signed-off-by: Sasha Levin <sashal@kernel.org>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261019135441.1420968-428-sashal@kernel.org?part=1
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH AUTOSEL 6.18-6.1] perf/x86/intel: Fallback to sw branch type decoding if no hw decoding
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-6.1] perf/x86/intel: Fallback to sw branch type decoding if no hw decoding Sasha Levin
@ 2026-10-19 15:25 ` sashiko-bot
0 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-10-19 15:25 UTC (permalink / raw)
To: Sasha Levin; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] perf/x86/intel: X86_BR_TYPE_SAVE forced in intel_pmu_setup_hw_lbr_filter()
--
commit c34c39f861fe5e2bf440b3a3e6e92d35016fb9be
Author: Dapeng Mi <dapeng1.mi@linux.intel.com>
perf/x86/intel: Fallback to sw branch type decoding if no hw decoding
This commit updates intel_pmu_lbr_filter() to check the x86_lbr_type static
branch instead of X86_FEATURE_ARCH_LBR, falling back to software branch-type
decoding when hardware branch-type decoding is unavailable on arch-LBR CPUs.
Link: https://patch.msgid.link/20260616044654.3468742-4-dapeng1.mi@linux.intel.com
> diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c
> index 7aa59966e7c3e..896aeaac9e6a4 100644
> --- a/arch/x86/events/intel/lbr.c
> +++ b/arch/x86/events/intel/lbr.c
> @@ -1230,7 +1230,7 @@ intel_pmu_lbr_filter(struct cpu_hw_events *cpuc)
> * Doesn't support OTHER_BRANCH decoding for now.
> * OTHER_BRANCH branch type still rely on software decoding.
> */
> - if (static_cpu_has(X86_FEATURE_ARCH_LBR) &&
> + if (static_branch_likely(&x86_lbr_type) &&
> type <= ARCH_LBR_BR_TYPE_KNOWN_MAX) {
> to_plm = kernel_ip(to) ? X86_BR_KERNEL : X86_BR_USER;
> type = arch_lbr_br_type_map[type] | to_plm;
[Severity: Medium]
Should intel_pmu_setup_hw_lbr_filter() also be updated to check
static_branch_likely(&x86_lbr_type) before forcing X86_BR_TYPE_SAVE?
Currently, intel_pmu_setup_hw_lbr_filter() checks X86_FEATURE_ARCH_LBR and
unconditionally enables X86_BR_TYPE_SAVE under the assumption that hardware
provides branch types without software disassembly:
arch/x86/events/intel/lbr.c:intel_pmu_setup_hw_lbr_filter() {
...
if (static_cpu_has(X86_FEATURE_ARCH_LBR)) {
reg->config = mask;
/*
* The Arch LBR HW can retrieve the common branch types
* from the LBR_INFO. It doesn't require the high overhead
* SW disassemble.
* Enable the branch type by default for the Arch LBR.
*/
reg->reg |= X86_BR_TYPE_SAVE;
return 0;
}
...
}
When an event is opened with PERF_SAMPLE_BRANCH_USER |
PERF_SAMPLE_BRANCH_KERNEL | PERF_SAMPLE_BRANCH_ANY (without
PERF_SAMPLE_BRANCH_TYPE_SAVE) on an arch-LBR CPU where x86_lbr_type is
disabled, forcing X86_BR_TYPE_SAVE into cpuc->br_sel causes
intel_pmu_lbr_filter() to bypass its fast-path return:
arch/x86/events/intel/lbr.c:intel_pmu_lbr_filter() {
/* if sampling all branches, then nothing to filter */
if (((br_sel & X86_BR_ALL) == X86_BR_ALL) &&
((br_sel & X86_BR_TYPE_SAVE) != X86_BR_TYPE_SAVE))
return;
With this change in intel_pmu_lbr_filter(), every LBR entry then falls back
to software disassembly via branch_type() in NMI context, and any entry where
branch_type() returns X86_BR_NONE (such as when copy_from_user_nmi() fails on
an unmapped user page) gets discarded even though the user asked to sample
all branches without branch-type saving:
/* if type does not correspond, then discard */
if (type == X86_BR_NONE || (br_sel & type) != type) {
cpuc->lbr_entries[i].from = 0;
compress = true;
}
Would it make sense to gate X86_BR_TYPE_SAVE in
intel_pmu_setup_hw_lbr_filter() on static_branch_likely(&x86_lbr_type) as
well?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261019135441.1420968-463-sashal@kernel.org?part=1
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH AUTOSEL 6.18-6.12] RISC-V: perf: fix resource cleanup on driver probe failure
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-6.12] RISC-V: perf: fix resource cleanup on driver probe failure Sasha Levin
@ 2026-10-19 15:33 ` sashiko-bot
0 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-10-19 15:33 UTC (permalink / raw)
To: Sasha Levin; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] perf: riscv: NULL deref in riscv_pmu_get_hpm_info() after probe failure
- [High] riscv: perf: incomplete snapshot and IRQ cleanup on probe failure
- [Medium] perf: riscv: leak sysctl table registration on pmu_sbi_device_probe() failure
--
commit 45f193117e60b41831289f45f79fab573ecae630
Author: Atish Patra <atishp@meta.com>
RISC-V: perf: fix resource cleanup on driver probe failure
This commit reorganizes the error handling in pmu_sbi_device_probe(),
pmu_sbi_setup_irqs(), and riscv_pmu_destroy() to clean up registered
PMU instances, per-CPU IRQs, pmu_ctr_list, and CPU hotplug state on
probe failure.
Link: https://patch.msgid.link/20260807-counter_delegation-v9-1-58658104e487@meta.com
> diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
> index 7dd282da67cef..e794a40522fe6 100644
> --- a/drivers/perf/riscv_pmu_sbi.c
> +++ b/drivers/perf/riscv_pmu_sbi.c
[ ... ]
> @@ -1515,9 +1525,20 @@ static int pmu_sbi_device_probe(struct platform_device *pdev)
> return 0;
>
> out_unregister:
> + perf_pmu_unregister(&pmu->pmu);
[Severity: Medium]
When cpuhp_state_add_instance() fails and jumps to out_unregister, does
this path leak the sysctl table header registered just beforehand in
pmu_sbi_device_probe()?
drivers/perf/riscv_pmu_sbi.c:pmu_sbi_device_probe() {
...
register_sysctl("kernel", sbi_pmu_sysctl_table);
ret = cpuhp_state_add_instance(CPUHP_AP_PERF_RISCV_STARTING, &pmu->node);
if (ret)
goto out_unregister;
}
Because the ctl_table_header pointer returned by register_sysctl() is not
saved or passed to unregister_sysctl_table() in out_unregister, the sysctl
registration remains active after probe failure.
> +
> +out_destroy:
> riscv_pmu_destroy(pmu);
> + if (irq_requested) {
> + free_percpu_irq(riscv_pmu_irq, pmu->hw_events);
> + irq_dispose_mapping(riscv_pmu_irq);
> + riscv_pmu_irq = 0;
> + }
[Severity: High]
If cpuhp_state_add_instance() fails on a secondary CPU during
pmu_sbi_starting_cpu(), can this cleanup leave the per-CPU IRQ enabled,
snapshot shared memory registered with SBI firmware, and the
sbi_pmu_snapshot_available static branch enabled?
First, in pmu_sbi_starting_cpu(), the per-CPU IRQ is enabled before
setting up the snapshot shared memory:
drivers/perf/riscv_pmu_sbi.c:pmu_sbi_starting_cpu() {
...
if (riscv_pmu_use_irq) {
cpu_hw_evt->irq = riscv_pmu_irq;
ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask);
enable_percpu_irq(riscv_pmu_irq, IRQ_TYPE_NONE);
}
if (sbi_pmu_snapshot_available())
return pmu_sbi_snapshot_setup(pmu, cpu);
return 0;
}
If pmu_sbi_snapshot_setup() fails on that CPU, pmu_sbi_starting_cpu()
returns an error with riscv_pmu_irq still enabled on the failing CPU, and
cpuhp_rollback_install() only invokes pmu_sbi_dying_cpu() on earlier CPUs.
When out_destroy then calls free_percpu_irq(riscv_pmu_irq, pmu->hw_events),
__free_percpu_irq() sees that desc->percpu_enabled is not empty, triggers a
warning, and returns without removing the irqaction before out_free calls
free_percpu(pmu->hw_events).
Second, pmu_sbi_device_probe() sets up the snapshot shared memory on the
initial probing CPU and enables the static key before calling
cpuhp_state_add_instance():
drivers/perf/riscv_pmu_sbi.c:pmu_sbi_device_probe() {
...
cpu = get_cpu();
ret = pmu_sbi_snapshot_setup(pmu, cpu);
put_cpu();
if (ret) {
/* Snapshot is an optional feature. Continue if not available */
pmu_sbi_snapshot_free(pmu);
} else {
pr_info("SBI PMU snapshot detected\n");
static_branch_enable(&sbi_pmu_snapshot_available);
}
}
In the error path, perf_pmu_unregister() can sleep and migrate the task to
another CPU before riscv_pmu_destroy() calls pmu_sbi_snapshot_disable() on
only the current CPU and frees the pages via pmu_sbi_snapshot_free(pmu). If
the initial probing CPU was not rolled back by cpuhp_state_add_instance()
(or if the task migrated), its freed physical page remains registered with
SBI firmware. In addition, riscv_pmu_destroy() does not call
static_branch_disable(&sbi_pmu_snapshot_available).
>
> out_free:
> + free_percpu(pmu->hw_events);
> + kfree(pmu_ctr_list);
> + pmu_ctr_list = NULL;
> kfree(pmu);
> return ret;
> }
[Severity: High]
Can freeing pmu_ctr_list and setting it to NULL here without clearing the
static global cmask cause a NULL pointer dereference in
riscv_pmu_get_hpm_info()?
In pmu_sbi_device_probe(), pmu_sbi_get_ctrinfo(num_counters, &cmask)
populates the file-scope cmask bitmask alongside allocating pmu_ctr_list.
If a later step in pmu_sbi_device_probe() fails, out_free frees
pmu_ctr_list and sets it to NULL, while cmask stays non-zero.
When kvm_riscv_vcpu_pmu_init() subsequently calls riscv_pmu_get_hpm_info():
drivers/perf/riscv_pmu_sbi.c:riscv_pmu_get_hpm_info() {
...
if (!cmask)
return -EINVAL;
for_each_set_bit(i, &cmask, RISCV_MAX_COUNTERS) {
info = &pmu_ctr_list[i];
if (!info)
continue;
if (!hpm_width && info->csr != CSR_CYCLE && info->csr != CSR_INSTRET)
hpm_width = info->width;
if (info->type == SBI_PMU_CTR_TYPE_HW)
hpm_count++;
}
...
}
Because cmask is non-zero, &pmu_ctr_list[i] for any set bit i > 0 evaluates
to a non-NULL offset from NULL, bypassing the !info check and dereferencing
info->csr and info->type. Should out_free also reset cmask = 0?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261019135441.1420968-443-sashal@kernel.org?part=1
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-10-19 15:33 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20261019135441.1420968-1-sashal@kernel.org>
2026-10-19 13:45 ` [PATCH AUTOSEL 6.18-5.15] perf/x86/intel/uncore: Fix PCI PMU cleanup on setup failure Sasha Levin
2026-10-19 14:02 ` sashiko-bot
2026-10-19 13:45 ` [PATCH AUTOSEL 6.18-6.1] perf/x86: Free hybrid state on PMU init failure Sasha Levin
2026-10-19 13:47 ` [PATCH AUTOSEL 6.18] perf/arm-cmn: Add workarounds for CMN-S3 on Graviton5 Sasha Levin
2026-10-19 14:35 ` sashiko-bot
2026-10-19 13:47 ` [PATCH AUTOSEL 6.18-6.1] perf: marvell: Cancel CN10K DDR PMU hrtimer on device remove Sasha Levin
2026-10-19 14:44 ` sashiko-bot
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18] perf/core: Fix kernel register info leak via hardware skid Sasha Levin
2026-10-19 14:42 ` sashiko-bot
2026-10-19 13:51 ` [PATCH AUTOSEL 6.18-6.1] perf/x86: Unregister PMI handler on PMU init failure Sasha Levin
2026-10-19 15:17 ` sashiko-bot
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-6.12] RISC-V: perf: fix resource cleanup on driver probe failure Sasha Levin
2026-10-19 15:33 ` sashiko-bot
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-6.1] perf/x86/intel: Fallback to sw branch type decoding if no hw decoding Sasha Levin
2026-10-19 15:25 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox