summaryrefslogtreecommitdiff
path: root/evdns.c
diff options
context:
space:
mode:
authorSergey Fionov <sfionov@adguard.com>2018-08-02 00:35:28 +0300
committerAzat Khuzhin <a3at.mail@gmail.com>2018-08-02 09:23:30 +0300
commitb59525ece4288d844fa31945eedddd859d58bfaa (patch)
treea613ae32c802b2d4407f65e10b412dfaf33589b3 /evdns.c
parente85818d24850540d220e6d7bc0a30653ba2135f2 (diff)
downloadlibevent-b59525ece4288d844fa31945eedddd859d58bfaa.tar.gz
evdns: fix race condition in evdns_getaddrinfo()
evdns_getaddrinfo() starts two parallel requests for A and AAAA record. But if request is created from thread different from dns_base's, request of A record is started immediately and may result in calling free_getaddrinfo_request() from evdns_getaddrinfo_gotresolve() because `other_req' doesn't exist yet. After that, request of AAAA record starts and finishes, and evdns_getaddrinfo_gotresolve() is called again for structure that is already freed. This commits adds locking into evdns_getaddrinfo() function.
Diffstat (limited to 'evdns.c')
-rw-r--r--evdns.c9
1 files changed, 8 insertions, 1 deletions
diff --git a/evdns.c b/evdns.c
index 40042925..a3f1226a 100644
--- a/evdns.c
+++ b/evdns.c
@@ -4637,6 +4637,7 @@ evdns_getaddrinfo(struct evdns_base *dns_base,
int err;
int port = 0;
int want_cname = 0;
+ int started = 0;
if (!dns_base) {
dns_base = current_base;
@@ -4715,6 +4716,8 @@ evdns_getaddrinfo(struct evdns_base *dns_base,
* launching those requests. (XXX we don't do that yet.)
*/
+ EVDNS_LOCK(dns_base);
+
if (hints.ai_family != PF_INET6) {
log(EVDNS_LOG_DEBUG, "Sending request for %s on ipv4 as %p",
nodename, &data->ipv4_request);
@@ -4741,7 +4744,11 @@ evdns_getaddrinfo(struct evdns_base *dns_base,
evtimer_assign(&data->timeout, dns_base->event_base,
evdns_getaddrinfo_timeout_cb, data);
- if (data->ipv4_request.r || data->ipv6_request.r) {
+ started = (data->ipv4_request.r || data->ipv6_request.r);
+
+ EVDNS_UNLOCK(dns_base);
+
+ if (started) {
return data;
} else {
mm_free(data);