[Python-checkins] cpython (3.5): Issue #25003: On Solaris 11.3 or newer, os.urandom() now uses the getrandom()

victor.stinner python-checkins at python.org
Thu Oct 1 03:51:52 EDT 2015


https://hg.python.org/cpython/rev/835085cc28cd
changeset:   98452:835085cc28cd
branch:      3.5
parent:      98450:898a9a959927
user:        Victor Stinner <victor.stinner at gmail.com>
date:        Thu Oct 01 09:47:30 2015 +0200
summary:
  Issue #25003: On Solaris 11.3 or newer, os.urandom() now uses the getrandom()
function instead of the getentropy() function. The getentropy() function is
blocking to generate very good quality entropy, os.urandom() doesn't need such
high-quality entropy.

files:
  Lib/test/test_os.py |  16 ++++++----
  Misc/NEWS           |   5 +++
  Python/random.c     |  49 ++++++++++++++++++++++----------
  configure           |  43 ++++++++++++++++++++++++++--
  configure.ac        |  31 ++++++++++++++++++--
  pyconfig.h.in       |   3 ++
  6 files changed, 119 insertions(+), 28 deletions(-)


diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -1226,13 +1226,15 @@
         self.assertNotEqual(data1, data2)
 
 
-HAVE_GETENTROPY = (sysconfig.get_config_var('HAVE_GETENTROPY') == 1)
-HAVE_GETRANDOM = (sysconfig.get_config_var('HAVE_GETRANDOM_SYSCALL') == 1)
-
- at unittest.skipIf(HAVE_GETENTROPY,
-                 "getentropy() does not use a file descriptor")
- at unittest.skipIf(HAVE_GETRANDOM,
-                 "getrandom() does not use a file descriptor")
+# os.urandom() doesn't use a file descriptor when it is implemented with the
+# getentropy() function, the getrandom() function or the getrandom() syscall
+OS_URANDOM_DONT_USE_FD = (
+    sysconfig.get_config_var('HAVE_GETENTROPY') == 1
+    or sysconfig.get_config_var('HAVE_GETRANDOM') == 1
+    or sysconfig.get_config_var('HAVE_GETRANDOM_SYSCALL') == 1)
+
+ at unittest.skipIf(OS_URANDOM_DONT_USE_FD ,
+                 "os.random() does not use a file descriptor")
 class URandomFDTests(unittest.TestCase):
     @unittest.skipUnless(resource, "test requires the resource module")
     def test_urandom_failure(self):
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -11,6 +11,11 @@
 Core and Builtins
 -----------------
 
+- Issue #25003: On Solaris 11.3 or newer, os.urandom() now uses the
+  getrandom() function instead of the getentropy() function. The getentropy()
+  function is blocking to generate very good quality entropy, os.urandom()
+  doesn't need such high-quality entropy.
+
 - Issue #25182: The stdprinter (used as sys.stderr before the io module is
   imported at startup) now uses the backslashreplace error handler.
 
diff --git a/Python/random.c b/Python/random.c
--- a/Python/random.c
+++ b/Python/random.c
@@ -6,7 +6,9 @@
 #  ifdef HAVE_SYS_STAT_H
 #    include <sys/stat.h>
 #  endif
-#  ifdef HAVE_GETRANDOM_SYSCALL
+#  ifdef HAVE_GETRANDOM
+#    include <sys/random.h>
+#  elif defined(HAVE_GETRANDOM_SYSCALL)
 #    include <sys/syscall.h>
 #  endif
 #endif
@@ -70,7 +72,9 @@
     return 0;
 }
 
-#elif HAVE_GETENTROPY
+#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.
 
@@ -105,16 +109,19 @@
     return 0;
 }
 
-#else   /* !HAVE_GETENTROPY */
+#else
 
