@@ -77,7 +77,7 @@ win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
77
77
}
78
78
79
79
/* 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. */
81
81
#elif defined(HAVE_GETENTROPY ) && !defined(sun )
82
82
#define PY_GETENTROPY 1
83
83
@@ -121,31 +121,28 @@ py_getentropy(char *buffer, Py_ssize_t size, int raise)
121
121
122
122
/* Call getrandom()
123
123
- 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.
125
127
- Raise an exception (if raise is non-zero) and return -1 on error:
126
128
getrandom() failed with EINTR and the Python signal handler raised an
127
129
exception, or getrandom() failed with a different error. */
128
130
static 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 )
130
132
{
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 */
133
136
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 ;
142
138
char * dest ;
143
139
long n ;
144
140
145
141
if (!getrandom_works ) {
146
142
return 0 ;
147
143
}
148
144
145
+ flags = blocking ? 0 : GRND_NONBLOCK ;
149
146
dest = buffer ;
150
147
while (0 < size ) {
151
148
#ifdef sun
@@ -185,15 +182,12 @@ py_getrandom(void *buffer, Py_ssize_t size, int raise)
185
182
getrandom_works = 0 ;
186
183
return 0 ;
187
184
}
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 ) {
197
191
return 0 ;
198
192
}
199
193
@@ -228,13 +222,13 @@ static struct {
228
222
} urandom_cache = { -1 };
229
223
230
224
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
232
226
/dev/urandom if getrandom() is not available.
233
227
234
228
Return 0 on success. Raise an exception (if raise is non-zero) and return -1
235
229
on error. */
236
230
static 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 )
238
232
{
239
233
int fd ;
240
234
Py_ssize_t n ;
@@ -245,7 +239,7 @@ dev_urandom(char *buffer, Py_ssize_t size, int raise)
245
239
assert (size > 0 );
246
240
247
241
#ifdef PY_GETRANDOM
248
- res = py_getrandom (buffer , size , raise );
242
+ res = py_getrandom (buffer , size , blocking , raise );
249
243
if (res < 0 ) {
250
244
return -1 ;
251
245
}
@@ -381,7 +375,7 @@ lcg_urandom(unsigned int x0, unsigned char *buffer, size_t size)
381
375
syscall)
382
376
- Don't release the GIL to call syscalls. */
383
377
static int
384
- pyurandom (void * buffer , Py_ssize_t size , int raise )
378
+ pyurandom (void * buffer , Py_ssize_t size , int blocking , int raise )
385
379
{
386
380
if (size < 0 ) {
387
381
if (raise ) {
@@ -400,19 +394,37 @@ pyurandom(void *buffer, Py_ssize_t size, int raise)
400
394
#elif defined(PY_GETENTROPY )
401
395
return py_getentropy (buffer , size , raise );
402
396
#else
403
- return dev_urandom (buffer , size , raise );
397
+ return dev_urandom (buffer , size , blocking , raise );
404
398
#endif
405
399
}
406
400
407
401
/* Fill buffer with size pseudo-random bytes from the operating system random
408
402
number generator (RNG). It is suitable for most cryptographic purposes
409
403
except long living private keys for asymmetric encryption.
410
404
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. */
412
410
int
413
411
_PyOS_URandom (void * buffer , Py_ssize_t size )
414
412
{
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 );
416
428
}
417
429
418
430
void
@@ -456,8 +468,11 @@ _PyRandom_Init(void)
456
468
int res ;
457
469
458
470
/* _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 );
461
476
if (res < 0 ) {
462
477
Py_FatalError ("failed to get random numbers to initialize Python" );
463
478
}
0 commit comments