| 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 | |
| 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|. |
| 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 | |
| 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. |
| 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|. |
| 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 | |