-#ifdef HAVE_GETRANDOM_SYSCALL
+#if defined(HAVE_GETRANDOM) || defined(HAVE_GETRANDOM_SYSCALL)
+#define PY_GETRANDOM 1
+
 static int
 py_getrandom(void *buffer, Py_ssize_t size, int raise)
 {
-    /* is getrandom() supported by the running kernel?
-     * need Linux kernel 3.17 or later */
+    /* Is getrandom() supported by the running kernel?
+     * Need Linux kernel 3.17 or newer, or Solaris 11.3 or newer */
     static int getrandom_works = 1;
-    /* Use /dev/urandom, block if the kernel has no entropy */
+    /* Use non-blocking /dev/urandom device. On Linux at boot, the getrandom()
+     * syscall blocks until /dev/urandom is initialized with enough entropy. */
     const int flags = 0;
     int n;
 
@@ -124,7 +131,18 @@
     while (0 < size) {
         errno = 0;
 
-        /* Use syscall() because the libc doesn't expose getrandom() yet, see:
+#ifdef HAVE_GETRANDOM
+        if (raise) {
+            Py_BEGIN_ALLOW_THREADS
+            n = getrandom(buffer, size, flags);
+            Py_END_ALLOW_THREADS
+        }
+        else {
+            n = getrandom(buffer, size, flags);
+        }
+#else
+        /* On Linux, use the syscall() function because the GNU libc doesn't
+         * expose the Linux getrandom() syscall yet. See:
          * https://sourceware.org/bugzilla/show_bug.cgi?id=17252 */
         if (raise) {
             Py_BEGIN_ALLOW_THREADS
@@ -134,6 +152,7 @@
         else {
             n = syscall(SYS_getrandom, buffer, size, flags);
         }
+#endif
 
         if (n < 0) {
             if (errno == ENOSYS) {
@@ -182,7 +201,7 @@
 
     assert (0 < size);
 
-#ifdef HAVE_GETRANDOM_SYSCALL
+#ifdef PY_GETRANDOM
     if (py_getrandom(buffer, size, 0) == 1)
         return;
     /* getrandom() is not supported by the running kernel, fall back
@@ -218,14 +237,14 @@
     int fd;
     Py_ssize_t n;
     struct _Py_stat_struct st;
-#ifdef HAVE_GETRANDOM_SYSCALL
+#ifdef PY_GETRANDOM
     int res;
 #endif
 
     if (size <= 0)
         return 0;
 
-#ifdef HAVE_GETRANDOM_SYSCALL
+#ifdef PY_GETRANDOM
     res = py_getrandom(buffer, size, 1);
     if (res < 0)
         return -1;
@@ -304,7 +323,7 @@
     }
 }
 
-#endif /* HAVE_GETENTROPY */
+#endif
 
 /* Fill buffer with pseudo-random bytes generated by a linear congruent
    generator (LCG):
@@ -345,7 +364,7 @@
 
 #ifdef MS_WINDOWS
     return win32_urandom((unsigned char *)buffer, size, 1);
-#elif HAVE_GETENTROPY
+#elif defined(PY_GETENTROPY)
     return py_getentropy(buffer, size, 0);
 #else
     return dev_urandom_python((char*)buffer, size);
@@ -392,7 +411,7 @@
     else {
 #ifdef MS_WINDOWS
         (void)win32_urandom(secret, secret_size, 0);
-#elif HAVE_GETENTROPY
+#elif defined(PY_GETENTROPY)
         (void)py_getentropy(secret, secret_size, 1);
 #else
         dev_urandom_noraise(secret, secret_size);
@@ -408,7 +427,7 @@
         CryptReleaseContext(hCryptProv, 0);
         hCryptProv = 0;
     }
-#elif HAVE_GETENTROPY
+#elif defined(PY_GETENTROPY)
     /* nothing to clean */
 #else
     dev_urandom_close();
diff --git a/configure b/configure
--- a/configure
+++ b/configure
@@ -16085,11 +16085,11 @@
     #include <sys/syscall.h>
 
     int main() {
+        char buffer[1];
+        const size_t buflen = sizeof(buffer);
         const int flags = 0;
-        char buffer[1];
-        int n;
         /* ignore the result, Python checks for ENOSYS at runtime */
-        (void)syscall(SYS_getrandom, buffer, sizeof(buffer), flags);
+        (void)syscall(SYS_getrandom, buffer, buflen, flags);
         return 0;
     }
 
@@ -16111,6 +16111,43 @@
 
 fi
 
+# check if the getrandom() function is available
+# the test was written for the Solaris function of <sys/random.h>
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the getrandom() function" >&5
+$as_echo_n "checking for the getrandom() function... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+    #include <sys/random.h>
+
+    int main() {
+        char buffer[1];
+        const size_t buflen = sizeof(buffer);
+        const int flags = 0;
+        /* ignore the result, Python checks for ENOSYS at runtime */
+        (void)getrandom(buffer, buflen, flags);
+        return 0;
+    }
+
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  have_getrandom=yes
+else
+  have_getrandom=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_getrandom" >&5
+$as_echo "$have_getrandom" >&6; }
+
+if test "$have_getrandom" = yes; then
+
+$as_echo "#define HAVE_GETRANDOM 1" >>confdefs.h
+
+fi
+
 # generate output files
 ac_config_files="$ac_config_files Makefile.pre Modules/Setup.config Misc/python.pc Misc/python-config.sh"
 
diff --git a/configure.ac b/configure.ac
--- a/configure.ac
+++ b/configure.ac
@@ -5154,11 +5154,11 @@
     #include <sys/syscall.h>
 
     int main() {
+        char buffer[1];
+        const size_t buflen = sizeof(buffer);
         const int flags = 0;
-        char buffer[1];
-        int n;
         /* ignore the result, Python checks for ENOSYS at runtime */
-        (void)syscall(SYS_getrandom, buffer, sizeof(buffer), flags);
+        (void)syscall(SYS_getrandom, buffer, buflen, flags);
         return 0;
     }
   ]])
@@ -5170,6 +5170,31 @@
               [Define to 1 if the Linux getrandom() syscall is available])
 fi
 
