dormouse / rpms / python35

Forked from rpms/python35 4 years ago
Clone
Blob Blame History Raw
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