diff --git a/SOURCES/bind99-CVE-2017-3135.patch b/SOURCES/bind99-CVE-2017-3135.patch new file mode 100644 index 0000000..2c43c67 --- /dev/null +++ b/SOURCES/bind99-CVE-2017-3135.patch @@ -0,0 +1,193 @@ +From f05af77f32742b8e601d766e1f2fe6a480c7e735 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Wed, 8 Feb 2017 12:23:20 +0100 +Subject: [PATCH] 4557. [security] Combining dns64 and rpz can result in + dereferencing a NULL pointer (read). (CVE-2017-3135) + [RT#44434] + +--- + bin/named/query.c | 59 +++++++++++++++++++++++++----------------------------- + lib/dns/message.c | 6 +++--- + lib/dns/rdataset.c | 1 + + 3 files changed, 31 insertions(+), 35 deletions(-) + +diff --git a/bin/named/query.c b/bin/named/query.c +index 1975dfc..f60078b 100644 +--- a/bin/named/query.c ++++ b/bin/named/query.c +@@ -5591,9 +5591,10 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) + dns_rpz_st_t *rpz_st; + isc_boolean_t resuming; + int line = -1; +- isc_boolean_t dns64_exclude, dns64; ++ isc_boolean_t dns64_exclude, dns64, rpz; + dns_clientinfomethods_t cm; + dns_clientinfo_t ci; ++ dns_name_t *rpzqname; + + CTRACE("query_find"); + +@@ -5619,7 +5620,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) + zone = NULL; + need_wildcardproof = ISC_FALSE; + empty_wild = ISC_FALSE; +- dns64_exclude = dns64 = ISC_FALSE; ++ dns64_exclude = dns64 = rpz = ISC_FALSE; + options = 0; + resuming = ISC_FALSE; + is_zone = ISC_FALSE; +@@ -5736,6 +5737,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) + authoritative = ISC_FALSE; + version = NULL; + need_wildcardproof = ISC_FALSE; ++ rpz = ISC_FALSE; + + if (client->view->checknames && + !dns_rdata_checkowner(client->query.qname, +@@ -5860,11 +5862,29 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) + } + + /* +- * Now look for an answer in the database. ++ * Now look for an answer in the database. If this is a dns64 ++ * AAAA lookup on a rpz database adjust the qname. + */ +- result = dns_db_findext(db, client->query.qname, version, type, ++ if (dns64 && rpz) ++ rpzqname = client->query.rpz_st->qname; ++ else ++ rpzqname = client->query.qname; ++ ++ result = dns_db_findext(db, rpzqname, version, type, + client->query.dboptions, client->now, + &node, fname, &cm, &ci, rdataset, sigrdataset); ++ /* ++ * Fixup fname and sigrdataset. ++ */ ++ if (dns64 && rpz) { ++ isc_result_t rresult; ++ ++ rresult = dns_name_copy(client->query.qname, fname, NULL); ++ RUNTIME_CHECK(rresult == ISC_R_SUCCESS); ++ if (sigrdataset != NULL && ++ dns_rdataset_isassociated(sigrdataset)) ++ dns_rdataset_disassociate(sigrdataset); ++ } + + resume: + CTRACE("query_find: resume"); +@@ -6067,9 +6087,11 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) + switch (rpz_st->m.policy) { + case DNS_RPZ_POLICY_NXDOMAIN: + result = DNS_R_NXDOMAIN; ++ rpz = ISC_TRUE; + break; + case DNS_RPZ_POLICY_NODATA: + result = DNS_R_NXRRSET; ++ rpz = ISC_TRUE; + break; + case DNS_RPZ_POLICY_RECORD: + result = rpz_st->m.result; +@@ -6089,6 +6111,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) + rdataset->ttl = ISC_MIN(rdataset->ttl, + rpz_st->m.ttl); + } ++ rpz = ISC_TRUE; + break; + case DNS_RPZ_POLICY_WILDCNAME: + result = dns_rdataset_first(rdataset); +@@ -6130,7 +6153,6 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) + client->attributes &= ~(NS_CLIENTATTR_WANTDNSSEC | + DNS_MESSAGEFLAG_AD); + query_putrdataset(client, &sigrdataset); +- rpz_st->q.is_zone = is_zone; + is_zone = ISC_TRUE; + rpz_log_rewrite(client, ISC_FALSE, rpz_st->m.policy, + rpz_st->m.type, zone, rpz_st->qname); +@@ -6509,15 +6531,6 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) + rdataset = NULL; + sigrdataset = NULL; + type = qtype = dns_rdatatype_a; +- rpz_st = client->query.rpz_st; +- if (rpz_st != NULL) { +- /* +- * Arrange for RPZ rewriting of any A records. +- */ +- if ((rpz_st->state & DNS_RPZ_REWRITTEN) != 0) +- is_zone = rpz_st->q.is_zone; +- rpz_st_clear(client); +- } + dns64 = ISC_TRUE; + goto db_find; + } +@@ -6786,15 +6799,6 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) + sigrdataset = NULL; + fname = NULL; + type = qtype = dns_rdatatype_a; +- rpz_st = client->query.rpz_st; +- if (rpz_st != NULL) { +- /* +- * Arrange for RPZ rewriting of any A records. +- */ +- if ((rpz_st->state & DNS_RPZ_REWRITTEN) != 0) +- is_zone = rpz_st->q.is_zone; +- rpz_st_clear(client); +- } + dns64 = ISC_TRUE; + goto db_find; + } +@@ -7296,15 +7300,6 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) + rdataset = NULL; + sigrdataset = NULL; + type = qtype = dns_rdatatype_a; +- rpz_st = client->query.rpz_st; +- if (rpz_st != NULL) { +- /* +- * Arrange for RPZ rewriting of any A records. +- */ +- if ((rpz_st->state & DNS_RPZ_REWRITTEN) != 0) +- is_zone = rpz_st->q.is_zone; +- rpz_st_clear(client); +- } + dns64_exclude = dns64 = ISC_TRUE; + goto db_find; + } +diff --git a/lib/dns/message.c b/lib/dns/message.c +index 884107e..1417067 100644 +--- a/lib/dns/message.c ++++ b/lib/dns/message.c +@@ -1234,8 +1234,8 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + { + isc_region_t r; + unsigned int count, rdatalen; +- dns_name_t *name; +- dns_name_t *name2; ++ dns_name_t *name = NULL; ++ dns_name_t *name2 = NULL; + dns_offsets_t *offsets; + dns_rdataset_t *rdataset; + dns_rdatalist_t *rdatalist; +@@ -1245,7 +1245,7 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + dns_rdata_t *rdata; + dns_ttl_t ttl; + dns_namelist_t *section; +- isc_boolean_t free_name, free_rdataset; ++ isc_boolean_t free_name = ISC_FALSE, free_rdataset = ISC_FALSE; + isc_boolean_t preserve_order, best_effort, seen_problem; + isc_boolean_t issigzero; + +diff --git a/lib/dns/rdataset.c b/lib/dns/rdataset.c +index 026d771..483ddfb 100644 +--- a/lib/dns/rdataset.c ++++ b/lib/dns/rdataset.c +@@ -336,6 +336,7 @@ towiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name, + */ + + REQUIRE(DNS_RDATASET_VALID(rdataset)); ++ REQUIRE(rdataset->methods != NULL); + REQUIRE(countp != NULL); + REQUIRE((order == NULL) == (order_arg == NULL)); + REQUIRE(cctx != NULL && cctx->mctx != NULL); +-- +2.9.3 + diff --git a/SOURCES/bind99-rt44318.patch b/SOURCES/bind99-rt44318.patch new file mode 100644 index 0000000..35389fc --- /dev/null +++ b/SOURCES/bind99-rt44318.patch @@ -0,0 +1,482 @@ +From e92ac3b83209ddc46ca9a3facd7edf1f14052edf Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Wed, 8 Feb 2017 13:49:47 +0100 +Subject: [PATCH] 4558. [bug] Synthesised CNAME before matching DNAME + was still being cached when it should not have been. [RT + #44318] + +Fixes and tests last case fixed by CVE-2016-9147 +--- + bin/tests/system/dname/ans3/ans.pl | 95 +++++++++++++++++++++++ + bin/tests/system/dname/ns1/root.db | 5 +- + bin/tests/system/dname/tests.sh | 25 ++++++- + lib/dns/resolver.c | 150 +++++++++++++++++++++++++------------ + 4 files changed, 225 insertions(+), 50 deletions(-) + create mode 100644 bin/tests/system/dname/ans3/ans.pl + +diff --git a/bin/tests/system/dname/ans3/ans.pl b/bin/tests/system/dname/ans3/ans.pl +new file mode 100644 +index 0000000..271fc7d +--- /dev/null ++++ b/bin/tests/system/dname/ans3/ans.pl +@@ -0,0 +1,95 @@ ++#!/usr/bin/env perl ++# ++# Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC") ++# ++# This Source Code Form is subject to the terms of the Mozilla Public ++# License, v. 2.0. If a copy of the MPL was not distributed with this ++# file, You can obtain one at http://mozilla.org/MPL/2.0/. ++ ++use strict; ++use warnings; ++ ++use IO::File; ++use Getopt::Long; ++use Net::DNS::Nameserver; ++ ++my $pidf = new IO::File "ans.pid", "w" or die "cannot open pid file: $!"; ++print $pidf "$$\n" or die "cannot write pid file: $!"; ++$pidf->close or die "cannot close pid file: $!"; ++sub rmpid { unlink "ans.pid"; exit 1; }; ++ ++$SIG{INT} = \&rmpid; ++$SIG{TERM} = \&rmpid; ++ ++my $localaddr = "10.53.0.3"; ++my $localport = 5300; ++my $verbose = 0; ++my $ttl = 60; ++my $zone = "example.broken"; ++my $nsname = "ns3.$zone"; ++my $synth = "synth-then-dname.$zone"; ++my $synth2 = "synth2-then-dname.$zone"; ++ ++sub reply_handler { ++ my ($qname, $qclass, $qtype, $peerhost, $query, $conn) = @_; ++ my ($rcode, @ans, @auth, @add); ++ ++ print ("request: $qname/$qtype\n"); ++ STDOUT->flush(); ++ ++ if ($qname eq "example.broken") { ++ if ($qtype eq "SOA") { ++ my $rr = new Net::DNS::RR("$qname $ttl $qclass SOA . . 0 0 0 0 0"); ++ push @ans, $rr; ++ } elsif ($qtype eq "NS") { ++ my $rr = new Net::DNS::RR("$qname $ttl $qclass NS $nsname"); ++ push @ans, $rr; ++ $rr = new Net::DNS::RR("$nsname $ttl $qclass A $localaddr"); ++ push @add, $rr; ++ } ++ $rcode = "NOERROR"; ++ } elsif ($qname eq "cname-to-$synth2") { ++ my $rr = new Net::DNS::RR("$qname $ttl $qclass CNAME name.$synth2"); ++ push @ans, $rr; ++ $rr = new Net::DNS::RR("name.$synth2 $ttl $qclass CNAME name"); ++ push @ans, $rr; ++ $rr = new Net::DNS::RR("$synth2 $ttl $qclass DNAME ."); ++ push @ans, $rr; ++ $rcode = "NOERROR"; ++ } elsif ($qname eq "$synth" || $qname eq "$synth2") { ++ if ($qtype eq "DNAME") { ++ my $rr = new Net::DNS::RR("$qname $ttl $qclass DNAME ."); ++ push @ans, $rr; ++ } ++ $rcode = "NOERROR"; ++ } elsif ($qname eq "name.$synth") { ++ my $rr = new Net::DNS::RR("$qname $ttl $qclass CNAME name."); ++ push @ans, $rr; ++ $rr = new Net::DNS::RR("$synth $ttl $qclass DNAME ."); ++ push @ans, $rr; ++ $rcode = "NOERROR"; ++ } elsif ($qname eq "name.$synth2") { ++ my $rr = new Net::DNS::RR("$qname $ttl $qclass CNAME name."); ++ push @ans, $rr; ++ $rr = new Net::DNS::RR("$synth2 $ttl $qclass DNAME ."); ++ push @ans, $rr; ++ $rcode = "NOERROR"; ++ } else { ++ $rcode = "REFUSED"; ++ } ++ return ($rcode, \@ans, \@auth, \@add, { aa => 1 }); ++} ++ ++GetOptions( ++ 'port=i' => \$localport, ++ 'verbose!' => \$verbose, ++); ++ ++my $ns = Net::DNS::Nameserver->new( ++ LocalAddr => $localaddr, ++ LocalPort => $localport, ++ ReplyHandler => \&reply_handler, ++ Verbose => $verbose, ++); ++ ++$ns->main_loop; +diff --git a/bin/tests/system/dname/ns1/root.db b/bin/tests/system/dname/ns1/root.db +index 7049e77..2e84ae0 100644 +--- a/bin/tests/system/dname/ns1/root.db ++++ b/bin/tests/system/dname/ns1/root.db +@@ -12,8 +12,6 @@ + ; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + ; PERFORMANCE OF THIS SOFTWARE. + +-; $Id: root.db,v 1.2 2011/03/18 21:14:19 fdupont Exp $ +- + $TTL 300 + . IN SOA gson.nominum.com. a.root.servers.nil. ( + 2000042100 ; serial +@@ -27,3 +25,6 @@ a.root-servers.nil. A 10.53.0.1 + + example. NS ns2.example. + ns2.example. A 10.53.0.2 ++ ++example.broken. NS ns3.example.broken. ++ns3.example.broken. A 10.53.0.3 +diff --git a/bin/tests/system/dname/tests.sh b/bin/tests/system/dname/tests.sh +index 04bfcb2..6dc9e88 100644 +--- a/bin/tests/system/dname/tests.sh ++++ b/bin/tests/system/dname/tests.sh +@@ -20,6 +20,7 @@ SYSTEMTESTTOP=.. + . $SYSTEMTESTTOP/conf.sh + + status=0 ++n=0 + + echo "I:checking short dname from authoritative" + ret=0 +@@ -81,6 +82,26 @@ 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" ++n=`expr $n + 1` ++echo "I:checking dname is returned with synthesized cname before dname ($n)" ++ret=0 ++$DIG @10.53.0.4 -p 5300 name.synth-then-dname.example.broken A > dig.out.test$n ++grep "status: NXDOMAIN" dig.out.test$n > /dev/null || ret=1 ++grep '^name.synth-then-dname\.example\.broken\..*CNAME.*name.$' dig.out.test$n > /dev/null || ret=1 ++grep '^synth-then-dname\.example\.broken\..*DNAME.*\.$' dig.out.test$n > /dev/null || ret=1 ++if [ $ret != 0 ]; then echo "I:failed"; fi ++status=`expr $status + $ret` + +-exit $status ++n=`expr $n + 1` ++echo "I:checking dname is returned with cname to synthesized cname before dname ($n)" ++ret=0 ++$DIG @10.53.0.4 -p 5300 cname-to-synth2-then-dname.example.broken A > dig.out.test$n ++grep "status: NXDOMAIN" dig.out.test$n > /dev/null || ret=1 ++grep '^cname-to-synth2-then-dname\.example\.broken\..*CNAME.*name\.synth2-then-dname\.example\.broken.$' dig.out.test$n > /dev/null || ret=1 ++grep '^name\.synth2-then-dname\.example\.broken\..*CNAME.*name.$' dig.out.test$n > /dev/null || ret=1 ++grep '^synth2-then-dname\.example\.broken\..*DNAME.*\.$' dig.out.test$n > /dev/null || ret=1 ++if [ $ret != 0 ]; then echo "I:failed"; fi ++status=`expr $status + $ret` ++ ++echo "I:exit status: $status" ++[ $status -eq 0 ] || exit 1 +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index bfd4dcb..c3607fa 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -5406,9 +5406,13 @@ cname_target(dns_rdataset_t *rdataset, dns_name_t *tname) { + 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_fixedname_t *fixeddname) ++ unsigned int nlabels, dns_name_t *target) + { + isc_result_t result; + dns_rdata_t rdata = DNS_RDATA_INIT; +@@ -5428,14 +5432,33 @@ dname_target(dns_rdataset_t *rdataset, dns_name_t *qname, + + dns_fixedname_init(&prefix); + dns_name_split(qname, nlabels, dns_fixedname_name(&prefix), NULL); +- dns_fixedname_init(fixeddname); + result = dns_name_concatenate(dns_fixedname_name(&prefix), +- &dname.dname, +- dns_fixedname_name(fixeddname), NULL); ++ &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) +@@ -6039,12 +6062,12 @@ 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; ++ dns_name_t *cname = NULL, *lastcname = NULL; + dns_rdataset_t *rdataset, *ns_rdataset; +- isc_boolean_t done, external, chaining, aa, found, want_chaining; ++ 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; ++ unsigned int aflag, chaining; + dns_rdatatype_t type; + dns_fixedname_t fdname, fqname; + dns_view_t *view; +@@ -6062,9 +6085,9 @@ answer_response(fetchctx_t *fctx) { + found_cname = ISC_FALSE; + found_dname = ISC_FALSE; + found_type = ISC_FALSE; +- chaining = 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; +@@ -6075,14 +6098,15 @@ answer_response(fetchctx_t *fctx) { + view = fctx->res->view; + result = dns_message_firstname(message, DNS_SECTION_ANSWER); + while (!done && result == ISC_R_SUCCESS) { +- dns_namereln_t namereln; +- int order; +- unsigned int nlabels; ++ dns_namereln_t namereln, lastreln; ++ int order, lastorder; ++ unsigned int nlabels, lastnlabels; + + 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; + for (rdataset = ISC_LIST_HEAD(name->list); +@@ -6188,6 +6212,7 @@ answer_response(fetchctx_t *fctx) { + &fctx->domain)) { + return (DNS_R_SERVFAIL); + } ++ lastcname = name; + } else if (rdataset->type == dns_rdatatype_rrsig + && rdataset->covers == + dns_rdatatype_cname +@@ -6211,7 +6236,7 @@ answer_response(fetchctx_t *fctx) { + rdataset->attributes |= + DNS_RDATASETATTR_CACHE; + rdataset->trust = dns_trust_answer; +- if (!chaining) { ++ if (chaining == 0) { + /* + * This data is "the" answer + * to our question only if +@@ -6288,10 +6313,21 @@ answer_response(fetchctx_t *fctx) { + * cause us to ignore the signatures of + * CNAMEs. + */ +- if (wanted_chaining) +- chaining = ISC_TRUE; ++ 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; ++ } + + /* + * Look for a DNAME (or its SIG). Anything else is +@@ -6320,7 +6356,7 @@ answer_response(fetchctx_t *fctx) { + * If we're not chaining, then the DNAME and + * its signature should not be external. + */ +- if (!chaining && external) { ++ if (chaining == 0 && external) { + char qbuf[DNS_NAME_FORMATSIZE]; + char obuf[DNS_NAME_FORMATSIZE]; + +@@ -6338,16 +6374,9 @@ answer_response(fetchctx_t *fctx) { + /* + * 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))) ++ !synthcname) + { + char qbuf[DNS_NAME_FORMATSIZE]; + char obuf[DNS_NAME_FORMATSIZE]; +@@ -6367,8 +6396,19 @@ answer_response(fetchctx_t *fctx) { + want_chaining = ISC_TRUE; + POST(want_chaining); + aflag = DNS_RDATASETATTR_ANSWER; +- result = dname_target(rdataset, qname, +- nlabels, &fdname); ++ 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 +@@ -6382,8 +6422,8 @@ answer_response(fetchctx_t *fctx) { + else + dnameset = rdataset; + +- dname = dns_fixedname_name(&fdname); +- if (!is_answertarget_allowed(view, ++ if (!synthcname && ++ !is_answertarget_allowed(view, + qname, rdataset->type, + dname, &fctx->domain)) + { +@@ -6404,7 +6444,13 @@ answer_response(fetchctx_t *fctx) { + name->attributes |= DNS_NAMEATTR_CACHE; + rdataset->attributes |= DNS_RDATASETATTR_CACHE; + rdataset->trust = dns_trust_answer; +- if (!chaining) { ++ /* ++ * 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 +@@ -6414,9 +6460,12 @@ answer_response(fetchctx_t *fctx) { + if (aflag == DNS_RDATASETATTR_ANSWER) { + have_answer = ISC_TRUE; + found_dname = ISC_TRUE; +- if (cname != NULL) ++ if (cname != NULL && ++ synthcname) ++ { + cname->attributes &= + ~DNS_NAMEATTR_ANSWER; ++ } + name->attributes |= + DNS_NAMEATTR_ANSWER; + } +@@ -6434,26 +6483,35 @@ answer_response(fetchctx_t *fctx) { + * DNAME chaining. + */ + if (dnameset != NULL) { +- /* +- * 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); ++ 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 (wanted_chaining) +- chaining = ISC_TRUE; ++ /* ++ * Ensure that we can't ever get chaining == 1 ++ * above if we have processed a DNAME. ++ */ ++ if (wanted_chaining && chaining < 2U) ++ chaining += 2; + } + result = dns_message_nextname(message, DNS_SECTION_ANSWER); + } +@@ -6478,7 +6536,7 @@ answer_response(fetchctx_t *fctx) { + /* + * Did chaining end before we got the final answer? + */ +- if (chaining) { ++ if (chaining != 0) { + /* + * Yes. This may be a negative reply, so hand off + * authority section processing to the noanswer code. +@@ -6527,7 +6585,7 @@ answer_response(fetchctx_t *fctx) { + DNS_NAMEATTR_CACHE; + rdataset->attributes |= + DNS_RDATASETATTR_CACHE; +- if (aa && !chaining) ++ if (aa && chaining == 0) + rdataset->trust = + dns_trust_authauthority; + else +-- +2.9.3 + diff --git a/SPECS/bind.spec b/SPECS/bind.spec index f66d909..69626bb 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}.1 +Release: 38%{?PATCHVER}%{?PREVER}%{?dist}.2 Epoch: 32 Url: http://www.isc.org/products/BIND/ Buildroot:%{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -117,6 +117,10 @@ patch170:bind99-CVE-2016-9131.patch patch171:bind99-CVE-2016-9147.patch Patch172:bind99-CVE-2016-9444.patch Patch173:bind99-rt43779.patch +# ISC 4557 +Patch174:bind99-CVE-2017-3135.patch +# ISC 4558 +Patch175:bind99-rt44318.patch # Native PKCS#11 functionality from 9.10 Patch150:bind-9.9-allow_external_dnskey.patch @@ -410,6 +414,8 @@ tar -xf %{SOURCE48} -C bin/tests/system/geoip/data %patch171 -p1 -b .CVE-2016-9147 %patch172 -p1 -b .CVE-2016-9444 %patch173 -p1 -b .rt43779 +%patch174 -p1 -b .CVE-2017-3135 +%patch175 -p1 -b .rt44318 %if %{PKCS11} cp -r bin/named{,-pkcs11} @@ -1089,6 +1095,10 @@ rm -rf ${RPM_BUILD_ROOT} %endif %changelog +* Wed Feb 08 2017 Petr Menšík - 32:9.9.4-38.2 +- Fix CVE-2017-3135 (ISC change 4557) +- Fix and test caching CNAME before DNAME (ISC change 4558) + * 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)