3124. [bug] Use an rdataset attribute flag to indicate

negative-cache records rather than using rrtype 0;
			this will prevent problems when that rrtype is
			used in actual DNS packets. [RT #24777]

3123.	[security]	Change #2912 exposed a latent flaw in
			dns_rdataset_totext() that could cause named to
			crash with an assertion failure. [RT #24777]
This commit is contained in:
Evan Hunt 2011-06-09 00:16:37 +00:00
parent 2d1f9f6af0
commit d7eaf06b5a
10 changed files with 129 additions and 50 deletions

View file

@ -1,3 +1,12 @@
3124. [bug] Use an rdataset attribute flag to indicate
negative-cache records rather than using rrtype 0;
this will prevent problems when that rrtype is
used in actual DNS packets. [RT #24777]
3123. [security] Change #2912 exposed a latent flaw in
dns_rdataset_totext() that could cause named to
crash with an assertion failure. [RT #24777]
--- 9.6-ESV-R5rc1 released ---
3121. [security] An authoritative name server sending a negative

View file

@ -15,7 +15,7 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: tests.sh,v 1.25.332.3 2011/05/23 22:24:12 each Exp $
# $Id: tests.sh,v 1.25.332.4 2011/06/09 00:16:33 each Exp $
SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
@ -68,6 +68,62 @@ if [ $ret -ne 0 ]; then
status=1
fi
n=`expr $n + 1`
ret=0
echo "I:check TYPE=0 update is rejected by nsupdate ($n)"
$NSUPDATE <<END > nsupdate.out 2>&1 && ret=1
server 10.53.0.1 5300
ttl 300
update add example.nil. in type0 ""
send
END
grep "unknown class/type" nsupdate.out > /dev/null 2>&1 ||
ret=1
if [ $ret -ne 0 ]; then
echo "I:failed"
status=1
fi
n=`expr $n + 1`
ret=0
echo "I:check TYPE=0 prerequisite is handled ($n)"
$NSUPDATE <<END > nsupdate.out 2>&1 || ret=1
server 10.53.0.1 5300
prereq nxrrset example.nil. type0
send
END
$DIG +tcp version.bind txt ch @10.53.0.1 -p 5300 > dig.out.ns1.$n
grep "status: NOERROR" dig.out.ns1.$n > /dev/null || ret=1
if [ $ret -ne 0 ]; then
echo "I:failed"
status=1
fi
n=`expr $n + 1`
ret=0
echo "I:check that TYPE=0 update is handled ($n)"
echo "a0e4280000010000000100000000060001c00c000000fe000000000000" |
$PERL ../packet.pl -a 10.53.0.1 -p 5300 -t tcp > /dev/null
$DIG +tcp version.bind txt ch @10.53.0.1 -p 5300 > dig.out.ns1.$n
grep "status: NOERROR" dig.out.ns1.$n > /dev/null || ret=1
if test $ret -ne 0
then
echo "I:failed"
status=1
fi
n=`expr $n + 1`
echo "I:check that TYPE=0 additional data is handled ($n)"
echo "a0e4280000010000000000010000060001c00c000000fe000000000000" |
$PERL ../packet.pl -a 10.53.0.1 -p 5300 -t tcp > /dev/null
$DIG +tcp version.bind txt ch @10.53.0.1 -p 5300 > dig.out.ns1.$n
grep "status: NOERROR" dig.out.ns1.$n > /dev/null || ret=1
if test $ret -ne 0
then
echo "I:failed"
status=1
fi
if $PERL -e 'use Net::DNS;' 2>/dev/null
then
echo "I:running update.pl test"
@ -185,8 +241,6 @@ if test $ret -ne 0
then
echo "I:failed"; status=1
fi
echo "I:exit status: $status"
exit $status
echo "I:exit status: $status"
exit $status

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: rdataset.h,v 1.65.50.6 2011/05/28 00:01:52 tbox Exp $ */
/* $Id: rdataset.h,v 1.65.50.7 2011/06/09 00:16:37 each Exp $ */
#ifndef DNS_RDATASET_H
#define DNS_RDATASET_H 1
@ -203,6 +203,7 @@ struct dns_rdataset {
#define DNS_RDATASETATTR_RESIGN 0x00040000
#define DNS_RDATASETATTR_CLOSEST 0x00080000
#define DNS_RDATASETATTR_OPTOUT 0x00100000 /*%< OPTOUT proof */
#define DNS_RDATASETATTR_NEGATIVE 0x00200000
/*%
* _OMITDNSSEC:

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: masterdump.c,v 1.94.50.9 2011/05/27 05:04:17 marka Exp $ */
/* $Id: masterdump.c,v 1.94.50.10 2011/06/09 00:16:34 each Exp $ */
/*! \file */
@ -356,6 +356,7 @@ rdataset_totext(dns_rdataset_t *rdataset,
isc_uint32_t current_ttl;
isc_boolean_t current_ttl_valid;
dns_rdatatype_t type;
unsigned int type_start;
REQUIRE(DNS_RDATASET_VALID(rdataset));
@ -437,29 +438,26 @@ rdataset_totext(dns_rdataset_t *rdataset,
* Type.
*/
if (rdataset->type == 0) {
if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
type = rdataset->covers;
} else {
type = rdataset->type;
}
{
unsigned int type_start;
INDENT_TO(type_column);
type_start = target->used;
if (rdataset->type == 0)
RETERR(str_totext("\\-", target));
result = dns_rdatatype_totext(type, target);
if (result != ISC_R_SUCCESS)
return (result);
column += (target->used - type_start);
}
INDENT_TO(type_column);
type_start = target->used;
if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0)
RETERR(str_totext("\\-", target));
result = dns_rdatatype_totext(type, target);
if (result != ISC_R_SUCCESS)
return (result);
column += (target->used - type_start);
/*
* Rdata.
*/
INDENT_TO(rdata_column);
if (rdataset->type == 0) {
if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
if (NXDOMAIN(rdataset))
RETERR(str_totext(";-$NXDOMAIN\n", target));
else
@ -813,7 +811,7 @@ dump_rdatasets_text(isc_mem_t *mctx, dns_name_t *name,
dns_rdataset_t *rds = sorted[i];
if (ctx->style.flags & DNS_STYLEFLAG_TRUST)
fprintf(f, "; %s\n", dns_trust_totext(rds->trust));
if (rds->type == 0 &&
if (((rds->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) &&
(ctx->style.flags & DNS_STYLEFLAG_NCACHE) == 0) {
/* Omit negative cache entries */
} else {
@ -978,7 +976,7 @@ dump_rdatasets_raw(isc_mem_t *mctx, dns_name_t *name,
dns_rdataset_init(&rdataset);
dns_rdatasetiter_current(rdsiter, &rdataset);
if (rdataset.type == 0 &&
if (((rdataset.attributes & DNS_RDATASETATTR_NEGATIVE) != 0) &&
(ctx->style.flags & DNS_STYLEFLAG_NCACHE) == 0) {
/* Omit negative cache entries */
} else {

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: message.c,v 1.245.50.9 2011/03/12 04:57:27 tbox Exp $ */
/* $Id: message.c,v 1.245.50.10 2011/06/09 00:16:34 each Exp $ */
/*! \file */
@ -2468,7 +2468,7 @@ dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp,
isc_result_t
dns_message_reply(dns_message_t *msg, isc_boolean_t want_question_section) {
unsigned int first_section;
unsigned int clear_after;
isc_result_t result;
REQUIRE(DNS_MESSAGE_VALID(msg));
@ -2480,15 +2480,15 @@ dns_message_reply(dns_message_t *msg, isc_boolean_t want_question_section) {
msg->opcode != dns_opcode_notify)
want_question_section = ISC_FALSE;
if (msg->opcode == dns_opcode_update)
first_section = DNS_SECTION_ADDITIONAL;
clear_after = DNS_SECTION_PREREQUISITE;
else if (want_question_section) {
if (!msg->question_ok)
return (DNS_R_FORMERR);
first_section = DNS_SECTION_ANSWER;
clear_after = DNS_SECTION_ANSWER;
} else
first_section = DNS_SECTION_QUESTION;
clear_after = DNS_SECTION_QUESTION;
msg->from_to_wire = DNS_MESSAGE_INTENTRENDER;
msgresetnames(msg, first_section);
msgresetnames(msg, clear_after);
msgresetopt(msg);
msgresetsigs(msg, ISC_TRUE);
msginitprivate(msg);

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: ncache.c,v 1.43.48.9 2011/05/26 23:45:46 tbox Exp $ */
/* $Id: ncache.c,v 1.43.48.10 2011/06/09 00:16:35 each Exp $ */
/*! \file */
@ -294,6 +294,7 @@ dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache,
RUNTIME_CHECK(dns_rdatalist_tordataset(&ncrdatalist, &ncrdataset)
== ISC_R_SUCCESS);
ncrdataset.trust = trust;
ncrdataset.attributes |= DNS_RDATASETATTR_NEGATIVE;
if (message->rcode == dns_rcode_nxdomain)
ncrdataset.attributes |= DNS_RDATASETATTR_NXDOMAIN;
if (optout)
@ -324,6 +325,7 @@ dns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx,
REQUIRE(rdataset != NULL);
REQUIRE(rdataset->type == 0);
REQUIRE((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0);
savedbuffer = *target;
count = 0;
@ -552,6 +554,7 @@ dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
REQUIRE(ncacherdataset != NULL);
REQUIRE(ncacherdataset->type == 0);
REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0);
REQUIRE(name != NULL);
REQUIRE(!dns_rdataset_isassociated(rdataset));
REQUIRE(type != dns_rdatatype_rrsig);
@ -628,6 +631,7 @@ dns_ncache_getsigrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
REQUIRE(ncacherdataset != NULL);
REQUIRE(ncacherdataset->type == 0);
REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0);
REQUIRE(name != NULL);
REQUIRE(!dns_rdataset_isassociated(rdataset));
@ -727,6 +731,7 @@ dns_ncache_current(dns_rdataset_t *ncacherdataset, dns_name_t *found,
REQUIRE(ncacherdataset != NULL);
REQUIRE(ncacherdataset->type == 0);
REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0);
REQUIRE(found != NULL);
REQUIRE(!dns_rdataset_isassociated(rdataset));

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: rbtdb.c,v 1.270.12.31 2011/03/11 10:49:55 marka Exp $ */
/* $Id: rbtdb.c,v 1.270.12.32 2011/06/09 00:16:35 each Exp $ */
/*! \file */
@ -278,6 +278,7 @@ typedef ISC_LIST(dns_rbtnode_t) rbtnodelist_t;
#define RDATASET_ATTR_RESIGN 0x0020
#define RDATASET_ATTR_STATCOUNT 0x0040
#define RDATASET_ATTR_OPTOUT 0x0080
#define RDATASET_ATTR_NEGATIVE 0x0100
typedef struct acache_cbarg {
dns_rdatasetadditional_t type;
@ -316,6 +317,8 @@ struct acachectl {
(((header)->attributes & RDATASET_ATTR_RESIGN) != 0)
#define OPTOUT(header) \
(((header)->attributes & RDATASET_ATTR_OPTOUT) != 0)
#define NEGATIVE(header) \
(((header)->attributes & RDATASET_ATTR_NEGATIVE) != 0)
#define DEFAULT_NODE_LOCK_COUNT 7 /*%< Should be prime. */
@ -696,11 +699,13 @@ update_rrsetstats(dns_rbtdb_t *rbtdb, rdatasetheader_t *header,
/* At the moment we count statistics only for cache DB */
INSIST(IS_CACHE(rbtdb));
if (NXDOMAIN(header))
statattributes = DNS_RDATASTATSTYPE_ATTR_NXDOMAIN;
else if (RBTDB_RDATATYPE_BASE(header->type) == 0) {
statattributes = DNS_RDATASTATSTYPE_ATTR_NXRRSET;
base = RBTDB_RDATATYPE_EXT(header->type);
if (NEGATIVE(header)) {
if (NXDOMAIN(header))
statattributes = DNS_RDATASTATSTYPE_ATTR_NXDOMAIN;
else {
statattributes = DNS_RDATASTATSTYPE_ATTR_NXRRSET;
base = RBTDB_RDATATYPE_EXT(header->type);
}
} else
base = RBTDB_RDATATYPE_BASE(header->type);
@ -2739,6 +2744,8 @@ bind_rdataset(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
rdataset->covers = RBTDB_RDATATYPE_EXT(header->type);
rdataset->ttl = header->rdh_ttl - now;
rdataset->trust = header->trust;
if (NEGATIVE(header))
rdataset->attributes |= DNS_RDATASETATTR_NEGATIVE;
if (NXDOMAIN(header))
rdataset->attributes |= DNS_RDATASETATTR_NXDOMAIN;
if (OPTOUT(header))
@ -4644,7 +4651,7 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
*nodep = node;
}
if (RBTDB_RDATATYPE_BASE(found->type) == 0) {
if (NEGATIVE(found)) {
/*
* We found a negative cache entry.
*/
@ -5316,7 +5323,7 @@ cache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
if (found == NULL)
return (ISC_R_NOTFOUND);
if (RBTDB_RDATATYPE_BASE(found->type) == 0) {
if (NEGATIVE(found)) {
/*
* We found a negative cache entry.
*/
@ -5527,7 +5534,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
negtype = 0;
if (rbtversion == NULL && !newheader_nx) {
rdtype = RBTDB_RDATATYPE_BASE(newheader->type);
if (rdtype == 0) {
if (NEGATIVE(newheader)) {
/*
* We're adding a negative cache entry.
*/
@ -6067,6 +6074,8 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
} else {
newheader->serial = 1;
newheader->resign = 0;
if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0)
newheader->attributes |= RDATASET_ATTR_NEGATIVE;
if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
newheader->attributes |= RDATASET_ATTR_NXDOMAIN;
if ((rdataset->attributes & DNS_RDATASETATTR_OPTOUT) != 0)
@ -7655,7 +7664,7 @@ rdatasetiter_next(dns_rdatasetiter_t *iterator) {
type = header->type;
rdtype = RBTDB_RDATATYPE_BASE(header->type);
if (rdtype == 0) {
if (NEGATIVE(header)) {
covers = RBTDB_RDATATYPE_EXT(header->type);
negtype = RBTDB_RDATATYPE_VALUE(covers, 0);
} else

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: rdataset.c,v 1.82.50.7 2011/05/27 05:04:17 marka Exp $ */
/* $Id: rdataset.c,v 1.82.50.8 2011/06/09 00:16:36 each Exp $ */
/*! \file */
@ -344,7 +344,7 @@ towiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name,
count = 1;
result = dns_rdataset_first(rdataset);
INSIST(result == ISC_R_NOMORE);
} else if (rdataset->type == 0) {
} else if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
/*
* This is a negative caching rdataset.
*/

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: resolver.c,v 1.384.14.31 2011/03/11 10:49:55 marka Exp $ */
/* $Id: resolver.c,v 1.384.14.32 2011/06/09 00:16:36 each Exp $ */
/*! \file */
@ -424,6 +424,7 @@ struct dns_resolver {
FCTX_ADDRINFO_TRIED) != 0)
#define NXDOMAIN(r) (((r)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
#define NEGATIVE(r) (((r)->attributes & DNS_RDATASETATTR_NEGATIVE) != 0)
static void destroy(dns_resolver_t *res);
static void empty_bucket(dns_resolver_t *res);
@ -1047,7 +1048,7 @@ fctx_sendevents(fetchctx_t *fctx, isc_result_t result, int line) {
* Negative results must be indicated in event->result.
*/
if (dns_rdataset_isassociated(event->rdataset) &&
event->rdataset->type == dns_rdatatype_none) {
NEGATIVE(event->rdataset)) {
INSIST(event->result == DNS_R_NCACHENXDOMAIN ||
event->result == DNS_R_NCACHENXRRSET);
}
@ -4176,7 +4177,7 @@ validated(isc_task_t *task, isc_event_t *event) {
if (result != ISC_R_SUCCESS &&
result != DNS_R_UNCHANGED)
goto noanswer_response;
if (ardataset != NULL && ardataset->type == 0) {
if (ardataset != NULL && NEGATIVE(ardataset)) {
if (NXDOMAIN(ardataset))
eresult = DNS_R_NCACHENXDOMAIN;
else
@ -4500,7 +4501,7 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
result = ISC_R_SUCCESS;
if (!need_validation &&
ardataset != NULL &&
ardataset->type == 0) {
NEGATIVE(ardataset)) {
/*
* The answer in the cache is
* better than the answer we
@ -4630,7 +4631,7 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
if (result == DNS_R_UNCHANGED) {
if (ANSWER(rdataset) &&
ardataset != NULL &&
ardataset->type == 0) {
NEGATIVE(ardataset)) {
/*
* The answer in the cache is better
* than the answer we found, and is
@ -4660,7 +4661,7 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
* Negative results must be indicated in event->result.
*/
if (dns_rdataset_isassociated(event->rdataset) &&
event->rdataset->type == dns_rdatatype_none) {
NEGATIVE(event->rdataset)) {
INSIST(eresult == DNS_R_NCACHENXDOMAIN ||
eresult == DNS_R_NCACHENXRRSET);
}
@ -4740,7 +4741,7 @@ ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
* care about whether it is DNS_R_NCACHENXDOMAIN or
* DNS_R_NCACHENXRRSET then extract it.
*/
if (ardataset->type == 0) {
if (NEGATIVE(ardataset)) {
/*
* The cache data is a negative cache entry.
*/

View file

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: validator.c,v 1.164.12.28 2011/05/27 00:50:10 marka Exp $ */
/* $Id: validator.c,v 1.164.12.29 2011/06/09 00:16:37 each Exp $ */
#include <config.h>
@ -129,6 +129,8 @@
#define SHUTDOWN(v) (((v)->attributes & VALATTR_SHUTDOWN) != 0)
#define CANCELED(v) (((v)->attributes & VALATTR_CANCELED) != 0)
#define NEGATIVE(r) (((r)->attributes & DNS_RDATASETATTR_NEGATIVE) != 0)
static void
destroy(dns_validator_t *val);
@ -737,7 +739,7 @@ dsvalidated(isc_task_t *task, isc_event_t *event) {
name = dns_fixedname_name(&val->fname);
if ((val->attributes & VALATTR_INSECURITY) != 0 &&
val->frdataset.covers == dns_rdatatype_ds &&
val->frdataset.type == 0 &&
NEGATIVE(&val->frdataset) &&
isdelegation(name, &val->frdataset, DNS_R_NCACHENXRRSET)) {
if (val->mustbesecure) {
validator_log(val, ISC_LOG_WARNING,
@ -3984,7 +3986,7 @@ validator_start(isc_task_t *task, isc_event_t *event) {
val->attributes |= VALATTR_NEEDNODATA;
result = nsecvalidate(val, ISC_FALSE);
} else if (val->event->rdataset != NULL &&
val->event->rdataset->type == 0)
NEGATIVE(val->event->rdataset))
{
/*
* This is a nonexistence validation.