|
18 | 18 |
|
19 | 19 | #ifdef WITH_THREAD |
20 | 20 | #include "pythread.h" |
| 21 | + |
| 22 | +#ifdef HAVE_PTHREAD_ATFORK |
| 23 | +# include <pthread.h> |
| 24 | +#endif |
| 25 | + |
21 | 26 | #define PySSL_BEGIN_ALLOW_THREADS_S(save) \ |
22 | 27 | do { if (_ssl_locks_count>0) { (save) = PyEval_SaveThread(); } } while (0) |
23 | 28 | #define PySSL_END_ALLOW_THREADS_S(save) \ |
@@ -2578,7 +2583,69 @@ Queries the entropy gather daemon (EGD) on the socket named by 'path'.\n\ |
2578 | 2583 | Returns number of bytes read. Raises SSLError if connection to EGD\n\ |
2579 | 2584 | fails or if it does not provide enough data to seed PRNG."); |
2580 | 2585 |
|
| 2586 | +/* Seed OpenSSL's PRNG at fork(), http://bugs.python.org/issue18747 |
| 2587 | + * |
| 2588 | + * The child handler seeds the PRNG from pseudo-random data like pid, the |
| 2589 | + * current time (nanoseconds, miliseconds or seconds) and an uninitialized |
| 2590 | + * array. The array contains stack variables that are impossible to predict |
| 2591 | + * on most systems, e.g. function return address (subject to ASLR), the |
| 2592 | + * stack protection canary and automatic variables. |
| 2593 | + * The code is inspired by Apache's ssl_rand_seed() function. |
| 2594 | + * |
| 2595 | + * Note: |
| 2596 | + * The code uses pthread_atfork() until Python has a proper atfork API. The |
| 2597 | + * handlers are not removed from the child process. |
| 2598 | + */ |
| 2599 | + |
| 2600 | +#if defined(HAVE_PTHREAD_ATFORK) && defined(WITH_THREAD) |
| 2601 | +#define PYSSL_RAND_ATFORK 1 |
| 2602 | + |
| 2603 | +static void |
| 2604 | +PySSL_RAND_atfork_child(void) |
| 2605 | +{ |
| 2606 | + struct { |
| 2607 | + char stack[128]; /* uninitialized (!) stack data, 128 is an |
| 2608 | + arbitrary number. */ |
| 2609 | + pid_t pid; /* current pid */ |
| 2610 | + _PyTime_timeval tp; /* current time */ |
| 2611 | + } seed; |
| 2612 | + |
| 2613 | +#ifdef WITH_VALGRIND |
| 2614 | + VALGRIND_MAKE_MEM_DEFINED(seed.stack, sizeof(seed.stack)); |
| 2615 | +#endif |
| 2616 | + seed.pid = getpid(); |
| 2617 | + _PyTime_gettimeofday(&(seed.tp)); |
| 2618 | + |
| 2619 | +#if 0 |
| 2620 | + fprintf(stderr, "PySSL_RAND_atfork_child() seeds %i bytes in pid %i\n", |
| 2621 | + (int)sizeof(seed), seed.pid); |
2581 | 2622 | #endif |
| 2623 | + RAND_add((unsigned char *)&seed, sizeof(seed), 0.0); |
| 2624 | +} |
| 2625 | + |
| 2626 | +static int |
| 2627 | +PySSL_RAND_atfork(void) |
| 2628 | +{ |
| 2629 | + static int registered = 0; |
| 2630 | + int retval; |
| 2631 | + |
| 2632 | + if (registered) |
| 2633 | + return 0; |
| 2634 | + |
| 2635 | + retval = pthread_atfork(NULL, /* prepare */ |
| 2636 | + NULL, /* parent */ |
| 2637 | + PySSL_RAND_atfork_child); /* child */ |
| 2638 | + if (retval != 0) { |
| 2639 | + PyErr_SetFromErrno(PyExc_OSError); |
| 2640 | + return -1; |
| 2641 | + } |
| 2642 | + registered = 1; |
| 2643 | + return 0; |
| 2644 | +} |
| 2645 | +#endif /* HAVE_PTHREAD_ATFORK */ |
| 2646 | + |
| 2647 | +#endif /* HAVE_OPENSSL_RAND */ |
| 2648 | + |
2582 | 2649 |
|
2583 | 2650 |
|
2584 | 2651 |
|
@@ -2956,5 +3023,10 @@ PyInit__ssl(void) |
2956 | 3023 | if (r == NULL || PyModule_AddObject(m, "_OPENSSL_API_VERSION", r)) |
2957 | 3024 | return NULL; |
2958 | 3025 |
|
| 3026 | +#ifdef PYSSL_RAND_ATFORK |
| 3027 | + if (PySSL_RAND_atfork() == -1) |
| 3028 | + return NULL; |
| 3029 | +#endif |
| 3030 | + |
2959 | 3031 | return m; |
2960 | 3032 | } |
0 commit comments