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.
This commit is contained in:
parent
6827fd867b
commit
dddf4849ec
|
@ -3733,14 +3733,21 @@ Miscellaneous Functions
|
||||||
|
|
||||||
This function returns random bytes from an OS-specific randomness source. The
|
This function returns random bytes from an OS-specific randomness source. The
|
||||||
returned data should be unpredictable enough for cryptographic applications,
|
returned data should be unpredictable enough for cryptographic applications,
|
||||||
though its exact quality depends on the OS implementation. On a Unix-like
|
though its exact quality depends on the OS implementation.
|
||||||
system this will query ``/dev/urandom``, and on Windows it will use
|
|
||||||
``CryptGenRandom()``. If a randomness source is not found,
|
On Linux, ``getrandom()`` syscall is used if available and the urandom
|
||||||
|
entropy pool is initialized (``getrandom()`` does not block).
|
||||||
|
On a Unix-like system this will query ``/dev/urandom``. On Windows, it
|
||||||
|
will use ``CryptGenRandom()``. If a randomness source is not found,
|
||||||
:exc:`NotImplementedError` will be raised.
|
:exc:`NotImplementedError` will be raised.
|
||||||
|
|
||||||
For an easy-to-use interface to the random number generator
|
For an easy-to-use interface to the random number generator
|
||||||
provided by your platform, please see :class:`random.SystemRandom`.
|
provided by your platform, please see :class:`random.SystemRandom`.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.5.2
|
||||||
|
On Linux, if ``getrandom()`` blocks (the urandom entropy pool is not
|
||||||
|
initialized yet), fall back on reading ``/dev/urandom``.
|
||||||
|
|
||||||
.. versionchanged:: 3.5
|
.. versionchanged:: 3.5
|
||||||
On Linux 3.17 and newer, the ``getrandom()`` syscall is now used
|
On Linux 3.17 and newer, the ``getrandom()`` syscall is now used
|
||||||
when available. On OpenBSD 5.6 and newer, the C ``getentropy()``
|
when available. On OpenBSD 5.6 and newer, the C ``getentropy()``
|
||||||
|
|
|
@ -200,6 +200,7 @@ Ian Bruntlett
|
||||||
Floris Bruynooghe
|
Floris Bruynooghe
|
||||||
Matt Bryant
|
Matt Bryant
|
||||||
Stan Bubrouski
|
Stan Bubrouski
|
||||||
|
Colm Buckley
|
||||||
Erik de Bueger
|
Erik de Bueger
|
||||||
Jan-Hein Bührman
|
Jan-Hein Bührman
|
||||||
Lars Buitinck
|
Lars Buitinck
|
||||||
|
|
|
@ -131,6 +131,10 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #26839: On Linux, :func:`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.
|
||||||
|
|
||||||
- Issue #27164: In the zlib module, allow decompressing raw Deflate streams
|
- Issue #27164: In the zlib module, allow decompressing raw Deflate streams
|
||||||
with a predefined zdict. Based on patch by Xiang Zhang.
|
with a predefined zdict. Based on patch by Xiang Zhang.
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
# ifdef HAVE_SYS_STAT_H
|
# ifdef HAVE_SYS_STAT_H
|
||||||
# include <sys/stat.h>
|
# include <sys/stat.h>
|
||||||
# endif
|
# endif
|
||||||
|
# ifdef HAVE_LINUX_RANDOM_H
|
||||||
|
# include <linux/random.h>
|
||||||
|
# endif
|
||||||
# ifdef HAVE_GETRANDOM
|
# ifdef HAVE_GETRANDOM
|
||||||
# include <sys/random.h>
|
# include <sys/random.h>
|
||||||
# elif defined(HAVE_GETRANDOM_SYSCALL)
|
# 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?
|
/* Is getrandom() supported by the running kernel?
|
||||||
* Need Linux kernel 3.17 or newer, or Solaris 11.3 or newer */
|
* Need Linux kernel 3.17 or newer, or Solaris 11.3 or newer */
|
||||||
static int getrandom_works = 1;
|
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. */
|
/* getrandom() on Linux will block if called before the kernel has
|
||||||
const int flags = 0;
|
* 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;
|
int n;
|
||||||
|
|
||||||
if (!getrandom_works)
|
if (!getrandom_works)
|
||||||
|
@ -168,6 +175,17 @@ py_getrandom(void *buffer, Py_ssize_t size, int raise)
|
||||||
getrandom_works = 0;
|
getrandom_works = 0;
|
||||||
return 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 (errno == EINTR) {
|
||||||
if (PyErr_CheckSignals()) {
|
if (PyErr_CheckSignals()) {
|
||||||
|
|
|
@ -2876,6 +2876,7 @@ fi
|
||||||
ac_config_headers="$ac_config_headers pyconfig.h"
|
ac_config_headers="$ac_config_headers pyconfig.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ac_aux_dir=
|
ac_aux_dir=
|
||||||
for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
|
for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
|
||||||
if test -f "$ac_dir/install-sh"; then
|
if test -f "$ac_dir/install-sh"; then
|
||||||
|
@ -7568,7 +7569,7 @@ sys/param.h sys/select.h sys/sendfile.h sys/socket.h sys/statvfs.h \
|
||||||
sys/stat.h sys/syscall.h sys/sys_domain.h sys/termio.h sys/time.h \
|
sys/stat.h sys/syscall.h sys/sys_domain.h sys/termio.h sys/time.h \
|
||||||
sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \
|
sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \
|
||||||
libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \
|
libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \
|
||||||
bluetooth/bluetooth.h linux/tipc.h spawn.h util.h alloca.h endian.h \
|
bluetooth/bluetooth.h linux/tipc.h linux/random.h spawn.h util.h alloca.h endian.h \
|
||||||
sys/endian.h
|
sys/endian.h
|
||||||
do :
|
do :
|
||||||
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
||||||
|
@ -16325,12 +16326,13 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
|
#include <linux/random.h>
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
char buffer[1];
|
char buffer[1];
|
||||||
const size_t buflen = sizeof(buffer);
|
const size_t buflen = sizeof(buffer);
|
||||||
const int flags = 0;
|
const int flags = GRND_NONBLOCK;
|
||||||
/* ignore the result, Python checks for ENOSYS at runtime */
|
/* ignore the result, Python checks for ENOSYS and EAGAIN at runtime */
|
||||||
(void)syscall(SYS_getrandom, buffer, buflen, flags);
|
(void)syscall(SYS_getrandom, buffer, buflen, flags);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1881,7 +1881,7 @@ sys/param.h sys/select.h sys/sendfile.h sys/socket.h sys/statvfs.h \
|
||||||
sys/stat.h sys/syscall.h sys/sys_domain.h sys/termio.h sys/time.h \
|
sys/stat.h sys/syscall.h sys/sys_domain.h sys/termio.h sys/time.h \
|
||||||
sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \
|
sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \
|
||||||
libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \
|
libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \
|
||||||
bluetooth/bluetooth.h linux/tipc.h spawn.h util.h alloca.h endian.h \
|
bluetooth/bluetooth.h linux/tipc.h linux/random.h spawn.h util.h alloca.h endian.h \
|
||||||
sys/endian.h)
|
sys/endian.h)
|
||||||
AC_HEADER_DIRENT
|
AC_HEADER_DIRENT
|
||||||
AC_HEADER_MAJOR
|
AC_HEADER_MAJOR
|
||||||
|
@ -5240,12 +5240,13 @@ AC_LINK_IFELSE(
|
||||||
AC_LANG_SOURCE([[
|
AC_LANG_SOURCE([[
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
|
#include <linux/random.h>
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
char buffer[1];
|
char buffer[1];
|
||||||
const size_t buflen = sizeof(buffer);
|
const size_t buflen = sizeof(buffer);
|
||||||
const int flags = 0;
|
const int flags = GRND_NONBLOCK;
|
||||||
/* ignore the result, Python checks for ENOSYS at runtime */
|
/* ignore the result, Python checks for ENOSYS and EAGAIN at runtime */
|
||||||
(void)syscall(SYS_getrandom, buffer, buflen, flags);
|
(void)syscall(SYS_getrandom, buffer, buflen, flags);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -546,6 +546,9 @@
|
||||||
/* Define to 1 if you have the <linux/tipc.h> header file. */
|
/* Define to 1 if you have the <linux/tipc.h> header file. */
|
||||||
#undef HAVE_LINUX_TIPC_H
|
#undef HAVE_LINUX_TIPC_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <linux/random.h> header file. */
|
||||||
|
#undef HAVE_LINUX_RANDOM_H
|
||||||
|
|
||||||
/* Define to 1 if you have the `lockf' function. */
|
/* Define to 1 if you have the `lockf' function. */
|
||||||
#undef HAVE_LOCKF
|
#undef HAVE_LOCKF
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue