[Python-checkins] cpython: py_getentropy() now supports ENOSYS, EPERM & EINTR

victor.stinner python-checkins at python.org
Fri Jan 6 05:40:37 EST 2017


https://hg.python.org/cpython/rev/4c11a01fa881
changeset:   106018:4c11a01fa881
user:        Victor Stinner <victor.stinner at gmail.com>
date:        Fri Jan 06 11:33:18 2017 +0100
summary:
  py_getentropy() now supports ENOSYS, EPERM & EINTR

Issue #29157.

files:
  Python/random.c |  42 ++++++++++++++++++++++++++++++++++--
  1 files changed, 39 insertions(+), 3 deletions(-)


diff --git a/Python/random.c b/Python/random.c
--- a/Python/random.c
+++ b/Python/random.c
@@ -183,14 +183,31 @@
 #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.
+/* Fill buffer with size pseudo-random bytes generated by getentropy():
 
-   If raise is zero, don't raise an exception on error. */
+   - Return 1 on success
+   - Return 0 if getentropy() syscall is not available (failed with ENOSYS or
+     EPERM).
+   - Raise an exception (if raise is non-zero) and return -1 on error:
+     if getentropy() failed with EINTR, raise is non-zero and the Python signal
+     handler raised an exception, or if getentropy() failed with a different
+     error.
+
+   getentropy() is retried if it failed with EINTR: interrupted by a signal. */
 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 or EPERM. */
+    static int getentropy_works = 1;
+
+    if (!getentropy_works) {
+        return 0;
+    }
+
     while (size > 0) {
+        /* getentropy() is limited to returning up to 256 bytes. Call it
+           multiple times if more bytes are requested. */
         Py_ssize_t len = Py_MIN(size, 256);
         int res;
 
@@ -204,6 +221,25 @@
         }
 
         if (res < 0) {
+            /* ENOSYS: the syscall is not supported by the running kernel.
+               EPERM: the syscall is blocked by a security policy (ex: SECCOMP)
+               or something else. */
+            if (errno == ENOSYS || errno == EPERM) {
+                getentropy_works = 0;
+                return 0;
+            }
+
+            if (errno == EINTR) {
+                if (raise) {
+                    if (PyErr_CheckSignals()) {
+                        return -1;
+                    }
+                }
+
+                /* retry getentropy() if it was interrupted by a signal */
+                continue;
+            }
+
             if (raise) {
                 PyErr_SetFromErrno(PyExc_OSError);
             }

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list