diff options
author | Werner Koch <wk@gnupg.org> | 2009-03-19 08:09:31 +0100 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2009-03-19 08:09:31 +0100 |
commit | 588a7c34bb6cdffa8ec40d1e7fda047c5da38a61 (patch) | |
tree | 1399895643266c827878425babeb84039d6f4295 /common | |
parent | Add server option with-ephemeral-keys. (diff) | |
download | gnupg2-588a7c34bb6cdffa8ec40d1e7fda047c5da38a61.tar.xz gnupg2-588a7c34bb6cdffa8ec40d1e7fda047c5da38a61.zip |
Make sure not to leak file descriptors if running gpg-agent with a
command. Restore the signal mask to solve a problem in Mono.
Diffstat (limited to 'common')
-rw-r--r-- | common/ChangeLog | 10 | ||||
-rw-r--r-- | common/Makefile.am | 3 | ||||
-rw-r--r-- | common/exechelp.c | 166 | ||||
-rw-r--r-- | common/exechelp.h | 21 |
4 files changed, 184 insertions, 16 deletions
diff --git a/common/ChangeLog b/common/ChangeLog index 986041f59..1cf4f50fc 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,3 +1,13 @@ +2009-03-18 Werner Koch <wk@g10code.com> + + * exechelp.c: Include sys/resource.h and sys/stat.h. + (get_max_open_fds): New. + (do_exec): Use it. + (get_all_open_fds): New. + (close_all_fds): New. + (do_exec): Use close_all_fds. + * t-exechelp.c: New. + 2009-03-13 David Shaw <dshaw@jabberwocky.com> * http.c (do_parse_uri): Properly handle IPv6 literal addresses as diff --git a/common/Makefile.am b/common/Makefile.am index d1a2d4822..72c7d179f 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -108,7 +108,7 @@ status-codes.h: Makefile mkstrtable.awk exstatus.awk status.h # # Module tests # -module_tests = t-convert t-percent t-gettime t-sysutils t-sexputil +module_tests = t-convert t-percent t-gettime t-sysutils t-sexputil t-exechelp module_maint_tests = t-helpfile t-b64 t_common_ldadd = libcommon.a ../jnlib/libjnlib.a ../gl/libgnu.a \ @@ -121,6 +121,7 @@ t_sysutils_LDADD = $(t_common_ldadd) t_helpfile_LDADD = $(t_common_ldadd) t_sexputil_LDADD = $(t_common_ldadd) t_b64_LDADD = $(t_common_ldadd) +t_exechelp_LDADD = $(t_common_ldadd) diff --git a/common/exechelp.c b/common/exechelp.c index 4da3c9787..3d1136609 100644 --- a/common/exechelp.c +++ b/common/exechelp.c @@ -1,5 +1,5 @@ /* exechelp.c - fork and exec helpers - * Copyright (C) 2004, 2007, 2008 Free Software Foundation, Inc. + * Copyright (C) 2004, 2007, 2008, 2009 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -40,6 +40,16 @@ #include <sys/wait.h> #endif +#ifdef HAVE_GETRLIMIT +#include <sys/time.h> +#include <sys/resource.h> +#endif /*HAVE_GETRLIMIT*/ + +#ifdef HAVE_STAT +# include <sys/stat.h> +#endif + + #include "util.h" #include "i18n.h" #include "exechelp.h" @@ -48,12 +58,6 @@ #define DEBUG_W32_SPAWN 1 -#ifdef _POSIX_OPEN_MAX -#define MAX_OPEN_FDS _POSIX_OPEN_MAX -#else -#define MAX_OPEN_FDS 20 -#endif - /* We have the usual problem here: Some modules are linked against pth and some are not. However we want to use pth_fork and pth_waitpid here. Using a weak symbol works but is not portable - we should @@ -85,6 +89,145 @@ #endif +/* Return the maximum number of currently allowed open file + descriptors. Only useful on POSIX systems but returns a value on + other systems too. */ +int +get_max_fds (void) +{ + int max_fds = -1; +#ifdef HAVE_GETRLIMIT + struct rlimit rl; + +# ifdef RLIMIT_NOFILE + if (!getrlimit (RLIMIT_NOFILE, &rl)) + max_fds = rl.rlim_max; +# endif + +# ifdef RLIMIT_OFILE + if (max_fds == -1 && !getrlimit (RLIMIT_OFILE, &rl)) + max_fds = rl.rlim_max; + +# endif +#endif /*HAVE_GETRLIMIT*/ + +#ifdef _SC_OPEN_MAX + if (max_fds == -1) + { + long int scres = sysconf (_SC_OPEN_MAX); + if (scres >= 0) + max_fds = scres; + } +#endif + +#ifdef _POSIX_OPEN_MAX + if (max_fds == -1) + max_fds = _POSIX_OPEN_MAX; +#endif + +#ifdef OPEN_MAX + if (max_fds == -1) + max_fds = OPEN_MAX; +#endif + + if (max_fds == -1) + max_fds = 256; /* Arbitrary limit. */ + + return max_fds; +} + + +/* Close all file descriptors starting with descriptor FIRST. If + EXCEPT is not NULL, it is expected to be a list of file descriptors + which shall not be closed. This list shall be sorted in ascending + order with the end marked by -1. */ +void +close_all_fds (int first, int *except) +{ + int max_fd = get_max_fds (); + int fd, i, except_start; + + if (except) + { + except_start = 0; + for (fd=first; fd < max_fd; fd++) + { + for (i=except_start; except[i] != -1; i++) + { + if (except[i] == fd) + { + /* If we found the descriptor in the exception list + we can start the next compare run at the next + index because the exception list is ordered. */ + except_start = i + 1; + break; + } + } + if (except[i] == -1) + close (fd); + } + } + else + { + for (fd=first; fd < max_fd; fd++) + close (fd); + } + + errno = 0; +} + + +/* Returns an array with all currently open file descriptors. The end + of the array is marked by -1. The caller needs to release this + array using the *standard free* and not with xfree. This allow the + use of this fucntion right at startup even before libgcrypt has + been initialized. Returns NULL on error and sets ERRNO + accordingly. */ +int * +get_all_open_fds (void) +{ + int *array; + size_t narray; + int fd, max_fd, idx; +#ifndef HAVE_STAT + array = calloc (1, sizeof *array); + if (array) + array[0] = -1; +#else /*HAVE_STAT*/ + struct stat statbuf; + + max_fd = get_max_fds (); + narray = 32; /* If you change this change also t-exechelp.c. */ + array = calloc (narray, sizeof *array); + if (!array) + return NULL; + + /* Note: The list we return is ordered. */ + for (idx=0, fd=0; fd < max_fd; fd++) + if (!(fstat (fd, &statbuf) == -1 && errno == EBADF)) + { + if (idx+1 >= narray) + { + int *tmp; + + narray += (narray < 256)? 32:256; + tmp = realloc (array, narray * sizeof *array); + if (!tmp) + { + free (array); + return NULL; + } + array = tmp; + } + array[idx++] = fd; + } + array[idx] = -1; +#endif /*HAVE_STAT*/ + return array; +} + + + #ifdef HAVE_W32_SYSTEM /* Helper function to build_w32_commandline. */ static char * @@ -216,7 +359,7 @@ do_exec (const char *pgmname, const char *argv[], void (*preexec)(void) ) { char **arg_list; - int n, i, j; + int i, j; int fds[3]; fds[0] = fd_in; @@ -259,12 +402,7 @@ do_exec (const char *pgmname, const char *argv[], } /* Close all other files. */ - n = sysconf (_SC_OPEN_MAX); - if (n < 0) - n = MAX_OPEN_FDS; - for (i=3; i < n; i++) - close(i); - errno = 0; + close_all_fds (3, NULL); if (preexec) preexec (); diff --git a/common/exechelp.h b/common/exechelp.h index 0ad956f7a..0efee294c 100644 --- a/common/exechelp.h +++ b/common/exechelp.h @@ -1,5 +1,5 @@ /* exechelp.h - Definitions for the fork and exec helpers - * Copyright (C) 2004 Free Software Foundation, Inc. + * Copyright (C) 2004, 2009 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -20,6 +20,25 @@ #ifndef GNUPG_COMMON_EXECHELP_H #define GNUPG_COMMON_EXECHELP_H +/* Return the maximum number of currently allowed file descriptors. + Only useful on POSIX systems. */ +int get_max_fds (void); + + +/* Close all file descriptors starting with descriptor FIRST. If + EXCEPT is not NULL, it is expected to be a list of file descriptors + which are not to close. This list shall be sorted in ascending + order with its end marked by -1. */ +void close_all_fds (int first, int *except); + + +/* Returns an array with all currently open file descriptors. The end + of the array is marked by -1. The caller needs to release this + array using the *standard free* and not with xfree. This allow the + use of this fucntion right at startup even before libgcrypt has + been initialized. Returns NULL on error and sets ERRNO accordingly. */ +int *get_all_open_fds (void); + /* Portable function to create a pipe. Under Windows the write end is inheritable. */ |