diff options
author | haiqing <haiqing.bai@windriver.com> | 2020-03-27 10:38:05 +0800 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2020-04-17 08:29:02 +0100 |
commit | a41085d1a63cc629cfb9b4fb1fc30ec43d8e56a7 (patch) | |
tree | d328c78409d5984eeb08be1aab803769288419dc /meta/recipes-core | |
parent | eb029c9ac0f5820c05912760a95388827a6d3f0d (diff) | |
download | poky-a41085d1a63cc629cfb9b4fb1fc30ec43d8e56a7.tar.gz |
glib-2.0: fix CVE-2020-6750
GSocketClient in GNOME GLib through 2.62.4 may occasionally connect directly
to a target address instead of connecting via a proxy server when configured
to do so, because the proxy_addr field is mishandled. This bug is timing-dependent
and may occur only sporadically depending on network delays. The greatest security
relevance is in use cases where a proxy is used to help with privacy/anonymity,
even though there is no technical barrier to a direct connection.
(From OE-Core rev: 29ed9fc7341cc3db716115aef1a6910fdb893145)
Signed-off-by: Haiqing Bai <Haiqing.Bai@windriver.com>
Signed-off-by: Anuj Mittal <anuj.mittal@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/recipes-core')
-rw-r--r-- | meta/recipes-core/glib-2.0/glib-2.0/CVE-2020-6750.patch | 741 | ||||
-rw-r--r-- | meta/recipes-core/glib-2.0/glib-2.0_2.60.7.bb | 1 |
2 files changed, 742 insertions, 0 deletions
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2020-6750.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2020-6750.patch new file mode 100644 index 0000000000..6db3934978 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2020-6750.patch | |||
@@ -0,0 +1,741 @@ | |||
1 | From 747f2c646f5a86ac58ad59be08036e81388e971d Mon Sep 17 00:00:00 2001 | ||
2 | From: Patrick Griffis <tingping@tingping.se> | ||
3 | Date: Thu, 23 Jan 2020 19:58:41 -0800 | ||
4 | Subject: [PATCH] Refactor g_socket_client_connect_async() | ||
5 | |||
6 | This is a fairly large refactoring. The highlights are: | ||
7 | |||
8 | - Removing in-progress connections/addresses from GSocketClientAsyncConnectData: | ||
9 | |||
10 | This caused issues where multiple ConnectionAttempt's would step over eachother | ||
11 | and modify shared state causing bugs like accidentally bypassing a set proxy. | ||
12 | |||
13 | Fixes #1871 | ||
14 | Fixes #1989 | ||
15 | Fixes #1902 | ||
16 | |||
17 | - Cancelling address enumeration on error/completion | ||
18 | |||
19 | - Queuing successful TCP connections and doing application layer work serially: | ||
20 | |||
21 | This is more in the spirit of Happy Eyeballs but it also greatly simplifies | ||
22 | the flow of connection handling so fewer tasks are happening in parallel | ||
23 | when they don't need to be. | ||
24 | |||
25 | The behavior also should more closely match that of g_socket_client_connect(). | ||
26 | |||
27 | - Better track the state of address enumeration: | ||
28 | |||
29 | Previously we were over eager to treat enumeration finishing as an error. | ||
30 | |||
31 | Fixes #1872 | ||
32 | See also #1982 | ||
33 | |||
34 | - Add more detailed documentation and logging. | ||
35 | |||
36 | Closes #1995 | ||
37 | |||
38 | CVE: CVE-2020-6750 | ||
39 | |||
40 | Upstream-Status: Backport [ https://gitlab.gnome.org/GNOME/glib.git; | ||
41 | commit=2722620e3291b930a3a228100d7c0e07b69534e3 ] | ||
42 | |||
43 | Signed-off-by: Haiqing Bai <Haiqing.Bai@windriver.com> | ||
44 | --- | ||
45 | gio/gsocketclient.c | 459 ++++++++++++++++++++++++++++---------------- | ||
46 | 1 file changed, 296 insertions(+), 163 deletions(-) | ||
47 | |||
48 | diff --git a/gio/gsocketclient.c b/gio/gsocketclient.c | ||
49 | index 81767c0..b1d5f6c 100644 | ||
50 | --- a/gio/gsocketclient.c | ||
51 | +++ b/gio/gsocketclient.c | ||
52 | @@ -1332,13 +1332,15 @@ typedef struct | ||
53 | |||
54 | GSocketConnectable *connectable; | ||
55 | GSocketAddressEnumerator *enumerator; | ||
56 | - GProxyAddress *proxy_addr; | ||
57 | - GSocket *socket; | ||
58 | - GIOStream *connection; | ||
59 | + GCancellable *enumeration_cancellable; | ||
60 | |||
61 | GSList *connection_attempts; | ||
62 | + GSList *successful_connections; | ||
63 | GError *last_error; | ||
64 | |||
65 | + gboolean enumerated_at_least_once; | ||
66 | + gboolean enumeration_completed; | ||
67 | + gboolean connection_in_progress; | ||
68 | gboolean completed; | ||
69 | } GSocketClientAsyncConnectData; | ||
70 | |||
71 | @@ -1350,10 +1352,9 @@ g_socket_client_async_connect_data_free (GSocketClientAsyncConnectData *data) | ||
72 | data->task = NULL; | ||
73 | g_clear_object (&data->connectable); | ||
74 | g_clear_object (&data->enumerator); | ||
75 | - g_clear_object (&data->proxy_addr); | ||
76 | - g_clear_object (&data->socket); | ||
77 | - g_clear_object (&data->connection); | ||
78 | + g_clear_object (&data->enumeration_cancellable); | ||
79 | g_slist_free_full (data->connection_attempts, connection_attempt_unref); | ||
80 | + g_slist_free_full (data->successful_connections, connection_attempt_unref); | ||
81 | |||
82 | g_clear_error (&data->last_error); | ||
83 | |||
84 | @@ -1365,6 +1366,7 @@ typedef struct | ||
85 | GSocketAddress *address; | ||
86 | GSocket *socket; | ||
87 | GIOStream *connection; | ||
88 | + GProxyAddress *proxy_addr; | ||
89 | GSocketClientAsyncConnectData *data; /* unowned */ | ||
90 | GSource *timeout_source; | ||
91 | GCancellable *cancellable; | ||
92 | @@ -1396,6 +1398,7 @@ connection_attempt_unref (gpointer pointer) | ||
93 | g_clear_object (&attempt->socket); | ||
94 | g_clear_object (&attempt->connection); | ||
95 | g_clear_object (&attempt->cancellable); | ||
96 | + g_clear_object (&attempt->proxy_addr); | ||
97 | if (attempt->timeout_source) | ||
98 | { | ||
99 | g_source_destroy (attempt->timeout_source); | ||
100 | @@ -1413,37 +1416,59 @@ connection_attempt_remove (ConnectionAttempt *attempt) | ||
101 | } | ||
102 | |||
103 | static void | ||
104 | -g_socket_client_async_connect_complete (GSocketClientAsyncConnectData *data) | ||
105 | +cancel_all_attempts (GSocketClientAsyncConnectData *data) | ||
106 | { | ||
107 | - g_assert (data->connection); | ||
108 | + GSList *l; | ||
109 | |||
110 | - if (!G_IS_SOCKET_CONNECTION (data->connection)) | ||
111 | + for (l = data->connection_attempts; l; l = g_slist_next (l)) | ||
112 | { | ||
113 | - GSocketConnection *wrapper_connection; | ||
114 | - | ||
115 | - wrapper_connection = g_tcp_wrapper_connection_new (data->connection, data->socket); | ||
116 | - g_object_unref (data->connection); | ||
117 | - data->connection = (GIOStream *)wrapper_connection; | ||
118 | + ConnectionAttempt *attempt_entry = l->data; | ||
119 | + g_cancellable_cancel (attempt_entry->cancellable); | ||
120 | + connection_attempt_unref (attempt_entry); | ||
121 | } | ||
122 | + g_slist_free (data->connection_attempts); | ||
123 | + data->connection_attempts = NULL; | ||
124 | |||
125 | - if (!data->completed) | ||
126 | + g_slist_free_full (data->successful_connections, connection_attempt_unref); | ||
127 | + data->successful_connections = NULL; | ||
128 | + | ||
129 | + g_cancellable_cancel (data->enumeration_cancellable); | ||
130 | +} | ||
131 | + | ||
132 | +static void | ||
133 | +g_socket_client_async_connect_complete (ConnectionAttempt *attempt) | ||
134 | +{ | ||
135 | + GSocketClientAsyncConnectData *data = attempt->data; | ||
136 | + GError *error = NULL; | ||
137 | + g_assert (attempt->connection); | ||
138 | + g_assert (!data->completed); | ||
139 | + | ||
140 | + if (!G_IS_SOCKET_CONNECTION (attempt->connection)) | ||
141 | { | ||
142 | - GError *error = NULL; | ||
143 | + GSocketConnection *wrapper_connection; | ||
144 | |||
145 | - if (g_cancellable_set_error_if_cancelled (g_task_get_cancellable (data->task), &error)) | ||
146 | - { | ||
147 | - g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_COMPLETE, data->connectable, NULL); | ||
148 | - g_task_return_error (data->task, g_steal_pointer (&error)); | ||
149 | - } | ||
150 | - else | ||
151 | - { | ||
152 | - g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_COMPLETE, data->connectable, data->connection); | ||
153 | - g_task_return_pointer (data->task, g_steal_pointer (&data->connection), g_object_unref); | ||
154 | - } | ||
155 | + wrapper_connection = g_tcp_wrapper_connection_new (attempt->connection, attempt->socket); | ||
156 | + g_object_unref (attempt->connection); | ||
157 | + attempt->connection = (GIOStream *)wrapper_connection; | ||
158 | + } | ||
159 | |||
160 | - data->completed = TRUE; | ||
161 | + data->completed = TRUE; | ||
162 | + cancel_all_attempts (data); | ||
163 | + | ||
164 | + if (g_cancellable_set_error_if_cancelled (g_task_get_cancellable (data->task), &error)) | ||
165 | + { | ||
166 | + g_debug ("GSocketClient: Connection cancelled!"); | ||
167 | + g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_COMPLETE, data->connectable, NULL); | ||
168 | + g_task_return_error (data->task, g_steal_pointer (&error)); | ||
169 | + } | ||
170 | + else | ||
171 | + { | ||
172 | + g_debug ("GSocketClient: Connection successful!"); | ||
173 | + g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_COMPLETE, data->connectable, attempt->connection); | ||
174 | + g_task_return_pointer (data->task, g_steal_pointer (&attempt->connection), g_object_unref); | ||
175 | } | ||
176 | |||
177 | + connection_attempt_unref (attempt); | ||
178 | g_object_unref (data->task); | ||
179 | } | ||
180 | |||
181 | @@ -1465,59 +1490,63 @@ static void | ||
182 | enumerator_next_async (GSocketClientAsyncConnectData *data, | ||
183 | gboolean add_task_ref) | ||
184 | { | ||
185 | - /* We need to cleanup the state */ | ||
186 | - g_clear_object (&data->socket); | ||
187 | - g_clear_object (&data->proxy_addr); | ||
188 | - g_clear_object (&data->connection); | ||
189 | - | ||
190 | /* Each enumeration takes a ref. This arg just avoids repeated unrefs when | ||
191 | an enumeration starts another enumeration */ | ||
192 | if (add_task_ref) | ||
193 | g_object_ref (data->task); | ||
194 | |||
195 | g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_RESOLVING, data->connectable, NULL); | ||
196 | + g_debug ("GSocketClient: Starting new address enumeration"); | ||
197 | g_socket_address_enumerator_next_async (data->enumerator, | ||
198 | - g_task_get_cancellable (data->task), | ||
199 | + data->enumeration_cancellable, | ||
200 | g_socket_client_enumerator_callback, | ||
201 | data); | ||
202 | } | ||
203 | |||
204 | +static void try_next_connection_or_finish (GSocketClientAsyncConnectData *, gboolean); | ||
205 | + | ||
206 | static void | ||
207 | g_socket_client_tls_handshake_callback (GObject *object, | ||
208 | GAsyncResult *result, | ||
209 | gpointer user_data) | ||
210 | { | ||
211 | - GSocketClientAsyncConnectData *data = user_data; | ||
212 | + ConnectionAttempt *attempt = user_data; | ||
213 | + GSocketClientAsyncConnectData *data = attempt->data; | ||
214 | |||
215 | if (g_tls_connection_handshake_finish (G_TLS_CONNECTION (object), | ||
216 | result, | ||
217 | &data->last_error)) | ||
218 | { | ||
219 | - g_object_unref (data->connection); | ||
220 | - data->connection = G_IO_STREAM (object); | ||
221 | + g_object_unref (attempt->connection); | ||
222 | + attempt->connection = G_IO_STREAM (object); | ||
223 | |||
224 | - g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_TLS_HANDSHAKED, data->connectable, data->connection); | ||
225 | - g_socket_client_async_connect_complete (data); | ||
226 | + g_debug ("GSocketClient: TLS handshake succeeded"); | ||
227 | + g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_TLS_HANDSHAKED, data->connectable, attempt->connection); | ||
228 | + g_socket_client_async_connect_complete (attempt); | ||
229 | } | ||
230 | else | ||
231 | { | ||
232 | g_object_unref (object); | ||
233 | - enumerator_next_async (data, FALSE); | ||
234 | + connection_attempt_unref (attempt); | ||
235 | + g_debug ("GSocketClient: TLS handshake failed: %s", data->last_error->message); | ||
236 | + try_next_connection_or_finish (data, TRUE); | ||
237 | } | ||
238 | } | ||
239 | |||
240 | static void | ||
241 | -g_socket_client_tls_handshake (GSocketClientAsyncConnectData *data) | ||
242 | +g_socket_client_tls_handshake (ConnectionAttempt *attempt) | ||
243 | { | ||
244 | + GSocketClientAsyncConnectData *data = attempt->data; | ||
245 | GIOStream *tlsconn; | ||
246 | |||
247 | if (!data->client->priv->tls) | ||
248 | { | ||
249 | - g_socket_client_async_connect_complete (data); | ||
250 | + g_socket_client_async_connect_complete (attempt); | ||
251 | return; | ||
252 | } | ||
253 | |||
254 | - tlsconn = g_tls_client_connection_new (data->connection, | ||
255 | + g_debug ("GSocketClient: Starting TLS handshake"); | ||
256 | + tlsconn = g_tls_client_connection_new (attempt->connection, | ||
257 | data->connectable, | ||
258 | &data->last_error); | ||
259 | if (tlsconn) | ||
260 | @@ -1529,11 +1558,12 @@ g_socket_client_tls_handshake (GSocketClientAsyncConnectData *data) | ||
261 | G_PRIORITY_DEFAULT, | ||
262 | g_task_get_cancellable (data->task), | ||
263 | g_socket_client_tls_handshake_callback, | ||
264 | - data); | ||
265 | + attempt); | ||
266 | } | ||
267 | else | ||
268 | { | ||
269 | - enumerator_next_async (data, FALSE); | ||
270 | + connection_attempt_unref (attempt); | ||
271 | + try_next_connection_or_finish (data, TRUE); | ||
272 | } | ||
273 | } | ||
274 | |||
275 | @@ -1542,23 +1572,38 @@ g_socket_client_proxy_connect_callback (GObject *object, | ||
276 | GAsyncResult *result, | ||
277 | gpointer user_data) | ||
278 | { | ||
279 | - GSocketClientAsyncConnectData *data = user_data; | ||
280 | + ConnectionAttempt *attempt = user_data; | ||
281 | + GSocketClientAsyncConnectData *data = attempt->data; | ||
282 | |||
283 | - g_object_unref (data->connection); | ||
284 | - data->connection = g_proxy_connect_finish (G_PROXY (object), | ||
285 | - result, | ||
286 | - &data->last_error); | ||
287 | - if (data->connection) | ||
288 | + g_object_unref (attempt->connection); | ||
289 | + attempt->connection = g_proxy_connect_finish (G_PROXY (object), | ||
290 | + result, | ||
291 | + &data->last_error); | ||
292 | + if (attempt->connection) | ||
293 | { | ||
294 | - g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_PROXY_NEGOTIATED, data->connectable, data->connection); | ||
295 | + g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_PROXY_NEGOTIATED, data->connectable, attempt->connection); | ||
296 | } | ||
297 | else | ||
298 | { | ||
299 | - enumerator_next_async (data, FALSE); | ||
300 | + connection_attempt_unref (attempt); | ||
301 | + try_next_connection_or_finish (data, TRUE); | ||
302 | return; | ||
303 | } | ||
304 | |||
305 | - g_socket_client_tls_handshake (data); | ||
306 | + g_socket_client_tls_handshake (attempt); | ||
307 | +} | ||
308 | + | ||
309 | +static void | ||
310 | +complete_connection_with_error (GSocketClientAsyncConnectData *data, | ||
311 | + GError *error) | ||
312 | +{ | ||
313 | + g_debug ("GSocketClient: Connection failed: %s", error->message); | ||
314 | + g_assert (!data->completed); | ||
315 | + | ||
316 | + g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_COMPLETE, data->connectable, NULL); | ||
317 | + data->completed = TRUE; | ||
318 | + cancel_all_attempts (data); | ||
319 | + g_task_return_error (data->task, error); | ||
320 | } | ||
321 | |||
322 | static gboolean | ||
323 | @@ -1572,15 +1617,114 @@ task_completed_or_cancelled (GSocketClientAsyncConnectData *data) | ||
324 | return TRUE; | ||
325 | else if (g_cancellable_set_error_if_cancelled (cancellable, &error)) | ||
326 | { | ||
327 | - g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_COMPLETE, data->connectable, NULL); | ||
328 | - g_task_return_error (task, g_steal_pointer (&error)); | ||
329 | - data->completed = TRUE; | ||
330 | + complete_connection_with_error (data, g_steal_pointer (&error)); | ||
331 | return TRUE; | ||
332 | } | ||
333 | else | ||
334 | return FALSE; | ||
335 | } | ||
336 | |||
337 | +static gboolean | ||
338 | +try_next_successful_connection (GSocketClientAsyncConnectData *data) | ||
339 | +{ | ||
340 | + ConnectionAttempt *attempt; | ||
341 | + const gchar *protocol; | ||
342 | + GProxy *proxy; | ||
343 | + | ||
344 | + if (data->connection_in_progress) | ||
345 | + return FALSE; | ||
346 | + | ||
347 | + g_assert (data->successful_connections != NULL); | ||
348 | + attempt = data->successful_connections->data; | ||
349 | + g_assert (attempt != NULL); | ||
350 | + data->successful_connections = g_slist_remove (data->successful_connections, attempt); | ||
351 | + data->connection_in_progress = TRUE; | ||
352 | + | ||
353 | + g_debug ("GSocketClient: Starting application layer connection"); | ||
354 | + | ||
355 | + if (!attempt->proxy_addr) | ||
356 | + { | ||
357 | + g_socket_client_tls_handshake (g_steal_pointer (&attempt)); | ||
358 | + return TRUE; | ||
359 | + } | ||
360 | + | ||
361 | + protocol = g_proxy_address_get_protocol (attempt->proxy_addr); | ||
362 | + | ||
363 | + /* The connection should not be anything other than TCP, | ||
364 | + * but let's put a safety guard in case | ||
365 | + */ | ||
366 | + if (!G_IS_TCP_CONNECTION (attempt->connection)) | ||
367 | + { | ||
368 | + g_critical ("Trying to proxy over non-TCP connection, this is " | ||
369 | + "most likely a bug in GLib IO library."); | ||
370 | + | ||
371 | + g_set_error_literal (&data->last_error, | ||
372 | + G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, | ||
373 | + _("Proxying over a non-TCP connection is not supported.")); | ||
374 | + } | ||
375 | + else if (g_hash_table_contains (data->client->priv->app_proxies, protocol)) | ||
376 | + { | ||
377 | + /* Simply complete the connection, we don't want to do TLS handshake | ||
378 | + * as the application proxy handling may need proxy handshake first */ | ||
379 | + g_socket_client_async_connect_complete (g_steal_pointer (&attempt)); | ||
380 | + return TRUE; | ||
381 | + } | ||
382 | + else if ((proxy = g_proxy_get_default_for_protocol (protocol))) | ||
383 | + { | ||
384 | + GIOStream *connection = attempt->connection; | ||
385 | + GProxyAddress *proxy_addr = attempt->proxy_addr; | ||
386 | + | ||
387 | + g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_PROXY_NEGOTIATING, data->connectable, attempt->connection); | ||
388 | + g_debug ("GSocketClient: Starting proxy connection"); | ||
389 | + g_proxy_connect_async (proxy, | ||
390 | + connection, | ||
391 | + proxy_addr, | ||
392 | + g_task_get_cancellable (data->task), | ||
393 | + g_socket_client_proxy_connect_callback, | ||
394 | + g_steal_pointer (&attempt)); | ||
395 | + g_object_unref (proxy); | ||
396 | + return TRUE; | ||
397 | + } | ||
398 | + else | ||
399 | + { | ||
400 | + g_clear_error (&data->last_error); | ||
401 | + | ||
402 | + g_set_error (&data->last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, | ||
403 | + _("Proxy protocol ā%sā is not supported."), | ||
404 | + protocol); | ||
405 | + } | ||
406 | + | ||
407 | + data->connection_in_progress = FALSE; | ||
408 | + g_clear_pointer (&attempt, connection_attempt_unref); | ||
409 | + return FALSE; /* All non-return paths are failures */ | ||
410 | +} | ||
411 | + | ||
412 | +static void | ||
413 | +try_next_connection_or_finish (GSocketClientAsyncConnectData *data, | ||
414 | + gboolean end_current_connection) | ||
415 | +{ | ||
416 | + if (end_current_connection) | ||
417 | + data->connection_in_progress = FALSE; | ||
418 | + | ||
419 | + if (data->connection_in_progress) | ||
420 | + return; | ||
421 | + | ||
422 | + /* Keep trying successful connections until one works, each iteration pops one */ | ||
423 | + while (data->successful_connections) | ||
424 | + { | ||
425 | + if (try_next_successful_connection (data)) | ||
426 | + return; | ||
427 | + } | ||
428 | + | ||
429 | + if (!data->enumeration_completed) | ||
430 | + { | ||
431 | + enumerator_next_async (data, FALSE); | ||
432 | + return; | ||
433 | + } | ||
434 | + | ||
435 | + complete_connection_with_error (data, data->last_error); | ||
436 | +} | ||
437 | + | ||
438 | static void | ||
439 | g_socket_client_connected_callback (GObject *source, | ||
440 | GAsyncResult *result, | ||
441 | @@ -1588,10 +1732,7 @@ g_socket_client_connected_callback (GObject *source, | ||
442 | { | ||
443 | ConnectionAttempt *attempt = user_data; | ||
444 | GSocketClientAsyncConnectData *data = attempt->data; | ||
445 | - GSList *l; | ||
446 | GError *error = NULL; | ||
447 | - GProxy *proxy; | ||
448 | - const gchar *protocol; | ||
449 | |||
450 | if (task_completed_or_cancelled (data) || g_cancellable_is_cancelled (attempt->cancellable)) | ||
451 | { | ||
452 | @@ -1613,11 +1754,12 @@ g_socket_client_connected_callback (GObject *source, | ||
453 | { | ||
454 | clarify_connect_error (error, data->connectable, attempt->address); | ||
455 | set_last_error (data, error); | ||
456 | + g_debug ("GSocketClient: Connection attempt failed: %s", error->message); | ||
457 | connection_attempt_remove (attempt); | ||
458 | - enumerator_next_async (data, FALSE); | ||
459 | connection_attempt_unref (attempt); | ||
460 | + try_next_connection_or_finish (data, FALSE); | ||
461 | } | ||
462 | - else | ||
463 | + else /* Silently ignore cancelled attempts */ | ||
464 | { | ||
465 | g_clear_error (&error); | ||
466 | g_object_unref (data->task); | ||
467 | @@ -1627,74 +1769,21 @@ g_socket_client_connected_callback (GObject *source, | ||
468 | return; | ||
469 | } | ||
470 | |||
471 | - data->socket = g_steal_pointer (&attempt->socket); | ||
472 | - data->connection = g_steal_pointer (&attempt->connection); | ||
473 | - | ||
474 | - for (l = data->connection_attempts; l; l = g_slist_next (l)) | ||
475 | - { | ||
476 | - ConnectionAttempt *attempt_entry = l->data; | ||
477 | - g_cancellable_cancel (attempt_entry->cancellable); | ||
478 | - connection_attempt_unref (attempt_entry); | ||
479 | - } | ||
480 | - g_slist_free (data->connection_attempts); | ||
481 | - data->connection_attempts = NULL; | ||
482 | - connection_attempt_unref (attempt); | ||
483 | - | ||
484 | - g_socket_connection_set_cached_remote_address ((GSocketConnection*)data->connection, NULL); | ||
485 | - g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_CONNECTED, data->connectable, data->connection); | ||
486 | + g_socket_connection_set_cached_remote_address ((GSocketConnection*)attempt->connection, NULL); | ||
487 | + g_debug ("GSocketClient: TCP connection successful"); | ||
488 | + g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_CONNECTED, data->connectable, attempt->connection); | ||
489 | |||
490 | /* wrong, but backward compatible */ | ||
491 | - g_socket_set_blocking (data->socket, TRUE); | ||
492 | + g_socket_set_blocking (attempt->socket, TRUE); | ||
493 | |||
494 | - if (!data->proxy_addr) | ||
495 | - { | ||
496 | - g_socket_client_tls_handshake (data); | ||
497 | - return; | ||
498 | - } | ||
499 | - | ||
500 | - protocol = g_proxy_address_get_protocol (data->proxy_addr); | ||
501 | - | ||
502 | - /* The connection should not be anything other than TCP, | ||
503 | - * but let's put a safety guard in case | ||
504 | + /* This ends the parallel "happy eyeballs" portion of connecting. | ||
505 | + Now that we have a successful tcp connection we will attempt to connect | ||
506 | + at the TLS/Proxy layer. If those layers fail we will move on to the next | ||
507 | + connection. | ||
508 | */ | ||
509 | - if (!G_IS_TCP_CONNECTION (data->connection)) | ||
510 | - { | ||
511 | - g_critical ("Trying to proxy over non-TCP connection, this is " | ||
512 | - "most likely a bug in GLib IO library."); | ||
513 | - | ||
514 | - g_set_error_literal (&data->last_error, | ||
515 | - G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, | ||
516 | - _("Proxying over a non-TCP connection is not supported.")); | ||
517 | - | ||
518 | - enumerator_next_async (data, FALSE); | ||
519 | - } | ||
520 | - else if (g_hash_table_contains (data->client->priv->app_proxies, protocol)) | ||
521 | - { | ||
522 | - /* Simply complete the connection, we don't want to do TLS handshake | ||
523 | - * as the application proxy handling may need proxy handshake first */ | ||
524 | - g_socket_client_async_connect_complete (data); | ||
525 | - } | ||
526 | - else if ((proxy = g_proxy_get_default_for_protocol (protocol))) | ||
527 | - { | ||
528 | - g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_PROXY_NEGOTIATING, data->connectable, data->connection); | ||
529 | - g_proxy_connect_async (proxy, | ||
530 | - data->connection, | ||
531 | - data->proxy_addr, | ||
532 | - g_task_get_cancellable (data->task), | ||
533 | - g_socket_client_proxy_connect_callback, | ||
534 | - data); | ||
535 | - g_object_unref (proxy); | ||
536 | - } | ||
537 | - else | ||
538 | - { | ||
539 | - g_clear_error (&data->last_error); | ||
540 | - | ||
541 | - g_set_error (&data->last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, | ||
542 | - _("Proxy protocol ā%sā is not supported."), | ||
543 | - protocol); | ||
544 | - | ||
545 | - enumerator_next_async (data, FALSE); | ||
546 | - } | ||
547 | + connection_attempt_remove (attempt); | ||
548 | + data->successful_connections = g_slist_append (data->successful_connections, g_steal_pointer (&attempt)); | ||
549 | + try_next_connection_or_finish (data, FALSE); | ||
550 | } | ||
551 | |||
552 | static gboolean | ||
553 | @@ -1702,7 +1791,11 @@ on_connection_attempt_timeout (gpointer data) | ||
554 | { | ||
555 | ConnectionAttempt *attempt = data; | ||
556 | |||
557 | - enumerator_next_async (attempt->data, TRUE); | ||
558 | + if (!attempt->data->enumeration_completed) | ||
559 | + { | ||
560 | + g_debug ("GSocketClient: Timeout reached, trying another enumeration"); | ||
561 | + enumerator_next_async (attempt->data, TRUE); | ||
562 | + } | ||
563 | |||
564 | g_clear_pointer (&attempt->timeout_source, g_source_unref); | ||
565 | return G_SOURCE_REMOVE; | ||
566 | @@ -1712,9 +1805,9 @@ static void | ||
567 | on_connection_cancelled (GCancellable *cancellable, | ||
568 | gpointer data) | ||
569 | { | ||
570 | - GCancellable *attempt_cancellable = data; | ||
571 | + GCancellable *linked_cancellable = G_CANCELLABLE (data); | ||
572 | |||
573 | - g_cancellable_cancel (attempt_cancellable); | ||
574 | + g_cancellable_cancel (linked_cancellable); | ||
575 | } | ||
576 | |||
577 | static void | ||
578 | @@ -1738,39 +1831,49 @@ g_socket_client_enumerator_callback (GObject *object, | ||
579 | result, &error); | ||
580 | if (address == NULL) | ||
581 | { | ||
582 | - if (data->connection_attempts) | ||
583 | + if (G_UNLIKELY (data->enumeration_completed)) | ||
584 | + return; | ||
585 | + | ||
586 | + data->enumeration_completed = TRUE; | ||
587 | + g_debug ("GSocketClient: Address enumeration completed (out of addresses)"); | ||
588 | + | ||
589 | + /* As per API docs: We only care about error if its the first call, | ||
590 | + after that the enumerator is done. | ||
591 | + | ||
592 | + Note that we don't care about cancellation errors because | ||
593 | + task_completed_or_cancelled() above should handle that. | ||
594 | + | ||
595 | + If this fails and nothing is in progress then we will complete task here. | ||
596 | + */ | ||
597 | + if ((data->enumerated_at_least_once && !data->connection_attempts && !data->connection_in_progress) || | ||
598 | + !data->enumerated_at_least_once) | ||
599 | { | ||
600 | - g_object_unref (data->task); | ||
601 | - return; | ||
602 | + g_debug ("GSocketClient: Address enumeration failed: %s", error ? error->message : NULL); | ||
603 | + if (data->last_error) | ||
604 | + { | ||
605 | + g_clear_error (&error); | ||
606 | + error = data->last_error; | ||
607 | + data->last_error = NULL; | ||
608 | + } | ||
609 | + else if (!error) | ||
610 | + { | ||
611 | + g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED, | ||
612 | + _("Unknown error on connect")); | ||
613 | + } | ||
614 | + | ||
615 | + complete_connection_with_error (data, error); | ||
616 | } | ||
617 | |||
618 | - g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_COMPLETE, data->connectable, NULL); | ||
619 | - data->completed = TRUE; | ||
620 | - if (!error) | ||
621 | - { | ||
622 | - if (data->last_error) | ||
623 | - { | ||
624 | - error = data->last_error; | ||
625 | - data->last_error = NULL; | ||
626 | - } | ||
627 | - else | ||
628 | - { | ||
629 | - g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED, | ||
630 | - _("Unknown error on connect")); | ||
631 | - } | ||
632 | - } | ||
633 | - g_task_return_error (data->task, error); | ||
634 | + /* Enumeration should never trigger again, drop our ref */ | ||
635 | g_object_unref (data->task); | ||
636 | return; | ||
637 | } | ||
638 | |||
639 | + data->enumerated_at_least_once = TRUE; | ||
640 | + g_debug ("GSocketClient: Address enumeration succeeded"); | ||
641 | g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_RESOLVED, | ||
642 | data->connectable, NULL); | ||
643 | |||
644 | - if (G_IS_PROXY_ADDRESS (address) && | ||
645 | - data->client->priv->enable_proxy) | ||
646 | - data->proxy_addr = g_object_ref (G_PROXY_ADDRESS (address)); | ||
647 | - | ||
648 | g_clear_error (&data->last_error); | ||
649 | |||
650 | socket = create_socket (data->client, address, &data->last_error); | ||
651 | @@ -1788,6 +1891,10 @@ g_socket_client_enumerator_callback (GObject *object, | ||
652 | attempt->cancellable = g_cancellable_new (); | ||
653 | attempt->connection = (GIOStream *)g_socket_connection_factory_create_connection (socket); | ||
654 | attempt->timeout_source = g_timeout_source_new (HAPPY_EYEBALLS_CONNECTION_ATTEMPT_TIMEOUT_MS); | ||
655 | + | ||
656 | + if (G_IS_PROXY_ADDRESS (address) && data->client->priv->enable_proxy) | ||
657 | + attempt->proxy_addr = g_object_ref (G_PROXY_ADDRESS (address)); | ||
658 | + | ||
659 | g_source_set_callback (attempt->timeout_source, on_connection_attempt_timeout, attempt, NULL); | ||
660 | g_source_attach (attempt->timeout_source, g_main_context_get_thread_default ()); | ||
661 | data->connection_attempts = g_slist_append (data->connection_attempts, attempt); | ||
662 | @@ -1797,6 +1904,7 @@ g_socket_client_enumerator_callback (GObject *object, | ||
663 | g_object_ref (attempt->cancellable), g_object_unref); | ||
664 | |||
665 | g_socket_connection_set_cached_remote_address ((GSocketConnection *)attempt->connection, address); | ||
666 | + g_debug ("GSocketClient: Starting TCP connection attempt"); | ||
667 | g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_CONNECTING, data->connectable, attempt->connection); | ||
668 | g_socket_connection_connect_async (G_SOCKET_CONNECTION (attempt->connection), | ||
669 | address, | ||
670 | @@ -1849,24 +1957,48 @@ g_socket_client_connect_async (GSocketClient *client, | ||
671 | else | ||
672 | data->enumerator = g_socket_connectable_enumerate (connectable); | ||
673 | |||
674 | - /* The flow and ownership here isn't quite obvious: | ||
675 | - - The task starts an async attempt to connect. | ||
676 | - - Each attempt holds a single ref on task. | ||
677 | - - Each attempt may create new attempts by timing out (not a failure) so | ||
678 | - there are multiple attempts happening in parallel. | ||
679 | - - Upon failure an attempt will start a new attempt that steals its ref | ||
680 | - until there are no more attempts left and it drops its ref. | ||
681 | - - Upon success it will cancel all other attempts and continue on | ||
682 | - to the rest of the connection (tls, proxies, etc) which do not | ||
683 | - happen in parallel and at the very end drop its ref. | ||
684 | - - Upon cancellation an attempt drops its ref. | ||
685 | - */ | ||
686 | + /* This function tries to match the behavior of g_socket_client_connect () | ||
687 | + which is simple enough but much of it is done in parallel to be as responsive | ||
688 | + as possible as per Happy Eyeballs (RFC 8305). This complicates flow quite a | ||
689 | + bit but we can describe it in 3 sections: | ||
690 | + | ||
691 | + Firstly we have address enumeration (DNS): | ||
692 | + - This may be triggered multiple times by enumerator_next_async(). | ||
693 | + - It also has its own cancellable (data->enumeration_cancellable). | ||
694 | + - Enumeration is done lazily because GNetworkAddressAddressEnumerator | ||
695 | + also does work in parallel and may lazily add new addresses. | ||
696 | + - If the first enumeration errors then the task errors. Otherwise all enumerations | ||
697 | + will potentially be used (until task or enumeration is cancelled). | ||
698 | + | ||
699 | + Then we start attempting connections (TCP): | ||
700 | + - Each connection is independent and kept in a ConnectionAttempt object. | ||
701 | + - They each hold a ref on the main task and have their own cancellable. | ||
702 | + - Multiple attempts may happen in parallel as per Happy Eyeballs. | ||
703 | + - Upon failure or timeouts more connection attempts are made. | ||
704 | + - If no connections succeed the task errors. | ||
705 | + - Upon success they are kept in a list of successful connections. | ||
706 | + | ||
707 | + Lastly we connect at the application layer (TLS, Proxies): | ||
708 | + - These are done in serial. | ||
709 | + - The reasoning here is that Happy Eyeballs is about making bad connections responsive | ||
710 | + at the IP/TCP layers. Issues at the application layer are generally not due to | ||
711 | + connectivity issues but rather misconfiguration. | ||
712 | + - Upon failure it will try the next TCP connection until it runs out and | ||
713 | + the task errors. | ||
714 | + - Upon success it cancels everything remaining (enumeration and connections) | ||
715 | + and returns the connection. | ||
716 | + */ | ||
717 | |||
718 | data->task = g_task_new (client, cancellable, callback, user_data); | ||
719 | g_task_set_check_cancellable (data->task, FALSE); /* We handle this manually */ | ||
720 | g_task_set_source_tag (data->task, g_socket_client_connect_async); | ||
721 | g_task_set_task_data (data->task, data, (GDestroyNotify)g_socket_client_async_connect_data_free); | ||
722 | |||
723 | + data->enumeration_cancellable = g_cancellable_new (); | ||
724 | + if (cancellable) | ||
725 | + g_cancellable_connect (cancellable, G_CALLBACK (on_connection_cancelled), | ||
726 | + g_object_ref (data->enumeration_cancellable), g_object_unref); | ||
727 | + | ||
728 | enumerator_next_async (data, FALSE); | ||
729 | } | ||
730 | |||
731 | @@ -1985,6 +2117,7 @@ g_socket_client_connect_to_uri_async (GSocketClient *client, | ||
732 | } | ||
733 | else | ||
734 | { | ||
735 | + g_debug("g_socket_client_connect_to_uri_async"); | ||
736 | g_socket_client_connect_async (client, | ||
737 | connectable, cancellable, | ||
738 | callback, user_data); | ||
739 | -- | ||
740 | 2.23.0 | ||
741 | |||
diff --git a/meta/recipes-core/glib-2.0/glib-2.0_2.60.7.bb b/meta/recipes-core/glib-2.0/glib-2.0_2.60.7.bb index 5aefa6ad8b..5be81a8f31 100644 --- a/meta/recipes-core/glib-2.0/glib-2.0_2.60.7.bb +++ b/meta/recipes-core/glib-2.0/glib-2.0_2.60.7.bb | |||
@@ -16,6 +16,7 @@ SRC_URI = "${GNOME_MIRROR}/glib/${SHRT_VER}/glib-${PV}.tar.xz \ | |||
16 | file://0001-Do-not-write-bindir-into-pkg-config-files.patch \ | 16 | file://0001-Do-not-write-bindir-into-pkg-config-files.patch \ |
17 | file://0001-meson.build-do-not-hardcode-linux-as-the-host-system.patch \ | 17 | file://0001-meson.build-do-not-hardcode-linux-as-the-host-system.patch \ |
18 | file://0001-meson-do-a-build-time-check-for-strlcpy-before-attem.patch \ | 18 | file://0001-meson-do-a-build-time-check-for-strlcpy-before-attem.patch \ |
19 | file://CVE-2020-6750.patch \ | ||
19 | " | 20 | " |
20 | 21 | ||
21 | SRC_URI_append_class-native = " file://relocate-modules.patch" | 22 | SRC_URI_append_class-native = " file://relocate-modules.patch" |