old-cross-binutils/gdb/nat/linux-procfs.c
Daniel Colascione 015de6884f Warn users about mismatched PID namespaces
Linux supports multiple "PID namespaces".  Processes in different PID
namespaces have different views of the system process list.  Sometimes,
a single process can appear in more than one PID namespace, but with a
different PID in each.  When GDB and its target are in different PID
namespaces, various features can break due to the mismatch between
what the target believes its PID to be and what GDB believes its PID
to be.  The most visible broken functionality is thread enumeration
silently failing.

This patch explicitly warns users against trying to debug across PID
namespaces.

The patch introduced no new failures in my test suite run on an x86_64
installation of Ubuntu 14.10.  It doesn't include a test: writing an
automated test that exercises this code would be very involved because
CLONE_NEWNS requires CAP_SYS_ADMIN; the easier way to reproduce the
problem is to start a new lxc container.

gdb/
2014-11-11  Daniel Colascione  <dancol@dancol.org>

	Warn about cross-PID-namespace debugging.
	* nat/linux-procfs.h (linux_proc_pid_get_ns): New prototype.
	* nat/linux-procfs.c (linux_proc_pid_get_ns): New function.
	* linux-thread-db.c (check_pid_namespace_match): New function.
	(thread_db_inferior_created): Call it.
2014-11-11 14:18:23 +00:00

134 lines
3.2 KiB
C

/* Linux-specific PROCFS manipulation routines.
Copyright (C) 2009-2014 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "common-defs.h"
#include "linux-procfs.h"
#include "filestuff.h"
/* Return the TGID of LWPID from /proc/pid/status. Returns -1 if not
found. */
static int
linux_proc_get_int (pid_t lwpid, const char *field)
{
size_t field_len = strlen (field);
FILE *status_file;
char buf[100];
int retval = -1;
snprintf (buf, sizeof (buf), "/proc/%d/status", (int) lwpid);
status_file = gdb_fopen_cloexec (buf, "r");
if (status_file == NULL)
{
warning (_("unable to open /proc file '%s'"), buf);
return -1;
}
while (fgets (buf, sizeof (buf), status_file))
if (strncmp (buf, field, field_len) == 0 && buf[field_len] == ':')
{
retval = strtol (&buf[field_len + 1], NULL, 10);
break;
}
fclose (status_file);
return retval;
}
/* Return the TGID of LWPID from /proc/pid/status. Returns -1 if not
found. */
int
linux_proc_get_tgid (pid_t lwpid)
{
return linux_proc_get_int (lwpid, "Tgid");
}
/* See linux-procfs.h. */
pid_t
linux_proc_get_tracerpid (pid_t lwpid)
{
return linux_proc_get_int (lwpid, "TracerPid");
}
/* Return non-zero if 'State' of /proc/PID/status contains STATE. */
static int
linux_proc_pid_has_state (pid_t pid, const char *state)
{
char buffer[100];
FILE *procfile;
int retval;
int have_state;
xsnprintf (buffer, sizeof (buffer), "/proc/%d/status", (int) pid);
procfile = gdb_fopen_cloexec (buffer, "r");
if (procfile == NULL)
{
warning (_("unable to open /proc file '%s'"), buffer);
return 0;
}
have_state = 0;
while (fgets (buffer, sizeof (buffer), procfile) != NULL)
if (strncmp (buffer, "State:", 6) == 0)
{
have_state = 1;
break;
}
retval = (have_state && strstr (buffer, state) != NULL);
fclose (procfile);
return retval;
}
/* Detect `T (stopped)' in `/proc/PID/status'.
Other states including `T (tracing stop)' are reported as false. */
int
linux_proc_pid_is_stopped (pid_t pid)
{
return linux_proc_pid_has_state (pid, "T (stopped)");
}
/* See linux-procfs.h declaration. */
int
linux_proc_pid_is_zombie (pid_t pid)
{
return linux_proc_pid_has_state (pid, "Z (zombie)");
}
/* See linux-procfs.h declaration. */
char *
linux_proc_pid_get_ns (pid_t pid, const char *ns)
{
char buf[100];
char nsval[64];
int ret;
xsnprintf (buf, sizeof (buf), "/proc/%d/ns/%s", (int) pid, ns);
ret = readlink (buf, nsval, sizeof (nsval));
if (0 < ret && ret < sizeof (nsval))
{
nsval[ret] = '\0';
return xstrdup (nsval);
}
return NULL;
}