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