Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: f63a8daa5812 ("perf: Fix event->ctx locking")
Reported-by: Norbert Slusarek <nslusarek@gmx.net>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Peter Zijlstra and committed by
Linus Torvalds
3ac6487e 3b5e1590

+14
+14
kernel/events/core.c
··· 12217 12217 * Do not allow to attach to a group in a different task 12218 12218 * or CPU context. If we're moving SW events, we'll fix 12219 12219 * this up later, so allow that. 12220 + * 12221 + * Racy, not holding group_leader->ctx->mutex, see comment with 12222 + * perf_event_ctx_lock(). 12220 12223 */ 12221 12224 if (!move_group && group_leader->ctx != ctx) 12222 12225 goto err_context; ··· 12285 12282 } else { 12286 12283 perf_event_ctx_unlock(group_leader, gctx); 12287 12284 move_group = 0; 12285 + goto not_move_group; 12288 12286 } 12289 12287 } 12290 12288 ··· 12302 12298 } 12303 12299 } else { 12304 12300 mutex_lock(&ctx->mutex); 12301 + 12302 + /* 12303 + * Now that we hold ctx->lock, (re)validate group_leader->ctx == ctx, 12304 + * see the group_leader && !move_group test earlier. 12305 + */ 12306 + if (group_leader && group_leader->ctx != ctx) { 12307 + err = -EINVAL; 12308 + goto err_locked; 12309 + } 12305 12310 } 12311 + not_move_group: 12306 12312 12307 12313 if (ctx->task == TASK_TOMBSTONE) { 12308 12314 err = -ESRCH;