summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2016-07-21 11:51:05 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2016-07-21 12:07:25 +0200
commit1c663d7d249fcddb8e55bc165317219042f2648f (patch)
treead2b135725c3dfc6067146cdca492b7d8eb24691
parent7ababc5f48503c165f1e06669225b2c1cb4de5a0 (diff)
downloadgnutls-1c663d7d249fcddb8e55bc165317219042f2648f.tar.gz
rnd-linux: make getrandom back-end robust against EINTR failures
-rw-r--r--lib/nettle/rnd-linux.c33
1 files changed, 26 insertions, 7 deletions
diff --git a/lib/nettle/rnd-linux.c b/lib/nettle/rnd-linux.c
index e61566b88d..3f59332977 100644
--- a/lib/nettle/rnd-linux.c
+++ b/lib/nettle/rnd-linux.c
@@ -74,19 +74,37 @@ static unsigned have_getrandom(void)
static int _rnd_get_system_entropy_getrandom(void* _rnd, size_t size)
{
int ret;
- ret = getrandom(_rnd, size, 0);
+ do {
+ ret = getrandom(_rnd, size, 0);
+ } while (ret == -1 && errno == EINTR);
+
if (ret == -1) {
+ int e = errno;
gnutls_assert();
_gnutls_debug_log
("Failed to use getrandom: %s\n",
- strerror(errno));
+ strerror(e));
return GNUTLS_E_RANDOM_DEVICE_ERROR;
}
- /* This function is only used internally for small sizes which
- * should be delivered by getrandom(). */
- if ((size_t)ret != size)
- return gnutls_assert_val(GNUTLS_E_RANDOM_DEVICE_ERROR);
+ /* Since this function is only used internally for small sizes,
+ * any limits of getrandom() are not reached. The only way
+ * to receive less data than asked, is due to a signal interrupting
+ * the system call. In that case we retry. */
+ if ((size_t)ret != size) {
+ unsigned i;
+ for (i=0;i<3;i++) {
+ do {
+ ret = getrandom(_rnd, size, 0);
+ } while (ret == -1 && errno == EINTR);
+
+ if ((size_t)ret == size)
+ break;
+ }
+
+ if (ret == -1 || (size_t)ret != size)
+ return gnutls_assert_val(GNUTLS_E_RANDOM_DEVICE_ERROR);
+ }
return 0;
}
@@ -106,10 +124,11 @@ static int _rnd_get_system_entropy_urandom(void* _rnd, size_t size)
} while (res < 0 && errno == EINTR);
if (res <= 0) {
+ int e = errno;
if (res < 0) {
_gnutls_debug_log
("Failed to read /dev/urandom: %s\n",
- strerror(errno));
+ strerror(e));
} else {
_gnutls_debug_log
("Failed to read /dev/urandom: end of file\n");