On Thu, May 11, 2017 at 08:27:57AM +0200, Salvatore Bonaccorso wrote:
> On Thu, May 11, 2017 at 08:19:15AM +0200, Salvatore Bonaccorso wrote:
> > Hi
> > 
> > Packages for testing can be found at:
> > 
> > https://people.debian.org/~carnil/tmp/bind9/
> > 
> > (amd64 build only), and attached the debdiff.
> 
> There was an error in those  packages and I have removed them again.

Corrected version re-uploaded.

Regards,
Salvatore
diff -u bind9-9.9.5.dfsg/bin/named/query.c bind9-9.9.5.dfsg/bin/named/query.c
--- bind9-9.9.5.dfsg/bin/named/query.c
+++ bind9-9.9.5.dfsg/bin/named/query.c
@@ -7325,6 +7325,7 @@
                        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 -u bind9-9.9.5.dfsg/bin/tests/system/dname/ns2/example.db 
bind9-9.9.5.dfsg/bin/tests/system/dname/ns2/example.db
--- bind9-9.9.5.dfsg/bin/tests/system/dname/ns2/example.db
+++ bind9-9.9.5.dfsg/bin/tests/system/dname/ns2/example.db
@@ -29,6 +29,7 @@
 short-dname            DNAME   short
 a.longlonglonglonglonglonglonglonglonglonglonglonglong A 10.0.0.2
 long-dname             DNAME   
longlonglonglonglonglonglonglonglonglonglonglonglong
+toolong-dname          DNAME   
longlonglonglonglonglonglonglonglonglonglonglonglong
 cname                  CNAME   a.cnamedname
 cnamedname             DNAME   target
 a.target               A       10.0.0.3
