@@ -183,14 +183,31 @@ py_getrandom(void *buffer, Py_ssize_t size, int blocking, int raise)
183183#elif defined(HAVE_GETENTROPY )
184184#define PY_GETENTROPY 1
185185
186- /* Fill buffer with size pseudo-random bytes generated by getentropy().
187- Return 1 on success, or raise an exception and return -1 on error.
186+ /* Fill buffer with size pseudo-random bytes generated by getentropy():
188187
189- If raise is zero, don't raise an exception on error. */
188+ - Return 1 on success
189+ - Return 0 if getentropy() syscall is not available (failed with ENOSYS or
190+ EPERM).
191+ - Raise an exception (if raise is non-zero) and return -1 on error:
192+ if getentropy() failed with EINTR, raise is non-zero and the Python signal
193+ handler raised an exception, or if getentropy() failed with a different
194+ error.
195+
196+ getentropy() is retried if it failed with EINTR: interrupted by a signal. */
190197static int
191198py_getentropy (char * buffer , Py_ssize_t size , int raise )
192199{
200+ /* Is getentropy() supported by the running kernel? Set to 0 if
201+ getentropy() failed with ENOSYS or EPERM. */
202+ static int getentropy_works = 1 ;
203+
204+ if (!getentropy_works ) {
205+ return 0 ;
206+ }
207+
193208 while (size > 0 ) {
209+ /* getentropy() is limited to returning up to 256 bytes. Call it
210+ multiple times if more bytes are requested. */
194211 Py_ssize_t len = Py_MIN (size , 256 );
195212 int res ;
196213
@@ -204,6 +221,25 @@ py_getentropy(char *buffer, Py_ssize_t size, int raise)
204221 }
205222
206223 if (res < 0 ) {
224+ /* ENOSYS: the syscall is not supported by the running kernel.
225+ EPERM: the syscall is blocked by a security policy (ex: SECCOMP)
226+ or something else. */
227+ if (errno == ENOSYS || errno == EPERM ) {
228+ getentropy_works = 0 ;
229+ return 0 ;
230+ }
231+
232+ if (errno == EINTR ) {
233+ if (raise ) {
234+ if (PyErr_CheckSignals ()) {
235+ return -1 ;
236+ }
237+ }
238+
239+ /* retry getentropy() if it was interrupted by a signal */
240+ continue ;
241+ }
242+
207243 if (raise ) {
208244 PyErr_SetFromErrno (PyExc_OSError );
209245 }
0 commit comments