]> granicus.if.org Git - python/commitdiff
Merge 3.4 (os.urandom)
authorVictor Stinner <victor.stinner@gmail.com>
Thu, 1 Oct 2015 08:00:23 +0000 (10:00 +0200)
committerVictor Stinner <victor.stinner@gmail.com>
Thu, 1 Oct 2015 08:00:23 +0000 (10:00 +0200)
1  2 
Python/random.c

diff --cc Python/random.c
index 1d57b1b6621cb493ca3c32213e6094284245a75a,af3d0bd0d57eff17819929e54de4fdc26a953137..772bfef0e87606e99459c9d0d2f45bafae18168d
@@@ -110,80 -107,6 +110,82 @@@ py_getentropy(unsigned char *buffer, Py
  }
  
  #else
 +
++/* Issue #25003: Don' use getentropy() on Solaris (available since
++ * Solaris 11.3), it is blocking whereas os.urandom() should not block. */
 +#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 newer, or Solaris 11.3 or newer */
 +    static int getrandom_works = 1;
 +    /* 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;
 +
 +    if (!getrandom_works)
 +        return 0;
 +
 +    while (0 < size) {
 +        errno = 0;
 +
 +#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
 +            n = syscall(SYS_getrandom, buffer, size, flags);
 +            Py_END_ALLOW_THREADS
 +        }
 +        else {
 +            n = syscall(SYS_getrandom, buffer, size, flags);
 +        }
 +#endif
 +
 +        if (n < 0) {
 +            if (errno == ENOSYS) {
 +                getrandom_works = 0;
 +                return 0;
 +            }
 +
 +            if (errno == EINTR) {
 +                if (PyErr_CheckSignals()) {
 +                    if (!raise)
 +                        Py_FatalError("getrandom() interrupted by a signal");
 +                    return -1;
 +                }
 +                /* retry getrandom() */
 +                continue;
 +            }
 +
 +            if (raise)
 +                PyErr_SetFromErrno(PyExc_OSError);
 +            else
 +                Py_FatalError("getrandom() failed");
 +            return -1;
 +        }
 +
 +        buffer += n;
 +        size -= n;
 +    }
 +    return 1;
 +}
 +#endif
 +
  static struct {
      int fd;
      dev_t st_dev;