diff --git a/cbits/posix/bsd_closefrom.c b/cbits/posix/bsd_closefrom.c new file mode 100644 index 00000000..5a5779e7 --- /dev/null +++ b/cbits/posix/bsd_closefrom.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2004-2005 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef HAVE_CLOSEFROM + +#include +#include +#include +#include +#ifdef HAVE_FCNTL_H +# include +#endif +#include +#include +#include +#include +#include +#ifdef HAVE_DIRENT_H +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# ifdef HAVE_SYS_NDIR_H +# include +# endif +# ifdef HAVE_SYS_DIR_H +# include +# endif +# ifdef HAVE_NDIR_H +# include +# endif +#endif +#if defined(HAVE_LIBPROC_H) +# include +#endif + +#ifndef OPEN_MAX +# define OPEN_MAX 256 +#endif + +#if 0 +__unused static const char rcsid[] = "$Sudo: closefrom.c,v 1.11 2006/08/17 15:26:54 millert Exp $"; +#endif /* lint */ + +#ifndef HAVE_FCNTL_CLOSEM +/* + * Close all file descriptors greater than or equal to lowfd. + */ +static void +closefrom_fallback(int lowfd) +{ + long fd, maxfd; + + /* + * Fall back on sysconf() or getdtablesize(). We avoid checking + * resource limits since it is possible to open a file descriptor + * and then drop the rlimit such that it is below the open fd. + */ +#ifdef HAVE_SYSCONF + maxfd = sysconf(_SC_OPEN_MAX); +#else + maxfd = getdtablesize(); +#endif /* HAVE_SYSCONF */ + if (maxfd < 0) + maxfd = OPEN_MAX; + + for (fd = lowfd; fd < maxfd; fd++) + (void) close((int) fd); +} +#endif /* HAVE_FCNTL_CLOSEM */ + +#ifdef HAVE_FCNTL_CLOSEM +void +closefrom(int lowfd) +{ + (void) fcntl(lowfd, F_CLOSEM, 0); +} +#elif defined(HAVE_LIBPROC_H) && defined(HAVE_PROC_PIDINFO) +void +closefrom(int lowfd) +{ + int i, r, sz; + pid_t pid = getpid(); + struct proc_fdinfo *fdinfo_buf = NULL; + + sz = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0); + if (sz == 0) + return; /* no fds, really? */ + else if (sz == -1) + goto fallback; + if ((fdinfo_buf = malloc(sz)) == NULL) + goto fallback; + r = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fdinfo_buf, sz); + if (r < 0 || r > sz) + goto fallback; + for (i = 0; i < r / (int)PROC_PIDLISTFD_SIZE; i++) { + if (fdinfo_buf[i].proc_fd >= lowfd) + close(fdinfo_buf[i].proc_fd); + } + free(fdinfo_buf); + return; + fallback: + free(fdinfo_buf); + closefrom_fallback(lowfd); + return; +} +#elif defined(HAVE_DIRFD) && defined(HAVE_PROC_PID) +void +closefrom(int lowfd) +{ + long fd; + char fdpath[PATH_MAX], *endp; + struct dirent *dent; + DIR *dirp; + int len; + + /* Check for a /proc/$$/fd directory. */ + len = snprintf(fdpath, sizeof(fdpath), "/proc/%ld/fd", (long)getpid()); + if (len > 0 && (size_t)len < sizeof(fdpath) && (dirp = opendir(fdpath))) { + while ((dent = readdir(dirp)) != NULL) { + fd = strtol(dent->d_name, &endp, 10); + if (dent->d_name != endp && *endp == '\0' && + fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp)) + (void) close((int) fd); + } + (void) closedir(dirp); + return; + } + /* /proc/$$/fd strategy failed, fall back to brute force closure */ + closefrom_fallback(lowfd); +} +#else +void +closefrom(int lowfd) +{ + closefrom_fallback(lowfd); +} +#endif /* !HAVE_FCNTL_CLOSEM */ +#endif /* HAVE_CLOSEFROM */ diff --git a/cbits/posix/close_fds.c b/cbits/posix/close_fds.c new file mode 100644 index 00000000..e2747514 --- /dev/null +++ b/cbits/posix/close_fds.c @@ -0,0 +1,22 @@ + +#include "common.h" + +#include + +#if defined(HAVE_CLOSERANGE) +#include +#endif + + +void closefrom_excluding(int lowfd, int excludingFd) { +#if defined(HAVE_CLOSERANGE) + close_range(lowfd, excludingFd - 1); + closefrom(excludingFd + 1); +#else + for (int i = lowfd; i < excludingFd; i++) { + close(i); + } + + closefrom(excludingFd + 1); +#endif +} diff --git a/cbits/posix/common.h b/cbits/posix/common.h index d7693ad8..1ec0492d 100644 --- a/cbits/posix/common.h +++ b/cbits/posix/common.h @@ -22,7 +22,8 @@ struct std_handle { }; }; -int get_max_fd(void); +void closefrom_excluding(int from, int excluding); +void closefrom(int lowfd); // defined in find_executable.c #if !defined(HAVE_EXECVPE) diff --git a/cbits/posix/fork_exec.c b/cbits/posix/fork_exec.c index dd6e58f1..8ce6f339 100644 --- a/cbits/posix/fork_exec.c +++ b/cbits/posix/fork_exec.c @@ -222,13 +222,7 @@ do_spawn_fork (char *const args[], setup_std_handle_fork(STDERR_FILENO, stdErrHdl, forkCommunicationFds[1]); if ((flags & RUN_PROCESS_IN_CLOSE_FDS) != 0) { - int max_fd = get_max_fd(); - // XXX Not the pipe - for (int i = 3; i < max_fd; i++) { - if (i != forkCommunicationFds[1]) { - close(i); - } - } + closefrom_excluding(3, forkCommunicationFds[1]); } /* Reset the SIGINT/SIGQUIT signal handlers in the child, if requested diff --git a/cbits/posix/runProcess.c b/cbits/posix/runProcess.c index bc350d97..3b7ab8ca 100644 --- a/cbits/posix/runProcess.c +++ b/cbits/posix/runProcess.c @@ -21,22 +21,6 @@ #include #endif -int -get_max_fd() -{ - static int cache = 0; - if (cache == 0) { -#if HAVE_SYSCONF - cache = sysconf(_SC_OPEN_MAX); - if (cache == -1) { - cache = 256; - } -#else - cache = 256; -#endif - } - return cache; -} // If a process was terminated by a signal, the exit status we return // via the System.Process API is (-signum). This encoding avoids collision with diff --git a/process.cabal b/process.cabal index fe7564e1..7169e5ab 100644 --- a/process.cabal +++ b/process.cabal @@ -66,6 +66,8 @@ library else c-sources: cbits/posix/runProcess.c + cbits/posix/bsd_closefrom.c + cbits/posix/close_fds.c cbits/posix/fork_exec.c cbits/posix/posix_spawn.c cbits/posix/find_executable.c