diff options
author | Andreas Schwab <schwab@suse.de> | 2013-07-30 11:58:45 +0200 |
---|---|---|
committer | Andreas Schwab <schwab@suse.de> | 2014-02-25 09:29:34 +0100 |
commit | b04acb2651e0aaf615de50e9138cddfd5c24021f (patch) | |
tree | 4908e5a456a4316f468ac3bc8cce6437eb874250 /elf/pldd.c | |
parent | d4ec6ae19e3290abbb3cfff70a8dd6018ecb6e2e (diff) | |
download | glibc-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.c | 25 |
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) |