]> granicus.if.org Git - python/commitdiff
Issue #25003: On Solaris 11.3 or newer, os.urandom() now uses the getrandom()
authorVictor Stinner <victor.stinner@gmail.com>
Fri, 18 Sep 2015 13:38:37 +0000 (15:38 +0200)
committerVictor Stinner <victor.stinner@gmail.com>
Fri, 18 Sep 2015 13:38:37 +0000 (15:38 +0200)
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.

Misc/NEWS
Python/random.c
configure
configure.ac
pyconfig.h.in

index 827d788286022d826764e9b00613d4716d660798..77efd05f913ece74b93465a52edca7c36862e021 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,11 @@ Release date: XXXX-XX-XX
 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 #9232: Modify Python's grammar to allow trailing commas in the
   argument list of a function declaration.  For example, "def f(*, a =
   3,): pass" is now legal. Patch from Mark Dickinson.
index ea09e84a7b0d73e5160ee865c8831c9fdc7e9c1e..8f3e6d60219dadb87fdcf0ab6aecd249c636a383 100644 (file)
@@ -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 @@ win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
     return 0;
 }
 
-#elif HAVE_GETENTROPY
+#elif defined(HAVE_GETENTROPY) && !defined(sun)
+#define PY_GETENTROPY
+
 /* 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 @@ py_getentropy(unsigned char *buffer, Py_ssize_t size, int fatal)
     return 0;
 }
 
-#else   /* !HAVE_GETENTROPY */
+#else
+
+#if defined(HAVE_GETRANDOM) || defined(HAVE_GETRANDOM_SYSCALL)
+#define PY_GETRANDOM
 
-#ifdef HAVE_GETRANDOM_SYSCALL
 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 @@ py_getrandom(void *buffer, Py_ssize_t size, int raise)
     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 @@ py_getrandom(void *buffer, Py_ssize_t size, int raise)
         else {
             n = syscall(SYS_getrandom, buffer, size, flags);
         }
+#endif
 
         if (n < 0) {
             if (errno == ENOSYS) {
@@ -182,7 +201,7 @@ dev_urandom_noraise(unsigned char *buffer, Py_ssize_t size)
 
     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 @@ dev_urandom_python(char *buffer, Py_ssize_t size)
     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 @@ dev_urandom_close(void)
     }
 }
 
-#endif /* HAVE_GETENTROPY */
+#endif
 
 /* Fill buffer with pseudo-random bytes generated by a linear congruent
    generator (LCG):
@@ -345,7 +364,7 @@ _PyOS_URandom(void *buffer, Py_ssize_t size)
 
 #ifdef MS_WINDOWS
     return win32_urandom((unsigned char *)buffer, size, 1);
-#elif HAVE_GETENTROPY
+#elif PY_GETENTROPY
     return py_getentropy(buffer, size, 0);
 #else
     return dev_urandom_python((char*)buffer, size);
@@ -392,7 +411,7 @@ _PyRandom_Init(void)
     else {
 #ifdef MS_WINDOWS
         (void)win32_urandom(secret, secret_size, 0);
-#elif HAVE_GETENTROPY
+#elif PY_GETENTROPY
         (void)py_getentropy(secret, secret_size, 1);
 #else
         dev_urandom_noraise(secret, secret_size);
@@ -408,7 +427,7 @@ _PyRandom_Fini(void)
         CryptReleaseContext(hCryptProv, 0);
         hCryptProv = 0;
     }
-#elif HAVE_GETENTROPY
+#elif PY_GETENTROPY
     /* nothing to clean */
 #else
     dev_urandom_close();
index 95d953ac3dab74378378471b3b6e25f5d1a9b6b4..f7b1839c1937c4881787275b96ed797b259e4bb7 100755 (executable)
--- a/configure
+++ b/configure
@@ -16005,11 +16005,11 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
     #include <sys/syscall.h>
 
     int main() {
-        const int flags = 0;
         char buffer[1];
-        int n;
+        const size_t buflen = sizeof(buffer);
+        const int flags = 0;
         /* 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;
     }
 
@@ -16031,6 +16031,43 @@ $as_echo "#define HAVE_GETRANDOM_SYSCALL 1" >>confdefs.h
 
 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"
 
index 668234d7e2ecf366f5c061b76329039901c462ad..180a421f707fd250b66da1def1450ce809bea47f 100644 (file)
@@ -5111,11 +5111,11 @@ AC_LINK_IFELSE(
     #include <sys/syscall.h>
 
     int main() {
-        const int flags = 0;
         char buffer[1];
-        int n;
+        const size_t buflen = sizeof(buffer);
+        const int flags = 0;
         /* 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;
     }
   ]])
@@ -5127,6 +5127,31 @@ if test "$have_getrandom_syscall" = yes; then
               [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])
index 0d40c94cd4c0a36057ef6658e00bb3ae0a5acafa..b0cafb318574c9ddf2ff1e296fbeabde90e76353 100644 (file)
 /* 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