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)
This commit is contained in:
Victor Stinner 2017-01-06 11:26:01 +01:00
parent a49a2078e8
commit 2f7964393d
1 changed files with 47 additions and 44 deletions

View File

@ -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;