@@ -39,10 +39,9 @@ win32_urandom_init(int raise)
3939 return 0 ;
4040
4141error :
42- if (raise )
42+ if (raise ) {
4343 PyErr_SetFromWindowsErr (0 );
44- else
45- Py_FatalError ("Failed to initialize Windows random API (CryptoGen)" );
44+ }
4645 return -1 ;
4746}
4847
@@ -55,8 +54,9 @@ win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
5554
5655 if (hCryptProv == 0 )
5756 {
58- if (win32_urandom_init (raise ) == -1 )
57+ if (win32_urandom_init (raise ) == -1 ) {
5958 return -1 ;
59+ }
6060 }
6161
6262 while (size > 0 )
@@ -65,11 +65,9 @@ win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
6565 if (!CryptGenRandom (hCryptProv , (DWORD )chunk , buffer ))
6666 {
6767 /* CryptGenRandom() failed */
68- if (raise )
68+ if (raise ) {
6969 PyErr_SetFromWindowsErr (0 );
70- else
71- Py_FatalError ("Failed to initialized the randomized hash "
72- "secret using CryptoGen)" );
70+ }
7371 return -1 ;
7472 }
7573 buffer += chunk ;
@@ -86,29 +84,28 @@ win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
8684/* Fill buffer with size pseudo-random bytes generated by getentropy().
8785 Return 0 on success, or raise an exception and return -1 on error.
8886
89- If fatal is nonzero, call Py_FatalError() instead of raising an exception
90- on error. */
87+ If raise is zero, don't raise an exception on error. */
9188static int
92- py_getentropy (unsigned char * buffer , Py_ssize_t size , int fatal )
89+ py_getentropy (char * buffer , Py_ssize_t size , int raise )
9390{
9491 while (size > 0 ) {
9592 Py_ssize_t len = Py_MIN (size , 256 );
9693 int res ;
9794
98- if (! fatal ) {
95+ if (raise ) {
9996 Py_BEGIN_ALLOW_THREADS
10097 res = getentropy (buffer , len );
10198 Py_END_ALLOW_THREADS
102-
103- if (res < 0 ) {
104- PyErr_SetFromErrno (PyExc_OSError );
105- return -1 ;
106- }
10799 }
108100 else {
109101 res = getentropy (buffer , len );
110- if (res < 0 )
111- Py_FatalError ("getentropy() failed" );
102+ }
103+
104+ if (res < 0 ) {
105+ if (raise ) {
106+ PyErr_SetFromErrno (PyExc_OSError );
107+ }
108+ return -1 ;
112109 }
113110
114111 buffer += len ;
@@ -195,18 +192,15 @@ py_getrandom(void *buffer, Py_ssize_t size, int raise)
195192
196193 if (errno == EINTR ) {
197194 if (PyErr_CheckSignals ()) {
198- if (!raise )
199- Py_FatalError ("getrandom() interrupted by a signal" );
200195 return -1 ;
201196 }
202197 /* retry getrandom() */
203198 continue ;
204199 }
205200
206- if (raise )
201+ if (raise ) {
207202 PyErr_SetFromErrno (PyExc_OSError );
208- else
209- Py_FatalError ("getrandom() failed" );
203+ }
210204 return -1 ;
211205 }
212206
@@ -225,41 +219,45 @@ static struct {
225219
226220
227221/* Read size bytes from /dev/urandom into buffer.
228- Call Py_FatalError() on error. */
229- static void
230- dev_urandom_noraise (unsigned char * buffer , Py_ssize_t size )
222+ Return 0 success, or return -1 on error. */
223+ static int
224+ dev_urandom_noraise (char * buffer , Py_ssize_t size )
231225{
232226 int fd ;
233227 Py_ssize_t n ;
234228
235229 assert (0 < size );
236230
237231#ifdef PY_GETRANDOM
238- if (py_getrandom (buffer , size , 0 ) == 1 )
239- return ;
232+ if (py_getrandom (buffer , size , 0 ) == 1 ) {
233+ return 0 ;
234+ }
240235 /* getrandom() is not supported by the running kernel, fall back
241236 * on reading /dev/urandom */
242237#endif
243238
244239 fd = _Py_open_noraise ("/dev/urandom" , O_RDONLY );
245- if (fd < 0 )
246- Py_FatalError ("Failed to open /dev/urandom" );
240+ if (fd < 0 ) {
241+ return -1 ;
242+ }
247243
248244 while (0 < size )
249245 {
250246 do {
251247 n = read (fd , buffer , (size_t )size );
252248 } while (n < 0 && errno == EINTR );
253- if ( n <= 0 )
254- {
249+
250+ if ( n <= 0 ) {
255251 /* stop on error or if read(size) returned 0 */
256- Py_FatalError ("Failed to read bytes from /dev/urandom" );
257- break ;
252+ return -1 ;
258253 }
254+
259255 buffer += n ;
260256 size -= n ;
261257 }
262258 close (fd );
259+
260+ return 0 ;
263261}
264262
265263/* Read size bytes from /dev/urandom into buffer.
@@ -379,31 +377,51 @@ lcg_urandom(unsigned int x0, unsigned char *buffer, size_t size)
379377 }
380378}
381379
382- /* Fill buffer with size pseudo-random bytes from the operating system random
383- number generator (RNG). It is suitable for most cryptographic purposes
384- except long living private keys for asymmetric encryption.
385-
386- Return 0 on success, raise an exception and return -1 on error . */
387- int
388- _PyOS_URandom (void * buffer , Py_ssize_t size )
380+ /* If raise is zero:
381+ * - Don't raise exceptions on error
382+ * - Don't call PyErr_CheckSignals() on EINTR (retry directly the interrupted
383+ * syscall)
384+ * - Don't release the GIL to call syscalls . */
385+ static int
386+ pyurandom (void * buffer , Py_ssize_t size , int raise )
389387{
390388 if (size < 0 ) {
391- PyErr_Format (PyExc_ValueError ,
392- "negative argument not allowed" );
389+ if (raise ) {
390+ PyErr_Format (PyExc_ValueError ,
391+ "negative argument not allowed" );
392+ }
393393 return -1 ;
394394 }
395- if (size == 0 )
395+
396+ if (size == 0 ) {
396397 return 0 ;
398+ }
397399
398400#ifdef MS_WINDOWS
399- return win32_urandom ((unsigned char * )buffer , size , 1 );
401+ return win32_urandom ((unsigned char * )buffer , size , raise );
400402#elif defined(PY_GETENTROPY )
401- return py_getentropy (buffer , size , 0 );
403+ return py_getentropy (buffer , size , raise );
402404#else
403- return dev_urandom_python ((char * )buffer , size );
405+ if (raise ) {
406+ return dev_urandom_python (buffer , size );
407+ }
408+ else {
409+ return dev_urandom_noraise (buffer , size );
410+ }
404411#endif
405412}
406413
414+ /* Fill buffer with size pseudo-random bytes from the operating system random
415+ number generator (RNG). It is suitable for most cryptographic purposes
416+ except long living private keys for asymmetric encryption.
417+
418+ Return 0 on success, raise an exception and return -1 on error. */
419+ int
420+ _PyOS_URandom (void * buffer , Py_ssize_t size )
421+ {
422+ return pyurandom (buffer , size , 1 );
423+ }
424+
407425void
408426_PyRandom_Init (void )
409427{
@@ -442,13 +460,14 @@ _PyRandom_Init(void)
442460 }
443461 }
444462 else {
445- #ifdef MS_WINDOWS
446- (void )win32_urandom (secret , secret_size , 0 );
447- #elif defined(PY_GETENTROPY )
448- (void )py_getentropy (secret , secret_size , 1 );
449- #else
450- dev_urandom_noraise (secret , secret_size );
451- #endif
463+ int res ;
464+
465+ /* _PyRandom_Init() is called very early in the Python initialization
466+ * and so exceptions cannot be used. */
467+ res = pyurandom (secret , secret_size , 0 );
468+ if (res < 0 ) {
469+ Py_FatalError ("failed to get random numbers to initialize Python" );
470+ }
452471 }
453472}
454473
0 commit comments