1 // Copyright 2014 The BoringSSL Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #if !defined(_GNU_SOURCE)
16 #define _GNU_SOURCE  // needed for syscall() on Linux.
17 #endif
18 
19 #include <openssl/rand.h>
20 
21 #include "../bcm_support.h"
22 #include "internal.h"
23 
24 #if defined(OPENSSL_RAND_URANDOM)
25 
26 #include <assert.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <unistd.h>
32 
33 #if defined(OPENSSL_LINUX)
34 #if defined(BORINGSSL_FIPS)
35 #include <linux/random.h>
36 #include <sys/ioctl.h>
37 #endif
38 #include <sys/syscall.h>
39 
40 #if defined(OPENSSL_ANDROID)
41 #include <sys/system_properties.h>
42 #endif
43 
44 #if !defined(OPENSSL_ANDROID)
45 #define OPENSSL_HAS_GETAUXVAL
46 #endif
47 // glibc prior to 2.16 does not have getauxval and sys/auxv.h. Android has some
48 // host builds (i.e. not building for Android itself, so |OPENSSL_ANDROID| is
49 // unset) which are still using a 2.15 sysroot.
50 //
51 // TODO(davidben): Remove this once Android updates their sysroot.
52 #if defined(__GLIBC_PREREQ)
53 #if !__GLIBC_PREREQ(2, 16)
54 #undef OPENSSL_HAS_GETAUXVAL
55 #endif
56 #endif
57 #if defined(OPENSSL_HAS_GETAUXVAL)
58 #include <sys/auxv.h>
59 #endif
60 #endif  // OPENSSL_LINUX
61 
62 #include <openssl/mem.h>
63 
64 #include "../internal.h"
65 #include "getrandom_fillin.h"
66 
67 
68 #if defined(USE_NR_getrandom)
69 
70 #if defined(OPENSSL_MSAN)
71 extern "C" {
72 void __msan_unpoison(void *, size_t);
73 }
74 #endif
75 
boringssl_getrandom(void * buf,size_t buf_len,unsigned flags)76 static ssize_t boringssl_getrandom(void *buf, size_t buf_len, unsigned flags) {
77   ssize_t ret;
78   do {
79     ret = syscall(__NR_getrandom, buf, buf_len, flags);
80   } while (ret == -1 && errno == EINTR);
81 
82 #if defined(OPENSSL_MSAN)
83   if (ret > 0) {
84     // MSAN doesn't recognise |syscall| and thus doesn't notice that we have
85     // initialised the output buffer.
86     __msan_unpoison(buf, ret);
87   }
88 #endif  // OPENSSL_MSAN
89 
90   return ret;
91 }
92 
93 #endif  // USE_NR_getrandom
94 
95 // kHaveGetrandom in |urandom_fd| signals that |getrandom| or |getentropy| is
96 // available and should be used instead.
97 static const int kHaveGetrandom = -3;
98 
99 // urandom_fd is a file descriptor to /dev/urandom. It's protected by |once|.
100 static int urandom_fd;
101 
102 #if defined(USE_NR_getrandom)
103 
104 // getrandom_ready is one if |getrandom| had been initialized by the time
105 // |init_once| was called and zero otherwise.
106 static int getrandom_ready;
107 
108 // extra_getrandom_flags_for_seed contains a value that is ORed into the flags
109 // for getrandom() when reading entropy for a seed.
110 static int extra_getrandom_flags_for_seed;
111 
112 // On Android, check a system property to decide whether to set
113 // |extra_getrandom_flags_for_seed| otherwise they will default to zero.  If
114 // ro.oem_boringcrypto_hwrand is true then |extra_getrandom_flags_for_seed| will
115 // be set to GRND_RANDOM, causing all random data to be drawn from the same
116 // source as /dev/random.
maybe_set_extra_getrandom_flags(void)117 static void maybe_set_extra_getrandom_flags(void) {
118 #if defined(BORINGSSL_FIPS) && defined(OPENSSL_ANDROID)
119   char value[PROP_VALUE_MAX + 1];
120   int length = __system_property_get("ro.boringcrypto.hwrand", value);
121   if (length < 0 || length > PROP_VALUE_MAX) {
122     return;
123   }
124 
125   value[length] = 0;
126   if (OPENSSL_strcasecmp(value, "true") == 0) {
127     extra_getrandom_flags_for_seed = GRND_RANDOM;
128   }
129 #endif
130 }
131 
132 #endif  // USE_NR_getrandom
133 
134 static CRYPTO_once_t rand_once = CRYPTO_ONCE_INIT;
135 
136 // init_once initializes the state of this module to values previously
137 // requested. This is the only function that modifies |urandom_fd|, which may be
138 // read safely after calling the once.
init_once(void)139 static void init_once(void) {
140 #if defined(USE_NR_getrandom)
141   int have_getrandom;
142   uint8_t dummy;
143   ssize_t getrandom_ret =
144       boringssl_getrandom(&dummy, sizeof(dummy), GRND_NONBLOCK);
145   if (getrandom_ret == 1) {
146     getrandom_ready = 1;
147     have_getrandom = 1;
148   } else if (getrandom_ret == -1 && errno == EAGAIN) {
149     // We have getrandom, but the entropy pool has not been initialized yet.
150     have_getrandom = 1;
151   } else if (getrandom_ret == -1 && errno == ENOSYS) {
152     // Fallthrough to using /dev/urandom, below.
153     have_getrandom = 0;
154   } else {
155     // Other errors are fatal.
156     perror("getrandom");
157     abort();
158   }
159 
160   if (have_getrandom) {
161     urandom_fd = kHaveGetrandom;
162     maybe_set_extra_getrandom_flags();
163     return;
164   }
165 #endif  // USE_NR_getrandom
166 
167   // FIPS builds must support getrandom.
168   //
169   // Historically, only Android FIPS builds required getrandom, while Linux FIPS
170   // builds had a /dev/urandom fallback which used RNDGETENTCNT as a poor
171   // approximation for getrandom's blocking behavior. This is now removed, but
172   // avoid making assumptions on this removal until March 2023, in case it needs
173   // to be restored. This comment can be deleted after March 2023.
174 #if defined(BORINGSSL_FIPS)
175   perror("getrandom not found");
176   abort();
177 #endif
178 
179   int fd;
180   do {
181     fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
182   } while (fd == -1 && errno == EINTR);
183 
184   if (fd < 0) {
185     perror("failed to open /dev/urandom");
186     abort();
187   }
188 
189   urandom_fd = fd;
190 }
191 
192 static CRYPTO_once_t wait_for_entropy_once = CRYPTO_ONCE_INIT;
193 
wait_for_entropy(void)194 static void wait_for_entropy(void) {
195   int fd = urandom_fd;
196   if (fd == kHaveGetrandom) {
197     // |getrandom| and |getentropy| support blocking in |fill_with_entropy|
198     // directly. For |getrandom|, we first probe with a non-blocking call to aid
199     // debugging.
200 #if defined(USE_NR_getrandom)
201     if (getrandom_ready) {
202       // The entropy pool was already initialized in |init_once|.
203       return;
204     }
205 
206     uint8_t dummy;
207     ssize_t getrandom_ret =
208         boringssl_getrandom(&dummy, sizeof(dummy), GRND_NONBLOCK);
209     if (getrandom_ret == -1 && errno == EAGAIN) {
210       // Attempt to get the path of the current process to aid in debugging when
211       // something blocks.
212       const char *current_process = "<unknown>";
213 #if defined(OPENSSL_HAS_GETAUXVAL)
214       const unsigned long getauxval_ret = getauxval(AT_EXECFN);
215       if (getauxval_ret != 0) {
216         current_process = (const char *)getauxval_ret;
217       }
218 #endif
219 
220       fprintf(
221           stderr,
222           "%s: getrandom indicates that the entropy pool has not been "
223           "initialized. Rather than continue with poor entropy, this process "
224           "will block until entropy is available.\n",
225           current_process);
226 
227       getrandom_ret =
228           boringssl_getrandom(&dummy, sizeof(dummy), 0 /* no flags */);
229     }
230 
231     if (getrandom_ret != 1) {
232       perror("getrandom");
233       abort();
234     }
235 #endif  // USE_NR_getrandom
236     return;
237   }
238 }
239 
240 // fill_with_entropy writes |len| bytes of entropy into |out|. It returns one
241 // on success and zero on error. If |block| is one, this function will block
242 // until the entropy pool is initialized. Otherwise, this function may fail,
243 // setting |errno| to |EAGAIN| if the entropy pool has not yet been initialized.
244 // If |seed| is one, this function will OR in the value of
245 // |*extra_getrandom_flags_for_seed()| when using |getrandom|.
fill_with_entropy(uint8_t * out,size_t len,int block,int seed)246 static int fill_with_entropy(uint8_t *out, size_t len, int block, int seed) {
247   if (len == 0) {
248     return 1;
249   }
250 
251 #if defined(USE_NR_getrandom) || defined(FREEBSD_GETRANDOM)
252   int getrandom_flags = 0;
253   if (!block) {
254     getrandom_flags |= GRND_NONBLOCK;
255   }
256 #endif
257 
258 #if defined(USE_NR_getrandom)
259   if (seed) {
260     getrandom_flags |= extra_getrandom_flags_for_seed;
261   }
262 #endif
263 
264   CRYPTO_init_sysrand();
265   if (block) {
266     CRYPTO_once(&wait_for_entropy_once, wait_for_entropy);
267   }
268 
269   // Clear |errno| so it has defined value if |read| or |getrandom|
270   // "successfully" returns zero.
271   errno = 0;
272   while (len > 0) {
273     ssize_t r;
274 
275     if (urandom_fd == kHaveGetrandom) {
276 #if defined(USE_NR_getrandom)
277       r = boringssl_getrandom(out, len, getrandom_flags);
278 #else  // USE_NR_getrandom
279       fprintf(stderr, "urandom fd corrupt.\n");
280       abort();
281 #endif
282     } else {
283       do {
284         r = read(urandom_fd, out, len);
285       } while (r == -1 && errno == EINTR);
286     }
287 
288     if (r <= 0) {
289       return 0;
290     }
291     out += r;
292     len -= r;
293   }
294 
295   return 1;
296 }
297 
CRYPTO_init_sysrand(void)298 void CRYPTO_init_sysrand(void) { CRYPTO_once(&rand_once, init_once); }
299 
300 // CRYPTO_sysrand puts |requested| random bytes into |out|.
CRYPTO_sysrand(uint8_t * out,size_t requested)301 void CRYPTO_sysrand(uint8_t *out, size_t requested) {
302   if (!fill_with_entropy(out, requested, /*block=*/1, /*seed=*/0)) {
303     perror("entropy fill failed");
304     abort();
305   }
306 }
307 
CRYPTO_sysrand_for_seed(uint8_t * out,size_t requested)308 void CRYPTO_sysrand_for_seed(uint8_t *out, size_t requested) {
309   if (!fill_with_entropy(out, requested, /*block=*/1, /*seed=*/1)) {
310     perror("entropy fill failed");
311     abort();
312   }
313 }
314 
CRYPTO_sysrand_if_available(uint8_t * out,size_t requested)315 int CRYPTO_sysrand_if_available(uint8_t *out, size_t requested) {
316   if (fill_with_entropy(out, requested, /*block=*/0, /*seed=*/0)) {
317     return 1;
318   } else if (errno == EAGAIN) {
319     OPENSSL_memset(out, 0, requested);
320     return 0;
321   } else {
322     perror("opportunistic entropy fill failed");
323     abort();
324   }
325 }
326 
327 #endif  // OPENSSL_RAND_URANDOM
328