Blame SOURCES/gnutls-3.3.8-urandom-fd.patch

873a72
diff -urN gnutls-3.3.8.orig/lib/crypto-backend.h gnutls-3.3.8/lib/crypto-backend.h
873a72
--- gnutls-3.3.8.orig/lib/crypto-backend.h	2014-07-29 22:22:47.000000000 +0200
873a72
+++ gnutls-3.3.8/lib/crypto-backend.h	2014-11-18 09:52:15.420936655 +0100
873a72
@@ -77,6 +77,7 @@
873a72
 
873a72
 typedef struct gnutls_crypto_rnd {
873a72
 	int (*init) (void **ctx);
873a72
+	int (*check) (void **ctx);
873a72
 	int (*rnd) (void *ctx, int level, void *data, size_t datasize);
873a72
 	void (*rnd_refresh) (void *ctx);
873a72
 	void (*deinit) (void *ctx);
873a72
diff -urN gnutls-3.3.8.orig/lib/gnutls_global.c gnutls-3.3.8/lib/gnutls_global.c
873a72
--- gnutls-3.3.8.orig/lib/gnutls_global.c	2014-09-04 21:05:54.000000000 +0200
873a72
+++ gnutls-3.3.8/lib/gnutls_global.c	2014-11-18 09:57:18.851879610 +0100
873a72
@@ -207,6 +207,16 @@
873a72
 
873a72
 	_gnutls_init++;
873a72
 	if (_gnutls_init > 1) {
873a72
+		if (_gnutls_init == 2 && _gnutls_init_ret == 0) {
873a72
+			/* some applications may close the urandom fd 
873a72
+			 * before calling gnutls_global_init(). in that
873a72
+			 * case reopen it */
873a72
+			ret = _gnutls_rnd_check();
873a72
+			if (ret < 0) {
873a72
+				gnutls_assert();
873a72
+				goto out;
873a72
+			}
873a72
+		}
873a72
 		ret = _gnutls_init_ret;
873a72
 		goto out;
873a72
 	}
873a72
diff -urN gnutls-3.3.8.orig/lib/nettle/rnd.c gnutls-3.3.8/lib/nettle/rnd.c
873a72
--- gnutls-3.3.8.orig/lib/nettle/rnd.c	2014-07-29 22:25:07.000000000 +0200
873a72
+++ gnutls-3.3.8/lib/nettle/rnd.c	2014-11-18 09:52:15.420936655 +0100
873a72
@@ -255,6 +255,15 @@
873a72
 	return 0;
873a72
 }
873a72
 
873a72
+/* This is called when gnutls_global_init() is called for second time.
873a72
+ * It must check whether any resources are still available.
873a72
+ * The particular problem it solves is to verify that the urandom fd is still
873a72
+ * open (for applications that for some reason closed all fds */
873a72
+static int wrap_nettle_rnd_check(void **ctx)
873a72
+{
873a72
+	return _rnd_system_entropy_check();
873a72
+}
873a72
+
873a72
 static int
873a72
 wrap_nettle_rnd_nonce(void *_ctx, void *data, size_t datasize)
