Package: release.debian.org Severity: normal User: release.debian....@packages.debian.org Usertags: unblock
Hi Please unblock package bind9 The upload fixes three issues: +bind9 (1:9.10.3.dfsg.P4-12.3) unstable; urgency=high + + * Non-maintainer upload. + * Dns64 with "break-dnssec yes;" can result in a assertion failure + (CVE-2017-3136) (Closes: #860224) + * Some chaining (CNAME or DNAME) responses to upstream queries could trigger + assertion failures (CVE-2017-3137) (Closes: #860225) + * 'rndc ""' could trigger a assertion failure in named (CVE-2017-3138) + (Closes: #860226) + + -- Salvatore Bonaccorso <car...@debian.org> Sun, 07 May 2017 15:22:46 +0200 of which CVE-2017-3137 should be considered RC (and filled as such), the other two are minor, but were included as well in the stable update released as DSA-3854-1. unblock bind9/1:9.10.3.dfsg.P4-12.3 Attached is the full debdiff agains the current version in testing. Regards, Salvatore
diff -Nru bind9-9.10.3.dfsg.P4/debian/changelog bind9-9.10.3.dfsg.P4/debian/changelog --- bind9-9.10.3.dfsg.P4/debian/changelog 2017-04-18 17:42:50.000000000 +0200 +++ bind9-9.10.3.dfsg.P4/debian/changelog 2017-05-07 15:22:46.000000000 +0200 @@ -1,3 +1,15 @@ +bind9 (1:9.10.3.dfsg.P4-12.3) unstable; urgency=high + + * Non-maintainer upload. + * Dns64 with "break-dnssec yes;" can result in a assertion failure + (CVE-2017-3136) (Closes: #860224) + * Some chaining (CNAME or DNAME) responses to upstream queries could trigger + assertion failures (CVE-2017-3137) (Closes: #860225) + * 'rndc ""' could trigger a assertion failure in named (CVE-2017-3138) + (Closes: #860226) + + -- Salvatore Bonaccorso <car...@debian.org> Sun, 07 May 2017 15:22:46 +0200 + bind9 (1:9.10.3.dfsg.P4-12.2) unstable; urgency=medium * Non-maintainer upload. diff -Nru bind9-9.10.3.dfsg.P4/debian/patches/CVE-2017-3136.patch bind9-9.10.3.dfsg.P4/debian/patches/CVE-2017-3136.patch --- bind9-9.10.3.dfsg.P4/debian/patches/CVE-2017-3136.patch 1970-01-01 01:00:00.000000000 +0100 +++ bind9-9.10.3.dfsg.P4/debian/patches/CVE-2017-3136.patch 2017-05-07 15:22:46.000000000 +0200 @@ -0,0 +1,19 @@ +From 764240ca07ab1b796226d5402ccd9fbfa77ec32a Mon Sep 17 00:00:00 2001 +From: Mark Andrews <ma...@isc.org> +Date: Wed, 15 Feb 2017 12:18:51 +1100 +Subject: [PATCH] 4575. [security] Dns64 with break-dnssec yes; can + result in a assertion failure. (CVE-2017-3136) [RT + #44653] + +(cherry picked from commit 3bce12e4b6d37f570ffc7747b499f8b90e8521ac) +--- +--- a/bin/named/query.c ++++ b/bin/named/query.c +@@ -8145,6 +8145,7 @@ query_find(ns_client_t *client, dns_fetc + result = query_dns64(client, &fname, rdataset, + sigrdataset, dbuf, + DNS_SECTION_ANSWER); ++ noqname = NULL; + dns_rdataset_disassociate(rdataset); + dns_message_puttemprdataset(client->message, &rdataset); + if (result == ISC_R_NOMORE) { diff -Nru bind9-9.10.3.dfsg.P4/debian/patches/CVE-2017-3137-1.patch bind9-9.10.3.dfsg.P4/debian/patches/CVE-2017-3137-1.patch --- bind9-9.10.3.dfsg.P4/debian/patches/CVE-2017-3137-1.patch 1970-01-01 01:00:00.000000000 +0100 +++ bind9-9.10.3.dfsg.P4/debian/patches/CVE-2017-3137-1.patch 2017-05-07 15:22:46.000000000 +0200 @@ -0,0 +1,83 @@ +From 69fd759b4aa02047e42e5cf4227f8257c4547988 Mon Sep 17 00:00:00 2001 +From: Evan Hunt <e...@isc.org> +Date: Thu, 23 Feb 2017 15:01:30 -0800 +Subject: [PATCH] [v9_10] remove unnecessary INSIST and prep 9.10.5rc2 + +4578. [security] Some chaining (CNAME or DNAME) responses to upstream + queries could trigger assertion failures. + (CVE-2017-3137) [RT #44734] + +(cherry picked from commit a1365a0042db8c1cd0ee4dbd0c91ce65ae09e098) +(cherry picked from commit 559cbe04e73cf601784a371e09554c20407a6c7b) +--- +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -6924,15 +6924,15 @@ answer_response(fetchctx_t *fctx) { + rdataset->attributes |= + DNS_RDATASETATTR_CACHE; + rdataset->trust = dns_trust_answer; +- if (chaining == 0) { ++ if (external) { + /* +- * This data is "the" answer +- * to our question only if +- * we're not chaining (i.e. +- * if we haven't followed +- * a CNAME or DNAME). ++ * This data is outside of ++ * our query domain, and ++ * may not be cached. + */ +- INSIST(!external); ++ rdataset->attributes |= ++ DNS_RDATASETATTR_EXTERNAL; ++ } else if (chaining == 0) { + /* + * Don't use found_cname here + * as we have just set it +@@ -6954,14 +6954,6 @@ answer_response(fetchctx_t *fctx) { + if (aa) + rdataset->trust = + dns_trust_authanswer; +- } else if (external) { +- /* +- * This data is outside of +- * our query domain, and +- * may not be cached. +- */ +- rdataset->attributes |= +- DNS_RDATASETATTR_EXTERNAL; + } + + /* +@@ -7136,15 +7128,12 @@ answer_response(fetchctx_t *fctx) { + * If we are not chaining or the first CNAME + * is a synthesised CNAME before the DNAME. + */ +- if ((chaining == 0) || +- (chaining == 1U && synthcname)) ++ if (external) { ++ rdataset->attributes |= ++ DNS_RDATASETATTR_EXTERNAL; ++ } else if ((chaining == 0) || ++ (chaining == 1U && synthcname)) + { +- /* +- * This data is "the" answer to +- * our question only if we're +- * not chaining. +- */ +- INSIST(!external); + if (aflag == DNS_RDATASETATTR_ANSWER) { + have_answer = ISC_TRUE; + found_dname = ISC_TRUE; +@@ -7161,9 +7150,6 @@ answer_response(fetchctx_t *fctx) { + if (aa) + rdataset->trust = + dns_trust_authanswer; +- } else if (external) { +- rdataset->attributes |= +- DNS_RDATASETATTR_EXTERNAL; + } + } + diff -Nru bind9-9.10.3.dfsg.P4/debian/patches/CVE-2017-3137-2.patch bind9-9.10.3.dfsg.P4/debian/patches/CVE-2017-3137-2.patch --- bind9-9.10.3.dfsg.P4/debian/patches/CVE-2017-3137-2.patch 1970-01-01 01:00:00.000000000 +0100 +++ bind9-9.10.3.dfsg.P4/debian/patches/CVE-2017-3137-2.patch 2017-05-07 15:22:46.000000000 +0200 @@ -0,0 +1,1022 @@ +From 6841d7b854c15df9ec56cab38da201b315bbcabb Mon Sep 17 00:00:00 2001 +From: Mark Andrews <ma...@isc.org> +Date: Wed, 1 Mar 2017 12:01:16 +1100 +Subject: [PATCH] Reimplement: 4578. [security] Some chaining (CNAME or + DNAME) responses to upstream queries could trigger + assertion failures. (CVE-2017-3137) [RT #44734] + +(cherry picked from commit f240f4a5decae09cdabb83f824e0fd339377ad7e) +--- + bin/tests/system/dname/ns2/example.db | 1 + + bin/tests/system/dname/tests.sh | 15 +- + bin/tests/system/rpz/tests.sh | 2 +- + lib/dns/resolver.c | 813 +++++++++++++--------------------- + 4 files changed, 320 insertions(+), 511 deletions(-) + +--- a/bin/tests/system/dname/ns2/example.db ++++ b/bin/tests/system/dname/ns2/example.db +@@ -29,4 +29,5 @@ a.short A 10.0.0.1 + short-dname DNAME short + a.longlonglonglonglonglonglonglonglonglonglonglonglong A 10.0.0.2 + long-dname DNAME longlonglonglonglonglonglonglonglonglonglonglonglong ++toolong-dname DNAME longlonglonglonglonglonglonglonglonglonglonglonglong + ; +--- a/bin/tests/system/dname/tests.sh ++++ b/bin/tests/system/dname/tests.sh +@@ -56,10 +56,19 @@ grep "status: YXDOMAIN" dig.out.ns2.tool + if [ $ret != 0 ]; then echo "I:failed"; fi + status=`expr $status + $ret` + +-echo "I:checking (too) long dname from recursive" ++echo "I:checking (too) long dname from recursive with cached DNAME" ++ret=0 ++$DIG 01234567890123456789012345678901234567890123456789.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.long-dname.example @10.53.0.4 a -p 5300 > dig.out.ns4.cachedtoolong || ret=1 ++grep "status: YXDOMAIN" dig.out.ns4.cachedtoolong > /dev/null || ret=1 ++grep '^long-dname\.example\..*DNAME.*long' dig.out.ns4.cachedtoolong > /dev/null || ret=1 ++if [ $ret != 0 ]; then echo "I:failed"; fi ++status=`expr $status + $ret` ++ ++echo "I:checking (too) long dname from recursive without cached DNAME" + ret=0 +-$DIG 01234567890123456789012345678901234567890123456789.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.long-dname.example @10.53.0.4 a -p 5300 > dig.out.ns4.toolong || ret=1 +-grep "status: YXDOMAIN" dig.out.ns4.toolong > /dev/null || ret=1 ++$DIG 01234567890123456789012345678901234567890123456789.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglong.toolong-dname.example @10.53.0.4 a -p 5300 > dig.out.ns4.uncachedtoolong || ret=1 ++grep "status: YXDOMAIN" dig.out.ns4.uncachedtoolong > /dev/null || ret=1 ++grep '^toolong-dname\.example\..*DNAME.*long' dig.out.ns4.uncachedtoolong > /dev/null || ret=1 + if [ $ret != 0 ]; then echo "I:failed"; fi + status=`expr $status + $ret` + +--- a/bin/tests/system/rpz/tests.sh ++++ b/bin/tests/system/rpz/tests.sh +@@ -383,7 +383,7 @@ nxdomain a0-1s-cname.tld2s +dnssec @$ns + drop a3-8.tld2 any @$ns6 # 20 drop + + end_group +-ckstatsrange $ns3 test1 ns3 22 25 ++ckstatsrange $ns3 test1 ns3 22 27 + ckstats $ns5 test1 ns5 0 + ckstats $ns6 test1 ns6 0 + +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -4443,6 +4443,7 @@ is_lame(fetchctx_t *fctx) { + isc_result_t result; + + if (message->rcode != dns_rcode_noerror && ++ message->rcode != dns_rcode_yxdomain && + message->rcode != dns_rcode_nxdomain) + return (ISC_FALSE); + +@@ -6061,79 +6062,6 @@ chase_additional(fetchctx_t *fctx) { + goto again; + } + +-static inline isc_result_t +-cname_target(dns_rdataset_t *rdataset, dns_name_t *tname) { +- isc_result_t result; +- dns_rdata_t rdata = DNS_RDATA_INIT; +- dns_rdata_cname_t cname; +- +- result = dns_rdataset_first(rdataset); +- if (result != ISC_R_SUCCESS) +- return (result); +- dns_rdataset_current(rdataset, &rdata); +- result = dns_rdata_tostruct(&rdata, &cname, NULL); +- if (result != ISC_R_SUCCESS) +- return (result); +- dns_name_init(tname, NULL); +- dns_name_clone(&cname.cname, tname); +- dns_rdata_freestruct(&cname); +- +- return (ISC_R_SUCCESS); +-} +- +-/*% +- * Construct the synthesised CNAME from the existing QNAME and +- * the DNAME RR and store it in 'target'. +- */ +-static inline isc_result_t +-dname_target(dns_rdataset_t *rdataset, dns_name_t *qname, +- unsigned int nlabels, dns_name_t *target) +-{ +- isc_result_t result; +- dns_rdata_t rdata = DNS_RDATA_INIT; +- dns_rdata_dname_t dname; +- dns_fixedname_t prefix; +- +- /* +- * Get the target name of the DNAME. +- */ +- result = dns_rdataset_first(rdataset); +- if (result != ISC_R_SUCCESS) +- return (result); +- dns_rdataset_current(rdataset, &rdata); +- result = dns_rdata_tostruct(&rdata, &dname, NULL); +- if (result != ISC_R_SUCCESS) +- return (result); +- +- dns_fixedname_init(&prefix); +- dns_name_split(qname, nlabels, dns_fixedname_name(&prefix), NULL); +- result = dns_name_concatenate(dns_fixedname_name(&prefix), +- &dname.dname, target, NULL); +- dns_rdata_freestruct(&dname); +- return (result); +-} +- +-/*% +- * Check if it was possible to construct 'qname' from 'lastcname' +- * and 'rdataset'. +- */ +-static inline isc_result_t +-fromdname(dns_rdataset_t *rdataset, dns_name_t *lastcname, +- unsigned int nlabels, const dns_name_t *qname) +-{ +- dns_fixedname_t fixed; +- isc_result_t result; +- dns_name_t *target; +- +- dns_fixedname_init(&fixed); +- target = dns_fixedname_name(&fixed); +- result = dname_target(rdataset, lastcname, nlabels, target); +- if (result != ISC_R_SUCCESS || !dns_name_equal(qname, target)) +- return (ISC_R_NOTFOUND); +- +- return (ISC_R_SUCCESS); +-} +- + static isc_boolean_t + is_answeraddress_allowed(dns_view_t *view, dns_name_t *name, + dns_rdataset_t *rdataset) +@@ -6209,9 +6137,8 @@ is_answeraddress_allowed(dns_view_t *vie + } + + static isc_boolean_t +-is_answertarget_allowed(dns_view_t *view, dns_name_t *name, +- dns_rdatatype_t type, dns_name_t *tname, +- dns_name_t *domain) ++is_answertarget_allowed(fetchctx_t *fctx, dns_name_t *qname, dns_name_t *rname, ++ dns_rdataset_t *rdataset) + { + isc_result_t result; + dns_rbtnode_t *node = NULL; +@@ -6219,18 +6146,58 @@ is_answertarget_allowed(dns_view_t *view + char tnamebuf[DNS_NAME_FORMATSIZE]; + char classbuf[64]; + char typebuf[64]; ++ dns_name_t *tname = NULL; ++ dns_rdata_cname_t cname; ++ dns_rdata_dname_t dname; ++ dns_view_t *view = fctx->res->view; ++ dns_rdata_t rdata = DNS_RDATA_INIT; ++ unsigned int nlabels; ++ dns_fixedname_t fixed; ++ dns_name_t prefix; ++ ++ REQUIRE(rdataset != NULL); ++ REQUIRE(rdataset->type == dns_rdatatype_cname || ++ rdataset->type == dns_rdatatype_dname); + + /* By default, we allow any target name. */ + if (view->denyanswernames == NULL) + return (ISC_TRUE); + ++ result = dns_rdataset_first(rdataset); ++ RUNTIME_CHECK(result == ISC_R_SUCCESS); ++ dns_rdataset_current(rdataset, &rdata); ++ switch (rdataset->type) { ++ case dns_rdatatype_cname: ++ result = dns_rdata_tostruct(&rdata, &cname, NULL); ++ RUNTIME_CHECK(result == ISC_R_SUCCESS); ++ tname = &cname.cname; ++ break; ++ case dns_rdatatype_dname: ++ result = dns_rdata_tostruct(&rdata, &dname, NULL); ++ RUNTIME_CHECK(result == ISC_R_SUCCESS); ++ dns_name_init(&prefix, NULL); ++ dns_fixedname_init(&fixed); ++ tname = dns_fixedname_name(&fixed); ++ nlabels = dns_name_countlabels(qname) - ++ dns_name_countlabels(rname); ++ dns_name_split(qname, nlabels, &prefix, NULL); ++ result = dns_name_concatenate(&prefix, &dname.dname, tname, ++ NULL); ++ if (result == ISC_R_NOSPACE) ++ return (ISC_TRUE); ++ RUNTIME_CHECK(result == ISC_R_SUCCESS); ++ break; ++ default: ++ INSIST(0); ++ } ++ + /* + * If the owner name matches one in the exclusion list, either exactly + * or partially, allow it. + */ + if (view->answernames_exclude != NULL) { +- result = dns_rbt_findnode(view->answernames_exclude, name, NULL, +- &node, NULL, 0, NULL, NULL); ++ result = dns_rbt_findnode(view->answernames_exclude, qname, ++ NULL, &node, NULL, 0, NULL, NULL); + if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) + return (ISC_TRUE); + } +@@ -6238,7 +6205,7 @@ is_answertarget_allowed(dns_view_t *view + /* + * If the target name is a subdomain of the search domain, allow it. + */ +- if (dns_name_issubdomain(tname, domain)) ++ if (dns_name_issubdomain(tname, &fctx->domain)) + return (ISC_TRUE); + + /* +@@ -6247,9 +6214,9 @@ is_answertarget_allowed(dns_view_t *view + result = dns_rbt_findnode(view->denyanswernames, tname, NULL, &node, + NULL, 0, NULL, NULL); + if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) { +- dns_name_format(name, qnamebuf, sizeof(qnamebuf)); ++ dns_name_format(qname, qnamebuf, sizeof(qnamebuf)); + dns_name_format(tname, tnamebuf, sizeof(tnamebuf)); +- dns_rdatatype_format(type, typebuf, sizeof(typebuf)); ++ dns_rdatatype_format(rdataset->type, typebuf, sizeof(typebuf)); + dns_rdataclass_format(view->rdclass, classbuf, + sizeof(classbuf)); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, +@@ -6745,459 +6712,297 @@ noanswer_response(fetchctx_t *fctx, dns_ + return (ISC_R_SUCCESS); + } + ++static isc_boolean_t ++validinanswer(dns_rdataset_t *rdataset, fetchctx_t *fctx) { ++ if (rdataset->type == dns_rdatatype_nsec3) { ++ /* ++ * NSEC3 records are not allowed to ++ * appear in the answer section. ++ */ ++ log_formerr(fctx, "NSEC3 in answer"); ++ return (ISC_FALSE); ++ } ++ if (rdataset->type == dns_rdatatype_tkey) { ++ /* ++ * TKEY is not a valid record in a ++ * response to any query we can make. ++ */ ++ log_formerr(fctx, "TKEY in answer"); ++ return (ISC_FALSE); ++ } ++ if (rdataset->rdclass != fctx->res->rdclass) { ++ log_formerr(fctx, "Mismatched class in answer"); ++ return (ISC_FALSE); ++ } ++ return (ISC_TRUE); ++} ++ + 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 *cname = NULL, *lastcname = NULL; +- dns_rdataset_t *rdataset, *ns_rdataset; +- isc_boolean_t done, external, aa, found, want_chaining; +- isc_boolean_t have_answer, found_cname, found_dname, found_type; +- isc_boolean_t wanted_chaining; +- unsigned int aflag, chaining; ++ dns_message_t *message = NULL; ++ dns_name_t *name = NULL, *qname = NULL, *ns_name = NULL; ++ dns_name_t *aname = NULL, *cname = NULL, *dname = NULL; ++ dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL; ++ dns_rdataset_t *ardataset = NULL, *crdataset = NULL; ++ dns_rdataset_t *drdataset = NULL, *ns_rdataset = NULL; ++ isc_boolean_t done = ISC_FALSE, aa; ++ unsigned int dname_labels, domain_labels; ++ isc_boolean_t chaining = ISC_FALSE; + dns_rdatatype_t type; +- dns_fixedname_t fdname, fqname; +- dns_view_t *view; ++ dns_view_t *view = NULL; ++ dns_trust_t trust; ++ ++ REQUIRE(VALID_FCTX(fctx)); + + FCTXTRACE("answer_response"); + + message = fctx->rmessage; ++ qname = &fctx->name; ++ view = fctx->res->view; ++ type = fctx->type; + + /* +- * Examine the answer section, marking those rdatasets which are +- * part of the answer and should be cached. ++ * There can be multiple RRSIG and SIG records at a name so ++ * we treat these types as a subset of ANY. + */ ++ if (type == dns_rdatatype_rrsig || type == dns_rdatatype_sig) { ++ type = dns_rdatatype_any; ++ } + +- done = ISC_FALSE; +- found_cname = ISC_FALSE; +- found_dname = ISC_FALSE; +- found_type = ISC_FALSE; +- have_answer = ISC_FALSE; +- want_chaining = ISC_FALSE; +- chaining = 0; +- POST(want_chaining); +- if ((message->flags & DNS_MESSAGEFLAG_AA) != 0) +- aa = ISC_TRUE; +- else +- aa = ISC_FALSE; +- qname = &fctx->name; +- type = fctx->type; +- view = fctx->res->view; +- result = dns_message_firstname(message, DNS_SECTION_ANSWER); +- while (!done && result == ISC_R_SUCCESS) { +- dns_namereln_t namereln, lastreln; +- int order, lastorder; +- unsigned int nlabels, lastnlabels; ++ /* ++ * Bigger than any valid DNAME label count. ++ */ ++ dname_labels = dns_name_countlabels(qname); ++ domain_labels = dns_name_countlabels(&fctx->domain); ++ ++ /* ++ * Perform a single pass looking for the answer, cname or covering ++ * dname. ++ */ ++ for (result = dns_message_firstname(message, DNS_SECTION_ANSWER); ++ result == ISC_R_SUCCESS; ++ result = dns_message_nextname(message, DNS_SECTION_ANSWER)) ++ { ++ int order; ++ unsigned int nlabels; ++ dns_namereln_t namereln; + + name = NULL; + 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); +- +- if (namereln == dns_namereln_equal) { +- wanted_chaining = ISC_FALSE; ++ switch (namereln) { ++ case dns_namereln_equal: + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; +- rdataset = ISC_LIST_NEXT(rdataset, link)) { +- found = ISC_FALSE; +- want_chaining = ISC_FALSE; +- aflag = 0; +- if (rdataset->type == dns_rdatatype_nsec3) { +- /* +- * NSEC3 records are not allowed to +- * appear in the answer section. +- */ +- log_formerr(fctx, "NSEC3 in answer"); +- return (DNS_R_FORMERR); +- } +- if (rdataset->type == dns_rdatatype_tkey) { +- /* +- * TKEY is not a valid record in a +- * response to any query we can make. +- */ +- log_formerr(fctx, "TKEY in answer"); +- return (DNS_R_FORMERR); +- } +- if (rdataset->rdclass != fctx->res->rdclass) { +- log_formerr(fctx, "Mismatched class " +- "in answer"); +- return (DNS_R_FORMERR); +- } +- +- /* +- * Apply filters, if given, on answers to reject +- * a malicious attempt of rebinding. +- */ +- if ((rdataset->type == dns_rdatatype_a || +- rdataset->type == dns_rdatatype_aaaa) && +- !is_answeraddress_allowed(view, name, +- rdataset)) { +- return (DNS_R_SERVFAIL); +- } +- +- if (rdataset->type == type && !found_cname) { +- /* +- * We've found an ordinary answer. +- */ +- found = ISC_TRUE; +- found_type = ISC_TRUE; +- done = ISC_TRUE; +- aflag = DNS_RDATASETATTR_ANSWER; +- } else if (type == dns_rdatatype_any) { +- /* +- * We've found an answer matching +- * an ANY query. There may be +- * more. +- */ +- found = ISC_TRUE; +- aflag = DNS_RDATASETATTR_ANSWER; +- } else if (rdataset->type == dns_rdatatype_rrsig +- && rdataset->covers == type +- && !found_cname) { +- /* +- * We've found a signature that +- * covers the type we're looking for. +- */ +- found = ISC_TRUE; +- found_type = ISC_TRUE; +- aflag = DNS_RDATASETATTR_ANSWERSIG; +- } else if (rdataset->type == +- dns_rdatatype_cname +- && !found_type) { +- /* +- * We're looking for something else, +- * but we found a CNAME. +- * +- * Getting a CNAME response for some +- * query types is an error, see +- * RFC 4035, Section 2.5. +- */ +- if (type == dns_rdatatype_rrsig || +- type == dns_rdatatype_key || +- type == dns_rdatatype_nsec) { +- char buf[DNS_RDATATYPE_FORMATSIZE]; +- dns_rdatatype_format(fctx->type, +- buf, sizeof(buf)); +- log_formerr(fctx, +- "CNAME response " +- "for %s RR", buf); +- return (DNS_R_FORMERR); +- } +- found = ISC_TRUE; +- found_cname = ISC_TRUE; +- want_chaining = ISC_TRUE; +- aflag = DNS_RDATASETATTR_ANSWER; +- result = cname_target(rdataset, +- &tname); +- if (result != ISC_R_SUCCESS) +- return (result); +- /* Apply filters on the target name. */ +- if (!is_answertarget_allowed(view, +- name, +- rdataset->type, +- &tname, +- &fctx->domain)) { +- return (DNS_R_SERVFAIL); ++ rdataset = ISC_LIST_NEXT(rdataset, link)) ++ { ++ if (rdataset->type == type || ++ type == dns_rdatatype_any) ++ { ++ aname = name; ++ if (type != dns_rdatatype_any) { ++ ardataset = rdataset; + } +- lastcname = name; +- } else if (rdataset->type == dns_rdatatype_rrsig +- && rdataset->covers == +- dns_rdatatype_cname +- && !found_type) { +- /* +- * We're looking for something else, +- * but we found a SIG CNAME. +- */ +- found = ISC_TRUE; +- found_cname = ISC_TRUE; +- aflag = DNS_RDATASETATTR_ANSWERSIG; ++ break; + } +- +- if (found) { +- /* +- * We've found an answer to our +- * question. +- */ +- name->attributes |= +- DNS_NAMEATTR_CACHE; +- rdataset->attributes |= +- DNS_RDATASETATTR_CACHE; +- rdataset->trust = dns_trust_answer; +- if (external) { +- /* +- * This data is outside of +- * our query domain, and +- * may not be cached. +- */ +- rdataset->attributes |= +- DNS_RDATASETATTR_EXTERNAL; +- } else if (chaining == 0) { +- /* +- * Don't use found_cname here +- * as we have just set it +- * above. +- */ +- if (cname == NULL && +- !found_dname && +- aflag == +- DNS_RDATASETATTR_ANSWER) +- { +- have_answer = ISC_TRUE; +- if (found_cname && +- cname == NULL) +- cname = name; +- name->attributes |= +- DNS_NAMEATTR_ANSWER; +- } +- rdataset->attributes |= aflag; +- if (aa) +- rdataset->trust = +- dns_trust_authanswer; +- } +- +- /* +- * Mark any additional data related +- * to this rdataset. +- */ +- (void)dns_rdataset_additionaldata( +- rdataset, +- check_related, +- fctx); +- +- /* +- * CNAME chaining. +- */ +- if (want_chaining) { +- wanted_chaining = ISC_TRUE; +- name->attributes |= +- DNS_NAMEATTR_CHAINING; +- rdataset->attributes |= +- DNS_RDATASETATTR_CHAINING; +- qname = &tname; +- } ++ if (rdataset->type == dns_rdatatype_cname) { ++ cname = name; ++ crdataset = rdataset; ++ break; + } +- /* +- * We could add an "else" clause here and +- * log that we're ignoring this rdataset. +- */ + } ++ break; ++ ++ case dns_namereln_subdomain: + /* +- * If wanted_chaining is true, we've done +- * some chaining as the result of processing +- * this node, and thus we need to set +- * chaining to true. +- * +- * We don't set chaining inside of the +- * rdataset loop because doing that would +- * cause us to ignore the signatures of +- * CNAMEs. ++ * In-scope DNAME records must have at least ++ * as many labels as the domain being queried. ++ * They also must be less that qname's labels ++ * and any previously found dname. + */ +- if (wanted_chaining && chaining < 2U) +- chaining++; +- } else { +- dns_rdataset_t *dnameset = NULL; +- isc_boolean_t synthcname = ISC_FALSE; +- +- if (lastcname != NULL) { +- lastreln = dns_name_fullcompare(lastcname, +- name, +- &lastorder, +- &lastnlabels); +- if (lastreln == dns_namereln_subdomain && +- lastnlabels == dns_name_countlabels(name)) +- synthcname = ISC_TRUE; ++ if (nlabels >= dname_labels || nlabels < domain_labels) ++ { ++ continue; + } + + /* +- * Look for a DNAME (or its SIG). Anything else is +- * ignored. ++ * We are looking for the shortest DNAME if there ++ * are multiple ones (which there shouldn't be). + */ +- wanted_chaining = ISC_FALSE; + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) + { +- if (rdataset->rdclass != fctx->res->rdclass) { +- log_formerr(fctx, "Mismatched class " +- "in answer"); +- return (DNS_R_FORMERR); +- } +- +- /* +- * Only pass DNAME or RRSIG(DNAME). +- */ +- if (rdataset->type != dns_rdatatype_dname && +- (rdataset->type != dns_rdatatype_rrsig || +- rdataset->covers != dns_rdatatype_dname)) ++ if (rdataset->type != dns_rdatatype_dname) { + continue; +- +- /* +- * If we're not chaining, then the DNAME and +- * its signature should not be external. +- */ +- if (chaining == 0 && external) { +- char qbuf[DNS_NAME_FORMATSIZE]; +- char obuf[DNS_NAME_FORMATSIZE]; +- +- dns_name_format(name, qbuf, +- sizeof(qbuf)); +- dns_name_format(&fctx->domain, obuf, +- sizeof(obuf)); +- log_formerr(fctx, "external DNAME or " +- "RRSIG covering DNAME " +- "in answer: %s is " +- "not in %s", qbuf, obuf); +- return (DNS_R_FORMERR); + } ++ dname = name; ++ drdataset = rdataset; ++ dname_labels = nlabels; ++ break; ++ } ++ break; ++ default: ++ break; ++ } ++ } + +- /* +- * If DNAME + synthetic CNAME then the +- * namereln is dns_namereln_subdomain. +- */ +- if (namereln != dns_namereln_subdomain && +- !synthcname) +- { +- char qbuf[DNS_NAME_FORMATSIZE]; +- char obuf[DNS_NAME_FORMATSIZE]; +- +- dns_name_format(qname, qbuf, +- sizeof(qbuf)); +- dns_name_format(name, obuf, +- sizeof(obuf)); +- log_formerr(fctx, "unrelated DNAME " +- "in answer: %s is " +- "not in %s", qbuf, obuf); +- return (DNS_R_FORMERR); +- } +- +- aflag = 0; +- if (rdataset->type == dns_rdatatype_dname) { +- want_chaining = ISC_TRUE; +- POST(want_chaining); +- aflag = DNS_RDATASETATTR_ANSWER; +- dns_fixedname_init(&fdname); +- dname = dns_fixedname_name(&fdname); +- if (synthcname) { +- result = fromdname(rdataset, +- lastcname, +- lastnlabels, +- qname); +- } else { +- result = dname_target(rdataset, +- qname, +- nlabels, +- dname); +- } +- if (result == ISC_R_NOSPACE) { +- /* +- * We can't construct the +- * DNAME target. Do not +- * try to continue. +- */ +- want_chaining = ISC_FALSE; +- POST(want_chaining); +- } else if (result != ISC_R_SUCCESS) +- return (result); +- else +- dnameset = rdataset; ++ if (dname != NULL) { ++ aname = NULL; ++ ardataset = NULL; ++ cname = NULL; ++ crdataset = NULL; ++ } else if (aname != NULL) { ++ cname = NULL; ++ crdataset = NULL; ++ } + +- if (!synthcname && +- !is_answertarget_allowed(view, +- qname, rdataset->type, +- dname, &fctx->domain)) +- { +- return (DNS_R_SERVFAIL); +- } +- } else { +- /* +- * We've found a signature that +- * covers the DNAME. +- */ +- aflag = DNS_RDATASETATTR_ANSWERSIG; +- } ++ aa = ISC_TF((message->flags & DNS_MESSAGEFLAG_AA) != 0); ++ trust = aa ? dns_trust_authanswer : dns_trust_answer; + +- /* +- * We've found an answer to our +- * question. +- */ +- name->attributes |= DNS_NAMEATTR_CACHE; +- rdataset->attributes |= DNS_RDATASETATTR_CACHE; +- rdataset->trust = dns_trust_answer; +- /* +- * If we are not chaining or the first CNAME +- * is a synthesised CNAME before the DNAME. +- */ +- if (external) { +- rdataset->attributes |= +- DNS_RDATASETATTR_EXTERNAL; +- } else if ((chaining == 0) || +- (chaining == 1U && synthcname)) +- { +- if (aflag == DNS_RDATASETATTR_ANSWER) { +- have_answer = ISC_TRUE; +- found_dname = ISC_TRUE; +- if (cname != NULL && +- synthcname) +- { +- cname->attributes &= +- ~DNS_NAMEATTR_ANSWER; +- } +- name->attributes |= +- DNS_NAMEATTR_ANSWER; +- } +- rdataset->attributes |= aflag; +- if (aa) +- rdataset->trust = +- dns_trust_authanswer; +- } ++ if (aname != NULL && type == dns_rdatatype_any) { ++ for (rdataset = ISC_LIST_HEAD(aname->list); ++ rdataset != NULL; ++ rdataset = ISC_LIST_NEXT(rdataset, link)) ++ { ++ if (!validinanswer(rdataset, fctx)) { ++ return (DNS_R_FORMERR); + } +- +- /* +- * DNAME chaining. +- */ +- if (dnameset != NULL) { +- if (!synthcname) { +- /* +- * Copy the dname into the qname fixed +- * name. +- * +- * Although we check for failure of the +- * copy operation, in practice it +- * should never fail since we already +- * know that the result fits in a +- * fixedname. +- */ +- dns_fixedname_init(&fqname); +- qname = dns_fixedname_name(&fqname); +- result = dns_name_copy(dname, qname, +- NULL); +- if (result != ISC_R_SUCCESS) +- return (result); +- } +- wanted_chaining = ISC_TRUE; +- name->attributes |= DNS_NAMEATTR_CHAINING; +- dnameset->attributes |= +- DNS_RDATASETATTR_CHAINING; ++ if ((fctx->type == dns_rdatatype_sig || ++ fctx->type == dns_rdatatype_rrsig) && ++ rdataset->type != fctx->type) ++ { ++ continue; + } +- /* +- * Ensure that we can't ever get chaining == 1 +- * above if we have processed a DNAME. +- */ +- if (wanted_chaining && chaining < 2U) +- chaining += 2; ++ if ((rdataset->type == dns_rdatatype_a || ++ rdataset->type == dns_rdatatype_aaaa) && ++ !is_answeraddress_allowed(view, aname, rdataset)) ++ { ++ return (DNS_R_SERVFAIL); ++ } ++ if ((rdataset->type == dns_rdatatype_cname || ++ rdataset->type == dns_rdatatype_dname) && ++ !is_answertarget_allowed(fctx, qname, aname, ++ rdataset)) ++ { ++ return (DNS_R_SERVFAIL); ++ } ++ aname->attributes |= DNS_NAMEATTR_CACHE; ++ aname->attributes |= DNS_NAMEATTR_ANSWER; ++ rdataset->attributes |= DNS_RDATASETATTR_ANSWER; ++ rdataset->attributes |= DNS_RDATASETATTR_CACHE; ++ rdataset->trust = trust; ++ (void)dns_rdataset_additionaldata(rdataset, ++ check_related, ++ fctx); + } +- result = dns_message_nextname(message, DNS_SECTION_ANSWER); +- } +- if (result == ISC_R_NOMORE) +- result = ISC_R_SUCCESS; +- if (result != ISC_R_SUCCESS) +- return (result); +- +- /* +- * We should have found an answer. +- */ +- if (!have_answer) { ++ } else if (aname != NULL) { ++ if (!validinanswer(ardataset, fctx)) ++ return (DNS_R_FORMERR); ++ if ((ardataset->type == dns_rdatatype_a || ++ ardataset->type == dns_rdatatype_aaaa) && ++ !is_answeraddress_allowed(view, aname, ardataset)) { ++ return (DNS_R_SERVFAIL); ++ } ++ if ((ardataset->type == dns_rdatatype_cname || ++ ardataset->type == dns_rdatatype_dname) && ++ !is_answertarget_allowed(fctx, qname, aname, ardataset)) { ++ return (DNS_R_SERVFAIL); ++ } ++ aname->attributes |= DNS_NAMEATTR_CACHE; ++ aname->attributes |= DNS_NAMEATTR_ANSWER; ++ ardataset->attributes |= DNS_RDATASETATTR_ANSWER; ++ ardataset->attributes |= DNS_RDATASETATTR_CACHE; ++ ardataset->trust = trust; ++ (void)dns_rdataset_additionaldata(ardataset, check_related, ++ fctx); ++ for (sigrdataset = ISC_LIST_HEAD(aname->list); ++ sigrdataset != NULL; ++ sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) { ++ if (!validinanswer(sigrdataset, fctx)) ++ return (DNS_R_FORMERR); ++ if (sigrdataset->type != dns_rdatatype_rrsig || ++ sigrdataset->covers != type) ++ continue; ++ sigrdataset->attributes |= DNS_RDATASETATTR_ANSWERSIG; ++ sigrdataset->attributes |= DNS_RDATASETATTR_CACHE; ++ sigrdataset->trust = trust; ++ break; ++ } ++ } else if (cname != NULL) { ++ if (!validinanswer(crdataset, fctx)) { ++ return (DNS_R_FORMERR); ++ } ++ if (type == dns_rdatatype_rrsig || type == dns_rdatatype_key || ++ type == dns_rdatatype_nsec) ++ { ++ char buf[DNS_RDATATYPE_FORMATSIZE]; ++ dns_rdatatype_format(type, buf, sizeof(buf)); ++ log_formerr(fctx, "CNAME response for %s RR", buf); ++ return (DNS_R_FORMERR); ++ } ++ if (!is_answertarget_allowed(fctx, qname, cname, crdataset)) { ++ return (DNS_R_SERVFAIL); ++ } ++ cname->attributes |= DNS_NAMEATTR_CACHE; ++ cname->attributes |= DNS_NAMEATTR_ANSWER; ++ cname->attributes |= DNS_NAMEATTR_CHAINING; ++ crdataset->attributes |= DNS_RDATASETATTR_ANSWER; ++ crdataset->attributes |= DNS_RDATASETATTR_CACHE; ++ crdataset->attributes |= DNS_RDATASETATTR_CHAINING; ++ crdataset->trust = trust; ++ for (sigrdataset = ISC_LIST_HEAD(cname->list); ++ sigrdataset != NULL; ++ sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) ++ { ++ if (!validinanswer(sigrdataset, fctx)) { ++ return (DNS_R_FORMERR); ++ } ++ if (sigrdataset->type != dns_rdatatype_rrsig || ++ sigrdataset->covers != dns_rdatatype_cname) ++ { ++ continue; ++ } ++ sigrdataset->attributes |= DNS_RDATASETATTR_ANSWERSIG; ++ sigrdataset->attributes |= DNS_RDATASETATTR_CACHE; ++ sigrdataset->trust = trust; ++ break; ++ } ++ chaining = ISC_TRUE; ++ } else if (dname != NULL) { ++ if (!validinanswer(drdataset, fctx)) { ++ return (DNS_R_FORMERR); ++ } ++ if (!is_answertarget_allowed(fctx, qname, dname, drdataset)) { ++ return (DNS_R_SERVFAIL); ++ } ++ dname->attributes |= DNS_NAMEATTR_CACHE; ++ dname->attributes |= DNS_NAMEATTR_ANSWER; ++ dname->attributes |= DNS_NAMEATTR_CHAINING; ++ drdataset->attributes |= DNS_RDATASETATTR_ANSWER; ++ drdataset->attributes |= DNS_RDATASETATTR_CACHE; ++ drdataset->attributes |= DNS_RDATASETATTR_CHAINING; ++ drdataset->trust = trust; ++ for (sigrdataset = ISC_LIST_HEAD(dname->list); ++ sigrdataset != NULL; ++ sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) ++ { ++ if (!validinanswer(sigrdataset, fctx)) { ++ return (DNS_R_FORMERR); ++ } ++ if (sigrdataset->type != dns_rdatatype_rrsig || ++ sigrdataset->covers != dns_rdatatype_dname) ++ { ++ continue; ++ } ++ sigrdataset->attributes |= DNS_RDATASETATTR_ANSWERSIG; ++ sigrdataset->attributes |= DNS_RDATASETATTR_CACHE; ++ sigrdataset->trust = trust; ++ break; ++ } ++ chaining = ISC_TRUE; ++ } else { + log_formerr(fctx, "reply has no answer"); + return (DNS_R_FORMERR); + } +@@ -7210,7 +7015,7 @@ answer_response(fetchctx_t *fctx) { + /* + * Did chaining end before we got the final answer? + */ +- if (chaining != 0) { ++ if (chaining) { + /* + * Yes. This may be a negative reply, so hand off + * authority section processing to the noanswer code. +@@ -7236,11 +7041,9 @@ answer_response(fetchctx_t *fctx) { + * We expect there to be only one owner name for all the rdatasets + * in this section, and we expect that it is not external. + */ +- done = ISC_FALSE; +- ns_name = NULL; +- ns_rdataset = NULL; + result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); + while (!done && result == ISC_R_SUCCESS) { ++ isc_boolean_t external; + name = NULL; + dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name); + external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain)); +@@ -7259,12 +7062,13 @@ answer_response(fetchctx_t *fctx) { + DNS_NAMEATTR_CACHE; + rdataset->attributes |= + DNS_RDATASETATTR_CACHE; +- if (aa && chaining == 0) ++ if (aa && !chaining) { + rdataset->trust = + dns_trust_authauthority; +- else ++ } else { + rdataset->trust = + dns_trust_additional; ++ } + + if (rdataset->type == dns_rdatatype_ns) + { +@@ -8064,6 +7868,7 @@ resquery_response(isc_task_t *task, isc_ + * Is the remote server broken, or does it dislike us? + */ + if (message->rcode != dns_rcode_noerror && ++ message->rcode != dns_rcode_yxdomain && + message->rcode != dns_rcode_nxdomain) { + isc_buffer_t b; + char code[64]; +@@ -8128,13 +7933,6 @@ resquery_response(isc_task_t *task, isc_ + log_formerr(fctx, "server sent FORMERR"); + result = DNS_R_FORMERR; + } +- } else if (message->rcode == dns_rcode_yxdomain) { +- /* +- * DNAME mapping failed because the new name +- * was too long. There's no chance of success +- * for this fetch. +- */ +- result = DNS_R_YXDOMAIN; + } else if (message->rcode == dns_rcode_badvers) { + unsigned int flags, mask; + unsigned int version; +@@ -8293,6 +8091,7 @@ resquery_response(isc_task_t *task, isc_ + */ + if (message->counts[DNS_SECTION_ANSWER] > 0 && + (message->rcode == dns_rcode_noerror || ++ message->rcode == dns_rcode_yxdomain || + message->rcode == dns_rcode_nxdomain)) { + /* + * [normal case] diff -Nru bind9-9.10.3.dfsg.P4/debian/patches/CVE-2017-3137-3.patch bind9-9.10.3.dfsg.P4/debian/patches/CVE-2017-3137-3.patch --- bind9-9.10.3.dfsg.P4/debian/patches/CVE-2017-3137-3.patch 1970-01-01 01:00:00.000000000 +0100 +++ bind9-9.10.3.dfsg.P4/debian/patches/CVE-2017-3137-3.patch 2017-05-07 15:22:46.000000000 +0200 @@ -0,0 +1,120 @@ +From 7ab9e8e00775782d474522a5b2bffba8daefefa5 Mon Sep 17 00:00:00 2001 +From: Mark Andrews <ma...@isc.org> +Date: Tue, 14 Mar 2017 15:07:00 +1100 +Subject: [PATCH] 4580. [bug] 4578 introduced a regression when + handling CNAME to referral below the current domain. + [RT #44850] + +(cherry picked from commit 638c7c635ddab0b717a675f49b1180dbf8ef803e) +--- +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -6138,7 +6138,7 @@ is_answeraddress_allowed(dns_view_t *vie + + static isc_boolean_t + is_answertarget_allowed(fetchctx_t *fctx, dns_name_t *qname, dns_name_t *rname, +- dns_rdataset_t *rdataset) ++ dns_rdataset_t *rdataset, isc_boolean_t *chainingp) + { + isc_result_t result; + dns_rbtnode_t *node = NULL; +@@ -6159,8 +6159,11 @@ is_answertarget_allowed(fetchctx_t *fctx + REQUIRE(rdataset->type == dns_rdatatype_cname || + rdataset->type == dns_rdatatype_dname); + +- /* By default, we allow any target name. */ +- if (view->denyanswernames == NULL) ++ /* ++ * By default, we allow any target name. ++ * If newqname != NULL we also need to extract the newqname. ++ */ ++ if (chainingp == NULL && view->denyanswernames == NULL) + return (ISC_TRUE); + + result = dns_rdataset_first(rdataset); +@@ -6183,7 +6186,7 @@ is_answertarget_allowed(fetchctx_t *fctx + dns_name_split(qname, nlabels, &prefix, NULL); + result = dns_name_concatenate(&prefix, &dname.dname, tname, + NULL); +- if (result == ISC_R_NOSPACE) ++ if (result == DNS_R_NAMETOOLONG) + return (ISC_TRUE); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + break; +@@ -6191,6 +6194,12 @@ is_answertarget_allowed(fetchctx_t *fctx + INSIST(0); + } + ++ if (chainingp != NULL) ++ *chainingp = ISC_TRUE; ++ ++ if (view->denyanswernames == NULL) ++ return (ISC_TRUE); ++ + /* + * If the owner name matches one in the exclusion list, either exactly + * or partially, allow it. +@@ -6884,7 +6893,7 @@ answer_response(fetchctx_t *fctx) { + if ((rdataset->type == dns_rdatatype_cname || + rdataset->type == dns_rdatatype_dname) && + !is_answertarget_allowed(fctx, qname, aname, +- rdataset)) ++ rdataset, NULL)) + { + return (DNS_R_SERVFAIL); + } +@@ -6907,7 +6916,9 @@ answer_response(fetchctx_t *fctx) { + } + if ((ardataset->type == dns_rdatatype_cname || + ardataset->type == dns_rdatatype_dname) && +- !is_answertarget_allowed(fctx, qname, aname, ardataset)) { ++ !is_answertarget_allowed(fctx, qname, aname, ardataset, ++ NULL)) ++ { + return (DNS_R_SERVFAIL); + } + aname->attributes |= DNS_NAMEATTR_CACHE; +@@ -6942,7 +6953,9 @@ answer_response(fetchctx_t *fctx) { + log_formerr(fctx, "CNAME response for %s RR", buf); + return (DNS_R_FORMERR); + } +- if (!is_answertarget_allowed(fctx, qname, cname, crdataset)) { ++ if (!is_answertarget_allowed(fctx, qname, cname, crdataset, ++ NULL)) ++ { + return (DNS_R_SERVFAIL); + } + cname->attributes |= DNS_NAMEATTR_CACHE; +@@ -6974,7 +6987,8 @@ answer_response(fetchctx_t *fctx) { + if (!validinanswer(drdataset, fctx)) { + return (DNS_R_FORMERR); + } +- if (!is_answertarget_allowed(fctx, qname, dname, drdataset)) { ++ if (!is_answertarget_allowed(fctx, qname, dname, drdataset, ++ &chaining)) { + return (DNS_R_SERVFAIL); + } + dname->attributes |= DNS_NAMEATTR_CACHE; +@@ -7001,7 +7015,6 @@ answer_response(fetchctx_t *fctx) { + sigrdataset->trust = trust; + break; + } +- chaining = ISC_TRUE; + } else { + log_formerr(fctx, "reply has no answer"); + return (DNS_R_FORMERR); +@@ -7016,13 +7029,7 @@ answer_response(fetchctx_t *fctx) { + * Did chaining end before we got the final answer? + */ + if (chaining) { +- /* +- * Yes. This may be a negative reply, so hand off +- * authority section processing to the noanswer code. +- * If it isn't a noanswer response, no harm will be +- * done. +- */ +- return (noanswer_response(fctx, qname, 0)); ++ return (ISC_R_SUCCESS); + } + + /* diff -Nru bind9-9.10.3.dfsg.P4/debian/patches/CVE-2017-3138.patch bind9-9.10.3.dfsg.P4/debian/patches/CVE-2017-3138.patch --- bind9-9.10.3.dfsg.P4/debian/patches/CVE-2017-3138.patch 1970-01-01 01:00:00.000000000 +0100 +++ bind9-9.10.3.dfsg.P4/debian/patches/CVE-2017-3138.patch 2017-05-07 15:22:46.000000000 +0200 @@ -0,0 +1,51 @@ +From a636604b20cc0aaabc8edbb7595f7c1c820b7610 Mon Sep 17 00:00:00 2001 +From: Mark Andrews <ma...@isc.org> +Date: Sat, 25 Mar 2017 02:00:17 +1100 +Subject: [PATCH] 4582. [security] 'rndc ""' could trigger a assertion + failure in named. (CVE-2017-3138) [RT #44924] + +(cherry picked from commit 8e8dfc5941e2375f2f8dadf3706258dd0db5f2e6) +--- + +--- a/bin/tests/system/rndc/tests.sh ++++ b/bin/tests/system/rndc/tests.sh +@@ -386,5 +386,13 @@ sleep 1 + if [ $ret != 0 ]; then echo "I:failed"; fi + status=`expr $status + $ret` + ++n=`expr $n + 1` ++echo "I:check 'rndc \"\"' is handled ($n)" ++ret=0 ++$RNDCCMD "" > rndc.out.test$n 2>&1 && ret=1 ++grep "rndc: '' failed: failure" rndc.out.test$n > /dev/null ++if [ $ret != 0 ]; then echo "I:failed"; fi ++status=`expr $status + $ret` ++ + echo "I:exit status: $status" + exit $status +--- a/lib/isc/include/isc/lex.h ++++ b/lib/isc/include/isc/lex.h +@@ -152,8 +152,6 @@ isc_lex_create(isc_mem_t *mctx, size_t m + * Requires: + *\li '*lexp' is a valid lexer. + * +- *\li max_token > 0. +- * + * Ensures: + *\li On success, *lexp is attached to the newly created lexer. + * +--- a/lib/isc/lex.c ++++ b/lib/isc/lex.c +@@ -94,9 +94,10 @@ isc_lex_create(isc_mem_t *mctx, size_t m + /* + * Create a lexer. + */ +- + REQUIRE(lexp != NULL && *lexp == NULL); +- REQUIRE(max_token > 0U); ++ ++ if (max_token == 0U) ++ max_token = 1; + + lex = isc_mem_get(mctx, sizeof(*lex)); + if (lex == NULL) diff -Nru bind9-9.10.3.dfsg.P4/debian/patches/series bind9-9.10.3.dfsg.P4/debian/patches/series --- bind9-9.10.3.dfsg.P4/debian/patches/series 2017-02-19 23:39:32.000000000 +0100 +++ bind9-9.10.3.dfsg.P4/debian/patches/series 2017-05-07 15:22:46.000000000 +0200 @@ -22,3 +22,11 @@ CVE-2016-8864-regression2.patch CVE-2017-3135.patch + +CVE-2017-3136.patch + +CVE-2017-3137-1.patch +CVE-2017-3137-2.patch +CVE-2017-3137-3.patch + +CVE-2017-3138.patch