diff options
Diffstat (limited to 'src/crypto/fipsmodule/rand/fork_detect.c')
-rw-r--r-- | src/crypto/fipsmodule/rand/fork_detect.c | 64 |
1 files changed, 51 insertions, 13 deletions
diff --git a/src/crypto/fipsmodule/rand/fork_detect.c b/src/crypto/fipsmodule/rand/fork_detect.c index 71a02c89..a2cf3a05 100644 --- a/src/crypto/fipsmodule/rand/fork_detect.c +++ b/src/crypto/fipsmodule/rand/fork_detect.c @@ -17,31 +17,34 @@ #endif #include <openssl/base.h> - #include "fork_detect.h" -#if defined(OPENSSL_LINUX) -#include <assert.h> -#include <sys/mman.h> +#if defined(OPENSSL_FORK_DETECTION_MADVISE) #include <unistd.h> #include <stdlib.h> - -#include "../delocate.h" -#include "../../internal.h" - - +#include <assert.h> +#include <sys/mman.h> #if defined(MADV_WIPEONFORK) static_assert(MADV_WIPEONFORK == 18, "MADV_WIPEONFORK is not 18"); #else #define MADV_WIPEONFORK 18 #endif +#elif defined(OPENSSL_FORK_DETECTION_PTHREAD_ATFORK) +#include <unistd.h> +#include <stdlib.h> +#include <pthread.h> +#endif // OPENSSL_FORK_DETECTION_MADVISE +#include "../delocate.h" +#include "../../internal.h" + +#if defined(OPENSSL_FORK_DETECTION_MADVISE) +DEFINE_BSS_GET(int, g_force_madv_wipeonfork); +DEFINE_BSS_GET(int, g_force_madv_wipeonfork_enabled); DEFINE_STATIC_ONCE(g_fork_detect_once); DEFINE_STATIC_MUTEX(g_fork_detect_lock); DEFINE_BSS_GET(CRYPTO_atomic_u32 *, g_fork_detect_addr); DEFINE_BSS_GET(uint64_t, g_fork_generation); -DEFINE_BSS_GET(int, g_force_madv_wipeonfork); -DEFINE_BSS_GET(int, g_force_madv_wipeonfork_enabled); static void init_fork_detect(void) { if (*g_force_madv_wipeonfork_bss_get()) { @@ -73,9 +76,12 @@ static void init_fork_detect(void) { CRYPTO_atomic_store_u32(addr, 1); *g_fork_detect_addr_bss_get() = addr; *g_fork_generation_bss_get() = 1; + } uint64_t CRYPTO_get_fork_generation(void) { + CRYPTO_once(g_fork_detect_once_bss_get(), init_fork_detect); + // In a single-threaded process, there are obviously no races because there's // only a single mutator in the address space. // @@ -87,7 +93,6 @@ uint64_t CRYPTO_get_fork_generation(void) { // child process is single-threaded, the child may become multi-threaded // before it observes this. Therefore, we must synchronize the logic below. - CRYPTO_once(g_fork_detect_once_bss_get(), init_fork_detect); CRYPTO_atomic_u32 *const flag_ptr = *g_fork_detect_addr_bss_get(); if (flag_ptr == NULL) { // Our kernel is too old to support |MADV_WIPEONFORK| or @@ -98,6 +103,12 @@ uint64_t CRYPTO_get_fork_generation(void) { // doesn't support it. return 42; } + // With Linux and clone(), we do not believe that pthread_atfork() is + // sufficient for detecting all forms of address space duplication. At this + // point we have a kernel that does not support MADV_WIPEONFORK. We could + // return the generation number from pthread_atfork() here and it would + // probably be safe in almost any situation, but to ensure safety we return + // 0 and force an entropy draw on every call. return 0; } @@ -140,7 +151,34 @@ void CRYPTO_fork_detect_force_madv_wipeonfork_for_testing(int on) { *g_force_madv_wipeonfork_enabled_bss_get() = on; } -#elif defined(OPENSSL_WINDOWS) || defined(OPENSSL_TRUSTY) +#elif defined(OPENSSL_FORK_DETECTION_PTHREAD_ATFORK) + +DEFINE_STATIC_ONCE(g_pthread_fork_detection_once); +DEFINE_BSS_GET(uint64_t, g_atfork_fork_generation); + +static void we_are_forked(void) { + // Immediately after a fork, the process must be single-threaded. + uint64_t value = *g_atfork_fork_generation_bss_get() + 1; + if (value == 0) { + value = 1; + } + *g_atfork_fork_generation_bss_get() = value; +} + +static void init_pthread_fork_detection(void) { + if (pthread_atfork(NULL, NULL, we_are_forked) != 0) { + abort(); + } + *g_atfork_fork_generation_bss_get() = 1; +} + +uint64_t CRYPTO_get_fork_generation(void) { + CRYPTO_once(g_pthread_fork_detection_once_bss_get(), init_pthread_fork_detection); + + return *g_atfork_fork_generation_bss_get(); +} + +#elif defined(OPENSSL_DOES_NOT_FORK) // These platforms are guaranteed not to fork, and therefore do not require // fork detection support. Returning a constant non zero value makes BoringSSL |