diff options
Diffstat (limited to 'src/lib/libcrypto/crypto/getentropy_linux.c')
| -rw-r--r-- | src/lib/libcrypto/crypto/getentropy_linux.c | 158 |
1 files changed, 80 insertions, 78 deletions
diff --git a/src/lib/libcrypto/crypto/getentropy_linux.c b/src/lib/libcrypto/crypto/getentropy_linux.c index 1a22d2d306..993c1d2a83 100644 --- a/src/lib/libcrypto/crypto/getentropy_linux.c +++ b/src/lib/libcrypto/crypto/getentropy_linux.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: getentropy_linux.c,v 1.1 2014/06/20 19:08:11 beck Exp $ */ | 1 | /* $OpenBSD: getentropy_linux.c,v 1.2 2014/06/20 19:53:36 otto Exp $ */ |
| 2 | 2 | ||
| 3 | /* | 3 | /* |
| 4 | * Copyright (c) 2014 Theo de Raadt <deraadt@openbsd.org> | 4 | * Copyright (c) 2014 Theo de Raadt <deraadt@openbsd.org> |
| @@ -61,8 +61,86 @@ | |||
| 61 | 61 | ||
| 62 | int getentropy(void *buf, size_t len); | 62 | int getentropy(void *buf, size_t len); |
| 63 | 63 | ||
| 64 | extern int main(int, char *argv[]); | ||
| 65 | static int gotdata(char *buf, size_t len); | 64 | static int gotdata(char *buf, size_t len); |
| 65 | static int getentropy_urandom(void *buf, size_t len); | ||
| 66 | static int getentropy_sysctl(void *buf, size_t len); | ||
| 67 | static int getentropy_fallback(void *buf, size_t len); | ||
| 68 | |||
| 69 | int | ||
| 70 | getentropy(void *buf, size_t len) | ||
| 71 | { | ||
| 72 | int ret = -1; | ||
| 73 | |||
| 74 | if (len > 256) { | ||
| 75 | errno = EIO; | ||
| 76 | return -1; | ||
| 77 | } | ||
| 78 | |||
| 79 | /* | ||
| 80 | * Try to get entropy with /dev/urandom | ||
| 81 | * | ||
| 82 | * This can fail if the process is inside a chroot or if file | ||
| 83 | * descriptors are exhausted. | ||
| 84 | */ | ||
| 85 | ret = getentropy_urandom(buf, len); | ||
| 86 | if (ret != -1) | ||
| 87 | return (ret); | ||
| 88 | |||
| 89 | #ifdef RANDOM_UUID | ||
| 90 | /* | ||
| 91 | * Try to use sysctl CTL_KERN, KERN_RANDOM, RANDOM_UUID. sysctl is | ||
| 92 | * a failsafe API, so it guarantees a result. This should work | ||
| 93 | * inside a chroot, or when file descriptors are exhuasted. | ||
| 94 | * | ||
| 95 | * However this can fail if the Linux kernel removes support for sysctl. | ||
| 96 | * Starting in 2007, there have been efforts to deprecate the sysctl | ||
| 97 | * API/ABI, and push callers towards use of the chroot-unavailable | ||
| 98 | * fd-using /proc mechanism -- essentially the same problems as | ||
| 99 | * /dev/urandom. | ||
| 100 | * | ||
| 101 | * Numerous setbacks have been encountered in their deprecation | ||
| 102 | * schedule, so as of June 2014 the kernel ABI still exists. The | ||
| 103 | * sysctl() stub in libc is missing on some systems. There are | ||
| 104 | * also reports that some kernels spew messages to the console. | ||
| 105 | */ | ||
| 106 | ret = getentropy_sysctl(buf, len); | ||
| 107 | if (ret != -1) | ||
| 108 | return (ret); | ||
| 109 | #endif /* RANDOM_UUID */ | ||
| 110 | |||
| 111 | /* | ||
| 112 | * Entropy collection via /dev/urandom and sysctl have failed. | ||
| 113 | * | ||
| 114 | * No other API exists for collecting entropy. See the large | ||
| 115 | * comment block above. | ||
| 116 | * | ||
| 117 | * We have very few options: | ||
| 118 | * - Even syslog_r is unsafe to call at this low level, so | ||
| 119 | * there is no way to alert the user or program. | ||
| 120 | * - Cannot call abort() because some systems have unsafe corefiles. | ||
| 121 | * - Could raise(SIGKILL) resulting in silent program termination. | ||
| 122 | * - Return EIO, to hint that arc4random's stir function | ||
| 123 | * should raise(SIGKILL) | ||
| 124 | * - Do the best under the circumstances.... | ||
| 125 | * | ||
| 126 | * This code path exists to bring light to the issue that Linux | ||
| 127 | * does not provide a failsafe API for entropy collection. | ||
| 128 | * | ||
| 129 | * We hope this demonstrates that Linux should either retain their | ||
| 130 | * sysctl ABI, or consider providing a new failsafe API which | ||
| 131 | * works in a chroot or when file descriptors are exhausted. | ||
| 132 | */ | ||
| 133 | #undef FAIL_HARD_WHEN_LINUX_DEPRECATES_SYSCTL | ||
| 134 | #ifdef FAIL_HARD_WHEN_LINUX_DEPRECATES_SYSCTL | ||
| 135 | raise(SIGKILL); | ||
| 136 | #endif | ||
| 137 | ret = getentropy_fallback(buf, len); | ||
| 138 | if (ret != -1) | ||
| 139 | return (ret); | ||
| 140 | |||
| 141 | errno = EIO; | ||
| 142 | return (ret); | ||
| 143 | } | ||
| 66 | 144 | ||
| 67 | /* | 145 | /* |
| 68 | * XXX Should be replaced with a proper entropy measure. | 146 | * XXX Should be replaced with a proper entropy measure. |
| @@ -361,79 +439,3 @@ getentropy_fallback(void *buf, size_t len) | |||
| 361 | errno = EIO; | 439 | errno = EIO; |
| 362 | return -1; | 440 | return -1; |
| 363 | } | 441 | } |
| 364 | |||
| 365 | int | ||
| 366 | getentropy(void *buf, size_t len) | ||
| 367 | { | ||
| 368 | int ret = -1; | ||
| 369 | |||
| 370 | if (len > 256) { | ||
| 371 | errno = EIO; | ||
| 372 | return -1; | ||
| 373 | } | ||
| 374 | |||
| 375 | /* | ||
| 376 | * Try to get entropy with /dev/urandom | ||
| 377 | * | ||
| 378 | * This can fail if the process is inside a chroot or if file | ||
| 379 | * descriptors are exhausted. | ||
| 380 | */ | ||
| 381 | ret = getentropy_urandom(buf, len); | ||
| 382 | if (ret != -1) | ||
| 383 | return (ret); | ||
| 384 | |||
| 385 | #ifdef RANDOM_UUID | ||
| 386 | /* | ||
| 387 | * Try to use sysctl CTL_KERN, KERN_RANDOM, RANDOM_UUID. sysctl is | ||
| 388 | * a failsafe API, so it guarantees a result. This should work | ||
| 389 | * inside a chroot, or when file descriptors are exhuasted. | ||
| 390 | * | ||
| 391 | * However this can fail if the Linux kernel removes support for sysctl. | ||
| 392 | * Starting in 2007, there have been efforts to deprecate the sysctl | ||
| 393 | * API/ABI, and push callers towards use of the chroot-unavailable | ||
| 394 | * fd-using /proc mechanism -- essentially the same problems as | ||
| 395 | * /dev/urandom. | ||
| 396 | * | ||
| 397 | * Numerous setbacks have been encountered in their deprecation | ||
| 398 | * schedule, so as of June 2014 the kernel ABI still exists. The | ||
| 399 | * sysctl() stub in libc is missing on some systems. There are | ||
| 400 | * also reports that some kernels spew messages to the console. | ||
| 401 | */ | ||
| 402 | ret = getentropy_sysctl(buf, len); | ||
| 403 | if (ret != -1) | ||
| 404 | return (ret); | ||
| 405 | #endif /* RANDOM_UUID */ | ||
| 406 | |||
| 407 | /* | ||
| 408 | * Entropy collection via /dev/urandom and sysctl have failed. | ||
| 409 | * | ||
| 410 | * No other API exists for collecting entropy. See the large | ||
| 411 | * comment block above. | ||
| 412 | * | ||
| 413 | * We have very few options: | ||
| 414 | * - Even syslog_r is unsafe to call at this low level, so | ||
| 415 | * there is no way to alert the user or program. | ||
| 416 | * - Cannot call abort() because some systems have unsafe corefiles. | ||
| 417 | * - Could raise(SIGKILL) resulting in silent program termination. | ||
| 418 | * - Return EIO, to hint that arc4random's stir function | ||
| 419 | * should raise(SIGKILL) | ||
| 420 | * - Do the best under the circumstances.... | ||
| 421 | * | ||
| 422 | * This code path exists to bring light to the issue that Linux | ||
| 423 | * does not provide a failsafe API for entropy collection. | ||
| 424 | * | ||
| 425 | * We hope this demonstrates that Linux should either retain their | ||
| 426 | * sysctl ABI, or consider providing a new failsafe API which | ||
| 427 | * works in a chroot or when file descriptors are exhausted. | ||
| 428 | */ | ||
| 429 | #undef FAIL_HARD_WHEN_LINUX_DEPRECATES_SYSCTL | ||
| 430 | #ifdef FAIL_HARD_WHEN_LINUX_DEPRECATES_SYSCTL | ||
| 431 | raise(SIGKILL); | ||
| 432 | #endif | ||
| 433 | ret = getentropy_fallback(buf, len); | ||
| 434 | if (ret != -1) | ||
| 435 | return (ret); | ||
| 436 | |||
| 437 | errno = EIO; | ||
| 438 | return (ret); | ||
| 439 | } | ||
