]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
4517. [security] Named could mishandle authority sections that were
authorMark Andrews <marka@isc.org>
Tue, 22 Nov 2016 01:31:39 +0000 (12:31 +1100)
committerMark Andrews <marka@isc.org>
Tue, 22 Nov 2016 01:39:15 +0000 (12:39 +1100)
                        missing RRSIGs triggering an assertion failure.
                        (CVE-2016-9444) [RT # 43632]

(cherry picked from commit 1df30cfd27c5a3c57fce357c54aaf6c702227d51)

CHANGES
lib/dns/message.c
lib/dns/resolver.c

diff --git a/CHANGES b/CHANGES
index 8461a9a9ffd7b7d8286c64a60a12c823a93f2238..c41ea2f07707d24eec57305850da3f17f8767c58 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,9 @@
        --- 9.10.4-P5 released ---
 
+4517.  [security]      Named could mishandle authority sections that were
+                       missing RRSIGs triggering an assertion failure.
+                       (CVE-2016-9444) [RT # 43632]
+
 4510.  [security]      Named mishandled some responses where covering RRSIG
                        records are returned without the requested data
                        resulting in a assertion failure. (CVE-2016-9147)
index 37455611a0ef9ab78de24fafda1cfde05ada8801..ad164a9ab0fd0ec0a98a14e0e262293b14cb666d 100644 (file)
@@ -1156,6 +1156,63 @@ update(dns_section_t section, dns_rdataclass_t rdclass) {
        return (ISC_FALSE);
 }
 
+/*
+ * Check to confirm that all DNSSEC records (DS, NSEC, NSEC3) have
+ * covering RRSIGs.
+ */
+static isc_boolean_t
+auth_signed(dns_namelist_t *section) {
+       dns_name_t *name;
+
+       for (name = ISC_LIST_HEAD(*section);
+            name != NULL;
+            name = ISC_LIST_NEXT(name, link))
+       {
+               int auth_dnssec = 0, auth_rrsig = 0;
+               dns_rdataset_t *rds;
+
+               for (rds = ISC_LIST_HEAD(name->list);
+                    rds != NULL;
+                    rds = ISC_LIST_NEXT(rds, link))
+               {
+                       switch (rds->type) {
+                       case dns_rdatatype_ds:
+                               auth_dnssec |= 0x1;
+                               break;
+                       case dns_rdatatype_nsec:
+                               auth_dnssec |= 0x2;
+                               break;
+                       case dns_rdatatype_nsec3:
+                               auth_dnssec |= 0x4;
+                               break;
+                       case dns_rdatatype_rrsig:
+                               break;
+                       default:
+                               continue;
+                       }
+
+                       switch (rds->covers) {
+                       case dns_rdatatype_ds:
+                               auth_rrsig |= 0x1;
+                               break;
+                       case dns_rdatatype_nsec:
+                               auth_rrsig |= 0x2;
+                               break;
+                       case dns_rdatatype_nsec3:
+                               auth_rrsig |= 0x4;
+                               break;
+                       default:
+                               break;
+                       }
+               }
+
+               if (auth_dnssec != auth_rrsig)
+                       return (ISC_FALSE);
+       }
+
+       return (ISC_TRUE);
+}
+
 static isc_result_t
 getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
           dns_section_t sectionid, unsigned int options)
@@ -1181,12 +1238,12 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
        best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
        seen_problem = ISC_FALSE;
 
+       section = &msg->sections[sectionid];
+
        for (count = 0; count < msg->counts[sectionid]; count++) {
                int recstart = source->current;
                isc_boolean_t skip_name_search, skip_type_search;
 
-               section = &msg->sections[sectionid];
-
                skip_name_search = ISC_FALSE;
                skip_type_search = ISC_FALSE;
                free_rdataset = ISC_FALSE;
@@ -1360,7 +1417,7 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
                        goto cleanup;
                rdata->rdclass = rdclass;
                issigzero = ISC_FALSE;
-               if (rdtype == dns_rdatatype_rrsig  &&
+               if (rdtype == dns_rdatatype_rrsig &&
                    rdata->flags == 0) {
                        covers = dns_rdata_covers(rdata);
                        if (covers == 0)
@@ -1571,6 +1628,19 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
                INSIST(free_rdataset == ISC_FALSE);
        }
 
+       /*
+        * If any of DS, NSEC or NSEC3 appeared in the
+        * authority section of a query response without
+        * a covering RRSIG, FORMERR
+        */
+       if (sectionid == DNS_SECTION_AUTHORITY &&
+           msg->opcode == dns_opcode_query &&
+           ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) &&
+           ((msg->flags & DNS_MESSAGEFLAG_TC) == 0) &&
+           !preserve_order &&
+           !auth_signed(section)) 
+               DO_ERROR(DNS_R_FORMERR);
+
        if (seen_problem)
                return (DNS_R_RECOVERABLE);
        return (ISC_R_SUCCESS);
index 90a419cc2a0dc21fa53134a5c29a8006300acde7..66647c0d527647a583c4bba64d09c4d9e1c4fb39 100644 (file)
@@ -5465,16 +5465,13 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
                                                              rdataset->type,
                                                              &noqname);
                                        if (tresult == ISC_R_SUCCESS &&
-                                           noqname != NULL) {
-                                               tresult =
-                                                    dns_rdataset_addnoqname(
+                                           noqname != NULL)
+                                               (void) dns_rdataset_addnoqname(
                                                            rdataset, noqname);
-                                               RUNTIME_CHECK(tresult ==
-                                                             ISC_R_SUCCESS);
-                                       }
                                }
-                               if ((fctx->options & DNS_FETCHOPT_PREFETCH) != 0)
-                                               options = DNS_DBADD_PREFETCH;
+                               if ((fctx->options &
+                                    DNS_FETCHOPT_PREFETCH) != 0)
+                                       options = DNS_DBADD_PREFETCH;
                                addedrdataset = ardataset;
                                result = dns_db_addrdataset(fctx->cache, node,
                                                            NULL, now, rdataset,
@@ -5607,11 +5604,9 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
                                tresult = findnoqname(fctx, name,
                                                      rdataset->type, &noqname);
                                if (tresult == ISC_R_SUCCESS &&
-                                   noqname != NULL) {
-                                       tresult = dns_rdataset_addnoqname(
-                                                           rdataset, noqname);
-                                       RUNTIME_CHECK(tresult == ISC_R_SUCCESS);
-                               }
+                                   noqname != NULL)
+                                       (void) dns_rdataset_addnoqname(
+                                                      rdataset, noqname);
                        }
 
                        /*