From 7c66fc970082f2f8b4a7ae1bbfca3531ab6798b4 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Fri, 21 Oct 2016 14:55:10 +1100 Subject: [PATCH] 4489. [security] It was possible to trigger assertions when processing a response. (CVE-2016-8864) [RT #43465] (cherry picked from commit bd6f27f5c353133b563fe69100b2f168c129f3ca) --- CHANGES | 3 ++ lib/dns/resolver.c | 69 +++++++++++++++++++++++++++++++--------------- 2 files changed, 50 insertions(+), 22 deletions(-) diff --git a/CHANGES b/CHANGES index 5bc1330f8c..525e344791 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +4489. [security] It was possible to trigger assertions when processing + a response. (CVE-2016-8864) [RT #43465] + 4488. [port] Darwin: use -framework for Kerberos. [RT #43418] 4487. [test] Make system tests work on Windows. [RT #42931] diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 91ea9a5f3e..f5153206b9 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -606,7 +606,9 @@ valcreate(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_name_t *name, valarg->addrinfo = addrinfo; if (!ISC_LIST_EMPTY(fctx->validators)) - INSIST((valoptions & DNS_VALIDATOR_DEFER) != 0); + valoptions |= DNS_VALIDATOR_DEFER; + else + valoptions &= ~DNS_VALIDATOR_DEFER; result = dns_validator_create(fctx->res->view, name, type, rdataset, sigrdataset, fctx->rmessage, @@ -5612,13 +5614,6 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, rdataset, sigrdataset, valoptions, task); - /* - * Defer any further validations. - * This prevents multiple validators - * from manipulating fctx->rmessage - * simultaneously. - */ - valoptions |= DNS_VALIDATOR_DEFER; } } else if (CHAINING(rdataset)) { if (rdataset->type == dns_rdatatype_cname) @@ -5733,6 +5728,11 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, eresult == DNS_R_NCACHENXRRSET); } event->result = eresult; + if (adbp != NULL && *adbp != NULL) { + if (anodep != NULL && *anodep != NULL) + dns_db_detachnode(*adbp, anodep); + dns_db_detach(adbp); + } dns_db_attach(fctx->cache, adbp); dns_db_transfernode(fctx->cache, &node, anodep); clone_results(fctx); @@ -5989,6 +5989,11 @@ ncache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, fctx->attributes |= FCTX_ATTR_HAVEANSWER; if (event != NULL) { event->result = eresult; + if (adbp != NULL && *adbp != NULL) { + if (anodep != NULL && *anodep != NULL) + dns_db_detachnode(*adbp, anodep); + dns_db_detach(adbp); + } dns_db_attach(fctx->cache, adbp); dns_db_transfernode(fctx->cache, &node, anodep); clone_results(fctx); @@ -6802,13 +6807,15 @@ static isc_result_t answer_response(fetchctx_t *fctx) { isc_result_t result; dns_message_t *message; - dns_name_t *name, *dname = NULL, *qname, tname, *ns_name; + dns_name_t *name, *dname = NULL, *qname, *dqname, tname, *ns_name; + dns_name_t *cname = NULL; dns_rdataset_t *rdataset, *ns_rdataset; isc_boolean_t done, external, chaining, aa, found, want_chaining; - isc_boolean_t have_answer, found_cname, found_type, wanted_chaining; + isc_boolean_t have_answer, found_cname, found_dname, found_type; + isc_boolean_t wanted_chaining; unsigned int aflag; dns_rdatatype_t type; - dns_fixedname_t fdname, fqname; + dns_fixedname_t fdname, fqname, fqdname; dns_view_t *view; FCTXTRACE("answer_response"); @@ -6822,6 +6829,7 @@ answer_response(fetchctx_t *fctx) { done = ISC_FALSE; found_cname = ISC_FALSE; + found_dname = ISC_FALSE; found_type = ISC_FALSE; chaining = ISC_FALSE; have_answer = ISC_FALSE; @@ -6831,12 +6839,13 @@ answer_response(fetchctx_t *fctx) { aa = ISC_TRUE; else aa = ISC_FALSE; - qname = &fctx->name; + dqname = qname = &fctx->name; type = fctx->type; view = fctx->res->view; + dns_fixedname_init(&fqdname); result = dns_message_firstname(message, DNS_SECTION_ANSWER); while (!done && result == ISC_R_SUCCESS) { - dns_namereln_t namereln; + dns_namereln_t namereln, dnamereln; int order; unsigned int nlabels; @@ -6844,6 +6853,8 @@ answer_response(fetchctx_t *fctx) { dns_message_currentname(message, DNS_SECTION_ANSWER, &name); external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain)); namereln = dns_name_fullcompare(qname, name, &order, &nlabels); + dnamereln = dns_name_fullcompare(dqname, name, &order, + &nlabels); if (namereln == dns_namereln_equal) { wanted_chaining = ISC_FALSE; for (rdataset = ISC_LIST_HEAD(name->list); @@ -6938,7 +6949,7 @@ answer_response(fetchctx_t *fctx) { } } else if (rdataset->type == dns_rdatatype_rrsig && rdataset->covers == - dns_rdatatype_cname + dns_rdatatype_cname && !found_type) { /* * We're looking for something else, @@ -6968,11 +6979,18 @@ answer_response(fetchctx_t *fctx) { * a CNAME or DNAME). */ INSIST(!external); - if (aflag == - DNS_RDATASETATTR_ANSWER) { + if ((rdataset->type != + dns_rdatatype_cname) || + !found_dname || + (aflag == + DNS_RDATASETATTR_ANSWER)) + { have_answer = ISC_TRUE; + if (rdataset->type == + dns_rdatatype_cname) + cname = name; name->attributes |= - DNS_NAMEATTR_ANSWER; + DNS_NAMEATTR_ANSWER; } rdataset->attributes |= aflag; if (aa) @@ -7066,11 +7084,11 @@ answer_response(fetchctx_t *fctx) { return (DNS_R_FORMERR); } - if (namereln != dns_namereln_subdomain) { + if (dnamereln != dns_namereln_subdomain) { char qbuf[DNS_NAME_FORMATSIZE]; char obuf[DNS_NAME_FORMATSIZE]; - dns_name_format(qname, qbuf, + dns_name_format(dqname, qbuf, sizeof(qbuf)); dns_name_format(name, obuf, sizeof(obuf)); @@ -7085,7 +7103,7 @@ answer_response(fetchctx_t *fctx) { want_chaining = ISC_TRUE; POST(want_chaining); aflag = DNS_RDATASETATTR_ANSWER; - result = dname_target(rdataset, qname, + result = dname_target(rdataset, dqname, nlabels, &fdname); if (result == ISC_R_NOSPACE) { /* @@ -7102,10 +7120,13 @@ answer_response(fetchctx_t *fctx) { dname = dns_fixedname_name(&fdname); if (!is_answertarget_allowed(view, - qname, rdataset->type, - dname, &fctx->domain)) { + dqname, rdataset->type, + dname, &fctx->domain)) + { return (DNS_R_SERVFAIL); } + dqname = dns_fixedname_name(&fqdname); + dns_name_copy(dname, dqname, NULL); } else { /* * We've found a signature that @@ -7130,6 +7151,10 @@ answer_response(fetchctx_t *fctx) { INSIST(!external); if (aflag == DNS_RDATASETATTR_ANSWER) { have_answer = ISC_TRUE; + found_dname = ISC_TRUE; + if (cname != NULL) + cname->attributes &= + ~DNS_NAMEATTR_ANSWER; name->attributes |= DNS_NAMEATTR_ANSWER; }