|  | // Copyright 2020 The BoringSSL Authors | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //     https://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | #if !defined(_GNU_SOURCE) | 
|  | #define _GNU_SOURCE  // needed for madvise() and MAP_ANONYMOUS on Linux. | 
|  | #endif | 
|  |  | 
|  | #include "../bcm_support.h" | 
|  | #include "../internal.h" | 
|  | #include "internal.h" | 
|  |  | 
|  | #if defined(OPENSSL_FORK_DETECTION_MADVISE) | 
|  | #include <assert.h> | 
|  | #include <stdlib.h> | 
|  | #include <sys/mman.h> | 
|  | #include <unistd.h> | 
|  | #if defined(MADV_WIPEONFORK) | 
|  | static_assert(MADV_WIPEONFORK == 18); | 
|  | #else | 
|  | #define MADV_WIPEONFORK 18 | 
|  | #endif | 
|  | #elif defined(OPENSSL_FORK_DETECTION_PTHREAD_ATFORK) | 
|  | #include <pthread.h> | 
|  | #include <stdlib.h> | 
|  | #include <unistd.h> | 
|  | #endif  // OPENSSL_FORK_DETECTION_PTHREAD_ATFORK | 
|  |  | 
|  | #if defined(OPENSSL_FORK_DETECTION_MADVISE) | 
|  | static int g_force_madv_wipeonfork; | 
|  | static int g_force_madv_wipeonfork_enabled; | 
|  | static CRYPTO_once_t g_fork_detect_once = CRYPTO_ONCE_INIT; | 
|  | static CRYPTO_MUTEX g_fork_detect_lock = CRYPTO_MUTEX_INIT; | 
|  | static CRYPTO_atomic_u32 *g_fork_detect_addr; | 
|  | static uint64_t g_fork_generation; | 
|  |  | 
|  | static void init_fork_detect(void) { | 
|  | if (g_force_madv_wipeonfork) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | long page_size = sysconf(_SC_PAGESIZE); | 
|  | if (page_size <= 0) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | void *addr = mmap(NULL, (size_t)page_size, PROT_READ | PROT_WRITE, | 
|  | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | 
|  | if (addr == MAP_FAILED) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Some versions of qemu (up to at least 5.0.0-rc4, see linux-user/syscall.c) | 
|  | // ignore |madvise| calls and just return zero (i.e. success). But we need to | 
|  | // know whether MADV_WIPEONFORK actually took effect. Therefore try an invalid | 
|  | // call to check that the implementation of |madvise| is actually rejecting | 
|  | // unknown |advice| values. | 
|  | if (madvise(addr, (size_t)page_size, -1) == 0 || | 
|  | madvise(addr, (size_t)page_size, MADV_WIPEONFORK) != 0) { | 
|  | munmap(addr, (size_t)page_size); | 
|  | return; | 
|  | } | 
|  |  | 
|  | CRYPTO_atomic_u32 *const atomic = reinterpret_cast<CRYPTO_atomic_u32 *>(addr); | 
|  | CRYPTO_atomic_store_u32(atomic, 1); | 
|  | g_fork_detect_addr = atomic; | 
|  | g_fork_generation = 1; | 
|  | } | 
|  |  | 
|  | uint64_t CRYPTO_get_fork_generation(void) { | 
|  | CRYPTO_once(&g_fork_detect_once, init_fork_detect); | 
|  |  | 
|  | // In a single-threaded process, there are obviously no races because there's | 
|  | // only a single mutator in the address space. | 
|  | // | 
|  | // In a multi-threaded environment, |CRYPTO_once| ensures that the flag byte | 
|  | // is initialised atomically, even if multiple threads enter this function | 
|  | // concurrently. | 
|  | // | 
|  | // Additionally, while the kernel will only clear WIPEONFORK at a point when a | 
|  | // child process is single-threaded, the child may become multi-threaded | 
|  | // before it observes this. Therefore, we must synchronize the logic below. | 
|  |  | 
|  | CRYPTO_atomic_u32 *const flag_ptr = g_fork_detect_addr; | 
|  | if (flag_ptr == NULL) { | 
|  | // Our kernel is too old to support |MADV_WIPEONFORK| or | 
|  | // |g_force_madv_wipeonfork| is set. | 
|  | if (g_force_madv_wipeonfork && g_force_madv_wipeonfork_enabled) { | 
|  | // A constant generation number to simulate support, even if the kernel | 
|  | // 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; | 
|  | } | 
|  |  | 
|  | // In the common case, try to observe the flag without taking a lock. This | 
|  | // avoids cacheline contention in the PRNG. | 
|  | uint64_t *const generation_ptr = &g_fork_generation; | 
|  | if (CRYPTO_atomic_load_u32(flag_ptr) != 0) { | 
|  | // If we observe a non-zero flag, it is safe to read |generation_ptr| | 
|  | // without a lock. The flag and generation number are fixed for this copy of | 
|  | // the address space. | 
|  | return *generation_ptr; | 
|  | } | 
|  |  | 
|  | // The flag was zero. The generation number must be incremented, but other | 
|  | // threads may have concurrently observed the zero, so take a lock before | 
|  | // incrementing. | 
|  | CRYPTO_MUTEX *const lock = &g_fork_detect_lock; | 
|  | CRYPTO_MUTEX_lock_write(lock); | 
|  | uint64_t current_generation = *generation_ptr; | 
|  | if (CRYPTO_atomic_load_u32(flag_ptr) == 0) { | 
|  | // A fork has occurred. | 
|  | current_generation++; | 
|  | if (current_generation == 0) { | 
|  | // Zero means fork detection isn't supported, so skip that value. | 
|  | current_generation = 1; | 
|  | } | 
|  |  | 
|  | // We must update |generation_ptr| before |flag_ptr|. Other threads may | 
|  | // observe |flag_ptr| without taking a lock. | 
|  | *generation_ptr = current_generation; | 
|  | CRYPTO_atomic_store_u32(flag_ptr, 1); | 
|  | } | 
|  | CRYPTO_MUTEX_unlock_write(lock); | 
|  |  | 
|  | return current_generation; | 
|  | } | 
|  |  | 
|  | void CRYPTO_fork_detect_force_madv_wipeonfork_for_testing(int on) { | 
|  | g_force_madv_wipeonfork = 1; | 
|  | g_force_madv_wipeonfork_enabled = on; | 
|  | } | 
|  |  | 
|  | #elif defined(OPENSSL_FORK_DETECTION_PTHREAD_ATFORK) | 
|  |  | 
|  | static CRYPTO_once_t g_pthread_fork_detection_once = CRYPTO_ONCE_INIT; | 
|  | static 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 + 1; | 
|  | if (value == 0) { | 
|  | value = 1; | 
|  | } | 
|  | g_atfork_fork_generation = value; | 
|  | } | 
|  |  | 
|  | static void init_pthread_fork_detection(void) { | 
|  | if (pthread_atfork(NULL, NULL, we_are_forked) != 0) { | 
|  | abort(); | 
|  | } | 
|  | g_atfork_fork_generation = 1; | 
|  | } | 
|  |  | 
|  | uint64_t CRYPTO_get_fork_generation(void) { | 
|  | CRYPTO_once(&g_pthread_fork_detection_once, init_pthread_fork_detection); | 
|  |  | 
|  | return g_atfork_fork_generation; | 
|  | } | 
|  |  | 
|  | #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 | 
|  | // assume address space duplication is not a concern and adding entropy to | 
|  | // every RAND_bytes call is not needed. | 
|  | uint64_t CRYPTO_get_fork_generation(void) { return 0xc0ffee; } | 
|  |  | 
|  | #else | 
|  |  | 
|  | // These platforms may fork, but we do not have a mitigation mechanism in | 
|  | // place.  Returning a constant zero value makes BoringSSL assume that address | 
|  | // space duplication could have occured on any call entropy must be added to | 
|  | // every RAND_bytes call. | 
|  | uint64_t CRYPTO_get_fork_generation(void) { return 0; } | 
|  |  | 
|  | #endif |