diff -u bind9-9.9.5.dfsg/bin/tests/system/dname/tests.sh 
bind9-9.9.5.dfsg/bin/tests/system/dname/tests.sh
--- bind9-9.9.5.dfsg/bin/tests/system/dname/tests.sh
+++ bind9-9.9.5.dfsg/bin/tests/system/dname/tests.sh
@@ -56,10 +56,19 @@
 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`
 
diff -u bind9-9.9.5.dfsg/debian/changelog bind9-9.9.5.dfsg/debian/changelog
--- bind9-9.9.5.dfsg/debian/changelog
+++ bind9-9.9.5.dfsg/debian/changelog
@@ -1,3 +1,22 @@
+bind9 (1:9.9.5.dfsg-9+deb8u11) jessie-security; urgency=high
+
+  * Non-maintainer upload by the Security Team.
+  * Dns64 with "break-dnssec yes;" can result in a assertion failure.
+    (CVE-2017-3136) (Closes: #860224)
+  * Prerequisite for CVE-2017-3137 cherry-picked from upstream change #4190.
+    If not cherry-picking this change the fix for CVE-2017-3137 can cause an
+    assertion failure to appear in name.c.
+  * Some chaining (CNAME or DNAME) responses to upstream queries could trigger
+    assertion failures (CVE-2017-3137) (Closes: #860225)
+  * Reimplement: Some chaining (CNAME or DNAME) responses to upstream queries
+    could trigger assertion failures. (CVE-2017-3137)
+  * Fix regression introduced when handling CNAME to referral below the
+    current domain
+  * 'rndc ""' could trigger a assertion failure in named. (CVE-2017-3138)
+    (Closes: #860226)
+
+ -- Salvatore Bonaccorso <car...@debian.org>  Thu, 11 May 2017 08:39:19 +0200
+
 bind9 (1:9.9.5.dfsg-9+deb8u10) jessie-security; urgency=medium
 
   * Fix regression caused by the fix for CVE-2016-8864 (closes: #855540).
diff -u bind9-9.9.5.dfsg/lib/dns/resolver.c bind9-9.9.5.dfsg/lib/dns/resolver.c
--- bind9-9.9.5.dfsg/lib/dns/resolver.c
+++ bind9-9.9.5.dfsg/lib/dns/resolver.c
@@ -3821,6 +3821,7 @@
        isc_result_t result;
 
        if (message->rcode != dns_rcode_noerror &&
+           message->rcode != dns_rcode_yxdomain &&
            message->rcode != dns_rcode_nxdomain)
                return (ISC_FALSE);
 
@@ -5396,79 +5397,6 @@
                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)
@@ -5544,9 +5472,8 @@
 }
 
 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_boolean_t *chainingp)
 {
        isc_result_t result;
        dns_rbtnode_t *node = NULL;
@@ -5554,8 +5481,57 @@
        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 newqname != NULL we also need to extract the newqname.
+        */
+       if (chainingp == NULL && 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 == DNS_R_NAMETOOLONG)
+                       return (ISC_TRUE);
+               RUNTIME_CHECK(result == ISC_R_SUCCESS);
+               break;
+       default:
+               INSIST(0);
+       }
+
+       if (chainingp != NULL)
+               *chainingp = ISC_TRUE;
 
-       /* By default, we allow any target name. */
        if (view->denyanswernames == NULL)
                return (ISC_TRUE);
 
@@ -5564,8 +5540,8 @@
         * 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);
        }
@@ -5573,7 +5549,7 @@
        /*
         * 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);
 
        /*
@@ -5582,9 +5558,9 @@
        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,
@@ -6067,473 +6043,301 @@
        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 (chaining == 0) {
-                                               /*
-                                                * 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).
-                                                */
-                                               INSIST(!external);
-                                               /*
-                                                * 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;
-                                       } else if (external) {
-                                               /*
-                                                * This data is outside of
-                                                * our query domain, and
-                                                * may not be cached.
-                                                */
-                                               rdataset->attributes |=
-                                                   DNS_RDATASETATTR_EXTERNAL;
-                                       }
-
-                                       /*
-                                        * 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);
-                               }
+       if (dname != NULL) {
+               aname = NULL;
+               ardataset = NULL;
+               cname = NULL;
+               crdataset = NULL;
+       } else if (aname != NULL) {
+               cname = NULL;
+               crdataset = NULL;
+       }
 
-                               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 (!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 ((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;
-                                               if (cname != NULL &&
-                                                   synthcname)
-                                               {
-                                                       cname->attributes &=
-                                                          ~DNS_NAMEATTR_ANSWER;
-                                               }
-                                               name->attributes |=
-                                                       DNS_NAMEATTR_ANSWER;
-                                       }
-                                       rdataset->attributes |= aflag;
-                                       if (aa)
-                                               rdataset->trust =
-                                                 dns_trust_authanswer;
-                               } else if (external) {
-                                       rdataset->attributes |=
-                                           DNS_RDATASETATTR_EXTERNAL;
-                               }
+       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, NULL))
+                       {
+                               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,
+                                             NULL))
+               {
+                       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,
+                                            NULL))
+               {
+                       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,
+                                            &chaining)) {
+                       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;
+               }
+       } else {
                log_formerr(fctx, "reply has no answer");
                return (DNS_R_FORMERR);
        }
@@ -6546,14 +6350,8 @@
        /*
         * Did chaining end before we got the final answer?
         */
-       if (chaining != 0) {
-               /*
-                * 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));
+       if (chaining) {
+               return (ISC_R_SUCCESS);
        }
 
        /*
@@ -6572,11 +6370,9 @@
         * 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));
@@ -6595,12 +6391,13 @@
                                                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)
                                        {
@@ -7259,6 +7056,7 @@
         * 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) {
                if (((message->rcode == dns_rcode_formerr ||
                      message->rcode == dns_rcode_notimp) ||
@@ -7303,13 +7101,6 @@
                                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;
@@ -7414,6 +7205,7 @@
         */
        if (message->counts[DNS_SECTION_ANSWER] > 0 &&
            (message->rcode == dns_rcode_noerror ||
+            message->rcode == dns_rcode_yxdomain ||
             message->rcode == dns_rcode_nxdomain)) {
                /*
                 * [normal case]
only in patch2:
unchanged:
--- bind9-9.9.5.dfsg.orig/bin/tests/system/rndc/tests.sh
+++ bind9-9.9.5.dfsg/bin/tests/system/rndc/tests.sh
@@ -245,5 +245,13 @@
 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
only in patch2:
unchanged:
--- bind9-9.9.5.dfsg.orig/lib/dns/name.c
+++ bind9-9.9.5.dfsg/lib/dns/name.c
@@ -2120,11 +2120,9 @@
        REQUIRE(prefix != NULL || suffix != NULL);
        REQUIRE(prefix == NULL ||
                (VALID_NAME(prefix) &&
-                prefix->buffer != NULL &&
                 BINDABLE(prefix)));
        REQUIRE(suffix == NULL ||
                (VALID_NAME(suffix) &&
-                suffix->buffer != NULL &&
                 BINDABLE(suffix)));
 
        splitlabel = name->labels - suffixlabels;
only in patch2:
unchanged:
--- bind9-9.9.5.dfsg.orig/lib/isc/include/isc/lex.h
+++ bind9-9.9.5.dfsg/lib/isc/include/isc/lex.h
@@ -152,8 +152,6 @@
  * Requires:
  *\li  '*lexp' is a valid lexer.
  *
- *\li  max_token > 0.
- *
  * Ensures:
  *\li  On success, *lexp is attached to the newly created lexer.
  *
only in patch2:
unchanged:
--- bind9-9.9.5.dfsg.orig/lib/isc/lex.c
+++ bind9-9.9.5.dfsg/lib/isc/lex.c
@@ -93,9 +93,10 @@
        /*
         * 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)

Reply via email to