diff options
Diffstat (limited to 'meta/recipes-core/glib-2.0/glib-2.0/CVE-2019-9633_p1.patch')
-rw-r--r-- | meta/recipes-core/glib-2.0/glib-2.0/CVE-2019-9633_p1.patch | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2019-9633_p1.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2019-9633_p1.patch new file mode 100644 index 0000000000..f95716aecf --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2019-9633_p1.patch | |||
@@ -0,0 +1,316 @@ | |||
1 | From c1e32b90576af11556c8a9178e43902f3394a4b0 Mon Sep 17 00:00:00 2001 | ||
2 | From: Patrick Griffis <pgriffis@igalia.com> | ||
3 | Date: Mon, 29 Oct 2018 09:53:07 -0400 | ||
4 | Subject: [PATCH] gsocketclient: Improve handling of slow initial connections | ||
5 | |||
6 | Currently a new connection will not be attempted until the previous | ||
7 | one has timed out and as the current API only exposes a single | ||
8 | timeout value in practice it often means that it will wait 30 seconds | ||
9 | (or forever with 0 (the default)) on each connection. | ||
10 | |||
11 | This is unacceptable so we are now trying to follow the behavior | ||
12 | RFC 8305 recommends by making multiple connection attempts if | ||
13 | the connection takes longer than 250ms. The first connection | ||
14 | to make it to completion then wins. | ||
15 | |||
16 | Upstream-Status: Backport | ||
17 | CVE: CVE-2019-9633 patch 1 | ||
18 | Affects: < 2.59.2 | ||
19 | Signed-off-by: Armin Kuster <akuster@mvista.com> | ||
20 | |||
21 | --- | ||
22 | gio/gsocketclient.c | 176 ++++++++++++++++++++++++++++++++++++++++++++-------- | ||
23 | 1 file changed, 151 insertions(+), 25 deletions(-) | ||
24 | |||
25 | diff --git a/gio/gsocketclient.c b/gio/gsocketclient.c | ||
26 | index ddd1497..5c6513c 100644 | ||
27 | --- a/gio/gsocketclient.c | ||
28 | +++ b/gio/gsocketclient.c | ||
29 | @@ -2,6 +2,7 @@ | ||
30 | * | ||
31 | * Copyright © 2008, 2009 codethink | ||
32 | * Copyright © 2009 Red Hat, Inc | ||
33 | + * Copyright © 2018 Igalia S.L. | ||
34 | * | ||
35 | * This library is free software; you can redistribute it and/or | ||
36 | * modify it under the terms of the GNU Lesser General Public | ||
37 | @@ -49,6 +50,10 @@ | ||
38 | #include <gio/ginetaddress.h> | ||
39 | #include "glibintl.h" | ||
40 | |||
41 | +/* As recommended by RFC 8305 this is the time it waits | ||
42 | + * on a connection before starting another concurrent attempt. | ||
43 | + */ | ||
44 | +#define HAPPY_EYEBALLS_CONNECTION_ATTEMPT_TIMEOUT_MS 250 | ||
45 | |||
46 | /** | ||
47 | * SECTION:gsocketclient | ||
48 | @@ -1328,28 +1333,82 @@ typedef struct | ||
49 | GSocketConnectable *connectable; | ||
50 | GSocketAddressEnumerator *enumerator; | ||
51 | GProxyAddress *proxy_addr; | ||
52 | - GSocketAddress *current_addr; | ||
53 | - GSocket *current_socket; | ||
54 | + GSocket *socket; | ||
55 | GIOStream *connection; | ||
56 | |||
57 | + GSList *connection_attempts; | ||
58 | GError *last_error; | ||
59 | } GSocketClientAsyncConnectData; | ||
60 | |||
61 | +static void connection_attempt_unref (gpointer attempt); | ||
62 | + | ||
63 | static void | ||
64 | g_socket_client_async_connect_data_free (GSocketClientAsyncConnectData *data) | ||
65 | { | ||
66 | g_clear_object (&data->connectable); | ||
67 | g_clear_object (&data->enumerator); | ||
68 | g_clear_object (&data->proxy_addr); | ||
69 | - g_clear_object (&data->current_addr); | ||
70 | - g_clear_object (&data->current_socket); | ||
71 | + g_clear_object (&data->socket); | ||
72 | g_clear_object (&data->connection); | ||
73 | + g_slist_free_full (data->connection_attempts, connection_attempt_unref); | ||
74 | |||
75 | g_clear_error (&data->last_error); | ||
76 | |||
77 | g_slice_free (GSocketClientAsyncConnectData, data); | ||
78 | } | ||
79 | |||
80 | +typedef struct | ||
81 | +{ | ||
82 | + GSocketAddress *address; | ||
83 | + GSocket *socket; | ||
84 | + GIOStream *connection; | ||
85 | + GSocketClientAsyncConnectData *data; /* unowned */ | ||
86 | + GSource *timeout_source; | ||
87 | + GCancellable *cancellable; | ||
88 | + grefcount ref; | ||
89 | +} ConnectionAttempt; | ||
90 | + | ||
91 | +static ConnectionAttempt * | ||
92 | +connection_attempt_new (void) | ||
93 | +{ | ||
94 | + ConnectionAttempt *attempt = g_new0 (ConnectionAttempt, 1); | ||
95 | + g_ref_count_init (&attempt->ref); | ||
96 | + return attempt; | ||
97 | +} | ||
98 | + | ||
99 | +static ConnectionAttempt * | ||
100 | +connection_attempt_ref (ConnectionAttempt *attempt) | ||
101 | +{ | ||
102 | + g_ref_count_inc (&attempt->ref); | ||
103 | + return attempt; | ||
104 | +} | ||
105 | + | ||
106 | +static void | ||
107 | +connection_attempt_unref (gpointer pointer) | ||
108 | +{ | ||
109 | + ConnectionAttempt *attempt = pointer; | ||
110 | + if (g_ref_count_dec (&attempt->ref)) | ||
111 | + { | ||
112 | + g_clear_object (&attempt->address); | ||
113 | + g_clear_object (&attempt->socket); | ||
114 | + g_clear_object (&attempt->connection); | ||
115 | + g_clear_object (&attempt->cancellable); | ||
116 | + if (attempt->timeout_source) | ||
117 | + { | ||
118 | + g_source_destroy (attempt->timeout_source); | ||
119 | + g_source_unref (attempt->timeout_source); | ||
120 | + } | ||
121 | + g_free (attempt); | ||
122 | + } | ||
123 | +} | ||
124 | + | ||
125 | +static void | ||
126 | +connection_attempt_remove (ConnectionAttempt *attempt) | ||
127 | +{ | ||
128 | + attempt->data->connection_attempts = g_slist_remove (attempt->data->connection_attempts, attempt); | ||
129 | + connection_attempt_unref (attempt); | ||
130 | +} | ||
131 | + | ||
132 | static void | ||
133 | g_socket_client_async_connect_complete (GSocketClientAsyncConnectData *data) | ||
134 | { | ||
135 | @@ -1359,8 +1418,7 @@ g_socket_client_async_connect_complete (GSocketClientAsyncConnectData *data) | ||
136 | { | ||
137 | GSocketConnection *wrapper_connection; | ||
138 | |||
139 | - wrapper_connection = g_tcp_wrapper_connection_new (data->connection, | ||
140 | - data->current_socket); | ||
141 | + wrapper_connection = g_tcp_wrapper_connection_new (data->connection, data->socket); | ||
142 | g_object_unref (data->connection); | ||
143 | data->connection = (GIOStream *)wrapper_connection; | ||
144 | } | ||
145 | @@ -1389,8 +1447,7 @@ static void | ||
146 | enumerator_next_async (GSocketClientAsyncConnectData *data) | ||
147 | { | ||
148 | /* We need to cleanup the state */ | ||
149 | - g_clear_object (&data->current_socket); | ||
150 | - g_clear_object (&data->current_addr); | ||
151 | + g_clear_object (&data->socket); | ||
152 | g_clear_object (&data->proxy_addr); | ||
153 | g_clear_object (&data->connection); | ||
154 | |||
155 | @@ -1485,34 +1542,68 @@ g_socket_client_connected_callback (GObject *source, | ||
156 | GAsyncResult *result, | ||
157 | gpointer user_data) | ||
158 | { | ||
159 | - GSocketClientAsyncConnectData *data = user_data; | ||
160 | + ConnectionAttempt *attempt = user_data; | ||
161 | + GSocketClientAsyncConnectData *data = attempt->data; | ||
162 | + GSList *l; | ||
163 | GError *error = NULL; | ||
164 | GProxy *proxy; | ||
165 | const gchar *protocol; | ||
166 | |||
167 | - if (g_task_return_error_if_cancelled (data->task)) | ||
168 | + /* data is NULL once the task is completed */ | ||
169 | + if (data && g_task_return_error_if_cancelled (data->task)) | ||
170 | { | ||
171 | g_object_unref (data->task); | ||
172 | + connection_attempt_unref (attempt); | ||
173 | return; | ||
174 | } | ||
175 | |||
176 | + if (attempt->timeout_source) | ||
177 | + { | ||
178 | + g_source_destroy (attempt->timeout_source); | ||
179 | + g_clear_pointer (&attempt->timeout_source, g_source_unref); | ||
180 | + } | ||
181 | + | ||
182 | if (!g_socket_connection_connect_finish (G_SOCKET_CONNECTION (source), | ||
183 | result, &error)) | ||
184 | { | ||
185 | - clarify_connect_error (error, data->connectable, | ||
186 | - data->current_addr); | ||
187 | - set_last_error (data, error); | ||
188 | + if (!g_cancellable_is_cancelled (attempt->cancellable)) | ||
189 | + { | ||
190 | + clarify_connect_error (error, data->connectable, attempt->address); | ||
191 | + set_last_error (data, error); | ||
192 | + } | ||
193 | + else | ||
194 | + g_clear_error (&error); | ||
195 | + | ||
196 | + if (data) | ||
197 | + { | ||
198 | + connection_attempt_remove (attempt); | ||
199 | + enumerator_next_async (data); | ||
200 | + } | ||
201 | + else | ||
202 | + connection_attempt_unref (attempt); | ||
203 | |||
204 | - /* try next one */ | ||
205 | - enumerator_next_async (data); | ||
206 | return; | ||
207 | } | ||
208 | |||
209 | + data->socket = g_steal_pointer (&attempt->socket); | ||
210 | + data->connection = g_steal_pointer (&attempt->connection); | ||
211 | + | ||
212 | + for (l = data->connection_attempts; l; l = g_slist_next (l)) | ||
213 | + { | ||
214 | + ConnectionAttempt *attempt_entry = l->data; | ||
215 | + g_cancellable_cancel (attempt_entry->cancellable); | ||
216 | + attempt_entry->data = NULL; | ||
217 | + connection_attempt_unref (attempt_entry); | ||
218 | + } | ||
219 | + g_slist_free (data->connection_attempts); | ||
220 | + data->connection_attempts = NULL; | ||
221 | + connection_attempt_unref (attempt); | ||
222 | + | ||
223 | g_socket_connection_set_cached_remote_address ((GSocketConnection*)data->connection, NULL); | ||
224 | g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_CONNECTED, data->connectable, data->connection); | ||
225 | |||
226 | /* wrong, but backward compatible */ | ||
227 | - g_socket_set_blocking (data->current_socket, TRUE); | ||
228 | + g_socket_set_blocking (data->socket, TRUE); | ||
229 | |||
230 | if (!data->proxy_addr) | ||
231 | { | ||
232 | @@ -1565,6 +1656,26 @@ g_socket_client_connected_callback (GObject *source, | ||
233 | } | ||
234 | } | ||
235 | |||
236 | +static gboolean | ||
237 | +on_connection_attempt_timeout (gpointer data) | ||
238 | +{ | ||
239 | + ConnectionAttempt *attempt = data; | ||
240 | + | ||
241 | + enumerator_next_async (attempt->data); | ||
242 | + | ||
243 | + g_clear_pointer (&attempt->timeout_source, g_source_unref); | ||
244 | + return G_SOURCE_REMOVE; | ||
245 | +} | ||
246 | + | ||
247 | +static void | ||
248 | +on_connection_cancelled (GCancellable *cancellable, | ||
249 | + gpointer data) | ||
250 | +{ | ||
251 | + GCancellable *attempt_cancellable = data; | ||
252 | + | ||
253 | + g_cancellable_cancel (attempt_cancellable); | ||
254 | +} | ||
255 | + | ||
256 | static void | ||
257 | g_socket_client_enumerator_callback (GObject *object, | ||
258 | GAsyncResult *result, | ||
259 | @@ -1573,6 +1684,7 @@ g_socket_client_enumerator_callback (GObject *object, | ||
260 | GSocketClientAsyncConnectData *data = user_data; | ||
261 | GSocketAddress *address = NULL; | ||
262 | GSocket *socket; | ||
263 | + ConnectionAttempt *attempt; | ||
264 | GError *error = NULL; | ||
265 | |||
266 | if (g_task_return_error_if_cancelled (data->task)) | ||
267 | @@ -1585,6 +1697,9 @@ g_socket_client_enumerator_callback (GObject *object, | ||
268 | result, &error); | ||
269 | if (address == NULL) | ||
270 | { | ||
271 | + if (data->connection_attempts) | ||
272 | + return; | ||
273 | + | ||
274 | g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_COMPLETE, data->connectable, NULL); | ||
275 | if (!error) | ||
276 | { | ||
277 | @@ -1621,16 +1736,27 @@ g_socket_client_enumerator_callback (GObject *object, | ||
278 | return; | ||
279 | } | ||
280 | |||
281 | - data->current_socket = socket; | ||
282 | - data->current_addr = address; | ||
283 | - data->connection = (GIOStream *) g_socket_connection_factory_create_connection (socket); | ||
284 | - | ||
285 | - g_socket_connection_set_cached_remote_address ((GSocketConnection*)data->connection, address); | ||
286 | - g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_CONNECTING, data->connectable, data->connection); | ||
287 | - g_socket_connection_connect_async (G_SOCKET_CONNECTION (data->connection), | ||
288 | + attempt = connection_attempt_new (); | ||
289 | + attempt->data = data; | ||
290 | + attempt->socket = socket; | ||
291 | + attempt->address = address; | ||
292 | + attempt->cancellable = g_cancellable_new (); | ||
293 | + attempt->connection = (GIOStream *)g_socket_connection_factory_create_connection (socket); | ||
294 | + attempt->timeout_source = g_timeout_source_new (HAPPY_EYEBALLS_CONNECTION_ATTEMPT_TIMEOUT_MS); | ||
295 | + g_source_set_callback (attempt->timeout_source, on_connection_attempt_timeout, attempt, NULL); | ||
296 | + g_source_attach (attempt->timeout_source, g_main_context_get_thread_default ()); | ||
297 | + data->connection_attempts = g_slist_append (data->connection_attempts, attempt); | ||
298 | + | ||
299 | + if (g_task_get_cancellable (data->task)) | ||
300 | + g_cancellable_connect (g_task_get_cancellable (data->task), G_CALLBACK (on_connection_cancelled), | ||
301 | + g_object_ref (attempt->cancellable), g_object_unref); | ||
302 | + | ||
303 | + g_socket_connection_set_cached_remote_address ((GSocketConnection *)attempt->connection, address); | ||
304 | + g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_CONNECTING, data->connectable, attempt->connection); | ||
305 | + g_socket_connection_connect_async (G_SOCKET_CONNECTION (attempt->connection), | ||
306 | address, | ||
307 | - g_task_get_cancellable (data->task), | ||
308 | - g_socket_client_connected_callback, data); | ||
309 | + attempt->cancellable, | ||
310 | + g_socket_client_connected_callback, connection_attempt_ref (attempt)); | ||
311 | } | ||
312 | |||
313 | /** | ||
314 | -- | ||
315 | 2.7.4 | ||
316 | |||