cURL / Mailing Lists / curl-library / Single Mail

curl-library

Use-after-free with libcurl+ares on windows?

From: Harshal Pradhan <keeda_at_hotpop.com>
Date: Thu, 04 Aug 2005 03:23:11 +0530

Hi All,

I am using libcurl 7.12.1 on Windows 2000 with the ares resolver. (I
know this is a fairly old version, but as of now I don't have an option
to do an immediate upgrade.)

I am seeing intermittent crashes in ares callbacks. It has been really
difficult to pin down a testcase since the application is a crawler that
does tens of thousands of requests against several hundred hosts in a
day. But, in general, the problem appears to be related somehow to
connect timeouts. I have been able to reproduce the problem under purify
much more frequently by reducing the value of CURLOPT_TIMEOUT to just
one sec. A typical instance of a purify report of the problem is attached.

It seems to me that what is happening is that there are some cases where
some ares query might outlive the connection data. This makes the
callback crash when it is fired since it ends up poking at already freed
data.

I really don't know much about the ares API and how ares is used in
curl. On a random hunch, I tried the following

diff -u -p -1 -0 -r1.4 url.c
--- url.c 14 Dec 2004 13:27:13 -0000 1.4
+++ url.c 3 Aug 2005 21:35:37 -0000
@@ -1494,20 +1494,24 @@ CURLcode Curl_disconnect(struct connectd
    Curl_safefree(conn->allocptr.host);
    Curl_safefree(conn->allocptr.cookiehost);

  #if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \
      defined(USE_THREADING_GETADDRINFO)
    /* possible left-overs from the async name resolve */
    Curl_safefree(conn->async.hostname);
    Curl_safefree(conn->async.os_specific);
  #endif

+#if defined(USE_ARES)
+ ares_cancel(conn->data->state.areschannel);
+#endif
+
    Curl_free_ssl_config(&conn->ssl_config);

    free(conn); /* free all the connection oriented data */

    return CURLE_OK;
  }

  /*
   * This function should return TRUE if the socket is to be assumed to
   * be dead. Most commonly this happens when the server has closed the

This makes my application much more stable.

So, getting to the point .... I have lots of questions: Has anyone
encountered such a problem earlier? Has there been any work on a similar
issue in later versions of curl? Is my reasoning above sane? Does the my
"random hunch" patch above make any sense at all?

Harshal

                [E] FMW: Free memory write in addrinfo_callback {1 occurrence}
                    Writing 1 byte to 0x09087884 (1 byte at 0x09087884 illegal)
                    Address 0x09087884 is 1908 bytes into a 1928 byte block at 0x09087110
                    Address 0x09087884 points to a malloc'd block in heap 0x04eb0000
                    Thread ID: 0x990
                    Error location
                    addrinfo_callback [hostasyn.c:118]
                      struct connectdata *conn = (struct connectdata *)arg;
                      struct Curl_dns_entry *dns = NULL;
                    
                 => conn->async.done = TRUE;
                      conn->async.status = status;
                    
                      if(CURL_ASYNC_SUCCESS == status) {
                    Curl_addrinfo4_callback [hostasyn.c:158]
                    end_hquery [ares_gethostbyname.c:150]
                    host_callback [ares_gethostbyname.c:139]
                    qcallback [ares_query.c:108]
                    end_query [ares_process.c:620]
                    process_answer [ares_process.c:352]
                    read_udp_packets [ares_process.c:266]
                    ares_process [ares_process.c:72]
                Curl_is_resolved [hostares.c:148]
                curl_multi_perform [multi.c:393]
                            struct Curl_dns_entry *dns = NULL;
                    
                            /* check if we have the name resolved by now */
                 => easy->result = Curl_is_resolved(easy->easy_conn, &dns);
                    
                            if(dns) {
                              /* Perform the next step in the connection phase, and then move on
                CurlMultiPageFetcher::run(void) [curlmultipagefetcher.cpp:541]
                Thread [_thread.cpp:76]
                threadstart [thread.c:196]
            Allocation location
                malloc [dbgheap.c:138]
                CreateConnection [url.c:2153]
                Curl_connect [url.c:3434]
                curl_multi_perform [multi.c:373]
                CurlMultiPageFetcher::run(void) [curlmultipagefetcher.cpp:495]
                Thread [_thread.cpp:76]
                threadstart [thread.c:196]
            Free location
                free [dbgheap.c:1024]
                Curl_disconnect [url.c:1510]
                ConnectionKillOne [url.c:1686]
                ConnectionStore [url.c:1714]
                CreateConnection [url.c:3167]
                Curl_connect [url.c:3434]
                curl_multi_perform [multi.c:373]
                            /* Connect. We get a connection identifier filled in. */
                            Curl_pgrsTime(easy->easy_handle, TIMER_STARTSINGLE);
                            easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn,
                 => &async);
                    
                            if(CURLE_OK == easy->result) {
                              if(async)
Received on 2005-08-04