summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2009-03-19 08:09:31 +0100
committerWerner Koch <wk@gnupg.org>2009-03-19 08:09:31 +0100
commit588a7c34bb6cdffa8ec40d1e7fda047c5da38a61 (patch)
tree1399895643266c827878425babeb84039d6f4295 /common
parentAdd server option with-ephemeral-keys. (diff)
downloadgnupg2-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/ChangeLog10
-rw-r--r--common/Makefile.am3
-rw-r--r--common/exechelp.c166
-rw-r--r--common/exechelp.h21
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. */