From 8259daad7242ab2af8731681177ef7e948a15ece Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Mon, 16 Nov 2015 13:12:20 +1100 Subject: [PATCH] 4260. [security] Insufficient testing when parsing a message allowed records with an incorrect class to be be accepted, triggering a REQUIRE failure when those records were subsequently cached. (CVE-2015-8000) [RT #4098] (cherry picked from commit c8821d124c532e0a65752b378f924d4259499fd3) (cherry picked from commit 3a4c24c4a52d4a2d21d2decbde3d4e514e27d51c) Upstream-Status: Backport https://source.isc.org/cgi-bin/gitweb.cgi?p=bind9.git;a=commit;h=8259daad7242ab2af8731681177ef7e948a15ece CVE: CVE-2015-8000 Signed-off-by: Armin Kuster --- CHANGES | 5 +++++ bin/tests/system/start.pl | 5 ++++- doc/arm/notes.xml | 9 +++++++++ lib/dns/include/dns/message.h | 13 +++++++++++-- lib/dns/message.c | 45 ++++++++++++++++++++++++++++++++++++++----- lib/dns/resolver.c | 9 +++++++++ lib/dns/xfrin.c | 2 ++ 7 files changed, 80 insertions(+), 8 deletions(-) Index: bind-9.10.2-P4/bin/tests/system/start.pl =================================================================== --- bind-9.10.2-P4.orig/bin/tests/system/start.pl +++ bind-9.10.2-P4/bin/tests/system/start.pl @@ -68,6 +68,7 @@ my $NAMED = $ENV{'NAMED'}; my $LWRESD = $ENV{'LWRESD'}; my $DIG = $ENV{'DIG'}; my $PERL = $ENV{'PERL'}; +my $PYTHON = $ENV{'PYTHON'}; # Start the server(s) @@ -213,7 +214,9 @@ sub start_server { $pid_file = "lwresd.pid"; } elsif ($server =~ /^ans/) { $cleanup_files = "{ans.run}"; - if (-e "$testdir/$server/ans.pl") { + if (-e "$testdir/$server/ans.py") { + $command = "$PYTHON ans.py 10.53.0.$' 5300"; + } elsif (-e "$testdir/$server/ans.pl") { $command = "$PERL ans.pl"; } else { $command = "$PERL $topdir/ans.pl 10.53.0.$'"; Index: bind-9.10.2-P4/doc/arm/notes.xml =================================================================== --- bind-9.10.2-P4.orig/doc/arm/notes.xml +++ bind-9.10.2-P4/doc/arm/notes.xml @@ -62,6 +62,15 @@ + Insufficient testing when parsing a message allowed + records with an incorrect class to be be accepted, + triggering a REQUIRE failure when those records + were subsequently cached. This flaw is disclosed + in CVE-2015-8000. [RT #4098] + + + + An incorrect boundary check in the OPENPGPKEY rdatatype could trigger an assertion failure. This flaw is disclosed in CVE-2015-5986. [RT #40286] Index: bind-9.10.2-P4/lib/dns/include/dns/message.h =================================================================== --- bind-9.10.2-P4.orig/lib/dns/include/dns/message.h +++ bind-9.10.2-P4/lib/dns/include/dns/message.h @@ -15,8 +15,6 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id$ */ - #ifndef DNS_MESSAGE_H #define DNS_MESSAGE_H 1 @@ -221,6 +219,8 @@ struct dns_message { unsigned int free_saved : 1; unsigned int sitok : 1; unsigned int sitbad : 1; + unsigned int tkey : 1; + unsigned int rdclass_set : 1; unsigned int opt_reserved; unsigned int sig_reserved; @@ -1400,6 +1400,15 @@ dns_message_buildopt(dns_message_t *msg, * \li other. */ +void +dns_message_setclass(dns_message_t *msg, dns_rdataclass_t rdclass); +/*%< + * Set the expected class of records in the response. + * + * Requires: + * \li msg be a valid message with parsing intent. + */ + ISC_LANG_ENDDECLS #endif /* DNS_MESSAGE_H */ Index: bind-9.10.2-P4/lib/dns/message.c =================================================================== --- bind-9.10.2-P4.orig/lib/dns/message.c +++ bind-9.10.2-P4/lib/dns/message.c @@ -439,6 +439,8 @@ msginit(dns_message_t *m) { m->free_saved = 0; m->sitok = 0; m->sitbad = 0; + m->tkey = 0; + m->rdclass_set = 0; m->querytsig = NULL; } @@ -1091,13 +1093,19 @@ getquestions(isc_buffer_t *source, dns_m * If this class is different than the one we already read, * this is an error. */ - if (msg->state == DNS_SECTION_ANY) { - msg->state = DNS_SECTION_QUESTION; + if (msg->rdclass_set == 0) { msg->rdclass = rdclass; + msg->rdclass_set = 1; } else if (msg->rdclass != rdclass) DO_FORMERR; /* + * Is this a TKEY query? + */ + if (rdtype == dns_rdatatype_tkey) + msg->tkey = 1; + + /* * Can't ask the same question twice. */ result = dns_message_find(name, rdclass, rdtype, 0, NULL); @@ -1241,12 +1249,12 @@ getsection(isc_buffer_t *source, dns_mes * If there was no question section, we may not yet have * established a class. Do so now. */ - if (msg->state == DNS_SECTION_ANY && + if (msg->rdclass_set == 0 && rdtype != dns_rdatatype_opt && /* class is UDP SIZE */ rdtype != dns_rdatatype_tsig && /* class is ANY */ rdtype != dns_rdatatype_tkey) { /* class is undefined */ msg->rdclass = rdclass; - msg->state = DNS_SECTION_QUESTION; + msg->rdclass_set = 1; } /* @@ -1256,7 +1264,7 @@ getsection(isc_buffer_t *source, dns_mes if (msg->opcode != dns_opcode_update && rdtype != dns_rdatatype_tsig && rdtype != dns_rdatatype_opt - && rdtype != dns_rdatatype_dnskey /* in a TKEY query */ + && rdtype != dns_rdatatype_key /* in a TKEY query */ && rdtype != dns_rdatatype_sig /* SIG(0) */ && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */ && msg->rdclass != dns_rdataclass_any @@ -1264,6 +1272,16 @@ getsection(isc_buffer_t *source, dns_mes DO_FORMERR; /* + * If this is not a TKEY query/response then the KEY + * record's class needs to match. + */ + if (msg->opcode != dns_opcode_update && !msg->tkey && + rdtype == dns_rdatatype_key && + msg->rdclass != dns_rdataclass_any && + msg->rdclass != rdclass) + DO_FORMERR; + + /* * Special type handling for TSIG, OPT, and TKEY. */ if (rdtype == dns_rdatatype_tsig) { @@ -1377,6 +1395,10 @@ getsection(isc_buffer_t *source, dns_mes skip_name_search = ISC_TRUE; skip_type_search = ISC_TRUE; issigzero = ISC_TRUE; + } else { + if (msg->rdclass != dns_rdataclass_any && + msg->rdclass != rdclass) + DO_FORMERR; } } else covers = 0; @@ -1625,6 +1647,7 @@ dns_message_parse(dns_message_t *msg, is msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source); msg->header_ok = 1; + msg->state = DNS_SECTION_QUESTION; /* * -1 means no EDNS. @@ -3706,3 +3729,15 @@ dns_message_buildopt(dns_message_t *mess dns_message_puttemprdatalist(message, &rdatalist); return (result); } + +void +dns_message_setclass(dns_message_t *msg, dns_rdataclass_t rdclass) { + + REQUIRE(DNS_MESSAGE_VALID(msg)); + REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE); + REQUIRE(msg->state == DNS_SECTION_ANY); + REQUIRE(msg->rdclass_set == 0); + + msg->rdclass = rdclass; + msg->rdclass_set = 1; +} Index: bind-9.10.2-P4/lib/dns/resolver.c =================================================================== --- bind-9.10.2-P4.orig/lib/dns/resolver.c +++ bind-9.10.2-P4/lib/dns/resolver.c @@ -7309,6 +7309,8 @@ resquery_response(isc_task_t *task, isc_ goto done; } + dns_message_setclass(message, fctx->res->rdclass); + if ((options & DNS_FETCHOPT_TCP) == 0) { if ((options & DNS_FETCHOPT_NOEDNS0) == 0) dns_adb_setudpsize(fctx->adb, query->addrinfo, @@ -7391,6 +7393,13 @@ resquery_response(isc_task_t *task, isc_ &dns_master_style_comment, ISC_LOG_DEBUG(10), fctx->res->mctx); + + if (message->rdclass != fctx->res->rdclass) { + resend = ISC_TRUE; + FCTXTRACE("bad class"); + goto done; + } + /* * Process receive opt record. */ Index: bind-9.10.2-P4/lib/dns/xfrin.c =================================================================== --- bind-9.10.2-P4.orig/lib/dns/xfrin.c +++ bind-9.10.2-P4/lib/dns/xfrin.c @@ -1225,6 +1225,8 @@ xfrin_recv_done(isc_task_t *task, isc_ev msg->tsigctx = xfr->tsigctx; xfr->tsigctx = NULL; + dns_message_setclass(msg, xfr->rdclass); + if (xfr->nmsg > 0) msg->tcp_continuation = 1; Index: bind-9.10.2-P4/CHANGES =================================================================== --- bind-9.10.2-P4.orig/CHANGES +++ bind-9.10.2-P4/CHANGES @@ -1,4 +1,9 @@ - --- 9.10.2-P4 released --- +4260. [security] Insufficient testing when parsing a message allowed + records with an incorrect class to be be accepted, + triggering a REQUIRE failure when those records + were subsequently cached. (CVE-2015-8000) [RT #4098] + + --- 9.10.2-P4 released --- 4170. [security] An incorrect boundary check in the OPENPGPKEY rdatatype could trigger an assertion failure.