]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
When gnutls_global_init() is called manually from the application check the urandom...
authorNikos Mavrogiannopoulos <nmav@redhat.com>
Fri, 31 Oct 2014 08:32:16 +0000 (09:32 +0100)
committerNikos Mavrogiannopoulos <nmav@redhat.com>
Fri, 31 Oct 2014 08:32:16 +0000 (09:32 +0100)
That addresses the issue where a server closes all open file descriptors
and then calls gnutls_global_init().

lib/crypto-backend.h
lib/gnutls_global.c
lib/nettle/rnd-common.c
lib/nettle/rnd-common.h
lib/nettle/rnd.c
lib/random.h

index 7f4e1b61c6dc642dd2a1655c921eed69953fa815..09a7d92c6707d4103b96907d8d02c951d90f7d99 100644 (file)
@@ -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);
index e4a303fcd60e59a8fd3f88749034e66a53c66c2e..5f340533d11134e4f568f011dd1acee080cc0cb6 100644 (file)
@@ -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;
        }
index 88aa7677d15d545e4c58a4d21f17dd1b13c8e508..4c83ac65497fe846ffd9ca3e85cfd7547d5b75c5 100644 (file)
 
 #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;
index a43f7be2334e4c5c9c3887f783aa144dd1cf3e10..c795f811316f3fbb69f308e2418e05a5675e2777 100644 (file)
@@ -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);
index 8dd98c3bf4e29d7822ad90f1275384d7e2861cf0..d4dbdc144fcb9126742ac6666a6365218b266092 100644 (file)
@@ -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,
index 8c755f8997c4f6c7d1c7ad0495582a3eca49f401..35857be357f3497ac7ea24cbc059ba91c3b709de 100644 (file)
@@ -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;