diff --git a/SOURCES/bind99-CVE-2016-9131.patch b/SOURCES/bind99-CVE-2016-9131.patch new file mode 100644 index 0000000..29e381c --- /dev/null +++ b/SOURCES/bind99-CVE-2016-9131.patch @@ -0,0 +1,37 @@ +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index 2bc4461..d9de369 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -6533,6 +6533,19 @@ answer_response(fetchctx_t *fctx) { + 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 +@@ -6719,6 +6732,12 @@ answer_response(fetchctx_t *fctx) { + 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). + */ diff --git a/SOURCES/bind99-CVE-2016-9147.patch b/SOURCES/bind99-CVE-2016-9147.patch new file mode 100644 index 0000000..221ff94 --- /dev/null +++ b/SOURCES/bind99-CVE-2016-9147.patch @@ -0,0 +1,31 @@ +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index 9ad5f81..ffdde5e 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -6229,15 +6229,19 @@ answer_response(fetchctx_t *fctx) { + * a CNAME or DNAME). + */ + INSIST(!external); +- if ((rdataset->type != +- dns_rdatatype_cname) || +- !found_dname || +- (aflag == +- DNS_RDATASETATTR_ANSWER)) ++ /* ++ * 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 (rdataset->type == +- dns_rdatatype_cname) ++ if (found_cname && ++ cname == NULL) + cname = name; + name->attributes |= + DNS_NAMEATTR_ANSWER; diff --git a/SOURCES/bind99-CVE-2016-9444.patch b/SOURCES/bind99-CVE-2016-9444.patch new file mode 100644 index 0000000..17ee09f --- /dev/null +++ b/SOURCES/bind99-CVE-2016-9444.patch @@ -0,0 +1,147 @@ +diff --git a/lib/dns/message.c b/lib/dns/message.c +index 869d258..c1f9498 100644 +--- a/lib/dns/message.c ++++ b/lib/dns/message.c +@@ -1150,6 +1150,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) +@@ -1175,12 +1232,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; +@@ -1354,7 +1411,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) +@@ -1565,6 +1622,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_FORMERR; ++ + if (seen_problem) + return (DNS_R_RECOVERABLE); + return (ISC_R_SUCCESS); +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index 2bc4461..e5600a3 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -5194,13 +5194,9 @@ 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); +- } + } + addedrdataset = ardataset; + result = dns_db_addrdataset(fctx->cache, node, +@@ -5330,11 +5326,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); + } + + /* diff --git a/SOURCES/bind99-rt43779.patch b/SOURCES/bind99-rt43779.patch new file mode 100644 index 0000000..fa6b6ec --- /dev/null +++ b/SOURCES/bind99-rt43779.patch @@ -0,0 +1,159 @@ +commit 524f5c0d8fa5bd55c98243be889528f48437a2f7 +Author: Mark Andrews +Date: Fri Dec 9 12:50:18 2016 +1100 + + 4530. [bug] Change 4489 broke the handling of CNAME -> DNAME + in responses resulting in SERVFAIL being returned. + [RT #43779] + + (cherry picked from commit 60cb462c56536f307fac4db8bdebf1247e2b5f66) + +diff --git a/bin/tests/system/dname/ns2/example.db b/bin/tests/system/dname/ns2/example.db +index ece3506..4289134 100644 +--- a/bin/tests/system/dname/ns2/example.db ++++ b/bin/tests/system/dname/ns2/example.db +@@ -29,4 +29,6 @@ a.short A 10.0.0.1 + short-dname DNAME short + a.longlonglonglonglonglonglonglonglonglonglonglonglong A 10.0.0.2 + long-dname DNAME longlonglonglonglonglonglonglonglonglonglonglonglong +-; ++cname CNAME a.cnamedname ++cnamedname DNAME target ++a.target A 10.0.0.3 +diff --git a/bin/tests/system/dname/tests.sh b/bin/tests/system/dname/tests.sh +index d22f54b..04bfcb2 100644 +--- a/bin/tests/system/dname/tests.sh ++++ b/bin/tests/system/dname/tests.sh +@@ -63,6 +63,24 @@ grep "status: YXDOMAIN" dig.out.ns4.toolong > /dev/null || ret=1 + if [ $ret != 0 ]; then echo "I:failed"; fi + status=`expr $status + $ret` + ++echo "I:checking cname to dname from authoritative" ++ret=0 ++$DIG cname.example @10.53.0.2 a -p 5300 > dig.out.ns2.cname ++grep "status: NOERROR" dig.out.ns2.cname > /dev/null || ret=1 ++if [ $ret != 0 ]; then echo "I:failed"; fi ++status=`expr $status + $ret` ++ ++echo "I:checking cname to dname from recursive" ++ret=0 ++$DIG cname.example @10.53.0.4 a -p 5300 > dig.out.ns4.cname ++grep "status: NOERROR" dig.out.ns4.cname > /dev/null || ret=1 ++grep '^cname.example.' dig.out.ns4.cname > /dev/null || ret=1 ++grep '^cnamedname.example.' dig.out.ns4.cname > /dev/null || ret=1 ++grep '^a.cnamedname.example.' dig.out.ns4.cname > /dev/null || ret=1 ++grep '^a.target.example.' dig.out.ns4.cname > /dev/null || ret=1 ++if [ $ret != 0 ]; then echo "I:failed"; fi ++status=`expr $status + $ret` ++ + echo "I:exit status: $status" + + exit $status +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index 4bef072..de80928 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -6463,7 +6463,7 @@ static isc_result_t + answer_response(fetchctx_t *fctx) { + isc_result_t result; + dns_message_t *message; +- dns_name_t *name, *dname = NULL, *qname, *dqname, tname, *ns_name; ++ dns_name_t *name, *dname = NULL, *qname, tname, *ns_name; + dns_name_t *cname = NULL; + dns_rdataset_t *rdataset, *ns_rdataset; + isc_boolean_t done, external, chaining, aa, found, want_chaining; +@@ -6471,7 +6471,7 @@ answer_response(fetchctx_t *fctx) { + isc_boolean_t wanted_chaining; + unsigned int aflag; + dns_rdatatype_t type; +- dns_fixedname_t fdname, fqname, fqdname; ++ dns_fixedname_t fdname, fqname; + dns_view_t *view; + + FCTXTRACE("answer_response"); +@@ -6495,13 +6495,12 @@ answer_response(fetchctx_t *fctx) { + aa = ISC_TRUE; + else + aa = ISC_FALSE; +- dqname = qname = &fctx->name; ++ qname = &fctx->name; + type = fctx->type; + view = fctx->res->view; +- dns_fixedname_init(&fqdname); + result = dns_message_firstname(message, DNS_SECTION_ANSWER); + while (!done && result == ISC_R_SUCCESS) { +- dns_namereln_t namereln, dnamereln; ++ dns_namereln_t namereln; + int order; + unsigned int nlabels; + +@@ -6509,8 +6508,6 @@ answer_response(fetchctx_t *fctx) { + dns_message_currentname(message, DNS_SECTION_ANSWER, &name); + external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain)); + namereln = dns_name_fullcompare(qname, name, &order, &nlabels); +- dnamereln = dns_name_fullcompare(dqname, name, &order, +- &nlabels); + if (namereln == dns_namereln_equal) { + wanted_chaining = ISC_FALSE; + for (rdataset = ISC_LIST_HEAD(name->list); +@@ -6763,11 +6760,24 @@ answer_response(fetchctx_t *fctx) { + return (DNS_R_FORMERR); + } + +- if (dnamereln != dns_namereln_subdomain) { ++ /* ++ * If DNAME + synthetic CNAME then the ++ * namereln is dns_namereln_subdomain. ++ * ++ * If synthetic CNAME + DNAME then the ++ * namereln is dns_namereln_commonancestor ++ * and the number of label must match the ++ * DNAME. This order is not RFC compliant. ++ */ ++ ++ if (namereln != dns_namereln_subdomain && ++ (namereln != dns_namereln_commonancestor || ++ nlabels != dns_name_countlabels(name))) ++ { + char qbuf[DNS_NAME_FORMATSIZE]; + char obuf[DNS_NAME_FORMATSIZE]; + +- dns_name_format(dqname, qbuf, ++ dns_name_format(qname, qbuf, + sizeof(qbuf)); + dns_name_format(name, obuf, + sizeof(obuf)); +@@ -6782,7 +6792,7 @@ answer_response(fetchctx_t *fctx) { + want_chaining = ISC_TRUE; + POST(want_chaining); + aflag = DNS_RDATASETATTR_ANSWER; +- result = dname_target(rdataset, dqname, ++ result = dname_target(rdataset, qname, + nlabels, &fdname); + if (result == ISC_R_NOSPACE) { + /* +@@ -6799,13 +6809,11 @@ answer_response(fetchctx_t *fctx) { + + dname = dns_fixedname_name(&fdname); + if (!is_answertarget_allowed(view, +- dqname, rdataset->type, ++ qname, rdataset->type, + dname, &fctx->domain)) + { + return (DNS_R_SERVFAIL); + } +- dqname = dns_fixedname_name(&fqdname); +- dns_name_copy(dname, dqname, NULL); + } else { + /* + * We've found a signature that +@@ -6951,7 +6959,8 @@ answer_response(fetchctx_t *fctx) { + rdataset->trust = + dns_trust_additional; + +- if (rdataset->type == dns_rdatatype_ns) { ++ if (rdataset->type == dns_rdatatype_ns) ++ { + ns_name = name; + ns_rdataset = rdataset; + } diff --git a/SPECS/bind.spec b/SPECS/bind.spec index 801e469..f66d909 100644 --- a/SPECS/bind.spec +++ b/SPECS/bind.spec @@ -25,7 +25,7 @@ Summary: The Berkeley Internet Name Domain (BIND) DNS (Domain Name System) serv Name: bind License: ISC Version: 9.9.4 -Release: 38%{?PATCHVER}%{?PREVER}%{?dist} +Release: 38%{?PATCHVER}%{?PREVER}%{?dist}.1 Epoch: 32 Url: http://www.isc.org/products/BIND/ Buildroot:%{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -113,6 +113,10 @@ Patch166:bind99-rh1220594-geoip.patch Patch167:bind99-automatic-interface-scanning-rh1294506.patch patch168:bind99-CVE-2016-2776.patch patch169:bind99-CVE-2016-8864.patch +patch170:bind99-CVE-2016-9131.patch +patch171:bind99-CVE-2016-9147.patch +Patch172:bind99-CVE-2016-9444.patch +Patch173:bind99-rt43779.patch # Native PKCS#11 functionality from 9.10 Patch150:bind-9.9-allow_external_dnskey.patch @@ -402,6 +406,10 @@ tar -xf %{SOURCE48} -C bin/tests/system/geoip/data %patch167 -p1 -b .rh1294506 %patch168 -p1 -b .CVE-2016-2776 %patch169 -p1 -b .CVE-2016-8864 +%patch170 -p1 -b .CVE-2016-9131 +%patch171 -p1 -b .CVE-2016-9147 +%patch172 -p1 -b .CVE-2016-9444 +%patch173 -p1 -b .rt43779 %if %{PKCS11} cp -r bin/named{,-pkcs11} @@ -1081,6 +1089,12 @@ rm -rf ${RPM_BUILD_ROOT} %endif %changelog +* Mon Jan 09 2017 Petr Menšík - 32:9.9.4-38.1 +- Fix CVE-2016-9131 (ISC change 4508) +- Fix CVE-2016-9147 (ISC change 4510) +- Fix regression introduced by CVE-2016-8864 (ISC change 4530) +- Fix CVE-2016-9444 (ISC change 4517) + * Mon Oct 31 2016 Tomas Hozza - 32:9.9.4-38 - Fix CVE-2016-8864