diff -r ee1390c9b585 Python/random.c --- a/Python/random.c Wed Jan 04 12:02:30 2017 +0100 +++ b/Python/random.c Wed Jan 04 18:32:21 2017 +0100 @@ -77,45 +77,8 @@ win32_urandom(unsigned char *buffer, Py_ return 0; } -/* Issue #25003: Don't use getentropy() on Solaris (available since - * Solaris 11.3), it is blocking whereas os.urandom() should not block. */ -#elif defined(HAVE_GETENTROPY) && !defined(sun) -#define PY_GETENTROPY 1 - -/* Fill buffer with size pseudo-random bytes generated by getentropy(). - Return 0 on success, or raise an exception and return -1 on error. - - If raise is zero, don't raise an exception on error. */ -static int -py_getentropy(char *buffer, Py_ssize_t size, int raise) -{ - while (size > 0) { - Py_ssize_t len = Py_MIN(size, 256); - int res; +#else /* !MS_WINDOWS */ - if (raise) { - Py_BEGIN_ALLOW_THREADS - res = getentropy(buffer, len); - Py_END_ALLOW_THREADS - } - else { - res = getentropy(buffer, len); - } - - if (res < 0) { - if (raise) { - PyErr_SetFromErrno(PyExc_OSError); - } - return -1; - } - - buffer += len; - size -= len; - } - return 0; -} - -#else #if defined(HAVE_GETRANDOM) || defined(HAVE_GETRANDOM_SYSCALL) #define PY_GETRANDOM 1 @@ -217,6 +180,59 @@ py_getrandom(void *buffer, Py_ssize_t si } return 1; } + +/* Issue #25003: Don't use getentropy() on Solaris (available since + * Solaris 11.3), it is blocking whereas os.urandom() should not block. */ +#elif defined(HAVE_GETENTROPY) && !defined(sun) +#define PY_GETENTROPY 1 + +/* Fill buffer with size pseudo-random bytes generated by getentropy(). + Return 1 on success, or raise an exception and return -1 on error. + + If raise is zero, don't raise an exception on error. */ +static int +py_getentropy(char *buffer, Py_ssize_t size, int raise) +{ + /* Is getentropy() supported by the running kernel? Set to 0 if + getentropy() failed with ENOSYS. */ + static int getentropy_works = 1; + + if (!getentropy_works) { + return 0; + } + + while (size > 0) { + Py_ssize_t len = Py_MIN(size, 256); + int res; + + if (raise) { + Py_BEGIN_ALLOW_THREADS + res = getentropy(buffer, len); + Py_END_ALLOW_THREADS + } + else { + res = getentropy(buffer, len); + } + + if (res < 0) { + /* ENOSYS: the inner syscall is not supported by the running + kernel. */ + if (errno == ENOSYS) { + getentropy_works = 0; + return 0; + } + + if (raise) { + PyErr_SetFromErrno(PyExc_OSError); + } + return -1; + } + + buffer += len; + size -= len; + } + return 1; +} #endif static struct { @@ -236,7 +252,7 @@ dev_urandom(char *buffer, Py_ssize_t siz { int fd; Py_ssize_t n; -#ifdef PY_GETRANDOM +#if defined(PY_GETRANDOM) || defined(PY_GETENTROPY) int res; #endif @@ -244,17 +260,20 @@ dev_urandom(char *buffer, Py_ssize_t siz #ifdef PY_GETRANDOM res = py_getrandom(buffer, size, blocking, raise); +#elif defined(PY_GETENTROPY) + res = py_getentropy(buffer, size, raise); +#endif +#if defined(PY_GETRANDOM) || defined(PY_GETENTROPY) if (res < 0) { return -1; } if (res == 1) { return 0; } - /* getrandom() failed with ENOSYS or EPERM, - fall back on reading /dev/urandom */ + /* function failed with ENOSYS or EPERM, fall back on reading + from /dev/urandom */ #endif - if (raise) { struct _Py_stat_struct st; @@ -349,8 +368,8 @@ dev_urandom_close(void) urandom_cache.fd = -1; } } +#endif /* !MS_WINDOWS */ -#endif /* Fill buffer with pseudo-random bytes generated by a linear congruent generator (LCG): @@ -395,8 +414,6 @@ pyurandom(void *buffer, Py_ssize_t size, #ifdef MS_WINDOWS return win32_urandom((unsigned char *)buffer, size, raise); -#elif defined(PY_GETENTROPY) - return py_getentropy(buffer, size, raise); #else return dev_urandom(buffer, size, blocking, raise); #endif @@ -491,8 +508,6 @@ void CryptReleaseContext(hCryptProv, 0); hCryptProv = 0; } -#elif defined(PY_GETENTROPY) - /* nothing to clean */ #else dev_urandom_close(); #endif