diff options
author | Sergey Fionov <sfionov@adguard.com> | 2018-08-02 00:35:28 +0300 |
---|---|---|
committer | Azat Khuzhin <a3at.mail@gmail.com> | 2018-08-02 09:23:30 +0300 |
commit | b59525ece4288d844fa31945eedddd859d58bfaa (patch) | |
tree | a613ae32c802b2d4407f65e10b412dfaf33589b3 /evdns.c | |
parent | e85818d24850540d220e6d7bc0a30653ba2135f2 (diff) | |
download | libevent-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.c | 9 |
1 files changed, 8 insertions, 1 deletions
@@ -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); |