Linux Perf Users
 help / color / mirror / Atom feed
* [PATCH] perf/core: Remove group siblings before the leader in move_group
@ 2026-10-22  8:38 Jun Yang
  2026-10-22  8:59 ` sashiko-bot
  0 siblings, 1 reply; 2+ messages in thread
From: Jun Yang @ 2026-10-22  8:38 UTC (permalink / raw)
  To: peterz, mingo
  Cc: acme, namhyung, mark.rutland, alexander.shishkin, jolsa, irogers,
	adrian.hunter, james.clark, ravi.bangoria, linux-perf-users,
	Jun Yang, stable, TencentOS Corvus AI

From: Jun Yang <junvyyang@tencent.com>

During group migration, perf_event_open() removes the group leader before
its siblings. The context's active lists contain only group leaders, so a
concurrent context switch can no longer reach the remaining active
siblings after the leader has been removed.

The context can then become inactive while those siblings are still
active. Removing a sibling in this state takes the inactive-context path
and calls pmu->del() on the calling CPU rather than the CPU where the event
is running.

Remove the siblings first so that a concurrent context switch can still
schedule them out through the leader.

Fixes: bd2756811766 ("perf: Rewrite core context handling")
Cc: stable@kernel.org
Reported-by: TencentOS Corvus AI <corvus@tencent.com>
Assisted-by: tencentos-corvus-ai:kimi-k3
Signed-off-by: Jun Yang <junvyyang@tencent.com>
---
A KASAN reproducer for this issue is available if requested.

 kernel/events/core.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/kernel/events/core.c b/kernel/events/core.c
index fe33fe1..5bf8053 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -14230,14 +14230,15 @@ SYSCALL_DEFINE5(perf_event_open,
 	 */
 
 	if (move_group) {
-		perf_remove_from_context(group_leader, 0);
-		put_pmu_ctx(group_leader->pmu_ctx);
-
+		/* Keep siblings reachable by group_sched_out(). */
 		for_each_sibling_event(sibling, group_leader) {
 			perf_remove_from_context(sibling, 0);
 			put_pmu_ctx(sibling->pmu_ctx);
 		}
 
+		perf_remove_from_context(group_leader, 0);
+		put_pmu_ctx(group_leader->pmu_ctx);
+
 		/*
 		 * Install the group siblings before the group leader.
 		 *
-- 
2.54.0 (Apple Git-157)

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] perf/core: Remove group siblings before the leader in move_group
  2026-10-22  8:38 [PATCH] perf/core: Remove group siblings before the leader in move_group Jun Yang
@ 2026-10-22  8:59 ` sashiko-bot
  0 siblings, 0 replies; 2+ messages in thread
From: sashiko-bot @ 2026-10-22  8:59 UTC (permalink / raw)
  To: Jun Yang; +Cc: linux-perf-users

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Critical] perf/core: use-after-free of sibling->pmu_ctx in perf_event_open()
--

commit dae4cdd7da7aed3ce65185b981d41f47553d78fb
Author: Jun Yang <junvyyang@tencent.com>

perf/core: Remove group siblings before the leader in move_group

This commit changes the group migration path in perf_event_open() to remove
sibling events from the context before removing the group leader, so that a
concurrent context switch can still schedule active siblings out through the
leader.

> diff --git a/kernel/events/core.c b/kernel/events/core.c
> index c180b174bac7c..d16178f3f53e6 100644
> --- a/kernel/events/core.c
> +++ b/kernel/events/core.c
> @@ -14335,14 +14335,15 @@ SYSCALL_DEFINE5(perf_event_open,
>  	 */
>  
>  	if (move_group) {
> -		perf_remove_from_context(group_leader, 0);
> -		put_pmu_ctx(group_leader->pmu_ctx);
> -
> +		/* Keep siblings reachable by group_sched_out(). */
>  		for_each_sibling_event(sibling, group_leader) {
>  			perf_remove_from_context(sibling, 0);
>  			put_pmu_ctx(sibling->pmu_ctx);
>  		}
>  
> +		perf_remove_from_context(group_leader, 0);
> +		put_pmu_ctx(group_leader->pmu_ctx);

[Severity: Critical]
Can calling put_pmu_ctx(sibling->pmu_ctx) before removing group_leader cause
a use-after-free of sibling->pmu_ctx during a concurrent context switch?

In a pure software group, a software sibling backed by a different software
PMU from group_leader (for example, perf_task_clock or perf_tracepoint paired
with a perf_swevent leader) keeps its own PMU because
in_software_context(group_leader) is true, and gets a separate
perf_event_pmu_context via find_get_pmu_context():

kernel/events/core.c:SYSCALL_DEFINE5(perf_event_open) {
    ...
    if (is_software_event(event) &&
        !in_software_context(group_leader)) {
        pmu = group_leader->pmu_ctx->pmu;
    }
    ...
    pmu_ctx = find_get_pmu_context(pmu, ctx, event);
    ...
    event->pmu_ctx = pmu_ctx;
}

When migrating that group to a hardware context (move_group == 1),
perf_remove_from_context(sibling, 0) leaves sibling on
group_leader->sibling_list, and put_pmu_ctx(sibling->pmu_ctx) is now called
while group_leader is still active in ctx and before sibling->pmu_ctx is
reassigned to the new pmu_ctx.

If sibling holds the sole reference to its perf_event_pmu_context,
put_pmu_ctx() drops epc->refcount to zero and queues free_epc_rcu() via
call_rcu(). Because perf_event_open() runs in preemptible process context
holding only pmus_srcu and ctx->mutex, and subsequent
perf_remove_from_context() calls invoke event_function_call() ->
task_function_call(), an RCU grace period can elapse and free
sibling->pmu_ctx before perf_remove_from_context(group_leader, 0) completes.

If a concurrent context switch or reschedule on the target task's CPU invokes
group_sched_out() -> event_sched_out() or group_sched_in() ->
event_sched_in() for group_leader, both functions walk
group_leader->sibling_list and dereference event->pmu_ctx->pmu via
this_cpc(epc->pmu) before checking event->state:

kernel/events/core.c:event_sched_out() {
    struct perf_event_pmu_context *epc = event->pmu_ctx;
    struct perf_cpu_pmu_context *cpc = this_cpc(epc->pmu);
    enum perf_event_state state = PERF_EVENT_STATE_INACTIVE;
    ...
    if (event->state != PERF_EVENT_STATE_ACTIVE)
        return;
}

kernel/events/core.c:event_sched_in() {
    struct perf_event_pmu_context *epc = event->pmu_ctx;
    struct perf_cpu_pmu_context *cpc = this_cpc(epc->pmu);
    int ret = 0;
    ...
    if (event->state <= PERF_EVENT_STATE_OFF)
        return 0;
}

Should put_pmu_ctx(sibling->pmu_ctx) be deferred until after group_leader has
been removed from ctx?

> +
>  		/*
>  		 * Install the group siblings before the group leader.
>  		 *

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261022083849.90948-1-juny24602@gmail.com?part=1

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-10-22  8:59 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-22  8:38 [PATCH] perf/core: Remove group siblings before the leader in move_group Jun Yang
2026-10-22  8:59 ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox