Commit 684b825f by Nikos Mavrogiannopoulos

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 {
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);
......
......@@ -207,6 +207,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;
}
......
......@@ -37,6 +37,10 @@
#include <rnd-common.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 */
#undef strerror
......@@ -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;
int _rnd_system_entropy_check(void)
{
return 0;
}
int _rnd_system_entropy_init(void)
{
int old;
......@@ -127,6 +136,7 @@ void _rnd_system_entropy_deinit(void)
#include "egd.h"
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)
{
......@@ -185,9 +195,22 @@ int _rnd_get_system_entropy_egd(void* _rnd, size_t size)
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 old;
int old;
struct stat st;
_gnutls_urandom_fd = open("/dev/urandom", O_RDONLY);
if (_gnutls_urandom_fd < 0) {
......@@ -199,6 +222,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;
......@@ -210,6 +237,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;
......
......@@ -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);
......
......@@ -260,6 +260,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)
{
......@@ -368,6 +377,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,
......
......@@ -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;
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!