summaryrefslogtreecommitdiffstats
path: root/Python/random.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/random.c')
-rw-r--r--Python/random.c49
1 files changed, 34 insertions, 15 deletions
diff --git a/Python/random.c b/Python/random.c
index ea09e84..8f3e6d6 100644
--- a/Python/random.c
+++ b/Python/random.c
@@ -6,7 +6,9 @@
# ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
# endif
-# ifdef HAVE_GETRANDOM_SYSCALL
+# ifdef HAVE_GETRANDOM
+# include <sys/random.h>
+# elif defined(HAVE_GETRANDOM_SYSCALL)
# include <sys/syscall.h>
# endif
#endif
@@ -70,7 +72,9 @@ win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
return 0;
}
-#elif HAVE_GETENTROPY
+#elif defined(HAVE_GETENTROPY) && !defined(sun)
+#define PY_GETENTROPY
+
/* Fill buffer with size pseudo-random bytes generated by getentropy().
Return 0 on success, or raise an exception and return -1 on error.
@@ -105,16 +109,19 @@ py_getentropy(unsigned char *buffer, Py_ssize_t size, int fatal)
return 0;
}
-#else /* !HAVE_GETENTROPY */
+#else
+
+#if defined(HAVE_GETRANDOM) || defined(HAVE_GETRANDOM_SYSCALL)
+#define PY_GETRANDOM
-#ifdef HAVE_GETRANDOM_SYSCALL
static int
py_getrandom(void *buffer, Py_ssize_t size, int raise)
{
- /* is getrandom() supported by the running kernel?
- * need Linux kernel 3.17 or later */
+ /* Is getrandom() supported by the running kernel?
+ * Need Linux kernel 3.17 or newer, or Solaris 11.3 or newer */
static int getrandom_works = 1;
- /* Use /dev/urandom, block if the kernel has no entropy */
+ /* Use non-blocking /dev/urandom device. On Linux at boot, the getrandom()
+ * syscall blocks until /dev/urandom is initialized with enough entropy. */
const int flags = 0;
int n;
@@ -124,7 +131,18 @@ py_getrandom(void *buffer, Py_ssize_t size, int raise)
while (0 < size) {
errno = 0;
- /* Use syscall() because the libc doesn't expose getrandom() yet, see:
+#ifdef HAVE_GETRANDOM
+ if (raise) {
+ Py_BEGIN_ALLOW_THREADS
+ n = getrandom(buffer, size, flags);
+ Py_END_ALLOW_THREADS
+ }
+ else {
+ n = getrandom(buffer, size, flags);
+ }
+#else
+ /* On Linux, use the syscall() function because the GNU libc doesn't
+ * expose the Linux getrandom() syscall yet. See:
* https://sourceware.org/bugzilla/show_bug.cgi?id=17252 */
if (raise) {
Py_BEGIN_ALLOW_THREADS
@@ -134,6 +152,7 @@ py_getrandom(void *buffer, Py_ssize_t size, int raise)
else {
n = syscall(SYS_getrandom, buffer, size, flags);
}
+#endif
if (n < 0) {
if (errno == ENOSYS) {
@@ -182,7 +201,7 @@ dev_urandom_noraise(unsigned char *buffer, Py_ssize_t size)
assert (0 < size);
-#ifdef HAVE_GETRANDOM_SYSCALL
+#ifdef PY_GETRANDOM
if (py_getrandom(buffer, size, 0) == 1)
return;
/* getrandom() is not supported by the running kernel, fall back
@@ -218,14 +237,14 @@ dev_urandom_python(char *buffer, Py_ssize_t size)
int fd;
Py_ssize_t n;
struct _Py_stat_struct st;
-#ifdef HAVE_GETRANDOM_SYSCALL
+#ifdef PY_GETRANDOM
int res;
#endif
if (size <= 0)
return 0;
-#ifdef HAVE_GETRANDOM_SYSCALL
+#ifdef PY_GETRANDOM
res = py_getrandom(buffer, size, 1);
if (res < 0)
return -1;
@@ -304,7 +323,7 @@ dev_urandom_close(void)
}
}
-#endif /* HAVE_GETENTROPY */
+#endif
/* Fill buffer with pseudo-random bytes generated by a linear congruent
generator (LCG):
@@ -345,7 +364,7 @@ _PyOS_URandom(void *buffer, Py_ssize_t size)
#ifdef MS_WINDOWS
return win32_urandom((unsigned char *)buffer, size, 1);
-#elif HAVE_GETENTROPY
+#elif PY_GETENTROPY
return py_getentropy(buffer, size, 0);
#else
return dev_urandom_python((char*)buffer, size);
@@ -392,7 +411,7 @@ _PyRandom_Init(void)
else {
#ifdef MS_WINDOWS
(void)win32_urandom(secret, secret_size, 0);
-#elif HAVE_GETENTROPY
+#elif PY_GETENTROPY
(void)py_getentropy(secret, secret_size, 1);
#else
dev_urandom_noraise(secret, secret_size);
@@ -408,7 +427,7 @@ _PyRandom_Fini(void)
CryptReleaseContext(hCryptProv, 0);
hCryptProv = 0;
}
-#elif HAVE_GETENTROPY
+#elif PY_GETENTROPY
/* nothing to clean */
#else
dev_urandom_close();