diff --git a/ChangeLog b/ChangeLog index ea2a0ea4..2b0ba971 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ * 2018-05-??: Version 1.4.2 - * Bugfix: #395. Clarify that libidn2 dependency is for version 2.0.0 + * Bugfix #394: Update src/compat/getentropy_linux.c in order to + handle ENOSYS (not implemented) fallback. + Thanks Brent Blood + * Bugfix #395: Clarify that libidn2 dependency is for version 2.0.0 or higher. Thanks mire3212 * 2018-03-12: Version 1.4.1 diff --git a/src/compat/getentropy_linux.c b/src/compat/getentropy_linux.c index 37d86a8f..a1159d0c 100644 --- a/src/compat/getentropy_linux.c +++ b/src/compat/getentropy_linux.c @@ -1,4 +1,4 @@ -/* $OpenBSD: getentropy_linux.c,v 1.20 2014/07/12 15:43:49 beck Exp $ */ +/* $OpenBSD: getentropy_linux.c,v 1.45 2018/03/13 22:53:28 bcook Exp $ */ /* * Copyright (c) 2014 Theo de Raadt @@ -15,6 +15,9 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Emulation of getentropy(2) as documented at: + * http://man.openbsd.org/getentropy.2 */ #include "config.h" @@ -39,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -55,7 +59,6 @@ #include #include -#include #ifdef HAVE_GETAUXVAL #include #endif @@ -75,6 +78,7 @@ #if defined(HAVE_SSL) #define CRYPTO_SHA512_CTX SHA512_CTX #define CRYPTO_SHA512_INIT(x) SHA512_Init(x) +#define CRYPTO_SHA512_UPDATE(c, x, l) (SHA512_Update((c), (char *)(x), (l)) #define CRYPTO_SHA512_FINAL(r, c) SHA512_Final(r, c) #define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l))) #define HD(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (x))) @@ -82,6 +86,7 @@ #elif defined(HAVE_NETTLE) #define CRYPTO_SHA512_CTX struct sha512_ctx #define CRYPTO_SHA512_INIT(x) sha512_init(x) +#define CRYPTO_SHA512_UPDATE(c, x, l) (sha512_update((c), (l), (uint8_t *)(x)) #define CRYPTO_SHA512_FINAL(r, c) sha512_digest(c, SHA512_DIGEST_SIZE, r) #define HR(x, l) (sha512_update(&ctx, (l), (uint8_t *)(x))) #define HD(x) (sha512_update(&ctx, sizeof (x), (uint8_t *)&(x))) @@ -90,11 +95,8 @@ int getentropy(void *buf, size_t len); -#ifdef CAN_REFERENCE_MAIN -extern int main(int, char *argv[]); -#endif static int gotdata(char *buf, size_t len); -#ifdef SYS_getrandom +#if defined(SYS_getrandom) && defined(GRND_NONBLOCK) static int getentropy_getrandom(void *buf, size_t len); #endif static int getentropy_urandom(void *buf, size_t len); @@ -102,6 +104,7 @@ static int getentropy_urandom(void *buf, size_t len); static int getentropy_sysctl(void *buf, size_t len); #endif static int getentropy_fallback(void *buf, size_t len); +static int getentropy_phdr(struct dl_phdr_info *info, size_t size, void *data); int getentropy(void *buf, size_t len) @@ -110,18 +113,21 @@ getentropy(void *buf, size_t len) if (len > 256) { errno = EIO; - return -1; + return (-1); } -#ifdef SYS_getrandom +#if defined(SYS_getrandom) && defined(GRND_NONBLOCK) /* - * Try descriptor-less getrandom() + * Try descriptor-less getrandom(), in non-blocking mode. + * + * The design of Linux getrandom is broken. It has an + * uninitialized phase coupled with blocking behaviour, which + * is unacceptable from within a library at boot time without + * possible recovery. See http://bugs.python.org/issue26839#msg267745 */ ret = getentropy_getrandom(buf, len); if (ret != -1) return (ret); - if (errno != ENOSYS) - return (-1); #endif /* @@ -175,7 +181,7 @@ getentropy(void *buf, size_t len) * - Do the best under the circumstances.... * * This code path exists to bring light to the issue that Linux - * does not provide a failsafe API for entropy collection. + * still does not provide a failsafe API for entropy collection. * * We hope this demonstrates that Linux should either retain their * sysctl ABI, or consider providing a new failsafe API which @@ -205,11 +211,11 @@ gotdata(char *buf, size_t len) for (i = 0; i < len; ++i) any_set |= buf[i]; if (any_set == 0) - return -1; - return 0; + return (-1); + return (0); } -#ifdef SYS_getrandom +#if defined(SYS_getrandom) && defined(GRND_NONBLOCK) static int getentropy_getrandom(void *buf, size_t len) { @@ -218,7 +224,7 @@ getentropy_getrandom(void *buf, size_t len) if (len > 256) return (-1); do { - ret = syscall(SYS_getrandom, buf, len, 0); + ret = syscall(SYS_getrandom, buf, len, GRND_NONBLOCK); } while (ret == -1 && errno == EINTR); if (ret != (int)len) @@ -266,7 +272,7 @@ start: } for (i = 0; i < len; ) { size_t wanted = len - i; - ssize_t ret = read(fd, (char*)buf + i, wanted); + ssize_t ret = read(fd, (char *)buf + i, wanted); if (ret == -1) { if (errno == EAGAIN || errno == EINTR) @@ -279,11 +285,11 @@ start: close(fd); if (gotdata(buf, len) == 0) { errno = save_errno; - return 0; /* satisfied */ + return (0); /* satisfied */ } nodevrandom: errno = EIO; - return -1; + return (-1); } #ifdef SYS__sysctl @@ -314,11 +320,11 @@ getentropy_sysctl(void *buf, size_t len) } sysctlfailed: errno = EIO; - return -1; + return (-1); } #endif /* SYS__sysctl */ -static int cl[] = { +static const int cl[] = { CLOCK_REALTIME, #ifdef CLOCK_MONOTONIC CLOCK_MONOTONIC, @@ -343,6 +349,15 @@ static int cl[] = { #endif }; +static int +getentropy_phdr(struct dl_phdr_info *info, size_t size, void *data) +{ + CRYPTO_SHA512_CTX *ctx = data; + + CRYPTO_SHA512_UPDATE(ctx, &info->dlpi_addr, sizeof (info->dlpi_addr)); + return (0); +} + static int getentropy_fallback(void *buf, size_t len) { @@ -379,6 +394,8 @@ getentropy_fallback(void *buf, size_t len) cnt += (int)tv.tv_usec; } + dl_iterate_phdr(getentropy_phdr, &ctx); + for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); ii++) HX(clock_gettime(cl[ii], &ts) == -1, ts); @@ -398,9 +415,6 @@ getentropy_fallback(void *buf, size_t len) HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1, sigset); -#ifdef CAN_REFERENCE_MAIN - HF(main); /* an addr in program */ -#endif HF(getentropy); /* an addr in this library */ HF(printf); /* an addr in libc */ p = (char *)&p; @@ -525,33 +539,34 @@ getentropy_fallback(void *buf, size_t len) HD(cnt); } #ifdef HAVE_GETAUXVAL -# ifdef AT_RANDOM +#ifdef AT_RANDOM /* Not as random as you think but we take what we are given */ p = (char *) getauxval(AT_RANDOM); if (p) HR(p, 16); -# endif -# ifdef AT_SYSINFO_EHDR +#endif +#ifdef AT_SYSINFO_EHDR p = (char *) getauxval(AT_SYSINFO_EHDR); if (p) HR(p, pgs); -# endif -# ifdef AT_BASE +#endif +#ifdef AT_BASE p = (char *) getauxval(AT_BASE); if (p) HD(p); -# endif -#endif /* HAVE_GETAUXVAL */ +#endif +#endif CRYPTO_SHA512_FINAL(results, &ctx); - memcpy((char*)buf + i, results, min(sizeof(results), len - i)); + memcpy((char *)buf + i, results, min(sizeof(results), len - i)); i += min(sizeof(results), len - i); } + memset(&ctx, 0, sizeof ctx); memset(results, 0, sizeof results); if (gotdata(buf, len) == 0) { errno = save_errno; - return 0; /* satisfied */ + return (0); /* satisfied */ } errno = EIO; - return -1; + return (-1); }