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

Reply via email to