summaryrefslogtreecommitdiff
path: root/Python
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2017-01-06 11:26:01 +0100
committerVictor Stinner <victor.stinner@gmail.com>2017-01-06 11:26:01 +0100
commit01741c248dc7a793030a2af0f19174d04537e71a (patch)
treef2f17b15dbb0501c5f534bdffa8e5bdbe3aa1535 /Python
parentf3aa440a3eb91c486875e11261af08f1fc29c12e (diff)
downloadcpython-01741c248dc7a793030a2af0f19174d04537e71a.tar.gz
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.c91
1 files changed, 47 insertions, 44 deletions
diff --git a/Python/random.c b/Python/random.c
index 32c85fc2ff..ad2c389bc8 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;