summaryrefslogtreecommitdiff
path: root/recipes-support/gnutls/gnutls-3.5.3/0002-rng-split-initialization-in-preinit-and-init.patch
blob: 29bcf5f7bb3a61e99f849ac8298b3f54f8686a18 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
From 834e8fc03cb27ae437a2044cfaf265752c3e6a26 Mon Sep 17 00:00:00 2001
From: Nikos Mavrogiannopoulos <nmav@redhat.com>
Date: Fri, 14 Oct 2016 14:16:51 +0200
Subject: [PATCH 2/3] rng: split initialization in preinit and init

This makes gnutls to initialize its random generator on the
first call to gnutls_rnd(). That prevents blocking due to
getrandom() on a constructor; that change allows to use gnutls-linked
applications even in early boot in systems where getrandom() blocks
waiting for entropy.

Upstream-Status: Backport

diff --git a/configure.ac b/configure.ac
index 0ba2230..f842e26 100644
--- a/configure.ac
+++ b/configure.ac
@@ -186,6 +186,7 @@ AM_SUBST_NOTMAKE([DEFINE_IOVEC_T])
 
 dnl Need netinet/tcp.h for TCP_FASTOPEN
 AC_CHECK_HEADERS([netinet/tcp.h])
+AC_CHECK_HEADERS([stdatomic.h])
 
 AC_ARG_ENABLE(padlock,
   AS_HELP_STRING([--disable-padlock], [unconditionally disable padlock acceleration]),
diff --git a/lib/global.c b/lib/global.c
index d75cea8..bdc3c1f 100644
--- a/lib/global.c
+++ b/lib/global.c
@@ -304,7 +304,7 @@ static int _gnutls_global_init(unsigned constructor)
 	}
 
 	/* Initialize the random generator */
-	ret = _gnutls_rnd_init();
+	ret = _gnutls_rnd_preinit();
 	if (ret < 0) {
 		gnutls_assert();
 		goto out;
diff --git a/lib/locks.h b/lib/locks.h
index 5807754..b1efbb5 100644
--- a/lib/locks.h
+++ b/lib/locks.h
@@ -27,6 +27,10 @@
 #include "gnutls_int.h"
 #include <system.h>
 
+#ifdef HAVE_STDATOMIC_H
+# include <stdatomic.h>
+#endif
+
 extern mutex_init_func gnutls_mutex_init;
 extern mutex_deinit_func gnutls_mutex_deinit;
 extern mutex_lock_func gnutls_mutex_lock;
diff --git a/lib/nettle/rnd-fips.c b/lib/nettle/rnd-fips.c
index 59795a9..0807701 100644
--- a/lib/nettle/rnd-fips.c
+++ b/lib/nettle/rnd-fips.c
@@ -172,10 +172,6 @@ static int _rngfips_init(void **_ctx)
 	struct fips_ctx *ctx;
 	int ret;
 
-	ret = _rnd_system_entropy_init();
-	if (ret < 0)
-		return gnutls_assert_val(ret);
-
 	ctx = gnutls_calloc(1, sizeof(*ctx));
 	if (ctx == NULL)
 		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
diff --git a/lib/nettle/rnd.c b/lib/nettle/rnd.c
index 39b99e1..c4fbc48 100644
--- a/lib/nettle/rnd.c
+++ b/lib/nettle/rnd.c
@@ -218,12 +218,6 @@ static int wrap_nettle_rnd_init(void **ctx)
 		return ret;
 	}
 
-	ret = _rnd_system_entropy_init();
-	if (ret < 0) {
-		gnutls_assert();
-		return ret;
-	}
-
 	/* initialize the main RNG */
 	yarrow256_init(&rnd_ctx.yctx, SOURCES, rnd_ctx.ysources);
 
diff --git a/lib/random.c b/lib/random.c
index d7f18f2..977d7aa 100644
--- a/lib/random.c
+++ b/lib/random.c
@@ -26,30 +26,80 @@
 #include "gnutls_int.h"
 #include "errors.h"
 #include <random.h>
+#include "locks.h"
 #include <fips.h>
 
 void *gnutls_rnd_ctx;
+GNUTLS_STATIC_MUTEX(gnutls_rnd_init_mutex);
 
