[Python-checkins] cpython (2.7): Issue #18747: Re-seed OpenSSL's pseudo-random number generator after fork.

christian.heimes python-checkins at python.org
Wed Aug 21 13:43:32 CEST 2013


http://hg.python.org/cpython/rev/2e6aa6c29be2
changeset:   85292:2e6aa6c29be2
branch:      2.7
parent:      85283:a4091c1de27a
user:        Christian Heimes <christian at cheimes.de>
date:        Wed Aug 21 13:26:05 2013 +0200
summary:
  Issue #18747: Re-seed OpenSSL's pseudo-random number generator after fork.
A pthread_atfork() child handler is used to seeded the PRNG with pid, time
and some stack data.

files:
  Misc/NEWS      |   4 ++
  Modules/_ssl.c |  72 ++++++++++++++++++++++++++++++++++++++
  configure      |  11 +++++
  configure.ac   |   1 +
  pyconfig.h.in  |   3 +
  5 files changed, 91 insertions(+), 0 deletions(-)


diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -32,6 +32,10 @@
 Library
 -------
 
+- Issue #18747: Re-seed OpenSSL's pseudo-random number generator after fork.
+  A pthread_atfork() child handler is used to seeded the PRNG with pid, time
+  and some stack data.
+
 - Issue #8865: Concurrent invocation of select.poll.poll() now raises a
   RuntimeError exception.  Patch by Christian Schubert.
 
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -18,6 +18,11 @@
 
 #ifdef WITH_THREAD
 #include "pythread.h"
+
+#ifdef HAVE_PTHREAD_ATFORK
+#  include <pthread.h>
+#endif
+
 #define PySSL_BEGIN_ALLOW_THREADS { \
             PyThreadState *_save = NULL;  \
             if (_ssl_locks_count>0) {_save = PyEval_SaveThread();}
@@ -1621,7 +1626,69 @@
 Returns number of bytes read.  Raises SSLError if connection to EGD\n\
 fails or if it does not provide enough data to seed PRNG.");
 
+/* Seed OpenSSL's PRNG at fork(), http://bugs.python.org/issue18747
+ *
+ * The child handler seeds the PRNG from pseudo-random data like pid, the
+ * current time (nanoseconds, miliseconds or seconds) and an uninitialized
+ * array. The array contains stack variables that are impossible to predict
+ * on most systems, e.g. function return address (subject to ASLR), the
+ * stack protection canary and automatic variables.
+ * The code is inspired by Apache's ssl_rand_seed() function.
+ *
+ * Note:
+ * The code uses pthread_atfork() until Python has a proper atfork API. The
+ * handlers are not removed from the child process.
+ */
+
+#if defined(HAVE_PTHREAD_ATFORK) && defined(WITH_THREAD)
+#define PYSSL_RAND_ATFORK 1
+
+static void
+PySSL_RAND_atfork_child(void)
+{
+    struct {
+        char stack[128];    /* uninitialized (!) stack data, 128 is an
+                               arbitrary number. */
+        pid_t pid;          /* current pid */
+        time_t time;        /* current time */
+    } seed;
+
+#ifdef WITH_VALGRIND
+    VALGRIND_MAKE_MEM_DEFINED(seed.stack, sizeof(seed.stack));
 #endif
+    seed.pid = getpid();
+    seed.time = time(NULL);
+
+#if 0
+    fprintf(stderr, "PySSL_RAND_atfork_child() seeds %i bytes in pid %i\n",
+            (int)sizeof(seed), seed.pid);
+#endif
+    RAND_add((unsigned char *)&seed, sizeof(seed), 0.0);
+}
+
+static int
+PySSL_RAND_atfork(void)
+{
+    static int registered = 0;
+    int retval;
+
+    if (registered)
+        return 0;
+
+    retval = pthread_atfork(NULL,                     /* prepare */
+                            NULL,                     /* parent */
+                            PySSL_RAND_atfork_child); /* child */
+    if (retval != 0) {
+        PyErr_SetFromErrno(PyExc_OSError);
+        return -1;
+    }
+    registered = 1;
+    return 0;
+}
+#endif /* HAVE_PTHREAD_ATFORK */
+
+#endif /* HAVE_OPENSSL_RAND */
+
 
 /* List of functions exported by this module. */
 
@@ -1833,4 +1900,9 @@
     r = PyString_FromString(SSLeay_version(SSLEAY_VERSION));
     if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION", r))
         return;
+
+#ifdef PYSSL_RAND_ATFORK
+    if (PySSL_RAND_atfork() == -1)
+        return;
+#endif
 }
diff --git a/configure b/configure
--- a/configure
+++ b/configure
@@ -9630,6 +9630,17 @@
 fi
 done
 
+      for ac_func in pthread_atfork
+do :
+  ac_fn_c_check_func "$LINENO" "pthread_atfork" "ac_cv_func_pthread_atfork"
+if test "x$ac_cv_func_pthread_atfork" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_PTHREAD_ATFORK 1
+_ACEOF
+
+fi
+done
+
 fi
 
 
diff --git a/configure.ac b/configure.ac
--- a/configure.ac
+++ b/configure.ac
@@ -2569,6 +2569,7 @@
             [Define if pthread_sigmask() does not work on your system.])
             ;;
         esac])
+      AC_CHECK_FUNCS(pthread_atfork)
 fi
 
 
diff --git a/pyconfig.h.in b/pyconfig.h.in
--- a/pyconfig.h.in
+++ b/pyconfig.h.in
@@ -520,6 +520,9 @@
 /* Define if you have GNU PTH threads. */
 #undef HAVE_PTH
 
+/* Define to 1 if you have the `pthread_atfork' function. */
+#undef HAVE_PTHREAD_ATFORK
+
 /* Defined for Solaris 2.6 bug in pthread header. */
 #undef HAVE_PTHREAD_DESTRUCTOR
 

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list