mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 10:26:02 +00:00 
			
		
		
		
	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
					
				
					 7 changed files with 48 additions and 12 deletions
				
			
		|  | @ -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()) { | ||||||
|  |  | ||||||
							
								
								
									
										8
									
								
								configure
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								configure
									
										
									
									
										vendored
									
									
								
							|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Victor Stinner
						Victor Stinner