]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-http: client: Fix panic occurring at connection failure.
authorStephan Bosch <stephan.bosch@dovecot.fi>
Fri, 7 Dec 2018 21:38:19 +0000 (22:38 +0100)
committerVille Savolainen <ville.savolainen@dovecot.fi>
Thu, 21 Mar 2019 08:02:31 +0000 (10:02 +0200)
In http_client_peer_connection_failed_pool(), all linked queues are notified
about the connection failure through http_client_queue_connection_failure().
That function can internally link and unlink peers to the queue, including the
calling one. This means that the peer->queues array can be modified while it is
iterated in the array_foreach() loop. The problem is fixed by making a local
copy of the peer->queues array.

src/lib-http/http-client-peer.c

index aaf098fe1d4920edab6300d7bc176df758a3a701..5a668f074d4e8626a8e494800e57f548afff094f 100644 (file)
@@ -1270,7 +1270,8 @@ static void
 http_client_peer_connection_failed_pool(struct http_client_peer *peer,
                                        const char *reason)
 {
-       struct http_client_queue *const *queue;
+       struct http_client_queue *const *queuep;
+       ARRAY_TYPE(http_client_queue) queues;
 
        e_debug(peer->event,
                "Failed to establish any connection within our peer pool: %s "
@@ -1279,11 +1280,17 @@ http_client_peer_connection_failed_pool(struct http_client_peer *peer,
 
        peer->connect_failed = TRUE;
 
+       /* make a copy of the queue array; queues get linked/unlinged while the
+          connection failure is handled */
+       t_array_init(&queues, array_count(&peer->queues));
+       array_copy(&queues.arr, 0, &peer->queues.arr, 0,
+                  array_count(&peer->queues));
+
        /* failed to make any connection. a second connect will probably also
           fail, so just try another IP for the hosts(s) or abort all requests
           if this was the only/last option. */
-       array_foreach(&peer->queues, queue)
-               http_client_queue_connection_failure(*queue, peer, reason);
+       array_foreach(&queues, queuep)
+               http_client_queue_connection_failure(*queuep, peer, reason);
 }
 
 void http_client_peer_connection_lost(struct http_client_peer *peer,