• 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)
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 #include <sys/syscall.h>
33 #endif
34 
35 #include <openssl/thread.h>
36 #include <openssl/mem.h>
37 
38 #include "internal.h"
39 #include "../internal.h"
40 
41 
42 #if defined(OPENSSL_LINUX)
43 
44 #if defined(OPENSSL_X86_64)
45 #define EXPECTED_SYS_getrandom 318
46 #elif defined(OPENSSL_X86)
47 #define EXPECTED_SYS_getrandom 355
48 #elif defined(OPENSSL_AARCH64)
49 #define EXPECTED_SYS_getrandom 278
50 #elif defined(OPENSSL_ARM)
51 #define EXPECTED_SYS_getrandom 384
52 #elif defined(OPENSSL_PPC64LE)
53 #define EXPECTED_SYS_getrandom 359
54 #endif
55 
56 #if defined(EXPECTED_SYS_getrandom)
57 #define USE_SYS_getrandom
58 
59 #if defined(SYS_getrandom)
60 
61 #if SYS_getrandom != EXPECTED_SYS_getrandom
62 #error "system call number for getrandom is not the expected value"
63 #endif
64 
65 #else  /* SYS_getrandom */
66 
67 #define SYS_getrandom EXPECTED_SYS_getrandom
68 
69 #endif  /* SYS_getrandom */
70 
71 #endif /* EXPECTED_SYS_getrandom */
72 
73 #if !defined(GRND_NONBLOCK)
74 #define GRND_NONBLOCK 1
75 #endif
76 
77 #endif  /* OPENSSL_LINUX */
78 
79 /* This file implements a PRNG by reading from /dev/urandom, optionally with a
80  * buffer, which is unsafe across |fork|. */
81 
82 #define BUF_SIZE 4096
83 
84 /* rand_buffer contains unused, random bytes, some of which may have been
85  * consumed already. */
86 struct rand_buffer {
87   size_t used;
88   uint8_t rand[BUF_SIZE];
89 };
90 
91 /* requested_lock is used to protect the |*_requested| variables. */
92 static struct CRYPTO_STATIC_MUTEX requested_lock = CRYPTO_STATIC_MUTEX_INIT;
93 
94 /* The following constants are magic values of |urandom_fd|. */
95 static const int kUnset = -2;
96 static const int kHaveGetrandom = -3;
97 
98 /* urandom_fd_requested is set by |RAND_set_urandom_fd|. It's protected by
99  * |requested_lock|. */
100 static int urandom_fd_requested = -2 /* kUnset */;
101 
102 /* urandom_fd is a file descriptor to /dev/urandom. It's protected by |once|. */
103 static int urandom_fd = -2 /* kUnset */;
104 
105 /* urandom_buffering_requested is set by |RAND_enable_fork_unsafe_buffering|.
106  * It's protected by |requested_lock|. */
107 static int urandom_buffering_requested = 0;
108 
109 /* urandom_buffering controls whether buffering is enabled (1) or not (0). This
110  * is protected by |once|. */
111 static int urandom_buffering = 0;
112 
113 static CRYPTO_once_t once = CRYPTO_ONCE_INIT;
114 
115 /* init_once initializes the state of this module to values previously
116  * requested. This is the only function that modifies |urandom_fd| and
117  * |urandom_buffering|, whose values may be read safely after calling the
118  * once. */
init_once(void)119 static void init_once(void) {
120   CRYPTO_STATIC_MUTEX_lock_read(&requested_lock);
121   urandom_buffering = urandom_buffering_requested;
122   int fd = urandom_fd_requested;
123   CRYPTO_STATIC_MUTEX_unlock_read(&requested_lock);
124 
125 #if defined(USE_SYS_getrandom)
126   uint8_t dummy;
127   long getrandom_ret =
128       syscall(SYS_getrandom, &dummy, sizeof(dummy), GRND_NONBLOCK);
129 
130   if (getrandom_ret == 1) {
131     urandom_fd = kHaveGetrandom;
132     return;
133   } else if (getrandom_ret == -1 && errno == EAGAIN) {
134     fprintf(stderr,
135             "getrandom indicates that the entropy pool has not been "
136             "initialized. Rather than continue with poor entropy, this process "
137             "will block until entropy is available.\n");
138     do {
139       getrandom_ret =
140           syscall(SYS_getrandom, &dummy, sizeof(dummy), 0 /* no flags */);
141     } while (getrandom_ret == -1 && errno == EINTR);
142 
143     if (getrandom_ret == 1) {
144       urandom_fd = kHaveGetrandom;
145       return;
146     }
147   }
148 #endif  /* USE_SYS_getrandom */
149 
150   if (fd == kUnset) {
151     do {
152       fd = open("/dev/urandom", O_RDONLY);
153     } while (fd == -1 && errno == EINTR);
154   }
155 
156   if (fd < 0) {
157     abort();
158   }
159 
160   int flags = fcntl(fd, F_GETFD);
161   if (flags == -1) {
162     /* Native Client doesn't implement |fcntl|. */
163     if (errno != ENOSYS) {
164       abort();
165     }
166   } else {
167     flags |= FD_CLOEXEC;
168     if (fcntl(fd, F_SETFD, flags) == -1) {
169       abort();
170     }
171   }
172   urandom_fd = fd;
173 }
174 
RAND_set_urandom_fd(int fd)175 void RAND_set_urandom_fd(int fd) {
176   fd = dup(fd);
177   if (fd < 0) {
178     abort();
179   }
180 
181   CRYPTO_STATIC_MUTEX_lock_write(&requested_lock);
182   urandom_fd_requested = fd;
183   CRYPTO_STATIC_MUTEX_unlock_write(&requested_lock);
184 
185   CRYPTO_once(&once, init_once);
186   if (urandom_fd == kHaveGetrandom) {
187     close(fd);
188   } else if (urandom_fd != fd) {
189     abort();  // Already initialized.
190   }
191 }
192 
RAND_enable_fork_unsafe_buffering(int fd)193 void RAND_enable_fork_unsafe_buffering(int fd) {
194   if (fd >= 0) {
195     fd = dup(fd);
196     if (fd < 0) {
197       abort();
198     }
199   } else {
200     fd = kUnset;
201   }
202 
203   CRYPTO_STATIC_MUTEX_lock_write(&requested_lock);
204   urandom_buffering_requested = 1;
205   urandom_fd_requested = fd;
206   CRYPTO_STATIC_MUTEX_unlock_write(&requested_lock);
207 
208   CRYPTO_once(&once, init_once);
209   if (urandom_buffering != 1) {
210     abort();  // Already initialized
211   }
212 
213   if (fd >= 0) {
214     if (urandom_fd == kHaveGetrandom) {
215       close(fd);
216     } else if (urandom_fd != fd) {
217       abort();  // Already initialized.
218     }
219   }
220 }
221 
get_thread_local_buffer(void)222 static struct rand_buffer *get_thread_local_buffer(void) {
223   struct rand_buffer *buf =
224       CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_URANDOM_BUF);
225   if (buf != NULL) {
226     return buf;
227   }
228 
229   buf = OPENSSL_malloc(sizeof(struct rand_buffer));
230   if (buf == NULL) {
231     return NULL;
232   }
233   buf->used = BUF_SIZE;  /* To trigger a |fill_with_entropy| on first use. */
234   if (!CRYPTO_set_thread_local(OPENSSL_THREAD_LOCAL_URANDOM_BUF, buf,
235                                OPENSSL_free)) {
236     OPENSSL_free(buf);
237     return NULL;
238   }
239 
240   return buf;
241 }
242 
243 #if defined(USE_SYS_getrandom) && defined(__has_feature)
244 #if __has_feature(memory_sanitizer)
245 void __msan_unpoison(void *, size_t);
246 #endif
247 #endif
248 
249 /* fill_with_entropy writes |len| bytes of entropy into |out|. It returns one
250  * on success and zero on error. */
fill_with_entropy(uint8_t * out,size_t len)251 static char fill_with_entropy(uint8_t *out, size_t len) {
252   while (len > 0) {
253     ssize_t r;
254 
255     if (urandom_fd == kHaveGetrandom) {
256 #if defined(USE_SYS_getrandom)
257       do {
258         r = syscall(SYS_getrandom, out, len, 0 /* no flags */);
259       } while (r == -1 && errno == EINTR);
260 
261 #if defined(__has_feature)
262 #if __has_feature(memory_sanitizer)
263       if (r > 0) {
264         /* MSAN doesn't recognise |syscall| and thus doesn't notice that we
265          * have initialised the output buffer. */
266         __msan_unpoison(out, r);
267       }
268 #endif /* memory_sanitizer */
269 #endif /*__has_feature */
270 
271 #else /* USE_SYS_getrandom */
272       abort();
273 #endif
274     } else {
275       do {
276         r = read(urandom_fd, out, len);
277       } while (r == -1 && errno == EINTR);
278     }
279 
280     if (r <= 0) {
281       return 0;
282     }
283     out += r;
284     len -= r;
285   }
286 
287   return 1;
288 }
289 
290 /* read_from_buffer reads |requested| random bytes from the buffer into |out|,
291  * refilling it if necessary to satisfy the request. */
read_from_buffer(struct rand_buffer * buf,uint8_t * out,size_t requested)292 static void read_from_buffer(struct rand_buffer *buf,
293                              uint8_t *out, size_t requested) {
294   size_t remaining = BUF_SIZE - buf->used;
295 
296   while (requested > remaining) {
297     OPENSSL_memcpy(out, &buf->rand[buf->used], remaining);
298     buf->used += remaining;
299     out += remaining;
300     requested -= remaining;
301 
302     if (!fill_with_entropy(buf->rand, BUF_SIZE)) {
303       abort();
304       return;
305     }
306     buf->used = 0;
307     remaining = BUF_SIZE;
308   }
309 
310   OPENSSL_memcpy(out, &buf->rand[buf->used], requested);
311   buf->used += requested;
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(&once, init_once);
321   if (urandom_buffering && requested < BUF_SIZE) {
322     struct rand_buffer *buf = get_thread_local_buffer();
323     if (buf != NULL) {
324       read_from_buffer(buf, out, requested);
325       return;
326     }
327   }
328 
329   if (!fill_with_entropy(out, requested)) {
330     abort();
331   }
332 }
333 
334 #endif /* !OPENSSL_WINDOWS && !defined(OPENSSL_FUCHSIA) && \
335           !BORINGSSL_UNSAFE_DETERMINISTIC_MODE */
336