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 c8821d124c)
This commit is contained in:
Mark Andrews 2015-11-16 13:12:20 +11:00
parent b73a3c4491
commit 9631d0769e
7 changed files with 80 additions and 8 deletions

View file

@ -1,3 +1,8 @@
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]
4258. [bug] Limit rndc query message sizes to 32 KiB. This should
not break any legitimate rndc commands, but will
prevent a rogue rndc query from allocating too

View file

@ -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)
@ -226,7 +227,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.$'";

View file

@ -40,6 +40,15 @@
<section xml:id="relnotes_security"><info><title>Security Fixes</title></info>
<itemizedlist>
<listitem>
<para>
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]
</para>
</listitem>
<listitem>
<para>
An incorrect boundary check in the OPENPGPKEY rdatatype

View file

@ -15,8 +15,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id$ */
#ifndef DNS_MESSAGE_H
#define DNS_MESSAGE_H 1
@ -216,6 +214,8 @@ struct dns_message {
unsigned int verify_attempted : 1;
unsigned int free_query : 1;
unsigned int free_saved : 1;
unsigned int tkey : 1;
unsigned int rdclass_set : 1;
unsigned int opt_reserved;
unsigned int sig_reserved;
@ -1380,6 +1380,15 @@ dns_message_buildopt(dns_message_t *msg, dns_rdataset_t **opt,
* \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 */

View file

@ -438,6 +438,8 @@ msginit(dns_message_t *m) {
m->saved.base = NULL;
m->saved.length = 0;
m->free_saved = 0;
m->tkey = 0;
m->rdclass_set = 0;
m->querytsig = NULL;
}
@ -1088,12 +1090,18 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
* 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.
*/
@ -1238,12 +1246,12 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
* 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;
}
/*
@ -1253,13 +1261,23 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
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
&& msg->rdclass != rdclass)
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.
*/
@ -1375,6 +1393,10 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
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;
@ -1619,6 +1641,7 @@ dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
msg->header_ok = 1;
msg->state = DNS_SECTION_QUESTION;
/*
* -1 means no EDNS.
@ -3608,3 +3631,15 @@ dns_message_buildopt(dns_message_t *message, dns_rdataset_t **rdatasetp,
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;
}

View file

@ -7403,8 +7403,11 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
}
}
dns_message_setclass(message, res->rdclass);
if ((options & DNS_FETCHOPT_TCP) == 0)
dns_adb_plainresponse(fctx->adb, query->addrinfo);
result = dns_message_parse(message, &devent->buffer, 0);
if (result != ISC_R_SUCCESS) {
FCTXTRACE3("message failed to parse", result);
@ -7477,6 +7480,12 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
*/
log_packet(message, ISC_LOG_DEBUG(10), res->mctx);
if (message->rdclass != res->rdclass) {
resend = ISC_TRUE;
FCTXTRACE("bad class");
goto done;
}
/*
* Process receive opt record.
*/

View file

@ -1221,6 +1221,8 @@ xfrin_recv_done(isc_task_t *task, isc_event_t *ev) {
msg->tsigctx = xfr->tsigctx;
xfr->tsigctx = NULL;
dns_message_setclass(msg, xfr->rdclass);
if (xfr->nmsg > 0)
msg->tcp_continuation = 1;