diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2016-06-07 09:21:42 (GMT) |
---|---|---|
committer | Victor Stinner <victor.stinner@gmail.com> | 2016-06-07 09:21:42 (GMT) |
commit | dddf4849ec1750ca02d03b9772eff7141ba626f3 (patch) | |
tree | 1add3bb9de96020956ebf0327c163df13af1bb25 /Python | |
parent | 6827fd867b9609c405cd25568aa91df1b0d011b4 (diff) | |
download | cpython-dddf4849ec1750ca02d03b9772eff7141ba626f3.zip cpython-dddf4849ec1750ca02d03b9772eff7141ba626f3.tar.gz cpython-dddf4849ec1750ca02d03b9772eff7141ba626f3.tar.bz2 |
os.urandom() doesn't block on Linux anymore
Issue #26839: On Linux, os.urandom() now calls getrandom() with GRND_NONBLOCK
to fall back on reading /dev/urandom if the urandom entropy pool is not
initialized yet. Patch written by Colm Buckley.
Diffstat (limited to 'Python')
-rw-r--r-- | Python/random.c | 24 |
1 files changed, 21 insertions, 3 deletions
diff --git a/Python/random.c b/Python/random.c index 79157b8..ecfd44b 100644 --- a/Python/random.c +++ b/Python/random.c @@ -6,6 +6,9 @@ # ifdef HAVE_SYS_STAT_H # include <sys/stat.h> # endif +# ifdef HAVE_LINUX_RANDOM_H +# include <linux/random.h> +# endif # ifdef HAVE_GETRANDOM # include <sys/random.h> # elif defined(HAVE_GETRANDOM_SYSCALL) @@ -122,9 +125,13 @@ 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; + + /* getrandom() on Linux will block if called before the kernel has + * initialized the urandom entropy pool. This will cause Python + * to hang on startup if called very early in the boot process - + * see https://bugs.python.org/issue26839. To avoid this, use the + * GRND_NONBLOCK flag. */ + const int flags = GRND_NONBLOCK; int n; if (!getrandom_works) @@ -168,6 +175,17 @@ py_getrandom(void *buffer, Py_ssize_t size, int raise) getrandom_works = 0; return 0; } + if (errno == EAGAIN) { + /* If we failed with EAGAIN, the entropy pool was + * uninitialized. In this case, we return failure to fall + * back to reading from /dev/urandom. + * + * Note: In this case the data read will not be random so + * should not be used for cryptographic purposes. Retaining + * the existing semantics for practical purposes. */ + getrandom_works = 0; + return 0; + } if (errno == EINTR) { if (PyErr_CheckSignals()) { |