diff -r 9c019475bb2f Modules/_ssl.c --- a/Modules/_ssl.c Thu Aug 15 02:18:55 2013 -0700 +++ b/Modules/_ssl.c Thu Aug 15 13:52:04 2013 +0200 @@ -51,6 +51,11 @@ #include #endif +#ifdef HAVE_PTHREAD_ATFORK +#include +#include +#endif + /* Include OpenSSL header files */ #include "openssl/rsa.h" #include "openssl/crypto.h" @@ -2882,7 +2887,87 @@ Returns number of bytes read. Raises SSLError if connection to EGD\n\ fails or if it does provide enough data to seed PRNG."); +#ifdef HAVE_PTHREAD_ATFORK + +/* Reset OpenSSL's PRNG at fork(), see CVE-2013-1900. + * + * We use pthread_atfork() until we have a proper atfork API in Python. Two + * handlers are registered. The prepare handler grabs a couple of bytes from + * the PRNG and stores them in a static buffer. These bytes are no longer in + * the internal state of the PRNG. + * The child handler re-seeds the PRNG from the static buffer. It also mixes + * the current time (with nanoseconds) and the child's PID into the PRNG + * state. The additional data takes care of race conditions, e.g. when a + * library does multiple fork() calls at once without looking. It make the + * PRNG more unpredictable, too. + * + * Note: The pthread_atfork() handlers are still registered after fork(). + */ + +static unsigned char RAND_atfork_buffer[64] = {0}; + +static void +PySSL_RAND_atfork_prepare(void) +{ + RAND_pseudo_bytes(RAND_atfork_buffer, sizeof(RAND_atfork_buffer)); +#if 1 + fprintf(stderr, "PySSL_RAND_atfork_prepare() in %i\n", getpid()); #endif +} + +static void +PySSL_RAND_atfork_child(void) +{ + pid_t pid; +#if defined(HAVE_CLOCK_GETTIME) + struct timespec ts; +#elif defined(HAVE_GETTIMEOFDAY) + struct timeval tv; +#endif + + pid = getpid(); + RAND_add(&pid, sizeof(pid_t), 0.0); +#if defined(HAVE_CLOCK_GETTIME) + if (clock_gettime(CLOCK_REALTIME, &ts) == 0) + RAND_add(&ts, sizeof(struct timespec), 0.0); +#elif defined(HAVE_GETTIMEOFDAY) + if (gettimeofday(&tv, NULL) == 0) + RAND_add(&tv, sizeof(struct timeval), 0.0); +#endif + RAND_add(RAND_atfork_buffer, sizeof(RAND_atfork_buffer), 0.0); +#if 1 + fprintf(stderr, "PySSL_RAND_atfork_handler() in %i\n", pid); +#endif +} + +static int +PySSL_RAND_atfork(void) +{ + static int registered = 0; + int retval; + + if (registered) + return 0; + + retval = pthread_atfork(PySSL_RAND_atfork_prepare, /* prepare */ + NULL, /* parent */ + PySSL_RAND_atfork_child /* child */ + ); + + if (retval != 0) { + if (errno == ENOMEM) + PyErr_NoMemory(); + else + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + registered = 1; + return 0; +} +#endif /* HAVE_PTHREAD_ATFORK */ + +#endif /* HAVE_OPENSSL_RAND */ + PyDoc_STRVAR(PySSL_get_default_verify_paths_doc, "get_default_verify_paths() -> tuple\n\ @@ -3479,5 +3564,10 @@ if (r == NULL || PyModule_AddObject(m, "_OPENSSL_API_VERSION", r)) return NULL; +#if defined(HAVE_OPENSSL_RAND) && defined(HAVE_PTHREAD_ATFORK) + if (PySSL_RAND_atfork() == -1) + return NULL; +#endif + return m; } diff -r 9c019475bb2f configure --- a/configure Thu Aug 15 02:18:55 2013 -0700 +++ b/configure Thu Aug 15 13:52:04 2013 +0200 @@ -9809,6 +9809,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 -r 9c019475bb2f configure.ac --- a/configure.ac Thu Aug 15 02:18:55 2013 -0700 +++ b/configure.ac Thu Aug 15 13:52:04 2013 +0200 @@ -2512,6 +2512,7 @@ [Define if pthread_sigmask() does not work on your system.]) ;; esac]) + AC_CHECK_FUNCS(pthread_atfork) fi diff -r 9c019475bb2f pyconfig.h.in --- a/pyconfig.h.in Thu Aug 15 02:18:55 2013 -0700 +++ b/pyconfig.h.in Thu Aug 15 13:52:04 2013 +0200 @@ -633,6 +633,9 @@ /* Define if your compiler supports function prototype */ #undef HAVE_PROTOTYPES +/* 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