PT-2026-30130 · Linux · Linux

Published

2026-04-03

·

Updated

2026-04-03

·

CVE-2026-23435

None

No severity ratings or metrics are available. When they are, we'll update the corresponding info on the page.
In the Linux kernel, the following vulnerability has been resolved:
perf/x86: Move event pointer setup earlier in x86 pmu enable()
A production AMD EPYC system crashed with a NULL pointer dereference in the PMU NMI handler:
BUG: kernel NULL pointer dereference, address: 0000000000000198 RIP: x86 perf event update+0xc/0xa0 Call Trace: amd pmu v2 handle irq+0x1a6/0x390 perf event nmi handler+0x24/0x40
The faulting instruction is cmpq $0x0, 0x198(%rdi) with RDI=0, corresponding to the if (unlikely(!hwc->event base)) check in x86 perf event update() where hwc = &event->hw and event is NULL.
drgn inspection of the vmcore on CPU 106 showed a mismatch between cpuc->active mask and cpuc->events[]:
active mask: 0x1e (bits 1, 2, 3, 4) events[1]: 0xff1100136cbd4f38 (valid) events[2]: 0x0 (NULL, but active mask bit 2 set) events[3]: 0xff1100076fd2cf38 (valid) events[4]: 0xff1100079e990a90 (valid)
The event that should occupy events[2] was found in event list[2] with hw.idx=2 and hw.state=0x0, confirming x86 pmu start() had run (which clears hw.state and sets active mask) but events[2] was never populated.
Another event (event list[0]) had hw.state=0x7 (STOPPED|UPTODATE|ARCH), showing it was stopped when the PMU rescheduled events, confirming the throttle-then-reschedule sequence occurred.
The root cause is commit 7e772a93eb61 ("perf/x86: Fix NULL event access and potential PEBS record loss") which moved the cpuc->events[idx] assignment out of x86 pmu start() and into step 2 of x86 pmu enable(), after the PERF HES ARCH check. This broke any path that calls pmu->start() without going through x86 pmu enable() -- specifically the unthrottle path:
perf adjust freq unthr events() -> perf event unthrottle group() -> perf event unthrottle() -> event->pmu->start(event, 0) -> x86 pmu start() // sets active mask but not events[]
The race sequence is:
  1. A group of perf events overflows, triggering group throttle via perf event throttle group(). All events are stopped: active mask bits cleared, events[] preserved (x86 pmu stop no longer clears events[] after commit 7e772a93eb61).
  2. While still throttled (PERF HES STOPPED), x86 pmu enable() runs due to other scheduling activity. Stopped events that need to move counters get PERF HES ARCH set and events[old idx] cleared. In step 2 of x86 pmu enable(), PERF HES ARCH causes these events to be skipped -- events[new idx] is never set.
  3. The timer tick unthrottles the group via pmu->start(). Since commit 7e772a93eb61 removed the events[] assignment from x86 pmu start(), active mask[new idx] is set but events[new idx] remains NULL.
  4. A PMC overflow NMI fires. The handler iterates active counters, finds active mask[2] set, reads events[2] which is NULL, and crashes dereferencing it.
Move the cpuc->events[hwc->idx] assignment in x86 pmu enable() to before the PERF HES ARCH check, so that events[] is populated even for events that are not immediately started. This ensures the unthrottle path via pmu->start() always finds a valid event pointer.

Related Identifiers

CVE-2026-23435

Affected Products

Linux