[PATCH v2] perf: Avoid undefined behavior from stopping/starting inactive events

From: Yunseong Kim
Date: Mon Aug 11 2025 - 21:27:50 EST


Calling pmu->start()/stop() on events in PERF_EVENT_STATE_OFF can leave
event->hw.idx at -1, which may lead to UBSAN shift-out-of-bounds reports
when the PMU code later shifts by a negative exponent.

Move the state check into perf_event_throttle()/perf_event_unthrottle() so
that inactive events are skipped entirely. This ensures only active events
with a valid hw.idx are processed, preventing undefined behavior and
silencing UBSAN warnings.

The problem can be reproduced with the syzkaller reproducer:
Link: https://lore.kernel.org/lkml/714b7ba2-693e-42e4-bce4-feef2a5e7613@xxxxxxxxxxx/

Fixes: 9734e25fbf5a ("perf: Fix the throttle logic for a group")
Cc: Mark Rutland <mark.rutland@xxxxxxx>
Signed-off-by: Yunseong Kim <ysk@xxxxxxxxxxx>
---
kernel/events/core.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/kernel/events/core.c b/kernel/events/core.c
index 8060c2857bb2..c9322029a8ae 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -2665,6 +2665,9 @@ static void perf_log_itrace_start(struct perf_event *event);

static void perf_event_unthrottle(struct perf_event *event, bool start)
{
+ if (event->state <= PERF_EVENT_STATE_OFF)
+ return;
+
event->hw.interrupts = 0;
if (start)
event->pmu->start(event, 0);
@@ -2674,6 +2677,9 @@ static void perf_event_unthrottle(struct perf_event *event, bool start)

static void perf_event_throttle(struct perf_event *event)
{
+ if (event->state <= PERF_EVENT_STATE_OFF)
+ return;
+
event->hw.interrupts = MAX_INTERRUPTS;
event->pmu->stop(event, 0);
if (event == event->group_leader)
--
2.50.0