When gnutls_global_init() is called manually from the application check the urandom fd for validity

That addresses the issue where a server closes all open file descriptors
and then calls gnutls_global_init().

Conflicts:
	lib/nettle/rnd-common.c
1 parent 7a1390c4
...@@ -77,6 +77,7 @@ typedef struct { ...@@ -77,6 +77,7 @@ typedef struct {
typedef struct gnutls_crypto_rnd { typedef struct gnutls_crypto_rnd {
int (*init) (void **ctx); int (*init) (void **ctx);
int (*check) (void **ctx);
int (*rnd) (void *ctx, int level, void *data, size_t datasize); int (*rnd) (void *ctx, int level, void *data, size_t datasize);
void (*rnd_refresh) (void *ctx); void (*rnd_refresh) (void *ctx);
void (*deinit) (void *ctx); void (*deinit) (void *ctx);
......
...@@ -207,6 +207,14 @@ int gnutls_global_init(void) ...@@ -207,6 +207,14 @@ int gnutls_global_init(void)
_gnutls_init++; _gnutls_init++;
if (_gnutls_init > 1) { 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; ret = _gnutls_init_ret;
goto out; goto out;
} }
......
...@@ -37,6 +37,10 @@ ...@@ -37,6 +37,10 @@
#include <rnd-common.h> #include <rnd-common.h>
#include <hash-pjw-bare.h> #include <hash-pjw-bare.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
/* gnulib wants to claim strerror even if it cannot provide it. WTF */ /* gnulib wants to claim strerror even if it cannot provide it. WTF */
#undef strerror #undef strerror
...@@ -93,6 +97,11 @@ int _rnd_get_system_entropy_win32(void* rnd, size_t size) ...@@ -93,6 +97,11 @@ int _rnd_get_system_entropy_win32(void* rnd, size_t size)
get_entropy_func _rnd_get_system_entropy = _rnd_get_system_entropy_win32; 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 _rnd_system_entropy_init(void)
{ {
int old; int old;
...@@ -127,6 +136,7 @@ void _rnd_system_entropy_deinit(void) ...@@ -127,6 +136,7 @@ void _rnd_system_entropy_deinit(void)
#include "egd.h" #include "egd.h"
int _gnutls_urandom_fd = -1; int _gnutls_urandom_fd = -1;
static mode_t _gnutls_urandom_fd_mode = 0;
static int _rnd_get_system_entropy_urandom(void* _rnd, size_t size) static int _rnd_get_system_entropy_urandom(void* _rnd, size_t size)
{ {
...@@ -185,9 +195,22 @@ int _rnd_get_system_entropy_egd(void* _rnd, size_t size) ...@@ -185,9 +195,22 @@ int _rnd_get_system_entropy_egd(void* _rnd, size_t size)
get_entropy_func _rnd_get_system_entropy = NULL; get_entropy_func _rnd_get_system_entropy = NULL;
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 _rnd_system_entropy_init(void)
{ {
int old; int old;
struct stat st;
_gnutls_urandom_fd = open("/dev/urandom", O_RDONLY); _gnutls_urandom_fd = open("/dev/urandom", O_RDONLY);
if (_gnutls_urandom_fd < 0) { if (_gnutls_urandom_fd < 0) {
...@@ -199,6 +222,10 @@ int old; ...@@ -199,6 +222,10 @@ int old;
if (old != -1) if (old != -1)
fcntl(_gnutls_urandom_fd, F_SETFD, old | FD_CLOEXEC); 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; _rnd_get_system_entropy = _rnd_get_system_entropy_urandom;
return 0; return 0;
...@@ -210,6 +237,11 @@ fallback: ...@@ -210,6 +237,11 @@ fallback:
gnutls_assert_val gnutls_assert_val
(GNUTLS_E_RANDOM_DEVICE_ERROR); (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; _rnd_get_system_entropy = _rnd_get_system_entropy_egd;
return 0; return 0;
......
...@@ -50,6 +50,7 @@ __attribute__((packed)) ...@@ -50,6 +50,7 @@ __attribute__((packed))
void _rnd_get_event(struct event_st *e); void _rnd_get_event(struct event_st *e);
int _rnd_system_entropy_init(void); int _rnd_system_entropy_init(void);
int _rnd_system_entropy_check(void);
void _rnd_system_entropy_deinit(void); void _rnd_system_entropy_deinit(void);
typedef int (*get_entropy_func)(void* rnd, size_t size); typedef int (*get_entropy_func)(void* rnd, size_t size);
......
...@@ -260,6 +260,15 @@ static int wrap_nettle_rnd_init(void **ctx) ...@@ -260,6 +260,15 @@ static int wrap_nettle_rnd_init(void **ctx)
return 0; 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 static int
wrap_nettle_rnd_nonce(void *_ctx, void *data, size_t datasize) wrap_nettle_rnd_nonce(void *_ctx, void *data, size_t datasize)
{ {
...@@ -368,6 +377,7 @@ int crypto_rnd_prio = INT_MAX; ...@@ -368,6 +377,7 @@ int crypto_rnd_prio = INT_MAX;
gnutls_crypto_rnd_st _gnutls_rnd_ops = { gnutls_crypto_rnd_st _gnutls_rnd_ops = {
.init = wrap_nettle_rnd_init, .init = wrap_nettle_rnd_init,
.check = wrap_nettle_rnd_check,
.deinit = wrap_nettle_rnd_deinit, .deinit = wrap_nettle_rnd_deinit,
.rnd = wrap_nettle_rnd, .rnd = wrap_nettle_rnd,
.rnd_refresh = wrap_nettle_rnd_refresh, .rnd_refresh = wrap_nettle_rnd_refresh,
......
...@@ -47,6 +47,7 @@ inline static void _gnutls_rnd_refresh(void) ...@@ -47,6 +47,7 @@ inline static void _gnutls_rnd_refresh(void)
void _gnutls_rnd_deinit(void); void _gnutls_rnd_deinit(void);
int _gnutls_rnd_init(void); int _gnutls_rnd_init(void);
int _gnutls_rnd_check(void);
#ifndef _WIN32 #ifndef _WIN32
extern int _gnutls_urandom_fd; extern int _gnutls_urandom_fd;
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!