From f9da4a8e543cf895b6171773e75d343b2914a7e7 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Wed, 24 Feb 2016 11:13:24 +1100 Subject: [PATCH] 4321. [bug] Zones using mapped files containing out-of-zone data could return SERVFAIL instead of the expected NODATA or NXDOMAIN results. [RT #41596] --- CHANGES | 4 ++ bin/tests/system/xfer/clean.sh | 3 + bin/tests/system/xfer/knowngood.mapped | 26 +++++++++ bin/tests/system/xfer/ns2/mapped.db.in | 17 ++++++ bin/tests/system/xfer/ns2/named.conf | 7 +++ bin/tests/system/xfer/ns3/named.conf | 7 ++- bin/tests/system/xfer/setup.sh | 2 + bin/tests/system/xfer/tests.sh | 29 +++++++++- lib/dns/rbtdb.c | 78 ++++++++++++++++---------- 9 files changed, 140 insertions(+), 33 deletions(-) create mode 100644 bin/tests/system/xfer/knowngood.mapped create mode 100644 bin/tests/system/xfer/ns2/mapped.db.in diff --git a/CHANGES b/CHANGES index 325b5fd45d..e26cad63c2 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +4321. [bug] Zones using mapped files containing out-of-zone data + could return SERVFAIL instead of the expected NODATA + or NXDOMAIN results. [RT #41596] + 4320. [bug] Insufficient memory allocation when handling "none" ACL could cause an assertion failure in named when parsing ACL configuration. [RT #41745] diff --git a/bin/tests/system/xfer/clean.sh b/bin/tests/system/xfer/clean.sh index 41d5284015..807b8fe405 100644 --- a/bin/tests/system/xfer/clean.sh +++ b/bin/tests/system/xfer/clean.sh @@ -40,3 +40,6 @@ rm -f */named.memstats rm -f */named.run rm -f */ans.run rm -f ns*/named.lock +rm -f ns2/mapped.db +rm -f ns3/mapped.bk +rm -f dig.out.?.* diff --git a/bin/tests/system/xfer/knowngood.mapped b/bin/tests/system/xfer/knowngood.mapped new file mode 100644 index 0000000000..5fcd00b511 --- /dev/null +++ b/bin/tests/system/xfer/knowngood.mapped @@ -0,0 +1,26 @@ + +; <<>> DiG 9.10.2-P3 <<>> -p 5300 axfr mapped @10.53.0.3 +;; global options: +cmd +mapped. 3600 IN SOA . . 0 0 0 2147483647 0 +example.aa. 3600 IN A 1.2.3.4 +example1.aa. 3600 IN A 1.2.3.4 +example.bb. 3600 IN A 1.2.3.4 +example1.bb. 3600 IN A 1.2.3.4 +example.com. 3600 IN A 1.2.3.4 +example1.com. 3600 IN A 1.2.3.4 +bar.dd. 3600 IN A 1.2.3.4 +foo.ee. 3600 IN A 1.2.3.4 +foo.ff. 3600 IN A 1.2.3.4 +foo.gg. 3600 IN A 1.2.3.4 +foo.hh. 3600 IN A 1.2.3.4 +foo.ii. 3600 IN A 1.2.3.4 +foo.jj. 3600 IN A 1.2.3.4 +foo.kk. 3600 IN A 1.2.3.4 +foo.ll. 3600 IN A 1.2.3.4 +mapped. 3600 IN NS . +mapped. 3600 IN SOA . . 0 0 0 2147483647 0 +;; Query time: 4 msec +;; SERVER: 10.53.0.3#5300(10.53.0.3) +;; WHEN: Tue Feb 16 14:38:25 EST 2016 +;; XFR size: 18 records (messages 1, bytes 468) + diff --git a/bin/tests/system/xfer/ns2/mapped.db.in b/bin/tests/system/xfer/ns2/mapped.db.in new file mode 100644 index 0000000000..66e4f1ca2f --- /dev/null +++ b/bin/tests/system/xfer/ns2/mapped.db.in @@ -0,0 +1,17 @@ +mapped. 3600 IN SOA . . 0 0 0 2147483647 0 +example.aa. 3600 IN A 1.2.3.4 +example1.aa. 3600 IN A 1.2.3.4 +example.bb. 3600 IN A 1.2.3.4 +example1.bb. 3600 IN A 1.2.3.4 +example.com. 3600 IN A 1.2.3.4 +example1.com. 3600 IN A 1.2.3.4 +bar.dd. 3600 IN A 1.2.3.4 +foo.ee. 3600 IN A 1.2.3.4 +foo.ff. 3600 IN A 1.2.3.4 +foo.gg. 3600 IN A 1.2.3.4 +foo.hh. 3600 IN A 1.2.3.4 +foo.ii. 3600 IN A 1.2.3.4 +foo.jj. 3600 IN A 1.2.3.4 +foo.kk. 3600 IN A 1.2.3.4 +foo.ll. 3600 IN A 1.2.3.4 +mapped. 3600 IN NS . diff --git a/bin/tests/system/xfer/ns2/named.conf b/bin/tests/system/xfer/ns2/named.conf index 03b06c2c6c..1ab566b30c 100644 --- a/bin/tests/system/xfer/ns2/named.conf +++ b/bin/tests/system/xfer/ns2/named.conf @@ -66,3 +66,10 @@ zone "slave" { masters { 10.53.0.1; }; masterfile-format text; }; + +zone "mapped" { + type slave; + file "mapped.db"; + masterfile-format text; + masters { 10.53.0.100; }; +}; diff --git a/bin/tests/system/xfer/ns3/named.conf b/bin/tests/system/xfer/ns3/named.conf index 2671c9b0f6..a8afbb5932 100644 --- a/bin/tests/system/xfer/ns3/named.conf +++ b/bin/tests/system/xfer/ns3/named.conf @@ -74,4 +74,9 @@ zone "tsigzone" { allow-transfer { key tsigzone.; }; }; - +zone "mapped" { + type slave; + masters { 10.53.0.2; }; + masterfile-format map; + file "mapped.bk"; +}; diff --git a/bin/tests/system/xfer/setup.sh b/bin/tests/system/xfer/setup.sh index 0745f2f24d..2e89bb4f3d 100644 --- a/bin/tests/system/xfer/setup.sh +++ b/bin/tests/system/xfer/setup.sh @@ -35,5 +35,7 @@ cp -f ns4/named.conf.base ns4/named.conf cp ns2/slave.db.in ns2/slave.db touch -t 200101010000 ns2/slave.db +cp ns2/mapped.db.in ns2/mapped.db + $PERL -e 'for ($i=0;$i<4096;$i++){ printf("name%u 259200 A 1.2.3.4\nname%u 259200 TXT \"Hello World %u\"\n", $i, $i, $i);}' > ns8/small.db $PERL -e 'printf("large IN TYPE45234 \\# 48000 "); for ($i=0;$i<16*3000;$i++) { printf("%02x", $i % 256); } printf("\n");' > ns8/large.db diff --git a/bin/tests/system/xfer/tests.sh b/bin/tests/system/xfer/tests.sh index 1c1c040f1c..7928d7d9ba 100644 --- a/bin/tests/system/xfer/tests.sh +++ b/bin/tests/system/xfer/tests.sh @@ -23,7 +23,9 @@ SYSTEMTESTTOP=.. DIGOPTS="+tcp +noadd +nosea +nostat +noquest +nocomm +nocmd" status=0 +n=0 +n=`expr $n + 1` echo "I:testing basic zone transfer functionality" $DIG $DIGOPTS example. \ @10.53.0.2 axfr -p 5300 > dig.out.ns2 || status=1 @@ -49,6 +51,7 @@ $PERL ../digcomp.pl dig1.good dig.out.ns2 || status=1 $PERL ../digcomp.pl dig1.good dig.out.ns3 || status=1 +n=`expr $n + 1` echo "I:testing TSIG signed zone transfers" $DIG $DIGOPTS tsigzone. \ @10.53.0.2 axfr -y tsigzone.:1234abcd8765 -p 5300 \ @@ -124,6 +127,7 @@ grep "1397051952 ; serial" ns2/slave.db > /dev/null 2>&1 || tmp=1 if test $tmp != 0 ; then echo "I:failed"; fi status=`expr $status + $tmp` +n=`expr $n + 1` echo "I:testing ixfr-from-differences yes;" tmp=0 for i in 0 1 2 3 4 5 6 7 8 9 @@ -146,6 +150,7 @@ test -f ns3/example.bk.jnl || tmp=1 if test $tmp != 0 ; then echo "I:failed"; fi status=`expr $status + $tmp` +n=`expr $n + 1` echo "I:testing ixfr-from-differences master; (master zone)" tmp=0 @@ -166,6 +171,7 @@ test -f ns3/master.bk.jnl || tmp=1 if test $tmp != 0 ; then echo "I:failed"; fi status=`expr $status + $tmp` +n=`expr $n + 1` echo "I:testing ixfr-from-differences master; (slave zone)" tmp=0 @@ -186,6 +192,7 @@ test -f ns6/slave.bk.jnl && tmp=1 if test $tmp != 0 ; then echo "I:failed"; fi status=`expr $status + $tmp` +n=`expr $n + 1` echo "I:testing ixfr-from-differences slave; (master zone)" tmp=0 @@ -195,6 +202,8 @@ test -f ns7/master2.db.jnl && tmp=1 if test $tmp != 0 ; then echo "I:failed"; fi status=`expr $status + $tmp` + +n=`expr $n + 1` echo "I:testing ixfr-from-differences slave; (slave zone)" tmp=0 @@ -368,7 +377,8 @@ $DIGCMD nil. TXT | grep 'incorrect key AXFR' >/dev/null && { status=1 } -echo "I:check that we ask for and get a EDNS EXPIRE response" +n=`expr $n + 1` +echo "I:check that we ask for and get a EDNS EXPIRE response ($n)" # force a refresh query $RNDC -s 10.53.0.7 -p 9953 -c ../common/rndc.conf refresh edns-expire 2>&1 | sed 's/^/I:ns7 /' sleep 10 @@ -380,7 +390,8 @@ test ${expire:-0} -gt 0 -a ${expire:-0} -lt 1814400 || { status=1 } -echo "I:test smaller transfer TCP message size" +n=`expr $n + 1` +echo "I:test smaller transfer TCP message size ($n)" $DIG $DIGOPTS example. @10.53.0.8 axfr -p 5300 \ -y key1.:1234abcd8765 > dig.out.msgsize || status=1 @@ -396,5 +407,19 @@ if [ $num_messages -le 300 ]; then status=1 fi +n=`expr $n + 1` +echo "I:test mapped zone with out of zone data ($n)" +tmp=0 +$DIG -p 5300 txt mapped @10.53.0.3 > dig.out.1.$n +grep "status: NOERROR," dig.out.1.$n > /dev/null || tmp=1 +$PERL $SYSTEMTESTTOP/stop.pl . ns3 +$PERL $SYSTEMTESTTOP/start.pl --noclean --restart . ns3 +$DIG -p 5300 txt mapped @10.53.0.3 > dig.out.2.$n +grep "status: NOERROR," dig.out.2.$n > /dev/null || tmp=1 +$DIG -p 5300 axfr mapped @10.53.0.3 > dig.out.3.$n +$PERL ../digcomp.pl knowngood.mapped dig.out.3.$n || tmp=1 +if test $tmp != 0 ; then echo "I:failed"; fi +status=`expr $status + $tmp` + echo "I:exit status: $status" exit $status diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index c7168cb9f0..7b10aa2d10 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -7282,8 +7282,9 @@ deserialize32(void *arg, FILE *f, off_t offset) { int fd; off_t filesize = 0; char *base; - dns_rbt_t *temporary_rbt = NULL; + dns_rbt_t *tree = NULL, *nsec = NULL, *nsec3 = NULL; int protect, flags; + dns_rbtnode_t *origin_node = NULL; REQUIRE(VALID_RBTDB(rbtdb)); @@ -7308,28 +7309,21 @@ deserialize32(void *arg, FILE *f, off_t offset) { header = (rbtdb_file_header_t *)(base + offset); - rbtdb->mmap_location = base; - rbtdb->mmap_size = (size_t) filesize; - rbtdb->origin_node = NULL; - if (header->tree != 0) { result = dns_rbt_deserialize_tree(base, filesize, (off_t) header->tree, rbtdb->common.mctx, delete_callback, rbtdb, rbt_datafixer, rbtdb, - &rbtdb->origin_node, - &temporary_rbt); - if (temporary_rbt != NULL) { - dns_rbt_destroy(&rbtdb->tree); - rbtdb->tree = temporary_rbt; - temporary_rbt = NULL; - - rbtdb->origin_node = - (dns_rbtnode_t *)(header->tree + base + 1024); - } + NULL, &tree); if (result != ISC_R_SUCCESS) - return (result); + goto cleanup; + + result = dns_rbt_findnode(tree, &rbtdb->common.origin, NULL, + &origin_node, NULL, + DNS_RBTFIND_EMPTYDATA, NULL, NULL); + if (result != ISC_R_SUCCESS) + goto cleanup; } if (header->nsec != 0) { @@ -7338,14 +7332,9 @@ deserialize32(void *arg, FILE *f, off_t offset) { rbtdb->common.mctx, delete_callback, rbtdb, rbt_datafixer, rbtdb, - NULL, &temporary_rbt); - if (temporary_rbt != NULL) { - dns_rbt_destroy(&rbtdb->nsec); - rbtdb->nsec = temporary_rbt; - temporary_rbt = NULL; - } + NULL, &nsec); if (result != ISC_R_SUCCESS) - return (result); + goto cleanup; } if (header->nsec3 != 0) { @@ -7354,17 +7343,46 @@ deserialize32(void *arg, FILE *f, off_t offset) { rbtdb->common.mctx, delete_callback, rbtdb, rbt_datafixer, rbtdb, - NULL, &temporary_rbt); - if (temporary_rbt != NULL) { - dns_rbt_destroy(&rbtdb->nsec3); - rbtdb->nsec3 = temporary_rbt; - temporary_rbt = NULL; - } + NULL, &nsec3); if (result != ISC_R_SUCCESS) - return (result); + goto cleanup; + } + + /* + * We have a successfully loaded all the rbt trees now update + * rbtdb to use them. + */ + + rbtdb->mmap_location = base; + rbtdb->mmap_size = (size_t) filesize; + + if (tree != NULL) { + dns_rbt_destroy(&rbtdb->tree); + rbtdb->tree = tree; + rbtdb->origin_node = origin_node; + } + + if (nsec != NULL) { + dns_rbt_destroy(&rbtdb->nsec); + rbtdb->nsec = nsec; + } + + if (nsec3 != NULL) { + dns_rbt_destroy(&rbtdb->nsec3); + rbtdb->nsec3 = nsec3; } return (ISC_R_SUCCESS); + + cleanup: + if (tree != NULL) + dns_rbt_destroy(&tree); + if (nsec != NULL) + dns_rbt_destroy(&nsec); + if (nsec3 != NULL) + dns_rbt_destroy(&nsec3); + isc_file_munmap(base, (size_t) filesize); + return (result); } static isc_result_t