diff options
-rw-r--r-- | lib/crypto-backend.h | 1 | ||||
-rw-r--r-- | lib/gnutls_global.c | 8 | ||||
-rw-r--r-- | lib/nettle/rnd-common.c | 40 | ||||
-rw-r--r-- | lib/nettle/rnd-common.h | 1 | ||||
-rw-r--r-- | lib/nettle/rnd.c | 10 | ||||
-rw-r--r-- | lib/random.h | 1 |
6 files changed, 58 insertions, 3 deletions
diff --git a/lib/crypto-backend.h b/lib/crypto-backend.h index 7f4e1b61c6..09a7d92c67 100644 --- a/lib/crypto-backend.h +++ b/lib/crypto-backend.h @@ -77,6 +77,7 @@ typedef struct { typedef struct gnutls_crypto_rnd { int (*init) (void **ctx); + int (*check) (void **ctx); int (*rnd) (void *ctx, int level, void *data, size_t datasize); void (*rnd_refresh) (void *ctx); void (*deinit) (void *ctx); diff --git a/lib/gnutls_global.c b/lib/gnutls_global.c index e4a303fcd6..5f340533d1 100644 --- a/lib/gnutls_global.c +++ b/lib/gnutls_global.c @@ -208,6 +208,14 @@ int gnutls_global_init(void) _gnutls_init++; if (_gnutls_init > 1) { + if (_gnutls_init == 1 && _gnutls_init_ret == 0) { + /* some applications may close the urandom fd + * before calling gnutls_global_init(). in that + * case reopen it */ + ret = _gnutls_rnd_check(); + if (ret < 0) + return gnutls_assert_val(ret); + } ret = _gnutls_init_ret; goto out; } diff --git a/lib/nettle/rnd-common.c b/lib/nettle/rnd-common.c index 88aa7677d1..4c83ac6549 100644 --- a/lib/nettle/rnd-common.c +++ b/lib/nettle/rnd-common.c @@ -39,9 +39,10 @@ #if defined(HAVE_LINUX_GETRANDOM) # include <linux/random.h> -#elif defined(HAVE_GETENTROPY) -# include <unistd.h> #endif +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> /* gnulib wants to claim strerror even if it cannot provide it. WTF */ #undef strerror @@ -99,6 +100,11 @@ int _rnd_get_system_entropy_win32(void* rnd, size_t size) get_entropy_func _rnd_get_system_entropy = _rnd_get_system_entropy_win32; +int _rnd_system_entropy_check(void) +{ + return 0; +} + int _rnd_system_entropy_init(void) { int old; @@ -133,6 +139,7 @@ void _rnd_system_entropy_deinit(void) #include "egd.h" int _gnutls_urandom_fd = -1; +static mode_t _gnutls_urandom_fd_mode = 0; get_entropy_func _rnd_get_system_entropy = NULL; @@ -167,6 +174,11 @@ int _rnd_system_entropy_init(void) return 0; } +int _rnd_system_entropy_check(void) +{ + return 0; +} + void _rnd_system_entropy_deinit(void) { return; @@ -229,9 +241,22 @@ int _rnd_get_system_entropy_egd(void* _rnd, size_t size) return 0; } +int _rnd_system_entropy_check(void) +{ + int ret; + struct stat st; + + ret = fstat(_gnutls_urandom_fd, &st); + if (ret < 0 && st.st_mode != _gnutls_urandom_fd_mode) { + return _rnd_system_entropy_init(); + } + return 0; +} + int _rnd_system_entropy_init(void) { -int old; + int old; + struct stat st; _gnutls_urandom_fd = open("/dev/urandom", O_RDONLY); if (_gnutls_urandom_fd < 0) { @@ -243,6 +268,10 @@ int old; if (old != -1) fcntl(_gnutls_urandom_fd, F_SETFD, old | FD_CLOEXEC); + if (fstat(_gnutls_urandom_fd, &st) >= 0) { + _gnutls_urandom_fd_mode = st.st_mode; + } + _rnd_get_system_entropy = _rnd_get_system_entropy_urandom; return 0; @@ -254,6 +283,11 @@ fallback: gnutls_assert_val (GNUTLS_E_RANDOM_DEVICE_ERROR); } + + if (fstat(_gnutls_urandom_fd, &st) >= 0) { + _gnutls_urandom_fd_mode = st.st_mode; + } + _rnd_get_system_entropy = _rnd_get_system_entropy_egd; return 0; diff --git a/lib/nettle/rnd-common.h b/lib/nettle/rnd-common.h index a43f7be233..c795f81131 100644 --- a/lib/nettle/rnd-common.h +++ b/lib/nettle/rnd-common.h @@ -50,6 +50,7 @@ __attribute__((packed)) void _rnd_get_event(struct event_st *e); int _rnd_system_entropy_init(void); +int _rnd_system_entropy_check(void); void _rnd_system_entropy_deinit(void); typedef int (*get_entropy_func)(void* rnd, size_t size); diff --git a/lib/nettle/rnd.c b/lib/nettle/rnd.c index 8dd98c3bf4..d4dbdc144f 100644 --- a/lib/nettle/rnd.c +++ b/lib/nettle/rnd.c @@ -257,6 +257,15 @@ static int wrap_nettle_rnd_init(void **ctx) return 0; } +/* This is called when gnutls_global_init() is called for second time. + * It must check whether any resources are still available. + * The particular problem it solves is to verify that the urandom fd is still + * open (for applications that for some reason closed all fds */ +static int wrap_nettle_rnd_check(void **ctx) +{ + return _rnd_system_entropy_check(); +} + static int wrap_nettle_rnd_nonce(void *_ctx, void *data, size_t datasize) { @@ -360,6 +369,7 @@ int crypto_rnd_prio = INT_MAX; gnutls_crypto_rnd_st _gnutls_rnd_ops = { .init = wrap_nettle_rnd_init, + .check = wrap_nettle_rnd_check, .deinit = wrap_nettle_rnd_deinit, .rnd = wrap_nettle_rnd, .rnd_refresh = wrap_nettle_rnd_refresh, diff --git a/lib/random.h b/lib/random.h index 8c755f8997..35857be357 100644 --- a/lib/random.h +++ b/lib/random.h @@ -47,6 +47,7 @@ inline static void _gnutls_rnd_refresh(void) void _gnutls_rnd_deinit(void); int _gnutls_rnd_init(void); +int _gnutls_rnd_check(void); #ifndef _WIN32 extern int _gnutls_urandom_fd; |