perf: Break deadlock involving exec_update_mutex
[ Upstream commit 78af4dc949daaa37b3fcd5f348f373085b4e858f ] Syzbot reported a lock inversion involving perf. The sore point being perf holding exec_update_mutex() for a very long time, specifically across a whole bunch of filesystem ops in pmu::event_init() (uprobes) and anon_inode_getfile(). This then inverts against procfs code trying to take exec_update_mutex. Move the permission checks later, such that we need to hold the mutex over less code. Reported-by: syzbot+db9cdf3dd1f64252c6ef@syzkaller.appspotmail.com Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
732251cabe
commit
71b8355ba6
@ -11001,24 +11001,6 @@ SYSCALL_DEFINE5(perf_event_open,
|
||||
goto err_task;
|
||||
}
|
||||
|
||||
if (task) {
|
||||
err = mutex_lock_interruptible(&task->signal->exec_update_mutex);
|
||||
if (err)
|
||||
goto err_task;
|
||||
|
||||
/*
|
||||
* Reuse ptrace permission checks for now.
|
||||
*
|
||||
* We must hold exec_update_mutex across this and any potential
|
||||
* perf_install_in_context() call for this new event to
|
||||
* serialize against exec() altering our credentials (and the
|
||||
* perf_event_exit_task() that could imply).
|
||||
*/
|
||||
err = -EACCES;
|
||||
if (!ptrace_may_access(task, PTRACE_MODE_READ_REALCREDS))
|
||||
goto err_cred;
|
||||
}
|
||||
|
||||
if (flags & PERF_FLAG_PID_CGROUP)
|
||||
cgroup_fd = pid;
|
||||
|
||||
@ -11026,7 +11008,7 @@ SYSCALL_DEFINE5(perf_event_open,
|
||||
NULL, NULL, cgroup_fd);
|
||||
if (IS_ERR(event)) {
|
||||
err = PTR_ERR(event);
|
||||
goto err_cred;
|
||||
goto err_task;
|
||||
}
|
||||
|
||||
if (is_sampling_event(event)) {
|
||||
@ -11145,6 +11127,24 @@ SYSCALL_DEFINE5(perf_event_open,
|
||||
goto err_context;
|
||||
}
|
||||
|
||||
if (task) {
|
||||
err = mutex_lock_interruptible(&task->signal->exec_update_mutex);
|
||||
if (err)
|
||||
goto err_file;
|
||||
|
||||
/*
|
||||
* Preserve ptrace permission check for backwards compatibility.
|
||||
*
|
||||
* We must hold exec_update_mutex across this and any potential
|
||||
* perf_install_in_context() call for this new event to
|
||||
* serialize against exec() altering our credentials (and the
|
||||
* perf_event_exit_task() that could imply).
|
||||
*/
|
||||
err = -EACCES;
|
||||
if (!ptrace_may_access(task, PTRACE_MODE_READ_REALCREDS))
|
||||
goto err_cred;
|
||||
}
|
||||
|
||||
if (move_group) {
|
||||
gctx = __perf_event_ctx_lock_double(group_leader, ctx);
|
||||
|
||||
@ -11320,7 +11320,10 @@ err_locked:
|
||||
if (move_group)
|
||||
perf_event_ctx_unlock(group_leader, gctx);
|
||||
mutex_unlock(&ctx->mutex);
|
||||
/* err_file: */
|
||||
err_cred:
|
||||
if (task)
|
||||
mutex_unlock(&task->signal->exec_update_mutex);
|
||||
err_file:
|
||||
fput(event_file);
|
||||
err_context:
|
||||
perf_unpin_context(ctx);
|
||||
@ -11332,9 +11335,6 @@ err_alloc:
|
||||
*/
|
||||
if (!event_file)
|
||||
free_event(event);
|
||||
err_cred:
|
||||
if (task)
|
||||
mutex_unlock(&task->signal->exec_update_mutex);
|
||||
err_task:
|
||||
if (task)
|
||||
put_task_struct(task);
|
||||
|
Loading…
x
Reference in New Issue
Block a user