873a72
 {
873a72
@@ -363,6 +372,7 @@
873a72
 
873a72
 gnutls_crypto_rnd_st _gnutls_rnd_ops = {
873a72
 	.init = wrap_nettle_rnd_init,
873a72
+	.check = wrap_nettle_rnd_check,
873a72
 	.deinit = wrap_nettle_rnd_deinit,
873a72
 	.rnd = wrap_nettle_rnd,
873a72
 	.rnd_refresh = wrap_nettle_rnd_refresh,
873a72
diff -urN gnutls-3.3.8.orig/lib/nettle/rnd-common.c gnutls-3.3.8/lib/nettle/rnd-common.c
873a72
--- gnutls-3.3.8.orig/lib/nettle/rnd-common.c	2014-08-03 14:22:42.000000000 +0200
873a72
+++ gnutls-3.3.8/lib/nettle/rnd-common.c	2014-11-18 10:25:56.962112669 +0100
873a72
@@ -37,6 +37,10 @@
873a72
 #include <rnd-common.h>
873a72
 #include <hash-pjw-bare.h>
873a72
 
873a72
+#include <sys/types.h>
873a72
+#include <sys/stat.h>
873a72
+#include <unistd.h>
873a72
+
873a72
 /* gnulib wants to claim strerror even if it cannot provide it. WTF */
873a72
 #undef strerror
873a72
 
873a72
@@ -94,6 +98,11 @@
873a72
 
873a72
 get_entropy_func _rnd_get_system_entropy = _rnd_get_system_entropy_win32;
873a72
 
873a72
+int _rnd_system_entropy_check(void)
873a72
+{
873a72
+	return 0;
873a72
+}
873a72
+
873a72
 int _rnd_system_entropy_init(void)
873a72
 {
873a72
 	int old;
873a72
@@ -127,7 +136,8 @@
873a72
 #include <locks.h>
873a72
 #include "egd.h"
873a72
 
873a72
-static int device_fd = -1;
873a72
+int _gnutls_urandom_fd = -1;
873a72
+static mode_t _gnutls_urandom_fd_mode = 0;
873a72
 
873a72
 static int _rnd_get_system_entropy_urandom(void* _rnd, size_t size)
873a72
 {
873a72
@@ -137,7 +147,7 @@
873a72
 	for (done = 0; done < size;) {
873a72
 		int res;
873a72
 		do {
873a72
-			res = read(device_fd, rnd + done, size - done);
873a72
+			res = read(_gnutls_urandom_fd, rnd + done, size - done);
873a72
 		} while (res < 0 && errno == EINTR);
873a72
 
873a72
 		if (res <= 0) {
873a72
@@ -168,7 +178,7 @@
873a72
 
873a72
 	for (done = 0; done < size;) {
873a72
 		res =
873a72
-		    _rndegd_read(&device_fd, rnd + done, size - done);
873a72
+		    _rndegd_read(&_gnutls_urandom_fd, rnd + done, size - done);
873a72
 		if (res <= 0) {
873a72
 			if (res < 0) {
873a72
 				_gnutls_debug_log("Failed to read egd.\n");
873a72
@@ -186,31 +196,53 @@
873a72
 
873a72
 get_entropy_func _rnd_get_system_entropy = NULL;
873a72
 
873a72
+int _rnd_system_entropy_check(void)
873a72
+{
873a72
+	int ret;
873a72
+	struct stat st;
873a72
+
873a72
+	ret = fstat(_gnutls_urandom_fd, &st);
873a72
+	if (ret < 0 || st.st_mode != _gnutls_urandom_fd_mode) {
873a72
+		return _rnd_system_entropy_init();
873a72
+	}
873a72
+	return 0;
873a72
+}
873a72
+
873a72
 int _rnd_system_entropy_init(void)
873a72
 {
873a72
-int old;
873a72
+	int old;
873a72
+	struct stat st;
873a72
 	
873a72
-	device_fd = open("/dev/urandom", O_RDONLY);
873a72
-	if (device_fd < 0) {
873a72
+	_gnutls_urandom_fd = open("/dev/urandom", O_RDONLY);
873a72
+	if (_gnutls_urandom_fd < 0) {
873a72
 		_gnutls_debug_log("Cannot open urandom!\n");
873a72
 		goto fallback;
873a72
 	}
873a72
 
873a72
-	old = fcntl(device_fd, F_GETFD);
873a72
+	old = fcntl(_gnutls_urandom_fd, F_GETFD);
873a72
 	if (old != -1)
873a72
-		fcntl(device_fd, F_SETFD, old | FD_CLOEXEC);
873a72
+		fcntl(_gnutls_urandom_fd, F_SETFD, old | FD_CLOEXEC);
873a72
+
873a72
+	if (fstat(_gnutls_urandom_fd, &st) >= 0) {
873a72
+		_gnutls_urandom_fd_mode = st.st_mode;
873a72
+	}
873a72
 
873a72
 	_rnd_get_system_entropy = _rnd_get_system_entropy_urandom;
873a72
 
873a72
 	return 0;
873a72
 fallback:
873a72
-	device_fd = _rndegd_connect_socket();
873a72
-	if (device_fd < 0) {
873a72
+	_gnutls_urandom_fd = _rndegd_connect_socket();
873a72
+	if (_gnutls_urandom_fd < 0) {
873a72
 		_gnutls_debug_log("Cannot open egd socket!\n");
873a72
 		return
873a72
 			gnutls_assert_val
873a72
 			(GNUTLS_E_RANDOM_DEVICE_ERROR);
873a72
 	}
873a72
+
873a72
+	if (fstat(_gnutls_urandom_fd, &st) >= 0) {
873a72
+		_gnutls_urandom_fd_mode = st.st_mode;
873a72
+	}
873a72
+
873a72
 	_rnd_get_system_entropy = _rnd_get_system_entropy_egd;
873a72
 	
873a72
 	return 0;
873a72
@@ -218,9 +250,9 @@
873a72
 
873a72
 void _rnd_system_entropy_deinit(void)
873a72
 {
873a72
-	if (device_fd >= 0) {
873a72
-		close(device_fd);
873a72
-		device_fd = -1;
873a72
+	if (_gnutls_urandom_fd >= 0) {
873a72
+		close(_gnutls_urandom_fd);
873a72
+		_gnutls_urandom_fd = -1;
873a72
 	}
873a72
 }
873a72
 #endif
873a72
diff -urN gnutls-3.3.8.orig/lib/nettle/rnd-common.h gnutls-3.3.8/lib/nettle/rnd-common.h
873a72
--- gnutls-3.3.8.orig/lib/nettle/rnd-common.h	2014-07-29 22:22:47.000000000 +0200
873a72
+++ gnutls-3.3.8/lib/nettle/rnd-common.h	2014-11-18 09:52:15.420936655 +0100
873a72
@@ -50,6 +50,7 @@
873a72
 void _rnd_get_event(struct event_st *e);
873a72
 
873a72
 int _rnd_system_entropy_init(void);
873a72
+int _rnd_system_entropy_check(void);
873a72
 void _rnd_system_entropy_deinit(void);
873a72
 
873a72
 typedef int (*get_entropy_func)(void* rnd, size_t size);
873a72
diff -urN gnutls-3.3.8.orig/lib/random.h gnutls-3.3.8/lib/random.h
873a72
--- gnutls-3.3.8.orig/lib/random.h	2014-07-29 22:22:47.000000000 +0200
873a72
+++ gnutls-3.3.8/lib/random.h	2014-11-18 09:58:19.458267672 +0100
873a72
@@ -48,4 +48,13 @@
873a72
 void _gnutls_rnd_deinit(void);
873a72
 int _gnutls_rnd_init(void);
873a72
 
873a72
+inline static int _gnutls_rnd_check(void)
873a72
+{
873a72
+       return _gnutls_rnd_ops.check(gnutls_rnd_ctx);
873a72
+}
873a72
+
873a72
+#ifndef _WIN32
873a72
+extern int _gnutls_urandom_fd;
873a72
+#endif
873a72
+
873a72
 #endif
873a72
diff -urN gnutls-3.3.8.orig/tests/init_fds.c gnutls-3.3.8/tests/init_fds.c
873a72
--- gnutls-3.3.8.orig/tests/init_fds.c	1970-01-01 01:00:00.000000000 +0100
873a72
+++ gnutls-3.3.8/tests/init_fds.c	2014-11-18 10:01:10.484365302 +0100
873a72
@@ -0,0 +1,80 @@
873a72
+/*
873a72
+ * Copyright (C) 2014 Nikos Mavrogiannopoulos
873a72
+ *
873a72
+ * Author: Nikos Mavrogiannopoulos
873a72
+ *
873a72
+ * This file is part of GnuTLS.
873a72
+ *
873a72
+ * GnuTLS is free software; you can redistribute it and/or modify it
873a72
+ * under the terms of the GNU General Public License as published by
873a72
+ * the Free Software Foundation; either version 3 of the License, or
873a72
+ * (at your option) any later version.
873a72
+ *
873a72
+ * GnuTLS is distributed in the hope that it will be useful, but
873a72
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
873a72
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
873a72
+ * General Public License for more details.
873a72
+ *
873a72
+ * You should have received a copy of the GNU General Public License
873a72
+ * along with GnuTLS; if not, write to the Free Software Foundation,
873a72
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
873a72
+ */
873a72
+
873a72
+#ifdef HAVE_CONFIG_H
873a72
+#include <config.h>
873a72
+#endif
873a72
+
873a72
+#include <stdio.h>
873a72
+#include <unistd.h>
873a72
+#include <gnutls/gnutls.h>
873a72
+#include <gnutls/crypto.h>
873a72
+
873a72
+#include "utils.h"
873a72
+
873a72
+/* See <https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=760476>. */
873a72
+
873a72
+void doit(void)
873a72
+{
873a72
+#ifndef _WIN32
873a72
+	int res;
873a72
+	unsigned i;
873a72
+	int serial = 0;
873a72
+	char buf[128];
873a72
+
873a72
+	res = read(3, buf, 16);
873a72
+	if (res == 16)
873a72
+		serial = 1;
873a72
+
873a72
+	/* close all descriptors */
873a72
+	for (i=3;i<1024;i++)
873a72
+		close(i);
873a72
+
873a72
+	res = gnutls_global_init();
873a72
+	if (res != 0)
873a72
+		fail("global_init\n");
873a72
+
873a72
+	if (serial != 0) {
873a72
+		res = read(3, buf, 16);
873a72
+		if (res != 16) {
873a72
+			fail("could not open fd, or OS doesn't assign fds in a serial way (%d)\n", res);
873a72
+		}
873a72
+	}
873a72
+
873a72
+	res = gnutls_global_init();
873a72
+	if (res != 0)
873a72
+		fail("global_init2\n");
873a72
+
873a72
+	gnutls_rnd_refresh();
873a72
+
873a72
+	res = gnutls_rnd(GNUTLS_RND_RANDOM, buf, sizeof(buf));
873a72
+	if (res != 0)
873a72
+		fail("gnutls_rnd\n");
873a72
+
873a72
+	gnutls_global_deinit();
873a72
+
873a72
+	if (debug)
873a72
+		success("init-close success\n");
873a72
+#else
873a72
+	return;
873a72
+#endif
873a72
+}
873a72
diff -urN gnutls-3.3.8.orig/tests/Makefile.am gnutls-3.3.8/tests/Makefile.am
873a72
--- gnutls-3.3.8.orig/tests/Makefile.am	2014-09-13 13:08:01.000000000 +0200
873a72
+++ gnutls-3.3.8/tests/Makefile.am	2014-11-18 10:01:10.483365293 +0100
873a72
@@ -84,7 +84,7 @@
873a72
 	 mini-cert-status mini-rsa-psk global-init sec-params \
873a72
 	 fips-test mini-global-load name-constraints x509-extensions \
873a72
 	 long-session-id mini-x509-callbacks-intr \
873a72
-	 crlverify
873a72
+	 crlverify init_fds
873a72
 
873a72
 if ENABLE_OCSP
873a72
 ctests += ocsp