diff options
author | Tom Tromey <tromey@redhat.com> | 2013-04-22 16:46:15 +0000 |
---|---|---|
committer | Tom Tromey <tromey@redhat.com> | 2013-04-22 16:46:15 +0000 |
commit | 614c279dda95dd69c3c14778fc600f4a265847d6 (patch) | |
tree | 9bd77eb734c303ecac4ffdc2477bf0c314b801f5 /gdb/common | |
parent | 5fda2332f3403df3e1c37da3e3697d6fb6bc4706 (diff) | |
download | gdb-614c279dda95dd69c3c14778fc600f4a265847d6.zip gdb-614c279dda95dd69c3c14778fc600f4a265847d6.tar.gz gdb-614c279dda95dd69c3c14778fc600f4a265847d6.tar.bz2 |
PR gdb/7912:
* Makefile.in (SFILES): Add filestuff.c
(COMMON_OBS): Add filestuff.o.
(filestuff.o): New target.
* auto-load.c (auto_load_objfile_script_1): Use
gdb_fopen_cloexec.
* auxv.c (procfs_xfer_auxv): Use gdb_open_cloexec.
* cli/cli-cmds.c (shell_escape): Call close_most_fds.
* cli/cli-dump.c (fopen_with_cleanup): Use gdb_fopen_cloexec.
* common/agent.c (gdb_connect_sync_socket): Use
gdb_socket_cloexec.
* common/filestuff.c: New file.
* common/filestuff.h: New file.
* common/linux-osdata.c (linux_common_core_of_thread)
(command_from_pid, commandline_from_pid, print_source_lines)
(linux_xfer_osdata_shm, linux_xfer_osdata_sem)
(linux_xfer_osdata_msg, linux_xfer_osdata_modules): Use
gdb_fopen_cloexec.
* common/linux-procfs.c (linux_proc_get_int)
(linux_proc_pid_has_state): Use gdb_fopen_cloexec.
* config.in, configure: Rebuild.
* configure.ac: Don't check for sys/socket.h. Check for
fdwalk, pipe2.
* corelow.c (core_open): Use gdb_open_cloexec.
* dwarf2read.c (write_psymtabs_to_index): Use gdb_fopen_cloexec.
* fork-child.c (fork_inferior): Call close_most_fds.
* gdb_bfd.c (gdb_bfd_open): Use gdb_open_cloexec.
* inf-child.c (inf_child_fileio_readlink): Use gdb_open_cloexec.
* linux-nat.c (linux_nat_thread_name, linux_proc_pending_signals):
Use gdb_fopen_cloexec.
(linux_proc_xfer_partial, linux_proc_xfer_spu): Use
gdb_open_cloexec.
(linux_async_pipe): Use gdb_pipe_cloexec.
* remote-fileio.c (remote_fileio_func_open): Use
gdb_open_cloexec.
* remote.c (remote_file_put, remote_file_get): Use
gdb_fopen_cloexec.
* ser-pipe.c (pipe_open): Use gdb_socketpair_cloexec,
close_most_fds.
* ser-tcp.c (net_open): Use gdb_socket_cloexec.
* ser-unix.c (hardwire_open): Use gdb_open_cloexec.
* solib.c (solib_find): Use gdb_open_cloexec.
* source.c (openp, find_and_open_source): Use gdb_open_cloexec.
* tracepoint.c (tfile_start): Use gdb_fopen_cloexec.
(tfile_open): Use gdb_open_cloexec.
* tui/tui-io.c (tui_initialize_io): Use gdb_pipe_cloexec.
* ui-file.c (gdb_fopen): Use gdb_fopen_cloexec.
* xml-support.c (xml_fetch_content_from_file): Use
gdb_fopen_cloexec.
* main.c (captured_main): Call notice_open_fds.
gdbserver
* Makefile.in (SFILES): Add filestuff.c.
(OBS): Add filestuff.o.
(filestuff.o): New target.
* config.in, configure: Rebuild.
* configure.ac: Check for fdwalk, pipe2.
Diffstat (limited to 'gdb/common')
-rw-r--r-- | gdb/common/agent.c | 3 | ||||
-rw-r--r-- | gdb/common/filestuff.c | 354 | ||||
-rw-r--r-- | gdb/common/filestuff.h | 59 | ||||
-rw-r--r-- | gdb/common/linux-osdata.c | 17 | ||||
-rw-r--r-- | gdb/common/linux-procfs.c | 5 |
5 files changed, 427 insertions, 11 deletions
diff --git a/gdb/common/agent.c b/gdb/common/agent.c index f7bedc2..99cef4f 100644 --- a/gdb/common/agent.c +++ b/gdb/common/agent.c @@ -28,6 +28,7 @@ #include <string.h> #include <unistd.h> #include "agent.h" +#include "filestuff.h" int debug_agent = 0; @@ -168,7 +169,7 @@ gdb_connect_sync_socket (int pid) if (res >= UNIX_PATH_MAX) return -1; - res = fd = socket (PF_UNIX, SOCK_STREAM, 0); + res = fd = gdb_socket_cloexec (PF_UNIX, SOCK_STREAM, 0); if (res == -1) { warning (_("error opening sync socket: %s"), strerror (errno)); diff --git a/gdb/common/filestuff.c b/gdb/common/filestuff.c new file mode 100644 index 0000000..2cc1c4d --- /dev/null +++ b/gdb/common/filestuff.c @@ -0,0 +1,354 @@ +/* Low-level file-handling. + Copyright (C) 2012, 2013 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/>. */ + +#ifdef GDBSERVER +#include "server.h" +#else +#include "defs.h" +#include "gdb_string.h" +#endif +#include "filestuff.h" +#include "gdb_vecs.h" + +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/stat.h> + +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif /* HAVE_SYS_RESOURCE_H */ + +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +#ifndef SOCK_CLOEXEC +#define SOCK_CLOEXEC 0 +#endif + + + +#ifndef HAVE_FDWALK + +#include <dirent.h> + +/* Replacement for fdwalk, if the system doesn't define it. Walks all + open file descriptors (though this implementation may walk closed + ones as well, depending on the host platform's capabilities) and + call FUNC with ARG. If FUNC returns non-zero, stops immediately + and returns the same value. Otherwise, returns zero when + finished. */ + +static int +fdwalk (int (*func) (void *, int), void *arg) +{ + /* Checking __linux__ isn't great but it isn't clear what would be + better. There doesn't seem to be a good way to check for this in + configure. */ +#ifdef __linux__ + DIR *dir; + + dir = opendir ("/proc/self/fd"); + if (dir != NULL) + { + struct dirent *entry; + int result = 0; + + for (entry = readdir (dir); entry != NULL; entry = readdir (dir)) + { + long fd; + char *tail; + int result; + + errno = 0; + fd = strtol (entry->d_name, &tail, 10); + if (*tail != '\0' || errno != 0) + continue; + if ((int) fd != fd) + { + /* What can we do here really? */ + continue; + } + + if (fd == dirfd (dir)) + continue; + + result = func (arg, fd); + if (result != 0) + break; + } + + closedir (dir); + return result; + } + /* We may fall through to the next case. */ +#endif + + { + int max, fd; + +#ifdef HAVE_GETRLIMIT + struct rlimit rlim; + + if (getrlimit (RLIMIT_NOFILE, &rlim) == 0 && rlim.rlim_max != RLIM_INFINITY) + max = rlim.rlim_max; + else +#endif + { +#ifdef _SC_OPEN_MAX + max = sysconf (_SC_OPEN_MAX); +#else + /* Whoops. */ + return 0; +#endif /* _SC_OPEN_MAX */ + } + + for (fd = 0; fd < max; ++fd) + { + struct stat sb; + int result; + + /* Only call FUNC for open fds. */ + if (fstat (fd, &sb) == -1) + continue; + + result = func (arg, fd); + if (result != 0) + return result; + } + + return 0; + } +} + +#endif /* HAVE_FDWALK */ + + + +/* A VEC holding all the fds open when notice_open_fds was called. We + don't use a hashtab because libiberty isn't linked into gdbserver; + and anyway we don't expect there to be many open fds. */ + +DEF_VEC_I (int); + +static VEC (int) *open_fds; + +/* An fdwalk callback function used by notice_open_fds. It puts the + given file descriptor into the vec. */ + +static int +do_mark_open_fd (void *ignore, int fd) +{ + VEC_safe_push (int, open_fds, fd); + return 0; +} + +/* See filestuff.h. */ + +void +notice_open_fds (void) +{ + fdwalk (do_mark_open_fd, NULL); +} + +/* Helper function for close_most_fds that closes the file descriptor + if appropriate. */ + +static int +do_close (void *ignore, int fd) +{ + int i, val; + + for (i = 0; VEC_iterate (int, open_fds, i, val); ++i) + { + if (fd == val) + { + /* Keep this one open. */ + return 0; + } + } + + close (fd); + return 0; +} + +/* See filestuff.h. */ + +void +close_most_fds (void) +{ + fdwalk (do_close, NULL); +} + + + +/* This is a tri-state flag. When zero it means we haven't yet tried + O_CLOEXEC. When positive it means that O_CLOEXEC works on this + host. When negative, it means that O_CLOEXEC doesn't work. We + track this state because, while gdb might have been compiled + against a libc that supplies O_CLOEXEC, there is no guarantee that + the kernel supports it. */ + +static int trust_o_cloexec; + +/* Mark FD as close-on-exec, ignoring errors. Update + TRUST_O_CLOEXEC. */ + +static void +mark_cloexec (int fd) +{ + int old = fcntl (fd, F_GETFD, 0); + + if (old != -1) + { + fcntl (fd, F_SETFD, old | FD_CLOEXEC); + + if (trust_o_cloexec == 0) + { + if ((old & FD_CLOEXEC) != 0) + trust_o_cloexec = 1; + else + trust_o_cloexec = -1; + } + } +} + +/* Depending on TRUST_O_CLOEXEC, mark FD as close-on-exec. */ + +static void +maybe_mark_cloexec (int fd) +{ + if (trust_o_cloexec <= 0) + mark_cloexec (fd); +} + +/* Like maybe_mark_cloexec, but for callers that use SOCK_CLOEXEC. */ + +static void +socket_mark_cloexec (int fd) +{ + if (SOCK_CLOEXEC == 0 || trust_o_cloexec <= 0) + mark_cloexec (fd); +} + + + +/* See filestuff.h. */ + +int +gdb_open_cloexec (const char *filename, int flags, mode_t mode) +{ + int fd = open (filename, flags | O_CLOEXEC, mode); + + if (fd >= 0) + maybe_mark_cloexec (fd); + + return fd; +} + +/* See filestuff.h. */ + +FILE * +gdb_fopen_cloexec (const char *filename, const char *opentype) +{ + FILE *result = NULL; + static int fopen_e_ever_failed; + + if (!fopen_e_ever_failed) + { + char *copy; + + copy = alloca (strlen (opentype) + 2); + strcpy (copy, opentype); + /* This is a glibc extension but we try it unconditionally on + this path. */ + strcat (copy, "e"); + result = fopen (filename, copy); + } + + if (result == NULL) + { + /* Fallback. */ + result = fopen (filename, opentype); + if (result != NULL) + fopen_e_ever_failed = 1; + } + + if (result != NULL) + maybe_mark_cloexec (fileno (result)); + + return result; +} + +/* See filestuff.h. */ + +int +gdb_socketpair_cloexec (int namespace, int style, int protocol, int filedes[2]) +{ + int result = socketpair (namespace, style | SOCK_CLOEXEC, protocol, filedes); + + if (result != -1) + { + socket_mark_cloexec (filedes[0]); + socket_mark_cloexec (filedes[1]); + } + + return result; +} + +/* See filestuff.h. */ + +int +gdb_socket_cloexec (int namespace, int style, int protocol) +{ + int result = socket (namespace, style | SOCK_CLOEXEC, protocol); + + if (result != -1) + socket_mark_cloexec (result); + + return result; +} + +/* See filestuff.h. */ + +int +gdb_pipe_cloexec (int filedes[2]) +{ + int result; + +#ifdef HAVE_PIPE2 + result = pipe2 (filedes, O_CLOEXEC); + if (result != -1) + { + maybe_mark_cloexec (filedes[0]); + maybe_mark_cloexec (filedes[1]); + } +#else + result = pipe (filedes); + if (result != -1) + { + mark_cloexec (filedes[0]); + mark_cloexec (filedes[1]); + } +#endif + + return result; +} diff --git a/gdb/common/filestuff.h b/gdb/common/filestuff.h new file mode 100644 index 0000000..747bff2 --- /dev/null +++ b/gdb/common/filestuff.h @@ -0,0 +1,59 @@ +/* Low-level file-handling. + Copyright (C) 2012, 2013 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/>. */ + +#ifndef FILESTUFF_H +#define FILESTUFF_H + +/* Note all the file descriptors which are open when this is called. + These file descriptors will not be closed by close_most_fds. */ + +extern void notice_open_fds (void); + +/* Close all open file descriptors other than those marked by + 'notice_open_fds', and stdin, stdout, and stderr. Errors that + occur while closing are ignored. */ + +extern void close_most_fds (void); + +/* Like 'open', but ensures that the returned file descriptor has the + close-on-exec flag set. */ + +extern int gdb_open_cloexec (const char *filename, int flags, mode_t mode); + +/* Like 'fopen', but ensures that the returned file descriptor has the + close-on-exec flag set. */ + +extern FILE *gdb_fopen_cloexec (const char *filename, const char *opentype); + +/* Like 'socketpair', but ensures that the returned file descriptors + have the close-on-exec flag set. */ + +extern int gdb_socketpair_cloexec (int namespace, int style, int protocol, + int filedes[2]); + +/* Like 'socket', but ensures that the returned file descriptor has + the close-on-exec flag set. */ + +extern int gdb_socket_cloexec (int namespace, int style, int protocol); + +/* Like 'pipe', but ensures that the returned file descriptors have + the close-on-exec flag set. */ + +extern int gdb_pipe_cloexec (int filedes[2]); + +#endif /* FILESTUFF_H */ diff --git a/gdb/common/linux-osdata.c b/gdb/common/linux-osdata.c index d55470b..9723839 100644 --- a/gdb/common/linux-osdata.c +++ b/gdb/common/linux-osdata.c @@ -44,6 +44,7 @@ #include "gdb_assert.h" #include "gdb_dirent.h" #include "gdb_stat.h" +#include "filestuff.h" /* Define PID_T to be a fixed size that is at least as large as pid_t, so that reading pid values embedded in /proc works @@ -76,7 +77,7 @@ linux_common_core_of_thread (ptid_t ptid) sprintf (filename, "/proc/%lld/task/%lld/stat", (PID_T) ptid_get_pid (ptid), (PID_T) ptid_get_lwp (ptid)); - f = fopen (filename, "r"); + f = gdb_fopen_cloexec (filename, "r"); if (!f) return -1; @@ -125,7 +126,7 @@ static void command_from_pid (char *command, int maxlen, PID_T pid) { char *stat_path = xstrprintf ("/proc/%lld/stat", pid); - FILE *fp = fopen (stat_path, "r"); + FILE *fp = gdb_fopen_cloexec (stat_path, "r"); command[0] = '\0'; @@ -165,7 +166,7 @@ commandline_from_pid (PID_T pid) { char *pathname = xstrprintf ("/proc/%lld/cmdline", pid); char *commandline = NULL; - FILE *f = fopen (pathname, "r"); + FILE *f = gdb_fopen_cloexec (pathname, "r"); if (f) { @@ -860,7 +861,7 @@ print_sockets (unsigned short family, int tcp, struct buffer *buffer) else return; - fp = fopen (proc_file, "r"); + fp = gdb_fopen_cloexec (proc_file, "r"); if (fp) { char buf[8192]; @@ -1088,7 +1089,7 @@ linux_xfer_osdata_shm (gdb_byte *readbuf, buffer_init (&buffer); buffer_grow_str (&buffer, "<osdata type=\"shared memory\">\n"); - fp = fopen ("/proc/sysvipc/shm", "r"); + fp = gdb_fopen_cloexec ("/proc/sysvipc/shm", "r"); if (fp) { char buf[8192]; @@ -1216,7 +1217,7 @@ linux_xfer_osdata_sem (gdb_byte *readbuf, buffer_init (&buffer); buffer_grow_str (&buffer, "<osdata type=\"semaphores\">\n"); - fp = fopen ("/proc/sysvipc/sem", "r"); + fp = gdb_fopen_cloexec ("/proc/sysvipc/sem", "r"); if (fp) { char buf[8192]; @@ -1328,7 +1329,7 @@ linux_xfer_osdata_msg (gdb_byte *readbuf, buffer_init (&buffer); buffer_grow_str (&buffer, "<osdata type=\"message queues\">\n"); - fp = fopen ("/proc/sysvipc/msg", "r"); + fp = gdb_fopen_cloexec ("/proc/sysvipc/msg", "r"); if (fp) { char buf[8192]; @@ -1454,7 +1455,7 @@ linux_xfer_osdata_modules (gdb_byte *readbuf, buffer_init (&buffer); buffer_grow_str (&buffer, "<osdata type=\"modules\">\n"); - fp = fopen ("/proc/modules", "r"); + fp = gdb_fopen_cloexec ("/proc/modules", "r"); if (fp) { char buf[8192]; diff --git a/gdb/common/linux-procfs.c b/gdb/common/linux-procfs.c index f5dccfd..583ec98 100644 --- a/gdb/common/linux-procfs.c +++ b/gdb/common/linux-procfs.c @@ -24,6 +24,7 @@ #endif #include "linux-procfs.h" +#include "filestuff.h" /* Return the TGID of LWPID from /proc/pid/status. Returns -1 if not found. */ @@ -37,7 +38,7 @@ linux_proc_get_int (pid_t lwpid, const char *field) int retval = -1; snprintf (buf, sizeof (buf), "/proc/%d/status", (int) lwpid); - status_file = fopen (buf, "r"); + status_file = gdb_fopen_cloexec (buf, "r"); if (status_file == NULL) { warning (_("unable to open /proc file '%s'"), buf); @@ -83,7 +84,7 @@ linux_proc_pid_has_state (pid_t pid, const char *state) int have_state; xsnprintf (buffer, sizeof (buffer), "/proc/%d/status", (int) pid); - procfile = fopen (buffer, "r"); + procfile = gdb_fopen_cloexec (buffer, "r"); if (procfile == NULL) { warning (_("unable to open /proc file '%s'"), buffer); |