aboutsummaryrefslogtreecommitdiffstats
path: root/src/_cffi_src
diff options
context:
space:
mode:
authorAlex Gaynor <alex.gaynor@gmail.com>2018-12-29 08:04:32 -0600
committerPaul Kehrer <paul.l.kehrer@gmail.com>2018-12-29 06:04:32 -0800
commit8f75d0779740d7221445ebd2da66ececb49cc05b (patch)
treedba121a38eece9bb516dfec3d99643f2f5c9d142 /src/_cffi_src
parent4bf93b7b18a99cdbf625161a7910ba5640fcdd9d (diff)
downloadcryptography-8f75d0779740d7221445ebd2da66ececb49cc05b.tar.gz
cryptography-8f75d0779740d7221445ebd2da66ececb49cc05b.tar.bz2
cryptography-8f75d0779740d7221445ebd2da66ececb49cc05b.zip
Fixes #4645 -- poll() on /dev/random before reading from /dev/urandom on Linux (#4656)
* Fixes #4645 -- select() on /dev/random before reading from /dev/urandom on linux * whoops * Missing header * whoops * Review notes * Potential uninitialized fix * Signals are literally impossible
Diffstat (limited to 'src/_cffi_src')
-rw-r--r--src/_cffi_src/openssl/src/osrandom_engine.c72
1 files changed, 55 insertions, 17 deletions
diff --git a/src/_cffi_src/openssl/src/osrandom_engine.c b/src/_cffi_src/openssl/src/osrandom_engine.c
index e6a76a34..315d5f1f 100644
--- a/src/_cffi_src/openssl/src/osrandom_engine.c
+++ b/src/_cffi_src/openssl/src/osrandom_engine.c
@@ -13,6 +13,10 @@
* Copyright 2001-2016 Python Software Foundation; All Rights Reserved.
*/
+#ifdef __linux__
+#include <poll.h>
+#endif
+
static const char *Cryptography_osrandom_engine_id = "osrandom";
/****************************************************************************
@@ -90,9 +94,47 @@ static struct {
ino_t st_ino;
} urandom_cache = { -1 };
+static int set_cloexec(int fd) {
+ int flags = fcntl(fd, F_GETFD);
+ if (flags == -1) {
+ return -1;
+ }
+ if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
+ return -1;
+ }
+ return 0;
+}
+
+#ifdef __linux__
+/* On Linux, we open("/dev/random") and use poll() to wait until it's readable
+ * before we read from /dev/urandom, this ensures that we don't read from
+ * /dev/urandom before the kernel CSPRNG is initialized. This isn't necessary on
+ * other platforms because they don't have the same _bug_ as Linux does with
+ * /dev/urandom and early boot. */
+static int wait_on_devrandom(void) {
+ struct pollfd pfd = {};
+ int ret = 0;
+ int random_fd = open("/dev/random", O_RDONLY);
+ if (random_fd < 0) {
+ return -1;
+ }
+ if (set_cloexec(random_fd) < 0) {
+ return -1;
+ }
+ pfd.fd = random_fd;
+ pfd.events = POLLIN;
+ pfd.revents = 0;
+ do {
+ ret = poll(&pfd, 1, -1);
+ } while (ret < 0 && (errno == EINTR || errno == EAGAIN));
+ close(random_fd);
+ return ret;
+}
+#endif
+
/* return -1 on error */
static int dev_urandom_fd(void) {
- int fd, n, flags;
+ int fd = -1;
struct stat st;
/* Check that fd still points to the correct device */
@@ -106,25 +148,25 @@ static int dev_urandom_fd(void) {
}
}
if (urandom_cache.fd < 0) {
+#ifdef __linux__
+ if (wait_on_devrandom() < 0) {
+ goto error;
+ }
+#endif
+
fd = open("/dev/urandom", O_RDONLY);
if (fd < 0) {
goto error;
}
- if (fstat(fd, &st)) {
+ if (set_cloexec(fd) < 0) {
goto error;
}
- /* set CLOEXEC flag */
- flags = fcntl(fd, F_GETFD);
- if (flags == -1) {
- goto error;
- } else if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
+ if (fstat(fd, &st)) {
goto error;
}
/* Another thread initialized the fd */
if (urandom_cache.fd >= 0) {
- do {
- n = close(fd);
- } while (n < 0 && errno == EINTR);
+ close(fd);
return urandom_cache.fd;
}
urandom_cache.st_dev = st.st_dev;
@@ -135,9 +177,7 @@ static int dev_urandom_fd(void) {
error:
if (fd != -1) {
- do {
- n = close(fd);
- } while (n < 0 && errno == EINTR);
+ close(fd);
}
ERR_Cryptography_OSRandom_error(
CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_FD,
@@ -177,7 +217,7 @@ static int dev_urandom_read(unsigned char *buffer, int size) {
static void dev_urandom_close(void) {
if (urandom_cache.fd >= 0) {
- int fd, n;
+ int fd;
struct stat st;
if (fstat(urandom_cache.fd, &st)
@@ -185,9 +225,7 @@ static void dev_urandom_close(void) {
&& st.st_ino == urandom_cache.st_ino) {
fd = urandom_cache.fd;
urandom_cache.fd = -1;
- do {
- n = close(fd);
- } while (n < 0 && errno == EINTR);
+ close(fd);
}
}
}