@@ -77,7 +77,7 @@ win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
7777}
7878
7979/* Issue #25003: Don't use getentropy() on Solaris (available since
80- Solaris 11.3), it is blocking whereas os.urandom() should not block. */
80+ * Solaris 11.3), it is blocking whereas os.urandom() should not block. */
8181#elif defined(HAVE_GETENTROPY ) && !defined(sun )
8282#define PY_GETENTROPY 1
8383
@@ -121,31 +121,28 @@ py_getentropy(char *buffer, Py_ssize_t size, int raise)
121121
122122/* Call getrandom()
123123 - Return 1 on success
124- - Return 0 if getrandom() syscall is not available (fails with ENOSYS).
124+ - Return 0 if getrandom() syscall is not available (fails with ENOSYS)
125+ or if getrandom(GRND_NONBLOCK) fails with EAGAIN (blocking=0 and system
126+ urandom not initialized yet) and raise=0.
125127 - Raise an exception (if raise is non-zero) and return -1 on error:
126128 getrandom() failed with EINTR and the Python signal handler raised an
127129 exception, or getrandom() failed with a different error. */
128130static int
129- py_getrandom (void * buffer , Py_ssize_t size , int raise )
131+ py_getrandom (void * buffer , Py_ssize_t size , int blocking , int raise )
130132{
131- /* Is getrandom() supported by the running kernel?
132- Need Linux kernel 3.17 or newer, or Solaris 11.3 or newer */
133+ /* Is getrandom() supported by the running kernel? Set to 0 if getrandom()
134+ fails with ENOSYS. Need Linux kernel 3.17 or newer, or Solaris 11.3
135+ or newer */
133136 static int getrandom_works = 1 ;
134-
135- /* getrandom() on Linux will block if called before the kernel has
136- initialized the urandom entropy pool. This will cause Python
137- to hang on startup if called very early in the boot process -
138- see https://bugs.python.org/issue26839. To avoid this, use the
139- GRND_NONBLOCK flag. */
140- const int flags = GRND_NONBLOCK ;
141-
137+ int flags ;
142138 char * dest ;
143139 long n ;
144140
145141 if (!getrandom_works ) {
146142 return 0 ;
147143 }
148144
145+ flags = blocking ? 0 : GRND_NONBLOCK ;
149146 dest = buffer ;
150147 while (0 < size ) {
151148#ifdef sun
@@ -185,15 +182,12 @@ py_getrandom(void *buffer, Py_ssize_t size, int raise)
185182 getrandom_works = 0 ;
186183 return 0 ;
187184 }
188- if (errno == EAGAIN ) {
189- /* If we failed with EAGAIN, the entropy pool was
190- uninitialized. In this case, we return failure to fall
191- back to reading from /dev/urandom.
192-
193- Note: In this case the data read will not be random so
194- should not be used for cryptographic purposes. Retaining
195- the existing semantics for practical purposes. */
196- getrandom_works = 0 ;
185+
186+ /* getrandom(GRND_NONBLOCK) fails with EAGAIN if the system urandom
187+ is not initialiazed yet. For _PyRandom_Init(), we ignore their
188+ error and fall back on reading /dev/urandom which never blocks,
189+ even if the system urandom is not initialized yet. */
190+ if (errno == EAGAIN && !raise && !blocking ) {
197191 return 0 ;
198192 }
199193
@@ -228,13 +222,13 @@ static struct {
228222} urandom_cache = { -1 };
229223
230224
231- /* Read 'size' random bytes from getrandom (). Fall back on reading from
225+ /* Read 'size' random bytes from py_getrandom (). Fall back on reading from
232226 /dev/urandom if getrandom() is not available.
233227
234228 Return 0 on success. Raise an exception (if raise is non-zero) and return -1
235229 on error. */
236230static int
237- dev_urandom (char * buffer , Py_ssize_t size , int raise )
231+ dev_urandom (char * buffer , Py_ssize_t size , int blocking , int raise )
238232{
239233 int fd ;
240234 Py_ssize_t n ;
@@ -245,7 +239,7 @@ dev_urandom(char *buffer, Py_ssize_t size, int raise)
245239 assert (size > 0 );
246240
247241#ifdef PY_GETRANDOM
248- res = py_getrandom (buffer , size , raise );
242+ res = py_getrandom (buffer , size , blocking , raise );
249243 if (res < 0 ) {
250244 return -1 ;
251245 }
@@ -381,7 +375,7 @@ lcg_urandom(unsigned int x0, unsigned char *buffer, size_t size)
381375 syscall)
382376 - Don't release the GIL to call syscalls. */
383377static int
384- pyurandom (void * buffer , Py_ssize_t size , int raise )
378+ pyurandom (void * buffer , Py_ssize_t size , int blocking , int raise )
385379{
386380 if (size < 0 ) {
387381 if (raise ) {
@@ -400,19 +394,37 @@ pyurandom(void *buffer, Py_ssize_t size, int raise)
400394#elif defined(PY_GETENTROPY )
401395 return py_getentropy (buffer , size , raise );
402396#else
403- return dev_urandom (buffer , size , raise );
397+ return dev_urandom (buffer , size , blocking , raise );
404398#endif
405399}
406400
407401/* Fill buffer with size pseudo-random bytes from the operating system random
408402 number generator (RNG). It is suitable for most cryptographic purposes
409403 except long living private keys for asymmetric encryption.
410404
411- Return 0 on success, raise an exception and return -1 on error. */
405+ On Linux 3.17 and newer, the getrandom() syscall is used in blocking mode:
406+ block until the system urandom entropy pool is initialized (128 bits are
407+ collected by the kernel).
408+
409+ Return 0 on success. Raise an exception and return -1 on error. */
412410int
413411_PyOS_URandom (void * buffer , Py_ssize_t size )
414412{
415- return pyurandom (buffer , size , 1 );
413+ return pyurandom (buffer , size , 1 , 1 );
414+ }
415+
416+ /* Fill buffer with size pseudo-random bytes from the operating system random
417+ number generator (RNG). It is not suitable for cryptographic purpose.
418+
419+ On Linux 3.17 and newer (when getrandom() syscall is used), if the system
420+ urandom is not initialized yet, the function returns "weak" entropy read
421+ from /dev/urandom.
422+
423+ Return 0 on success. Raise an exception and return -1 on error. */
424+ int
425+ _PyOS_URandomNonblock (void * buffer , Py_ssize_t size )
426+ {
427+ return pyurandom (buffer , size , 0 , 1 );
416428}
417429
418430void
@@ -456,8 +468,11 @@ _PyRandom_Init(void)
456468 int res ;
457469
458470 /* _PyRandom_Init() is called very early in the Python initialization
459- and so exceptions cannot be used (use raise=0). */
460- res = pyurandom (secret , secret_size , 0 );
471+ and so exceptions cannot be used (use raise=0).
472+
473+ _PyRandom_Init() must not block Python initialization: call
474+ pyurandom() is non-blocking mode (blocking=0): see the PEP 524. */
475+ res = pyurandom (secret , secret_size , 0 , 0 );
461476 if (res < 0 ) {
462477 Py_FatalError ("failed to get random numbers to initialize Python" );
463478 }
0 commit comments