From: Victor Stinner Date: Thu, 1 Oct 2015 08:00:23 +0000 (+0200) Subject: Merge 3.4 (os.urandom) X-Git-Tag: v3.5.1rc1~233 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=861f0672014067dc1cd5bf239ae188140f79b07d;p=python Merge 3.4 (os.urandom) --- 861f0672014067dc1cd5bf239ae188140f79b07d diff --cc Python/random.c index 1d57b1b662,af3d0bd0d5..772bfef0e8 --- a/Python/random.c +++ b/Python/random.c @@@ -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;