diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2016-07-21 11:51:05 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2016-07-21 12:07:25 +0200 |
commit | 1c663d7d249fcddb8e55bc165317219042f2648f (patch) | |
tree | ad2b135725c3dfc6067146cdca492b7d8eb24691 | |
parent | 7ababc5f48503c165f1e06669225b2c1cb4de5a0 (diff) | |
download | gnutls-1c663d7d249fcddb8e55bc165317219042f2648f.tar.gz |
rnd-linux: make getrandom back-end robust against EINTR failures
-rw-r--r-- | lib/nettle/rnd-linux.c | 33 |
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"); |