diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2017-01-06 10:26:01 (GMT) |
---|---|---|
committer | Victor Stinner <victor.stinner@gmail.com> | 2017-01-06 10:26:01 (GMT) |
commit | 2f7964393d6a17e746596918c4a272d0a5009479 (patch) | |
tree | 2657f344337532e2fc060cc49d0ecb74039d5a63 /Python | |
parent | a49a2078e84b594cc42988bf181be7cc5da66f78 (diff) | |
download | cpython-2f7964393d6a17e746596918c4a272d0a5009479.zip cpython-2f7964393d6a17e746596918c4a272d0a5009479.tar.gz cpython-2f7964393d6a17e746596918c4a272d0a5009479.tar.bz2 |
Issue #29157: getrandom() is now preferred over getentropy()
The glibc now implements getentropy() on Linux using the getrandom() syscall.
But getentropy() doesn't support non-blocking mode.
Since getrandom() is tried first, it's not more needed to explicitly exclude
getentropy() on Solaris. Replace:
if defined(HAVE_GETENTROPY) && !defined(sun)
with
if defined(HAVE_GETENTROPY)
Diffstat (limited to 'Python')
-rw-r--r-- | Python/random.c | 91 |
1 files changed, 47 insertions, 44 deletions
diff --git a/Python/random.c b/Python/random.c index 32c85fc..ad2c389 100644 --- a/Python/random.c +++ b/Python/random.c @@ -79,45 +79,7 @@ win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise) #else /* !MS_WINDOWS */ -/* Issue #25003: Don't use getentropy() on Solaris (available since - * Solaris 11.3), it is blocking whereas os.urandom() should not block. */ -#if 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) -{ - 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) { - if (raise) { - PyErr_SetFromErrno(PyExc_OSError); - } - return -1; - } - - buffer += len; - size -= len; - } - return 1; -} - -#elif defined(HAVE_GETRANDOM) || defined(HAVE_GETRANDOM_SYSCALL) +#if defined(HAVE_GETRANDOM) || defined(HAVE_GETRANDOM_SYSCALL) #define PY_GETRANDOM 1 /* Call getrandom() @@ -217,7 +179,43 @@ py_getrandom(void *buffer, Py_ssize_t size, int blocking, int raise) } return 1; } -#endif /* defined(HAVE_GETRANDOM) || defined(HAVE_GETRANDOM_SYSCALL) */ + +#elif defined(HAVE_GETENTROPY) +#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) +{ + 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) { + if (raise) { + PyErr_SetFromErrno(PyExc_OSError); + } + return -1; + } + + buffer += len; + size -= len; + } + return 1; +} +#endif /* defined(HAVE_GETENTROPY) && !defined(sun) */ static struct { @@ -385,13 +383,18 @@ lcg_urandom(unsigned int x0, unsigned char *buffer, size_t size) Used sources of entropy ordered by preference, preferred source first: - CryptGenRandom() on Windows - - getentropy() function (ex: OpenBSD): call py_getentropy() - getrandom() function (ex: Linux and Solaris): call py_getrandom() + - getentropy() function (ex: OpenBSD): call py_getentropy() - /dev/urandom device Read from the /dev/urandom device if getrandom() or getentropy() function is not available or does not work. + Prefer getrandom() over getentropy() because getrandom() supports blocking + and non-blocking mode: see the PEP 524. Python requires non-blocking RNG at + startup to initialize its hash secret, but os.urandom() must block until the + system urandom is initialized (at least on Linux 3.17 and newer). + Prefer getrandom() and getentropy() over reading directly /dev/urandom because these functions don't need file descriptors and so avoid ENFILE or EMFILE errors (too many open files): see the issue #18756. @@ -439,10 +442,10 @@ pyurandom(void *buffer, Py_ssize_t size, int blocking, int raise) #else #if defined(PY_GETRANDOM) || defined(PY_GETENTROPY) -#ifdef PY_GETENTROPY - res = py_getentropy(buffer, size, raise); -#else +#ifdef PY_GETRANDOM res = py_getrandom(buffer, size, blocking, raise); +#else + res = py_getentropy(buffer, size, raise); #endif if (res < 0) { return -1; |