From: Vitaly Mayatskikh <vmayatsk@redhat.com> Date: Tue, 22 Dec 2009 15:18:46 -0500 Subject: [misc] ptrace: PTRACE_KILL hangs in 100% cpu loop Message-id: <87skb3ca09.wl%vmayatsk@redhat.com> Patchwork-id: 22251 O-Subject: [RHEL-5.5 patch] bz544138 PTRACE_KILL hangs in 100% cpu loop Bugzilla: 544138 RH-Acked-by: Oleg Nesterov <oleg@redhat.com> https://bugzilla.redhat.com/show_bug.cgi?id=544138 PTRACE_KILL in upstream and RHEL-4 kernel return OK for tasks not in states TASK_STOPPED and TASK_TRACED. RHEL-5 ptrace implementation differs in that respect: it hangs in an infinite loop if the tracee is not either stopped or traced. Tested with reproducer from bz. Signed-off-by: Jarod Wilson <jarod@redhat.com> diff --git a/kernel/ptrace.c b/kernel/ptrace.c index edaccb7..30d01c8 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -931,31 +931,33 @@ ptrace_start(long pid, long request, * To do this purely in utrace terms, we could do: * (void) utrace_regset(child, engine, utrace_native_view(child), 0); */ - wait_task_inactive(child); - while (child->state != TASK_TRACED && child->state != TASK_STOPPED) { - if (child->exit_state) { - __ptrace_state_free(state); - goto out_tsk; - } + if (request != PTRACE_KILL) { + wait_task_inactive(child); + while (child->state != TASK_TRACED && child->state != TASK_STOPPED) { + if (child->exit_state) { + __ptrace_state_free(state); + goto out_tsk; + } - task_lock(child); - if (child->mm && child->mm->core_waiters) { + task_lock(child); + if (child->mm && child->mm->core_waiters) { + task_unlock(child); + __ptrace_state_free(state); + goto out_tsk; + } task_unlock(child); - __ptrace_state_free(state); - goto out_tsk; - } - task_unlock(child); - /* - * This is a dismal kludge, but it only comes up on ia64. - * It might be blocked inside regset->writeback() called - * from ptrace_report(), when it's on its way to quiescing - * in TASK_TRACED real soon now. We actually need that - * writeback call to have finished, before a PTRACE_PEEKDATA - * here, for example. So keep waiting until it's really there. - */ - yield(); - wait_task_inactive(child); + /* + * This is a dismal kludge, but it only comes up on ia64. + * It might be blocked inside regset->writeback() called + * from ptrace_report(), when it's on its way to quiescing + * in TASK_TRACED real soon now. We actually need that + * writeback call to have finished, before a PTRACE_PEEKDATA + * here, for example. So keep waiting until it's really there. + */ + yield(); + wait_task_inactive(child); + } } wait_task_inactive(child);