summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2017-01-06 10:33:18 (GMT)
committerVictor Stinner <victor.stinner@gmail.com>2017-01-06 10:33:18 (GMT)
commitde2f1ea12457780bfa4dac0f2d1ed2c8f02d591e (patch)
tree566d6d614581744948c967b658280a058e7fc658 /Python
parent2f7964393d6a17e746596918c4a272d0a5009479 (diff)
downloadcpython-de2f1ea12457780bfa4dac0f2d1ed2c8f02d591e.zip
cpython-de2f1ea12457780bfa4dac0f2d1ed2c8f02d591e.tar.gz
cpython-de2f1ea12457780bfa4dac0f2d1ed2c8f02d591e.tar.bz2
py_getentropy() now supports ENOSYS, EPERM & EINTR
Issue #29157.
Diffstat (limited to 'Python')
-rw-r--r--Python/random.c42
1 files changed, 39 insertions, 3 deletions
diff --git a/Python/random.c b/Python/random.c
index ad2c389..bc96226 100644
--- a/Python/random.c
+++ b/Python/random.c
@@ -183,14 +183,31 @@ py_getrandom(void *buffer, Py_ssize_t size, int blocking, int raise)
#elif defined(HAVE_GETENTROPY)
#define PY_GETENTROPY 1
-/* Fill buffer with size pseudo-random bytes generated by getentropy().
- Return 1 on success, or raise an exception and return -1 on error.
+/* Fill buffer with size pseudo-random bytes generated by getentropy():
- If raise is zero, don't raise an exception on error. */
+ - Return 1 on success
+ - Return 0 if getentropy() syscall is not available (failed with ENOSYS or
+ EPERM).
+ - Raise an exception (if raise is non-zero) and return -1 on error:
+ if getentropy() failed with EINTR, raise is non-zero and the Python signal
+ handler raised an exception, or if getentropy() failed with a different
+ error.
+
+ getentropy() is retried if it failed with EINTR: interrupted by a signal. */
static int
py_getentropy(char *buffer, Py_ssize_t size, int raise)
{
+ /* Is getentropy() supported by the running kernel? Set to 0 if
+ getentropy() failed with ENOSYS or EPERM. */
+ static int getentropy_works = 1;
+
+ if (!getentropy_works) {
+ return 0;
+ }
+
while (size > 0) {
+ /* getentropy() is limited to returning up to 256 bytes. Call it
+ multiple times if more bytes are requested. */
Py_ssize_t len = Py_MIN(size, 256);
int res;
@@ -204,6 +221,25 @@ py_getentropy(char *buffer, Py_ssize_t size, int raise)
}
if (res < 0) {
+ /* ENOSYS: the syscall is not supported by the running kernel.
+ EPERM: the syscall is blocked by a security policy (ex: SECCOMP)
+ or something else. */
+ if (errno == ENOSYS || errno == EPERM) {
+ getentropy_works = 0;
+ return 0;
+ }
+
+ if (errno == EINTR) {
+ if (raise) {
+ if (PyErr_CheckSignals()) {
+ return -1;
+ }
+ }
+
+ /* retry getentropy() if it was interrupted by a signal */
+ continue;
+ }
+
if (raise) {
PyErr_SetFromErrno(PyExc_OSError);
}