From f0f3370e14df26eff427579795ae4eeccefad5bc Mon Sep 17 00:00:00 2001 From: Aram Sargsyan Date: Thu, 10 Feb 2022 20:06:30 +0000 Subject: [PATCH] Check if the fetch is shutting down in resume_dslookup() The fetch can be in the shutting down state when resume_dslookup() is trying to operate on it. This is also a security issue, because a malicious actor can set up a name server which delays certain queries in such a way that the fetch will time out and shut down, which will cause named to crash. Add a check to see if the fetch has the shutting down attribute set, and cancel any further operations on it in such case. A similar bug had been fixed earlier for the resume_qmin() function, see [GL #966]. --- lib/dns/resolver.c | 49 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index b57c5308bb..1816723749 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -7242,18 +7242,21 @@ fctx__detach(fetchctx_t **fctxp, const char *file, unsigned int line, static void resume_dslookup(isc_task_t *task, isc_event_t *event) { - dns_fetchevent_t *fevent; - fetchctx_t *fctx; + dns_fetchevent_t *fevent = NULL; + dns_resolver_t *res = NULL; + fetchctx_t *fctx = NULL; isc_result_t result; dns_rdataset_t nameservers; dns_fixedname_t fixed; - dns_name_t *domain; + dns_name_t *domain = NULL; fetchctx_t *ev_fctx = NULL; REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE); fevent = (dns_fetchevent_t *)event; fctx = event->ev_arg; + REQUIRE(VALID_FCTX(fctx)); + res = fctx->res; UNUSED(task); FCTXTRACE("resume_dslookup"); @@ -7282,6 +7285,15 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) { isc_event_free(&event); dns_resolver_destroyfetch(&fctx->nsfetch); + + LOCK(&res->buckets[fctx->bucketnum].lock); + if (SHUTTINGDOWN(fctx)) { + maybe_destroy(fctx, true); + UNLOCK(&res->buckets[fctx->bucketnum].lock); + goto cleanup; + } + UNLOCK(&res->buckets[fctx->bucketnum].lock); + fctx_done(fctx, ISC_R_CANCELED, __LINE__); } else if (fevent->result == ISC_R_SUCCESS) { FCTXTRACE("resuming DS lookup"); @@ -7301,6 +7313,14 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) { fevent = NULL; isc_event_free(&event); + LOCK(&res->buckets[fctx->bucketnum].lock); + if (SHUTTINGDOWN(fctx)) { + maybe_destroy(fctx, true); + UNLOCK(&res->buckets[fctx->bucketnum].lock); + goto cleanup; + } + UNLOCK(&res->buckets[fctx->bucketnum].lock); + fcount_decr(fctx); dns_name_copy(fctx->nsname, fctx->domain); result = fcount_incr(fctx, true); @@ -7329,8 +7349,17 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) { fevent = NULL; isc_event_free(&event); - fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); dns_resolver_destroyfetch(&fctx->nsfetch); + + LOCK(&res->buckets[fctx->bucketnum].lock); + if (SHUTTINGDOWN(fctx)) { + maybe_destroy(fctx, true); + UNLOCK(&res->buckets[fctx->bucketnum].lock); + goto cleanup; + } + UNLOCK(&res->buckets[fctx->bucketnum].lock); + + fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); goto cleanup; } if (dns_rdataset_isassociated( @@ -7351,13 +7380,21 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) { fevent = NULL; isc_event_free(&event); + LOCK(&res->buckets[fctx->bucketnum].lock); + if (SHUTTINGDOWN(fctx)) { + maybe_destroy(fctx, true); + UNLOCK(&res->buckets[fctx->bucketnum].lock); + goto cleanup; + } + UNLOCK(&res->buckets[fctx->bucketnum].lock); + FCTXTRACE("continuing to look for parent's NS records"); fctx_attach(fctx, &ev_fctx); result = dns_resolver_createfetch( - fctx->res, fctx->nsname, dns_rdatatype_ns, domain, - nsrdataset, NULL, NULL, 0, fctx->options, 0, NULL, task, + res, fctx->nsname, dns_rdatatype_ns, domain, nsrdataset, + NULL, NULL, 0, fctx->options, 0, NULL, task, resume_dslookup, ev_fctx, &fctx->nsrrset, NULL, &fctx->nsfetch); /*