• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2020, Google Inc.
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14 
15 #if !defined(_GNU_SOURCE)
16 #define _GNU_SOURCE  // needed for madvise() and MAP_ANONYMOUS on Linux.
17 #endif
18 
19 #include <openssl/base.h>
20 #include "fork_detect.h"
21 
22 #if defined(OPENSSL_FORK_DETECTION_MADVISE)
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <assert.h>
26 #include <sys/mman.h>
27 #if defined(MADV_WIPEONFORK)
28 static_assert(MADV_WIPEONFORK == 18, "MADV_WIPEONFORK is not 18");
29 #else
30 #define MADV_WIPEONFORK 18
31 #endif
32 #elif defined(OPENSSL_FORK_DETECTION_PTHREAD_ATFORK)
33 #include <unistd.h>
34 #include <stdlib.h>
35 #include <pthread.h>
36 #endif // OPENSSL_FORK_DETECTION_MADVISE
37 
38 #include "../delocate.h"
39 #include "../../internal.h"
40 
41 #if defined(OPENSSL_FORK_DETECTION_MADVISE)
42 DEFINE_BSS_GET(int, g_force_madv_wipeonfork);
43 DEFINE_BSS_GET(int, g_force_madv_wipeonfork_enabled);
44 DEFINE_STATIC_ONCE(g_fork_detect_once);
45 DEFINE_STATIC_MUTEX(g_fork_detect_lock);
46 DEFINE_BSS_GET(CRYPTO_atomic_u32 *, g_fork_detect_addr);
47 DEFINE_BSS_GET(uint64_t, g_fork_generation);
48 
init_fork_detect(void)49 static void init_fork_detect(void) {
50   if (*g_force_madv_wipeonfork_bss_get()) {
51     return;
52   }
53 
54   long page_size = sysconf(_SC_PAGESIZE);
55   if (page_size <= 0) {
56     return;
57   }
58 
59   void *addr = mmap(NULL, (size_t)page_size, PROT_READ | PROT_WRITE,
60                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
61   if (addr == MAP_FAILED) {
62     return;
63   }
64 
65   // Some versions of qemu (up to at least 5.0.0-rc4, see linux-user/syscall.c)
66   // ignore |madvise| calls and just return zero (i.e. success). But we need to
67   // know whether MADV_WIPEONFORK actually took effect. Therefore try an invalid
68   // call to check that the implementation of |madvise| is actually rejecting
69   // unknown |advice| values.
70   if (madvise(addr, (size_t)page_size, -1) == 0 ||
71       madvise(addr, (size_t)page_size, MADV_WIPEONFORK) != 0) {
72     munmap(addr, (size_t)page_size);
73     return;
74   }
75 
76   CRYPTO_atomic_store_u32(addr, 1);
77   *g_fork_detect_addr_bss_get() = addr;
78   *g_fork_generation_bss_get() = 1;
79 
80 }
81 
CRYPTO_get_fork_generation(void)82 uint64_t CRYPTO_get_fork_generation(void) {
83   CRYPTO_once(g_fork_detect_once_bss_get(), init_fork_detect);
84 
85   // In a single-threaded process, there are obviously no races because there's
86   // only a single mutator in the address space.
87   //
88   // In a multi-threaded environment, |CRYPTO_once| ensures that the flag byte
89   // is initialised atomically, even if multiple threads enter this function
90   // concurrently.
91   //
92   // Additionally, while the kernel will only clear WIPEONFORK at a point when a
93   // child process is single-threaded, the child may become multi-threaded
94   // before it observes this. Therefore, we must synchronize the logic below.
95 
96   CRYPTO_atomic_u32 *const flag_ptr = *g_fork_detect_addr_bss_get();
97   if (flag_ptr == NULL) {
98     // Our kernel is too old to support |MADV_WIPEONFORK| or
99     // |g_force_madv_wipeonfork| is set.
100     if (*g_force_madv_wipeonfork_bss_get() &&
101         *g_force_madv_wipeonfork_enabled_bss_get()) {
102       // A constant generation number to simulate support, even if the kernel
103       // doesn't support it.
104       return 42;
105     }
106     // With Linux and clone(), we do not believe that pthread_atfork() is
107     // sufficient for detecting all forms of address space duplication. At this
108     // point we have a kernel that does not support MADV_WIPEONFORK. We could
109     // return the generation number from pthread_atfork() here and it would
110     // probably be safe in almost any situation, but to ensure safety we return
111     // 0 and force an entropy draw on every call.
112     return 0;
113   }
114 
115   // In the common case, try to observe the flag without taking a lock. This
116   // avoids cacheline contention in the PRNG.
117   uint64_t *const generation_ptr = g_fork_generation_bss_get();
118   if (CRYPTO_atomic_load_u32(flag_ptr) != 0) {
119     // If we observe a non-zero flag, it is safe to read |generation_ptr|
120     // without a lock. The flag and generation number are fixed for this copy of
121     // the address space.
122     return *generation_ptr;
123   }
124 
125   // The flag was zero. The generation number must be incremented, but other
126   // threads may have concurrently observed the zero, so take a lock before
127   // incrementing.
128   CRYPTO_MUTEX *const lock = g_fork_detect_lock_bss_get();
129   CRYPTO_MUTEX_lock_write(lock);
130   uint64_t current_generation = *generation_ptr;
131   if (CRYPTO_atomic_load_u32(flag_ptr) == 0) {
132     // A fork has occurred.
133     current_generation++;
134     if (current_generation == 0) {
135       // Zero means fork detection isn't supported, so skip that value.
136       current_generation = 1;
137     }
138 
139     // We must update |generation_ptr| before |flag_ptr|. Other threads may
140     // observe |flag_ptr| without taking a lock.
141     *generation_ptr = current_generation;
142     CRYPTO_atomic_store_u32(flag_ptr, 1);
143   }
144   CRYPTO_MUTEX_unlock_write(lock);
145 
146   return current_generation;
147 }
148 
CRYPTO_fork_detect_force_madv_wipeonfork_for_testing(int on)149 void CRYPTO_fork_detect_force_madv_wipeonfork_for_testing(int on) {
150   *g_force_madv_wipeonfork_bss_get() = 1;
151   *g_force_madv_wipeonfork_enabled_bss_get() = on;
152 }
153 
154 #elif defined(OPENSSL_FORK_DETECTION_PTHREAD_ATFORK)
155 
156 DEFINE_STATIC_ONCE(g_pthread_fork_detection_once);
157 DEFINE_BSS_GET(uint64_t, g_atfork_fork_generation);
158 
we_are_forked(void)159 static void we_are_forked(void) {
160   // Immediately after a fork, the process must be single-threaded.
161   uint64_t value = *g_atfork_fork_generation_bss_get() + 1;
162   if (value == 0) {
163     value = 1;
164   }
165   *g_atfork_fork_generation_bss_get() = value;
166 }
167 
init_pthread_fork_detection(void)168 static void init_pthread_fork_detection(void) {
169   if (pthread_atfork(NULL, NULL, we_are_forked) != 0) {
170     abort();
171   }
172   *g_atfork_fork_generation_bss_get() = 1;
173 }
174 
CRYPTO_get_fork_generation(void)175 uint64_t CRYPTO_get_fork_generation(void) {
176   CRYPTO_once(g_pthread_fork_detection_once_bss_get(), init_pthread_fork_detection);
177 
178   return *g_atfork_fork_generation_bss_get();
179 }
180 
181 #elif defined(OPENSSL_DOES_NOT_FORK)
182 
183 // These platforms are guaranteed not to fork, and therefore do not require
184 // fork detection support. Returning a constant non zero value makes BoringSSL
185 // assume address space duplication is not a concern and adding entropy to
186 // every RAND_bytes call is not needed.
CRYPTO_get_fork_generation(void)187 uint64_t CRYPTO_get_fork_generation(void) { return 0xc0ffee; }
188 
189 #else
190 
191 // These platforms may fork, but we do not have a mitigation mechanism in
192 // place.  Returning a constant zero value makes BoringSSL assume that address
193 // space duplication could have occured on any call entropy must be added to
194 // every RAND_bytes call.
CRYPTO_get_fork_generation(void)195 uint64_t CRYPTO_get_fork_generation(void) { return 0; }
196 
197 #endif
198