Skip to content

Commit 3ac6487

Browse files
Peter Zijlstratorvalds
authored andcommitted
perf: Fix sys_perf_event_open() race against self
Norbert reported that it's possible to race sys_perf_event_open() such that the looser ends up in another context from the group leader, triggering many WARNs. The move_group case checks for races against itself, but the !move_group case doesn't, seemingly relying on the previous group_leader->ctx == ctx check. However, that check is racy due to not holding any locks at that time. Therefore, re-check the result after acquiring locks and bailing if they no longer match. Additionally, clarify the not_move_group case from the move_group-vs-move_group race. Fixes: f63a8da ("perf: Fix event->ctx locking") Reported-by: Norbert Slusarek <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 3b5e159 commit 3ac6487

File tree

1 file changed

+14
-0
lines changed

1 file changed

+14
-0
lines changed

kernel/events/core.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12217,6 +12217,9 @@ SYSCALL_DEFINE5(perf_event_open,
1221712217
* Do not allow to attach to a group in a different task
1221812218
* or CPU context. If we're moving SW events, we'll fix
1221912219
* this up later, so allow that.
12220+
*
12221+
* Racy, not holding group_leader->ctx->mutex, see comment with
12222+
* perf_event_ctx_lock().
1222012223
*/
1222112224
if (!move_group && group_leader->ctx != ctx)
1222212225
goto err_context;
@@ -12282,6 +12285,7 @@ SYSCALL_DEFINE5(perf_event_open,
1228212285
} else {
1228312286
perf_event_ctx_unlock(group_leader, gctx);
1228412287
move_group = 0;
12288+
goto not_move_group;
1228512289
}
1228612290
}
1228712291

@@ -12298,7 +12302,17 @@ SYSCALL_DEFINE5(perf_event_open,
1229812302
}
1229912303
} else {
1230012304
mutex_lock(&ctx->mutex);
12305+
12306+
/*
12307+
* Now that we hold ctx->lock, (re)validate group_leader->ctx == ctx,
12308+
* see the group_leader && !move_group test earlier.
12309+
*/
12310+
if (group_leader && group_leader->ctx != ctx) {
12311+
err = -EINVAL;
12312+
goto err_locked;
12313+
}
1230112314
}
12315+
not_move_group:
1230212316

1230312317
if (ctx->task == TASK_TOMBSTONE) {
1230412318
err = -ESRCH;

0 commit comments

Comments
 (0)