• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2014, 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 syscall() on Linux.
17 #endif
18 
19 #include <openssl/rand.h>
20 
21 #if !defined(OPENSSL_WINDOWS) && !defined(OPENSSL_FUCHSIA) && \
22     !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE) && !defined(OPENSSL_TRUSTY)
23 
24 #include <assert.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <unistd.h>
30 
31 #if defined(OPENSSL_LINUX)
32 #if defined(BORINGSSL_FIPS)
33 #include <linux/random.h>
34 #include <sys/ioctl.h>
35 #endif
36 #include <sys/syscall.h>
37 
38 #if !defined(OPENSSL_ANDROID)
39 #define OPENSSL_HAS_GETAUXVAL
40 #endif
41 // glibc prior to 2.16 does not have getauxval and sys/auxv.h. Android has some
42 // host builds (i.e. not building for Android itself, so |OPENSSL_ANDROID| is
43 // unset) which are still using a 2.15 sysroot.
44 //
45 // TODO(davidben): Remove this once Android updates their sysroot.
46 #if defined(__GLIBC_PREREQ)
47 #if !__GLIBC_PREREQ(2, 16)
48 #undef OPENSSL_HAS_GETAUXVAL
49 #endif
50 #endif
51 #if defined(OPENSSL_HAS_GETAUXVAL)
52 #include <sys/auxv.h>
53 #endif
54 #endif  // OPENSSL_LINUX
55 
56 #include <openssl/thread.h>
57 #include <openssl/mem.h>
58 
59 #include "internal.h"
60 #include "../delocate.h"
61 #include "../../internal.h"
62 
63 
64 #if defined(OPENSSL_LINUX)
65 
66 #if defined(OPENSSL_X86_64)
67 #define EXPECTED_NR_getrandom 318
68 #elif defined(OPENSSL_X86)
69 #define EXPECTED_NR_getrandom 355
70 #elif defined(OPENSSL_AARCH64)
71 #define EXPECTED_NR_getrandom 278
72 #elif defined(OPENSSL_ARM)
73 #define EXPECTED_NR_getrandom 384
74 #elif defined(OPENSSL_PPC64LE)
75 #define EXPECTED_NR_getrandom 359
76 #endif
77 
78 #if defined(EXPECTED_NR_getrandom)
79 #define USE_NR_getrandom
80 
81 #if defined(__NR_getrandom)
82 
83 #if __NR_getrandom != EXPECTED_NR_getrandom
84 #error "system call number for getrandom is not the expected value"
85 #endif
86 
87 #else  // __NR_getrandom
88 
89 #define __NR_getrandom EXPECTED_NR_getrandom
90 
91 #endif  // __NR_getrandom
92 
93 #if defined(OPENSSL_MSAN)
94 void __msan_unpoison(void *, size_t);
95 #endif
96 
boringssl_getrandom(void * buf,size_t buf_len,unsigned flags)97 static ssize_t boringssl_getrandom(void *buf, size_t buf_len, unsigned flags) {
98   ssize_t ret;
99   do {
100     ret = syscall(__NR_getrandom, buf, buf_len, flags);
101   } while (ret == -1 && errno == EINTR);
102 
103 #if defined(OPENSSL_MSAN)
104   if (ret > 0) {
105     // MSAN doesn't recognise |syscall| and thus doesn't notice that we have
106     // initialised the output buffer.
107     __msan_unpoison(buf, ret);
108   }
109 #endif  // OPENSSL_MSAN
110 
111   return ret;
112 }
113 
114 #endif  // EXPECTED_NR_getrandom
115 
116 #if !defined(GRND_NONBLOCK)
117 #define GRND_NONBLOCK 1
118 #endif
119 
120 #endif  // OPENSSL_LINUX
121 
122 // rand_lock is used to protect the |*_requested| variables.
123 DEFINE_STATIC_MUTEX(rand_lock)
124 
125 // The following constants are magic values of |urandom_fd|.
126 static const int kUnset = 0;
127 static const int kHaveGetrandom = -3;
128 
129 // urandom_fd_requested is set by |RAND_set_urandom_fd|. It's protected by
130 // |rand_lock|.
DEFINE_BSS_GET(int,urandom_fd_requested)131 DEFINE_BSS_GET(int, urandom_fd_requested)
132 
133 // urandom_fd is a file descriptor to /dev/urandom. It's protected by |once|.
134 DEFINE_BSS_GET(int, urandom_fd)
135 
136 DEFINE_STATIC_ONCE(rand_once)
137 
138 // init_once initializes the state of this module to values previously
139 // requested. This is the only function that modifies |urandom_fd| and
140 // |urandom_buffering|, whose values may be read safely after calling the
141 // once.
142 static void init_once(void) {
143   CRYPTO_STATIC_MUTEX_lock_read(rand_lock_bss_get());
144   int fd = *urandom_fd_requested_bss_get();
145   CRYPTO_STATIC_MUTEX_unlock_read(rand_lock_bss_get());
146 
147 #if defined(USE_NR_getrandom)
148   uint8_t dummy;
149   ssize_t getrandom_ret =
150       boringssl_getrandom(&dummy, sizeof(dummy), GRND_NONBLOCK);
151 
152   if (getrandom_ret == -1 && errno == EAGAIN) {
153     // Attempt to get the path of the current process to aid in debugging when
154     // something blocks.
155     const char *current_process = "<unknown>";
156 #if defined(OPENSSL_HAS_GETAUXVAL)
157     const unsigned long getauxval_ret = getauxval(AT_EXECFN);
158     if (getauxval_ret != 0) {
159       current_process = (const char *)getauxval_ret;
160     }
161 #endif
162 
163     fprintf(stderr,
164             "%s: getrandom indicates that the entropy pool has not been "
165             "initialized. Rather than continue with poor entropy, this process "
166             "will block until entropy is available.\n",
167             current_process);
168 
169     getrandom_ret =
170         boringssl_getrandom(&dummy, sizeof(dummy), 0 /* no flags */);
171   }
172 
173   if (getrandom_ret == 1) {
174     *urandom_fd_bss_get() = kHaveGetrandom;
175     return;
176   }
177 
178   // Ignore ENOSYS and fallthrough to using /dev/urandom, below. Otherwise it's
179   // a fatal error.
180   if (getrandom_ret != -1 || errno != ENOSYS) {
181     perror("getrandom");
182     abort();
183   }
184 #endif  // USE_NR_getrandom
185 
186   if (fd == kUnset) {
187     do {
188       fd = open("/dev/urandom", O_RDONLY);
189     } while (fd == -1 && errno == EINTR);
190   }
191 
192   if (fd < 0) {
193     perror("failed to open /dev/urandom");
194     abort();
195   }
196 
197   assert(kUnset == 0);
198   if (fd == kUnset) {
199     // Because we want to keep |urandom_fd| in the BSS, we have to initialise
200     // it to zero. But zero is a valid file descriptor too. Thus if open
201     // returns zero for /dev/urandom, we dup it to get a non-zero number.
202     fd = dup(fd);
203     close(kUnset);
204 
205     if (fd <= 0) {
206       perror("failed to dup /dev/urandom fd");
207       abort();
208     }
209   }
210 
211 #if defined(BORINGSSL_FIPS)
212   // In FIPS mode we ensure that the kernel has sufficient entropy before
213   // continuing. This is automatically handled by getrandom, which requires
214   // that the entropy pool has been initialised, but for urandom we have to
215   // poll.
216   for (;;) {
217     int entropy_bits;
218     if (ioctl(fd, RNDGETENTCNT, &entropy_bits)) {
219       fprintf(stderr,
220               "RNDGETENTCNT on /dev/urandom failed. We cannot continue in this "
221               "case when in FIPS mode.\n");
222       abort();
223     }
224 
225     static const int kBitsNeeded = 256;
226     if (entropy_bits >= kBitsNeeded) {
227       break;
228     }
229 
230     usleep(250000);
231   }
232 #endif
233 
234   int flags = fcntl(fd, F_GETFD);
235   if (flags == -1) {
236     // Native Client doesn't implement |fcntl|.
237     if (errno != ENOSYS) {
238       perror("failed to get flags from urandom fd");
239       abort();
240     }
241   } else {
242     flags |= FD_CLOEXEC;
243     if (fcntl(fd, F_SETFD, flags) == -1) {
244       perror("failed to set FD_CLOEXEC on urandom fd");
245       abort();
246     }
247   }
248   *urandom_fd_bss_get() = fd;
249 }
250 
RAND_set_urandom_fd(int fd)251 void RAND_set_urandom_fd(int fd) {
252   fd = dup(fd);
253   if (fd < 0) {
254     perror("failed to dup supplied urandom fd");
255     abort();
256   }
257 
258   assert(kUnset == 0);
259   if (fd == kUnset) {
260     // Because we want to keep |urandom_fd| in the BSS, we have to initialise
261     // it to zero. But zero is a valid file descriptor too. Thus if dup
262     // returned zero we dup it again to get a non-zero number.
263     fd = dup(fd);
264     close(kUnset);
265 
266     if (fd <= 0) {
267       perror("failed to dup supplied urandom fd");
268       abort();
269     }
270   }
271 
272   CRYPTO_STATIC_MUTEX_lock_write(rand_lock_bss_get());
273   *urandom_fd_requested_bss_get() = fd;
274   CRYPTO_STATIC_MUTEX_unlock_write(rand_lock_bss_get());
275 
276   CRYPTO_once(rand_once_bss_get(), init_once);
277   if (*urandom_fd_bss_get() == kHaveGetrandom) {
278     close(fd);
279   } else if (*urandom_fd_bss_get() != fd) {
280     fprintf(stderr, "RAND_set_urandom_fd called after initialisation.\n");
281     abort();
282   }
283 }
284 
285 // fill_with_entropy writes |len| bytes of entropy into |out|. It returns one
286 // on success and zero on error.
fill_with_entropy(uint8_t * out,size_t len)287 static char fill_with_entropy(uint8_t *out, size_t len) {
288   while (len > 0) {
289     ssize_t r;
290 
291     if (*urandom_fd_bss_get() == kHaveGetrandom) {
292 #if defined(USE_NR_getrandom)
293       r = boringssl_getrandom(out, len, 0 /* no flags */);
294 #else  // USE_NR_getrandom
295       fprintf(stderr, "urandom fd corrupt.\n");
296       abort();
297 #endif
298     } else {
299       do {
300         r = read(*urandom_fd_bss_get(), out, len);
301       } while (r == -1 && errno == EINTR);
302     }
303 
304     if (r <= 0) {
305       return 0;
306     }
307     out += r;
308     len -= r;
309   }
310 
311   return 1;
312 }
313 
314 // CRYPTO_sysrand puts |requested| random bytes into |out|.
CRYPTO_sysrand(uint8_t * out,size_t requested)315 void CRYPTO_sysrand(uint8_t *out, size_t requested) {
316   if (requested == 0) {
317     return;
318   }
319 
320   CRYPTO_once(rand_once_bss_get(), init_once);
321 
322   if (!fill_with_entropy(out, requested)) {
323     perror("entropy fill failed");
324     abort();
325   }
326 
327 #if defined(BORINGSSL_FIPS_BREAK_CRNG)
328   // This breaks the "continuous random number generator test" defined in FIPS
329   // 140-2, section 4.9.2, and implemented in rand_get_seed().
330   OPENSSL_memset(out, 0, requested);
331 #endif
332 }
333 
334 #endif /* !OPENSSL_WINDOWS && !defined(OPENSSL_FUCHSIA) && \
335           !BORINGSSL_UNSAFE_DETERMINISTIC_MODE && !OPENSSL_TRUSTY */
336