+# check if the getrandom() function is available
+# the test was written for the Solaris function of <sys/random.h>
+AC_MSG_CHECKING(for the getrandom() function)
+AC_LINK_IFELSE(
+[
+  AC_LANG_SOURCE([[
+    #include <sys/random.h>
+
+    int main() {
+        char buffer[1];
+        const size_t buflen = sizeof(buffer);
+        const int flags = 0;
+        /* ignore the result, Python checks for ENOSYS at runtime */
+        (void)getrandom(buffer, buflen, flags);
+        return 0;
+    }
+  ]])
+],[have_getrandom=yes],[have_getrandom=no])
+AC_MSG_RESULT($have_getrandom)
+
+if test "$have_getrandom" = yes; then
+    AC_DEFINE(HAVE_GETRANDOM, 1,
+              [Define to 1 if the getrandom() function is available])
+fi
+
 # generate output files
 AC_CONFIG_FILES(Makefile.pre Modules/Setup.config Misc/python.pc Misc/python-config.sh)
 AC_CONFIG_FILES([Modules/ld_so_aix], [chmod +x Modules/ld_so_aix])
diff --git a/pyconfig.h.in b/pyconfig.h.in
--- a/pyconfig.h.in
+++ b/pyconfig.h.in
@@ -395,6 +395,9 @@
 /* Define to 1 if you have the `getpwent' function. */
 #undef HAVE_GETPWENT
 
+/* Define to 1 if the getrandom() function is available */
+#undef HAVE_GETRANDOM
+
 /* Define to 1 if the Linux getrandom() syscall is available */
 #undef HAVE_GETRANDOM_SYSCALL
 

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


More information about the Python-checkins mailing list