-int _gnutls_rnd_init(void)
+#ifdef HAVE_STDATOMIC_H
+static atomic_uint rnd_initialized = 0;
+
+inline static int _gnutls_rnd_init(void)
+{
+	if (unlikely(!rnd_initialized)) {
+		if (_gnutls_rnd_ops.init == NULL) {
+			rnd_initialized = 1;
+			return 0;
+		}
+
+		GNUTLS_STATIC_MUTEX_LOCK(gnutls_rnd_init_mutex);
+		if (!rnd_initialized) {
+			if (_gnutls_rnd_ops.init(&gnutls_rnd_ctx) < 0) {
+				gnutls_assert();
+				GNUTLS_STATIC_MUTEX_UNLOCK(gnutls_rnd_init_mutex);
+				return GNUTLS_E_RANDOM_FAILED;
+			}
+			rnd_initialized = 1;
+		}
+		GNUTLS_STATIC_MUTEX_UNLOCK(gnutls_rnd_init_mutex);
+	}
+	return 0;
+}
+#else
+static unsigned rnd_initialized = 0;
+
+inline static int _gnutls_rnd_init(void)
+{
+	GNUTLS_STATIC_MUTEX_LOCK(gnutls_rnd_init_mutex);
+	if (unlikely(!rnd_initialized)) {
+		if (_gnutls_rnd_ops.init == NULL) {
+			rnd_initialized = 1;
+			GNUTLS_STATIC_MUTEX_UNLOCK(gnutls_rnd_init_mutex);
+			return 0;
+		}
+
+		if (_gnutls_rnd_ops.init(&gnutls_rnd_ctx) < 0) {
+			gnutls_assert();
+			GNUTLS_STATIC_MUTEX_UNLOCK(gnutls_rnd_init_mutex);
+			return GNUTLS_E_RANDOM_FAILED;
+		}
+		rnd_initialized = 1;
+	}
+	GNUTLS_STATIC_MUTEX_UNLOCK(gnutls_rnd_init_mutex);
+	return 0;
+}
+#endif
+
+int _gnutls_rnd_preinit(void)
 {
+	int ret;
+
 #ifdef ENABLE_FIPS140
 	/* The FIPS140 random generator is only enabled when we are compiled
 	 * with FIPS support, _and_ the system requires FIPS140.
 	 */
 	if (_gnutls_fips_mode_enabled() == 1) {
-		int ret;
-
 		ret = gnutls_crypto_rnd_register(100, &_gnutls_fips_rnd_ops);
 		if (ret < 0)
 			return ret;
 	}
 #endif
 
-	if (_gnutls_rnd_ops.init != NULL) {
-		if (_gnutls_rnd_ops.init(&gnutls_rnd_ctx) < 0) {
-			gnutls_assert();
-			return GNUTLS_E_RANDOM_FAILED;
-		}
+	ret = _rnd_system_entropy_init();
+	if (ret < 0) {
+		gnutls_assert();
+		return GNUTLS_E_RANDOM_FAILED;
 	}
 
 	return 0;
@@ -57,9 +107,12 @@ int _gnutls_rnd_init(void)
 
 void _gnutls_rnd_deinit(void)
 {
-	if (_gnutls_rnd_ops.deinit != NULL) {
+	if (rnd_initialized && _gnutls_rnd_ops.deinit != NULL) {
 		_gnutls_rnd_ops.deinit(gnutls_rnd_ctx);
 	}
+	rnd_initialized = 0;
+
+	_rnd_system_entropy_deinit();
 
 	return;
 }
@@ -81,8 +134,17 @@ void _gnutls_rnd_deinit(void)
  **/
 int gnutls_rnd(gnutls_rnd_level_t level, void *data, size_t len)
 {
+	int ret;
 	FAIL_IF_LIB_ERROR;
-	return _gnutls_rnd(level, data, len);
+
+	if (unlikely((ret=_gnutls_rnd_init()) < 0))
+		return gnutls_assert_val(ret);
+
+	if (likely(len > 0)) {
+		return _gnutls_rnd_ops.rnd(gnutls_rnd_ctx, level, data,
+					   len);
+	}
+	return 0;
 }
 
 /**
@@ -98,5 +160,6 @@ int gnutls_rnd(gnutls_rnd_level_t level, void *data, size_t len)
  **/
 void gnutls_rnd_refresh(void)
 {
-	_gnutls_rnd_refresh();
+	if (rnd_initialized && _gnutls_rnd_ops.rnd_refresh)
+		_gnutls_rnd_ops.rnd_refresh(gnutls_rnd_ctx);
 }
diff --git a/lib/random.h b/lib/random.h
index 1538ec8..2ef7bc4 100644
--- a/lib/random.h
+++ b/lib/random.h
@@ -31,31 +31,15 @@ extern int crypto_rnd_prio;
 extern void *gnutls_rnd_ctx;
 extern gnutls_crypto_rnd_st _gnutls_rnd_ops;
 
-inline static int
-_gnutls_rnd(gnutls_rnd_level_t level, void *data, size_t len)
-{
-	if (len > 0) {
-		return _gnutls_rnd_ops.rnd(gnutls_rnd_ctx, level, data,
-					   len);
-	}
-	return 0;
-}
-
-inline static void _gnutls_rnd_refresh(void)
-{
-	_gnutls_rnd_ops.rnd_refresh(gnutls_rnd_ctx);
-}
+#define _gnutls_rnd gnutls_rnd
+#define _gnutls_rnd_refresh gnutls_rnd_refresh
 
 void _gnutls_rnd_deinit(void);
-int _gnutls_rnd_init(void);
+int _gnutls_rnd_preinit(void);
 
 inline static int _gnutls_rnd_check(void)
 {
 	return _rnd_system_entropy_check();
 }
 
-#ifndef _WIN32
-extern int _gnutls_urandom_fd;
-#endif
-
 #endif
-- 
2.6.6