[PATCH 5.10.y 2/3] perf: Fix dangling cgroup pointer in cpuctx
Sasha Levin <[email protected]>
| Newsgroups | org.kernel.vger.stable |
|---|---|
| Message-ID | <[email protected]> |
From: Yeoreum Yun <[email protected]> [ Upstream commit 3b7a34aebbdf2a4b7295205bf0c654294283ec82 ] Commit a3c3c6667("perf/core: Fix child_total_time_enabled accounting bug at task exit") moves the event->state update to before list_del_event(). This makes the event->state test in list_del_event() always false; never calling perf_cgroup_event_disable(). As a result, cpuctx->cgrp won't be cleared properly; causing havoc. Fixes: a3c3c6667("perf/core: Fix child_total_time_enabled accounting bug at task exit") Signed-off-by: Yeoreum Yun <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Tested-by: David Wang <[email protected]> Link: https://lore.kernel.org/all/aD2TspKH%[email protected]/ Stable-dep-of: 42c5ca1f0a28 ("perf/core: Fix group leader use-after-free after sibling detach") Signed-off-by: Sasha Levin <[email protected]> --- kernel/events/core.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 756152374a3b9..5e4d1b090db70 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -2117,18 +2117,6 @@ list_del_event(struct perf_event *event, struct perf_event_context *ctx) if (event->group_leader == event) del_event_from_groups(event, ctx); - /* - * If event was in error state, then keep it - * that way, otherwise bogus counts will be - * returned on read(). The only way to get out - * of error state is by explicit re-enabling - * of the event - */ - if (event->state > PERF_EVENT_STATE_OFF) { - perf_cgroup_event_disable(event, ctx); - perf_event_set_state(event, PERF_EVENT_STATE_OFF); - } - ctx->generation++; } @@ -2422,6 +2410,7 @@ __perf_remove_from_context(struct perf_event *event, struct perf_event_context *ctx, void *info) { + enum perf_event_state state = PERF_EVENT_STATE_OFF; unsigned long flags = (unsigned long)info; if (ctx->is_active & EVENT_TIME) { @@ -2430,6 +2419,12 @@ __perf_remove_from_context(struct perf_event *event, } event_sched_out(event, cpuctx, ctx); + + if (event->state > PERF_EVENT_STATE_OFF) + perf_cgroup_event_disable(event, ctx); + + perf_event_set_state(event, min(event->state, state)); + if (flags & DETACH_GROUP) perf_group_detach(event); list_del_event(event, ctx); -- 2.53.0