- Dmitry Popov filed bug report #1911069

(http://curl.haxx.se/bug/view.cgi?id=1911069) that identified a race
  condition in the name resolver code when the DNS cache is shared between
  multiple easy handles, each running in simultaneous threads that could cause
  crashes.
This commit is contained in:
Daniel Stenberg 2008-03-11 22:55:23 +00:00
parent ecf1c6ca5d
commit b9d66dca51
3 changed files with 24 additions and 28 deletions

View File

@ -7,6 +7,12 @@
Changelog
Daniel Stenberg (11 Mar 2008)
- Dmitry Popov filed bug report #1911069
(http://curl.haxx.se/bug/view.cgi?id=1911069) that identified a race
condition in the name resolver code when the DNS cache is shared between
multiple easy handles, each running in simultaneous threads that could cause
crashes.
- Added a macro for curl_easy_setopt() that accepts three arguments and simply
does nothing with them, just to make sure libcurl users always use three
arguments to this function. Due to its use of ... for the third argument, it

View File

@ -42,6 +42,8 @@ This release includes the following bugfixes:
o better MIT kerberos configure check
o curl_easy_reset() + SFTP re-used connection download crash
o SFTP non-existing file + SFTP existing file error
o sharing DNS cache between easy handles running in multiple threads could
lead to crash
This release includes the following known bugs:
@ -61,6 +63,6 @@ advice from friends like these:
Michal Marek, Dmitry Kurochkin, Niklas Angebrand, Günter Knauf, Yang Tse,
Dan Fandrich, Mike Hommey, Pooyan McSporran, Jerome Muffat-Meridol,
Kaspar Brand, Gautam Kachroo, Zmey Petroff, Georg Lippitsch, Sam Listopad,
Anatoli Tubman, Mike Protts, Michael Calmer, Brian Ulm
Anatoli Tubman, Mike Protts, Michael Calmer, Brian Ulm, Dmitry Popov
Thanks! (and sorry if I forgot to mention someone)

View File

@ -268,6 +268,9 @@ void Curl_hostcache_prune(struct SessionHandle *data)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
}
/*
* Check if the entry should be pruned. Assumes a locked cache.
*/
static int
remove_entry_if_stale(struct SessionHandle *data, struct Curl_dns_entry *dns)
{
@ -284,19 +287,10 @@ remove_entry_if_stale(struct SessionHandle *data, struct Curl_dns_entry *dns)
if( !hostcache_timestamp_remove(&user,dns) )
return 0;
/* ok, we do need to clear the cache. although we need to remove just a
single entry we clean the entire hash, as no explicit delete function
is provided */
if(data->share)
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
Curl_hash_clean_with_criterium(data->dns.hostcache,
(void *) &user,
hostcache_timestamp_remove);
if(data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
return 1;
}
@ -397,7 +391,7 @@ int Curl_resolv(struct connectdata *conn,
size_t entry_len;
struct SessionHandle *data = conn->data;
CURLcode result;
int rc;
int rc = CURLRESOLV_ERROR; /* default to failure */
*entry = NULL;
#ifdef HAVE_SIGSETJMP
@ -407,7 +401,7 @@ int Curl_resolv(struct connectdata *conn,
if(sigsetjmp(curl_jmpenv, 1)) {
/* this is coming from a siglongjmp() */
failf(data, "name lookup timed out");
return CURLRESOLV_ERROR;
return rc;
}
}
#endif
@ -416,7 +410,7 @@ int Curl_resolv(struct connectdata *conn,
entry_id = create_hostcache_id(hostname, port);
/* If we can't create the entry id, fail */
if(!entry_id)
return CURLRESOLV_ERROR;
return rc;
entry_len = strlen(entry_id);
@ -426,19 +420,21 @@ int Curl_resolv(struct connectdata *conn,
/* See if its already in our dns cache */
dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);
/* See whether the returned entry is stale. Done before we release lock */
if( remove_entry_if_stale(data, dns) )
dns = NULL; /* the memory deallocation is being handled by the hash */
if(dns) {
dns->inuse++; /* we use it! */
rc = CURLRESOLV_RESOLVED;
}
if(data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
/* free the allocated entry_id again */
free(entry_id);
/* See whether the returned entry is stale. Deliberately done after the
locked block */
if( remove_entry_if_stale(data,dns) )
dns = NULL; /* the memory deallocation is being handled by the hash */
rc = CURLRESOLV_ERROR; /* default to failure */
if(!dns) {
/* The entry was not in the cache. Resolve it to IP address */
@ -486,14 +482,6 @@ int Curl_resolv(struct connectdata *conn,
rc = CURLRESOLV_RESOLVED;
}
}
else {
if(data->share)
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
dns->inuse++; /* we use it! */
if(data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
rc = CURLRESOLV_RESOLVED;
}
*entry = dns;