diff --git a/Python/random.c b/Python/random.c index d203939..4c27585 100644 --- a/Python/random.c +++ b/Python/random.c @@ -76,46 +76,7 @@ win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise) 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 fatal is nonzero, call Py_FatalError() instead of raising an exception - on error. */ -static int -py_getentropy(unsigned char *buffer, Py_ssize_t size, int fatal) -{ - while (size > 0) { - Py_ssize_t len = Py_MIN(size, 256); - int res; - - if (!fatal) { - Py_BEGIN_ALLOW_THREADS - res = getentropy(buffer, len); - Py_END_ALLOW_THREADS - - if (res < 0) { - PyErr_SetFromErrno(PyExc_OSError); - return -1; - } - } - else { - res = getentropy(buffer, len); - if (res < 0) - Py_FatalError("getentropy() failed"); - } - - buffer += len; - size -= len; - } - return 0; -} - -#else +#else /* !MS_WINDOWS */ #if defined(HAVE_GETRANDOM) || defined(HAVE_GETRANDOM_SYSCALL) #define PY_GETRANDOM 1 @@ -227,6 +188,59 @@ py_getrandom(void *buffer, Py_ssize_t size, int raise) } 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 { @@ -288,7 +302,7 @@ dev_urandom_python(char *buffer, Py_ssize_t size) int fd; Py_ssize_t n; struct _Py_stat_struct st; -#ifdef PY_GETRANDOM +#if defined(PY_GETRANDOM) || defined(PY_GETENTROPY) int res; #endif @@ -297,6 +311,10 @@ dev_urandom_python(char *buffer, Py_ssize_t size) #ifdef PY_GETRANDOM res = py_getrandom(buffer, size, 1); +#elif defined(PY_GETENTROPY) + res = py_getentropy(buffer, size, 1); +#endif +#if defined(PY_GETRANDOM) || defined(PY_GETENTROPY) if (res < 0) { return -1; } @@ -376,8 +394,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): @@ -418,8 +436,6 @@ _PyOS_URandom(void *buffer, Py_ssize_t size) #ifdef MS_WINDOWS return win32_urandom((unsigned char *)buffer, size, 1); -#elif defined(PY_GETENTROPY) - return py_getentropy(buffer, size, 0); #else return dev_urandom_python((char*)buffer, size); #endif @@ -481,8 +497,6 @@ _PyRandom_Fini(void) CryptReleaseContext(hCryptProv, 0); hCryptProv = 0; } -#elif defined(PY_GETENTROPY) - /* nothing to clean */ #else dev_urandom_close(); #endif