changeset: 85292:2e6aa6c29be2 branch: 2.7 parent: 85283:a4091c1de27a user: Christian Heimes date: Wed Aug 21 13:26:05 2013 +0200 files: Misc/NEWS Modules/_ssl.c configure configure.ac pyconfig.h.in description: 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. diff -r a4091c1de27a -r 2e6aa6c29be2 Misc/NEWS --- a/Misc/NEWS Tue Aug 20 20:38:21 2013 +0300 +++ b/Misc/NEWS Wed Aug 21 13:26:05 2013 +0200 @@ -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 -r a4091c1de27a -r 2e6aa6c29be2 Modules/_ssl.c --- a/Modules/_ssl.c Tue Aug 20 20:38:21 2013 +0300 +++ b/Modules/_ssl.c Wed Aug 21 13:26:05 2013 +0200 @@ -18,6 +18,11 @@ #ifdef WITH_THREAD #include "pythread.h" + +#ifdef HAVE_PTHREAD_ATFORK +# include +#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 -r a4091c1de27a -r 2e6aa6c29be2 configure --- a/configure Tue Aug 20 20:38:21 2013 +0300 +++ b/configure Wed Aug 21 13:26:05 2013 +0200 @@ -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 -r a4091c1de27a -r 2e6aa6c29be2 configure.ac --- a/configure.ac Tue Aug 20 20:38:21 2013 +0300 +++ b/configure.ac Wed Aug 21 13:26:05 2013 +0200 @@ -2569,6 +2569,7 @@ [Define if pthread_sigmask() does not work on your system.]) ;; esac]) + AC_CHECK_FUNCS(pthread_atfork) fi diff -r a4091c1de27a -r 2e6aa6c29be2 pyconfig.h.in --- a/pyconfig.h.in Tue Aug 20 20:38:21 2013 +0300 +++ b/pyconfig.h.in Wed Aug 21 13:26:05 2013 +0200 @@ -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