mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-12 16:20:06 +00:00
Prevent possible race conditions by attaching pldd to all threads
This commit is contained in:
parent
174baab3f9
commit
2772459841
@ -1,3 +1,8 @@
|
||||
2011-08-17 Ulrich Drepper <drepper@gmail.com>
|
||||
|
||||
* elf/pldd.c (main): Attach to all threads in the process.
|
||||
Rewrite /proc handling to use *at functions.
|
||||
|
||||
2011-08-16 Ulrich Drepper <drepper@gmail.com>
|
||||
|
||||
* elf/dl-open.c (_dl_show_scope): Take additional parameter which
|
||||
|
115
elf/pldd.c
115
elf/pldd.c
@ -20,6 +20,8 @@
|
||||
|
||||
#include <alloca.h>
|
||||
#include <argp.h>
|
||||
#include <assert.h>
|
||||
#include <dirent.h>
|
||||
#include <elf.h>
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
@ -83,7 +85,7 @@ static int memfd;
|
||||
static char *exe;
|
||||
|
||||
/* Local functions. */
|
||||
static int get_process_info (pid_t pid);
|
||||
static int get_process_info (int dfd, long int pid);
|
||||
|
||||
|
||||
int
|
||||
@ -101,33 +103,96 @@ main (int argc, char *argv[])
|
||||
return 1;
|
||||
}
|
||||
|
||||
assert (sizeof (pid_t) == sizeof (int)
|
||||
|| sizeof (pid_t) == sizeof (long int));
|
||||
char *endp;
|
||||
errno = 0;
|
||||
pid_t pid = strtoul (argv[remaining], &endp, 10);
|
||||
if ((pid == ULONG_MAX && errno == ERANGE) || *endp != '\0')
|
||||
long int pid = strtol (argv[remaining], &endp, 10);
|
||||
if (pid < 0 || (pid == ULONG_MAX && errno == ERANGE) || *endp != '\0'
|
||||
|| (sizeof (pid_t) < sizeof (pid) && pid > INT_MAX))
|
||||
error (EXIT_FAILURE, 0, gettext ("invalid process ID '%s'"),
|
||||
argv[remaining]);
|
||||
|
||||
/* Determine the program name. */
|
||||
char buf[11 + 3 * sizeof (pid)];
|
||||
snprintf (buf, sizeof (buf), "/proc/%lu/exe", (unsigned long int) pid);
|
||||
char buf[7 + 3 * sizeof (pid)];
|
||||
snprintf (buf, sizeof (buf), "/proc/%lu", pid);
|
||||
int dfd = open (buf, O_RDONLY | O_DIRECTORY);
|
||||
if (dfd == -1)
|
||||
error (EXIT_FAILURE, errno, gettext ("cannot open %s"), buf);
|
||||
|
||||
size_t exesize = 1024;
|
||||
#ifdef PATH_MAX
|
||||
exesize = PATH_MAX;
|
||||
#endif
|
||||
exe = alloca (exesize);
|
||||
ssize_t nexe;
|
||||
while ((nexe = readlink (buf, exe, exesize)) == exesize)
|
||||
while ((nexe = readlinkat (dfd, "exe", exe, exesize)) == exesize)
|
||||
extend_alloca (exe, exesize, 2 * exesize);
|
||||
if (nexe == -1)
|
||||
exe = (char *) "<program name undetermined>";
|
||||
else
|
||||
exe[nexe] = '\0';
|
||||
|
||||
if (ptrace (PTRACE_ATTACH, pid, NULL, NULL) != 0)
|
||||
error (EXIT_FAILURE, errno, gettext ("cannot attach to process %lu"),
|
||||
(unsigned long int) pid);
|
||||
/* Stop all threads since otherwise the list of loaded modules might
|
||||
change while we are reading it. */
|
||||
struct thread_list
|
||||
{
|
||||
pid_t tid;
|
||||
struct thread_list *next;
|
||||
} *thread_list = NULL;
|
||||
|
||||
int status = get_process_info (pid);
|
||||
int taskfd = openat (dfd, "task", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
|
||||
if (taskfd == 1)
|
||||
error (EXIT_FAILURE, errno, gettext ("cannot open %s/task"), buf);
|
||||
DIR *dir = fdopendir (taskfd);
|
||||
if (dir == NULL)
|
||||
error (EXIT_FAILURE, errno, gettext ("cannot prepare reading %s/task"),
|
||||
buf);
|
||||
|
||||
ptrace (PTRACE_DETACH, pid, NULL, NULL);
|
||||
struct dirent64 *d;
|
||||
while ((d = readdir64 (dir)) != NULL)
|
||||
{
|
||||
if (! isdigit (d->d_name[0]))
|
||||
continue;
|
||||
|
||||
errno = 0;
|
||||
long int tid = strtol (d->d_name, &endp, 10);
|
||||
if (tid < 0 || (tid == ULONG_MAX && errno == ERANGE) || *endp != '\0'
|
||||
|| (sizeof (pid_t) < sizeof (pid) && tid > INT_MAX))
|
||||
error (EXIT_FAILURE, 0, gettext ("invalid thread ID '%s'"),
|
||||
d->d_name);
|
||||
|
||||
if (ptrace (PTRACE_ATTACH, tid, NULL, NULL) != 0)
|
||||
{
|
||||
/* There might be a race between reading the directory and
|
||||
threads terminating. Ignore errors attaching to unknown
|
||||
threads unless this is the main thread. */
|
||||
if (errno == ESRCH && tid != pid)
|
||||
continue;
|
||||
|
||||
error (EXIT_FAILURE, errno, gettext ("cannot attach to process %lu"),
|
||||
tid);
|
||||
}
|
||||
|
||||
struct thread_list *newp = alloca (sizeof (*newp));
|
||||
newp->tid = tid;
|
||||
newp->next = thread_list;
|
||||
thread_list = newp;
|
||||
}
|
||||
|
||||
closedir (dir);
|
||||
|
||||
int status = get_process_info (dfd, pid);
|
||||
|
||||
assert (thread_list != NULL);
|
||||
do
|
||||
{
|
||||
ptrace (PTRACE_DETACH, thread_list->tid, NULL, NULL);
|
||||
thread_list = thread_list->next;
|
||||
}
|
||||
while (thread_list != NULL);
|
||||
|
||||
close (dfd);
|
||||
|
||||
return status;
|
||||
}
|
||||
@ -167,22 +232,18 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
|
||||
|
||||
|
||||
static int
|
||||
get_process_info (pid_t pid)
|
||||
get_process_info (int dfd, long int pid)
|
||||
{
|
||||
char buf[12 + 3 * sizeof (pid)];
|
||||
|
||||
snprintf (buf, sizeof (buf), "/proc/%lu/mem", (unsigned long int) pid);
|
||||
memfd = open (buf, O_RDONLY);
|
||||
memfd = openat (dfd, "mem", O_RDONLY);
|
||||
if (memfd == -1)
|
||||
goto no_info;
|
||||
|
||||
snprintf (buf, sizeof (buf), "/proc/%lu/exe", (unsigned long int) pid);
|
||||
int fd = open (buf, O_RDONLY);
|
||||
int fd = openat (dfd, "exe", O_RDONLY);
|
||||
if (fd == -1)
|
||||
{
|
||||
no_info:
|
||||
error (0, errno, gettext ("cannot get information about process %lu"),
|
||||
(unsigned long int) pid);
|
||||
pid);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
@ -198,13 +259,11 @@ get_process_info (pid_t pid)
|
||||
|
||||
if (memcmp (uehdr.ehdr32.e_ident, ELFMAG, SELFMAG) != 0)
|
||||
{
|
||||
error (0, 0, gettext ("process %lu is no ELF program"),
|
||||
(unsigned long int) pid);
|
||||
error (0, 0, gettext ("process %lu is no ELF program"), pid);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
snprintf (buf, sizeof (buf), "/proc/%lu/auxv", (unsigned long int) pid);
|
||||
fd = open (buf, O_RDONLY);
|
||||
fd = openat (dfd, "auxv", O_RDONLY);
|
||||
if (fd == -1)
|
||||
goto no_info;
|
||||
|
||||
@ -227,8 +286,14 @@ get_process_info (pid_t pid)
|
||||
|
||||
close (fd);
|
||||
|
||||
int retval;
|
||||
if (uehdr.ehdr32.e_ident[EI_CLASS] == ELFCLASS32)
|
||||
return find_maps32 (pid, &uehdr.ehdr32, auxv, auxv_size);
|
||||
retval = find_maps32 (pid, &uehdr.ehdr32, auxv, auxv_size);
|
||||
else
|
||||
return find_maps64 (pid, &uehdr.ehdr64, auxv, auxv_size);
|
||||
retval = find_maps64 (pid, &uehdr.ehdr64, auxv, auxv_size);
|
||||
|
||||
free (auxv);
|
||||
close (memfd);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user