Kaydet (Commit) 2f796439 authored tarafından Victor Stinner's avatar Victor Stinner

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)
üst a49a2078
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment