66# ifdef HAVE_SYS_STAT_H
77# include <sys/stat.h>
88# endif
9- # ifdef HAVE_GETRANDOM_SYSCALL
9+ # ifdef HAVE_GETRANDOM
10+ # include <sys/random.h>
11+ # elif defined(HAVE_GETRANDOM_SYSCALL )
1012# include <sys/syscall.h>
1113# endif
1214#endif
@@ -70,7 +72,9 @@ win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
7072 return 0 ;
7173}
7274
73- #elif HAVE_GETENTROPY
75+ #elif defined(HAVE_GETENTROPY ) && !defined(sun )
76+ #define PY_GETENTROPY 1
77+
7478/* Fill buffer with size pseudo-random bytes generated by getentropy().
7579 Return 0 on success, or raise an exception and return -1 on error.
7680
@@ -105,16 +109,19 @@ py_getentropy(unsigned char *buffer, Py_ssize_t size, int fatal)
105109 return 0 ;
106110}
107111
108- #else /* !HAVE_GETENTROPY */
112+ #else
113+
114+ #if defined(HAVE_GETRANDOM ) || defined(HAVE_GETRANDOM_SYSCALL )
115+ #define PY_GETRANDOM 1
109116
110- #ifdef HAVE_GETRANDOM_SYSCALL
111117static int
112118py_getrandom (void * buffer , Py_ssize_t size , int raise )
113119{
114- /* is getrandom() supported by the running kernel?
115- * need Linux kernel 3.17 or later */
120+ /* Is getrandom() supported by the running kernel?
121+ * Need Linux kernel 3.17 or newer, or Solaris 11.3 or newer */
116122 static int getrandom_works = 1 ;
117- /* Use /dev/urandom, block if the kernel has no entropy */
123+ /* Use non-blocking /dev/urandom device. On Linux at boot, the getrandom()
124+ * syscall blocks until /dev/urandom is initialized with enough entropy. */
118125 const int flags = 0 ;
119126 int n ;
120127
@@ -124,7 +131,18 @@ py_getrandom(void *buffer, Py_ssize_t size, int raise)
124131 while (0 < size ) {
125132 errno = 0 ;
126133
127- /* Use syscall() because the libc doesn't expose getrandom() yet, see:
134+ #ifdef HAVE_GETRANDOM
135+ if (raise ) {
136+ Py_BEGIN_ALLOW_THREADS
137+ n = getrandom (buffer , size , flags );
138+ Py_END_ALLOW_THREADS
139+ }
140+ else {
141+ n = getrandom (buffer , size , flags );
142+ }
143+ #else
144+ /* On Linux, use the syscall() function because the GNU libc doesn't
145+ * expose the Linux getrandom() syscall yet. See:
128146 * https://sourceware.org/bugzilla/show_bug.cgi?id=17252 */
129147 if (raise ) {
130148 Py_BEGIN_ALLOW_THREADS
@@ -134,6 +152,7 @@ py_getrandom(void *buffer, Py_ssize_t size, int raise)
134152 else {
135153 n = syscall (SYS_getrandom , buffer , size , flags );
136154 }
155+ #endif
137156
138157 if (n < 0 ) {
139158 if (errno == ENOSYS ) {
@@ -182,7 +201,7 @@ dev_urandom_noraise(unsigned char *buffer, Py_ssize_t size)
182201
183202 assert (0 < size );
184203
185- #ifdef HAVE_GETRANDOM_SYSCALL
204+ #ifdef PY_GETRANDOM
186205 if (py_getrandom (buffer , size , 0 ) == 1 )
187206 return ;
188207 /* getrandom() is not supported by the running kernel, fall back
@@ -218,14 +237,14 @@ dev_urandom_python(char *buffer, Py_ssize_t size)
218237 int fd ;
219238 Py_ssize_t n ;
220239 struct _Py_stat_struct st ;
221- #ifdef HAVE_GETRANDOM_SYSCALL
240+ #ifdef PY_GETRANDOM
222241 int res ;
223242#endif
224243
225244 if (size <= 0 )
226245 return 0 ;
227246
228- #ifdef HAVE_GETRANDOM_SYSCALL
247+ #ifdef PY_GETRANDOM
229248 res = py_getrandom (buffer , size , 1 );
230249 if (res < 0 )
231250 return -1 ;
@@ -304,7 +323,7 @@ dev_urandom_close(void)
304323 }
305324}
306325
307- #endif /* HAVE_GETENTROPY */
326+ #endif
308327
309328/* Fill buffer with pseudo-random bytes generated by a linear congruent
310329 generator (LCG):
@@ -345,7 +364,7 @@ _PyOS_URandom(void *buffer, Py_ssize_t size)
345364
346365#ifdef MS_WINDOWS
347366 return win32_urandom ((unsigned char * )buffer , size , 1 );
348- #elif HAVE_GETENTROPY
367+ #elif defined( PY_GETENTROPY )
349368 return py_getentropy (buffer , size , 0 );
350369#else
351370 return dev_urandom_python ((char * )buffer , size );
@@ -392,7 +411,7 @@ _PyRandom_Init(void)
392411 else {
393412#ifdef MS_WINDOWS
394413 (void )win32_urandom (secret , secret_size , 0 );
395- #elif HAVE_GETENTROPY
414+ #elif defined( PY_GETENTROPY )
396415 (void )py_getentropy (secret , secret_size , 1 );
397416#else
398417 dev_urandom_noraise (secret , secret_size );
@@ -408,7 +427,7 @@ _PyRandom_Fini(void)
408427 CryptReleaseContext (hCryptProv , 0 );
409428 hCryptProv = 0 ;
410429 }
411- #elif HAVE_GETENTROPY
430+ #elif defined( PY_GETENTROPY )
412431 /* nothing to clean */
413432#else
414433 dev_urandom_close ();
0 commit comments