about summary refs log tree commit diff
path: root/elf/pldd.c
diff options
context:
space:
mode:
authorAndreas Schwab <schwab@suse.de>2013-07-30 11:58:45 +0200
committerAndreas Schwab <schwab@suse.de>2014-02-25 09:29:34 +0100
commitb04acb2651e0aaf615de50e9138cddfd5c24021f (patch)
tree4908e5a456a4316f468ac3bc8cce6437eb874250 /elf/pldd.c
parentd4ec6ae19e3290abbb3cfff70a8dd6018ecb6e2e (diff)
downloadglibc-b04acb2651e0aaf615de50e9138cddfd5c24021f.tar.gz
glibc-b04acb2651e0aaf615de50e9138cddfd5c24021f.tar.xz
glibc-b04acb2651e0aaf615de50e9138cddfd5c24021f.zip
Fix race conditions in pldd that may leave the process stopped after detaching
Fixes bug 15804
Diffstat (limited to 'elf/pldd.c')
-rw-r--r--elf/pldd.c25
1 files changed, 25 insertions, 0 deletions
diff --git a/elf/pldd.c b/elf/pldd.c
index 684aff4dba..75f78120df 100644
--- a/elf/pldd.c
+++ b/elf/pldd.c
@@ -34,6 +34,7 @@
 #include <unistd.h>
 #include <sys/ptrace.h>
 #include <sys/stat.h>
+#include <sys/wait.h>
 
 #include <ldsodefs.h>
 #include <version.h>
@@ -82,6 +83,7 @@ static char *exe;
 
 /* Local functions.  */
 static int get_process_info (int dfd, long int pid);
+static void wait_for_ptrace_stop (long int pid);
 
 
 int
@@ -170,6 +172,8 @@ main (int argc, char *argv[])
 		 tid);
 	}
 
+      wait_for_ptrace_stop (tid);
+
       struct thread_list *newp = alloca (sizeof (*newp));
       newp->tid = tid;
       newp->next = thread_list;
@@ -194,6 +198,27 @@ main (int argc, char *argv[])
 }
 
 
+/* Wait for PID to enter ptrace-stop state after being attached.  */
+static void
+wait_for_ptrace_stop (long int pid)
+{
+  int status;
+
+  /* While waiting for SIGSTOP being delivered to the tracee we have to
+     reinject any other pending signal.  Ignore all other errors.  */
+  while (waitpid (pid, &status, __WALL) == pid && WIFSTOPPED (status))
+    {
+      /* The STOP signal should not be delivered to the tracee.  */
+      if (WSTOPSIG (status) == SIGSTOP)
+	return;
+      if (ptrace (PTRACE_CONT, pid, NULL,
+		  (void *) (uintptr_t) WSTOPSIG (status)))
+	/* The only possible error is that the process died.  */
+	return;
+    }
+}
+
+
 /* Handle program arguments.  */
 static error_t
 parse_opt (int key, char *arg, struct argp_state *state)