]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-imap-client: Fix crash when ostream output blocks before connection finishes
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Mon, 18 Jun 2018 10:15:55 +0000 (13:15 +0300)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Tue, 26 Jun 2018 08:29:50 +0000 (11:29 +0300)
It's possible that ostream tries to add IO_WRITE callback before
imapc_connection_connected() callback is called.

Fixes:
Panic: io_add(0x2) called twice fd=15, callback=0x... -> 0x...

src/lib-imap-client/imapc-connection.c

index c9e2b97f864c2f309eface0d04d38fa0eb2c65fc..5ac544f5c628a89160fc3a455258a875433c8c41 100644 (file)
@@ -1695,13 +1695,14 @@ static int imapc_connection_ssl_init(struct imapc_connection *conn)
        return 0;
 }
 
-static void imapc_connection_connected(struct imapc_connection *conn)
+static int imapc_connection_connected(struct imapc_connection *conn)
 {
        const struct ip_addr *ip = &conn->ips[conn->prev_connect_idx];
        struct ip_addr local_ip;
        in_port_t local_port;
        int err;
-       io_remove(&conn->io);
+
+       i_assert(conn->io == NULL);
 
        err = net_geterror(conn->fd);
        if (err != 0) {
@@ -1709,7 +1710,7 @@ static void imapc_connection_connected(struct imapc_connection *conn)
                        "connect(%s, %u) failed: %s",
                        net_ip2addr(ip), conn->client->set.port,
                        strerror(err)), conn->client->set.connect_retry_interval_msecs, TRUE);
-               return;
+               return -1;
        }
        if (net_getsockname(conn->fd, &local_ip, &local_port) < 0)
                local_port = 0;
@@ -1717,11 +1718,14 @@ static void imapc_connection_connected(struct imapc_connection *conn)
               net_ip2addr(ip), conn->client->set.port,
               net_ip2addr(&local_ip), local_port);
        conn->io = io_add(conn->fd, IO_READ, imapc_connection_input, conn);
+       o_stream_set_flush_callback(conn->output, imapc_connection_output,
+                                   conn);
 
        if (conn->client->set.ssl_mode == IMAPC_CLIENT_SSL_MODE_IMMEDIATE) {
                if (imapc_connection_ssl_init(conn) < 0)
                        imapc_connection_disconnect(conn);
        }
+       return imapc_connection_output(conn);
 }
 
 static void imapc_connection_timeout(struct imapc_connection *conn)
@@ -1818,9 +1822,9 @@ static void imapc_connection_connect_next_ip(struct imapc_connection *conn)
                                       &conn->input, &conn->output);
        }
 
-       o_stream_set_flush_callback(conn->output, imapc_connection_output,
+       o_stream_set_flush_pending(conn->output, TRUE);
+       o_stream_set_flush_callback(conn->output, imapc_connection_connected,
                                    conn);
-       conn->io = io_add(fd, IO_WRITE, imapc_connection_connected, conn);
        conn->parser = imap_parser_create(conn->input, NULL,
                                          conn->client->set.max_line_length);
        conn->to = timeout_add(conn->client->set.connect_timeout_msecs,