Now that siglock protects tsk->parent and tsk->ptrace there is no need to grab tasklist_lock in ptrace_check_attach. The siglock can handle all of the locking needs of ptrace_check_attach.
Signed-off-by: "Eric W. Biederman" <ebied...@xmission.com> --- kernel/ptrace.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 0634da7ac685..842511ee9a9f 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -189,17 +189,14 @@ static bool ptrace_freeze_traced(struct task_struct *task) { bool ret = false; - /* Lockless, nobody but us can set this flag */ if (task->jobctl & JOBCTL_LISTENING) return ret; - spin_lock_irq(&task->sighand->siglock); if (task_is_traced(task) && !looks_like_a_spurious_pid(task) && !__fatal_signal_pending(task)) { WRITE_ONCE(task->__state, __TASK_TRACED); ret = true; } - spin_unlock_irq(&task->sighand->siglock); return ret; } @@ -237,33 +234,35 @@ static void ptrace_unfreeze_traced(struct task_struct *task) * state. * * CONTEXT: - * Grabs and releases tasklist_lock and @child->sighand->siglock. + * Grabs and releases @child->sighand->siglock. * * RETURNS: * 0 on success, -ESRCH if %child is not ready. */ static int ptrace_check_attach(struct task_struct *child, bool ignore_state) { + unsigned long flags; int ret = -ESRCH; /* - * We take the read lock around doing both checks to close a + * We take the siglock around doing both checks to close a * possible race where someone else was tracing our child and * detached between these two checks. After this locked check, * we are sure that this is our traced child and that can only * be changed by us so it's not changing right after this. */ - read_lock(&tasklist_lock); - if (child->ptrace && child->parent == current) { - WARN_ON(READ_ONCE(child->__state) == __TASK_TRACED); - /* - * child->sighand can't be NULL, release_task() - * does ptrace_unlink() before __exit_signal(). - */ - if (ignore_state || ptrace_freeze_traced(child)) - ret = 0; + if (lock_task_sighand(child, &flags)) { + if (child->ptrace && child->parent == current) { + WARN_ON(READ_ONCE(child->__state) == __TASK_TRACED); + /* + * child->sighand can't be NULL, release_task() + * does ptrace_unlink() before __exit_signal(). + */ + if (ignore_state || ptrace_freeze_traced(child)) + ret = 0; + } + unlock_task_sighand(child, &flags); } - read_unlock(&tasklist_lock); if (!ret && !ignore_state && WARN_ON_ONCE(!wait_task_inactive(child, 0))) -- 2.35.3 _______________________________________________ linux-um mailing list linux-um@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-um