Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 2076

kernel-2.6.18-238.el5.src.rpm

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);