Commit 25b42801 authored by Michał Kępień's avatar Michał Kępień

Merge branch 'may-2020-cve-fixes' into 'master'

[CVE-2020-8616] [CVE-2020-8617] May 2020 CVE fixes

Closes #1703 and #1388

See merge request !3562
parents a53bc0b2 f533a73d
Pipeline #42183 passed with stages
in 32 minutes and 37 seconds
......@@ -71,7 +71,12 @@
UV_UDP_RECVMMSG flag to enable recvmmsg() support in
libuv. [GL #1797]
5395. [placeholder]
5395. [security] Further limit the number of queries that can be
triggered from a request. Root and TLD servers
are no longer exempt from max-recursion-queries.
Fetches for missing name server address records
are limited to 4 for any domain. (CVE-2020-8616)
[GL #1388]
5394. [cleanup] Named formerly attempted to change the effective UID and
GID in named_os_openfile(), which could trigger a
......@@ -91,7 +96,9 @@
from the Git repository, run "autoreconf -fi" first.
[GL #4]
5390. [placeholder]
5390. [security] Replaying a TSIG BADTIME response as a request could
trigger an assertion failure. (CVE-2020-8617)
[GL #1703]
5389. [bug] Finish PKCS#11 code cleanup, fix a couple of smaller
bugs and use PKCS#11 v3.0 EdDSA macros and constants.
......
......@@ -17,8 +17,7 @@ rm -f */named.memstats
rm -f */named.run
rm -f */ans.run
rm -f */*.jdb
rm -f dig.out dig.out.*
rm -f dig.*.out.*
rm -f dig.out dig.out.* dig.*.out.*
rm -f dig.*.foo.*
rm -f dig.*.bar.*
rm -f dig.*.prime.*
......@@ -28,6 +27,7 @@ rm -f ns6/example.net.db.signed ns6/example.net.db
rm -f ns6/ds.example.net.db.signed ns6/ds.example.net.db
rm -f ns6/dsset-ds.example.net*
rm -f ns6/dsset-example.net* ns6/example.net.db.signed.jnl
rm -f ns6/named.stats*
rm -f ns6/to-be-removed.tld.db ns6/to-be-removed.tld.db.jnl
rm -f ns7/server.db ns7/server.db.jnl
rm -f resolve.out.*.test*
......
......@@ -50,6 +50,11 @@ zone "broken" {
file "broken.db";
};
zone "sourcens" {
type master;
file "sourcens.db";
};
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
......
......@@ -26,3 +26,7 @@ no-questions. NS ns.no-questions.
ns.no-questions. A 10.53.0.8
formerr-to-all. NS ns.formerr-to-all.
ns.formerr-to-all. A 10.53.0.8
sourcens. NS ns.sourcens.
ns.sourcens. A 10.53.0.4
targetns. NS ns.targetns.
ns.targetns. A 10.53.0.6
; Copyright (C) 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/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
; This zone contains a set of delegations with varying numbers of NS
; records. This is used to check that BIND is limiting the number of
; NS records it follows when resolving a delegation. It tests all
; numbers of NS records up to twice the number followed.
$TTL 60
@ IN SOA marka.isc.org. ns.server. (
2010 ; serial
600 ; refresh
600 ; retry
1200 ; expire
600 ; minimum
)
@ NS ns
ns A 10.53.0.4
target1 NS ns.fake11.targetns.
target2 NS ns.fake21.targetns.
NS ns.fake22.targetns.
target3 NS ns.fake31.targetns.
NS ns.fake32.targetns.
NS ns.fake33.targetns.
target4 NS ns.fake41.targetns.
NS ns.fake42.targetns.
NS ns.fake43.targetns.
NS ns.fake44.targetns.
target5 NS ns.fake51.targetns.
NS ns.fake52.targetns.
NS ns.fake53.targetns.
NS ns.fake54.targetns.
NS ns.fake55.targetns.
target6 NS ns.fake61.targetns.
NS ns.fake62.targetns.
NS ns.fake63.targetns.
NS ns.fake64.targetns.
NS ns.fake65.targetns.
NS ns.fake66.targetns.
target7 NS ns.fake71.targetns.
NS ns.fake72.targetns.
NS ns.fake73.targetns.
NS ns.fake74.targetns.
NS ns.fake75.targetns.
NS ns.fake76.targetns.
NS ns.fake77.targetns.
target8 NS ns.fake81.targetns.
NS ns.fake82.targetns.
NS ns.fake83.targetns.
NS ns.fake84.targetns.
NS ns.fake85.targetns.
NS ns.fake86.targetns.
NS ns.fake87.targetns.
NS ns.fake88.targetns.
target9 NS ns.fake91.targetns.
NS ns.fake92.targetns.
NS ns.fake93.targetns.
NS ns.fake94.targetns.
NS ns.fake95.targetns.
NS ns.fake96.targetns.
NS ns.fake97.targetns.
NS ns.fake98.targetns.
NS ns.fake99.targetns.
target10 NS ns.fake101.targetns.
NS ns.fake102.targetns.
NS ns.fake103.targetns.
NS ns.fake104.targetns.
NS ns.fake105.targetns.
NS ns.fake106.targetns.
NS ns.fake107.targetns.
NS ns.fake108.targetns.
NS ns.fake109.targetns.
NS ns.fake1010.targetns.
......@@ -48,4 +48,11 @@ zone "delegation-only" {
type delegation-only;
};
include "trusted.conf";
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
};
controls {
inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
......@@ -22,6 +22,7 @@ options {
recursion no;
dnssec-validation no;
querylog yes;
statistics-file "named.stats";
/*
* test that named loads with root-delegation-only that
* has a exclude list.
......@@ -72,3 +73,17 @@ zone "fetch.tld" {
type master;
file "fetch.tld.db";
};
zone "targetns" {
type master;
file "targetns.db";
};
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
};
controls {
inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
; Copyright (C) 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/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
; In the test for checking how many NS records BIND will follow, this
; zone marks the server as the one to which the NS lookups will be
; directed.
$TTL 300
@ IN SOA marka.isc.org. ns.server. (
2010 ; serial
600 ; refresh
600 ; retry
1200 ; expire
600 ; minimum
)
NS ns
ns A 10.53.0.6
......@@ -255,6 +255,40 @@ grep "foo.glue-in-answer.example.org.*192.0.2.1" dig.ns1.out.${n} > /dev/null ||
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "check that the resolver limits the number of NS records it follows in a referral response ($n)"
# ns5 is the recusor being tested. ns4 holds the sourcens zone containing names with varying numbers of NS
# records pointing to non-existent nameservers in the targetns zone on ns6.
ret=0
$RNDCCMD 10.53.0.5 flush || ret=1 # Ensure cache is empty before doing this test
for nscount in 1 2 3 4 5 6 7 8 9 10
do
# Verify number of NS records at source server
$DIG $DIGOPTS +norecurse @10.53.0.4 target${nscount}.sourcens ns > dig.ns4.out.${nscount}.${n}
sourcerecs=`grep NS dig.ns4.out.${nscount}.${n} | grep -v ';' | wc -l`
test $sourcerecs -eq $nscount || ret=1
test $sourcerecs -eq $nscount || echo_i "NS count incorrect for target${nscount}.sourcens"
# Expected queries = 2 * number of NS records, up to a maximum of 10.
expected=`expr 2 \* $nscount`
if [ $expected -gt 10 ]; then expected=10; fi
# Work out the queries made by checking statistics on the target before and after the test
$RNDCCMD 10.53.0.6 stats || ret=1
initial_count=`awk '/responses sent/ {print $1}' ns6/named.stats`
mv ns6/named.stats ns6/named.stats.initial.${nscount}.${n}
$DIG $DIGOPTS @10.53.0.5 target${nscount}.sourcens A > dig.ns5.out.${nscount}.${n} || ret=1
$RNDCCMD 10.53.0.6 stats || ret=1
final_count=`awk '/responses sent/ {print $1}' ns6/named.stats`
mv ns6/named.stats ns6/named.stats.final.${nscount}.${n}
# Check number of queries during the test is as expected
actual=`expr $final_count - $initial_count`
if [ $actual -ne $expected ]; then
echo_i "query count error: $nscount NS records: expected queries $expected, actual $actual"
ret=1
fi
done
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "RT21594 regression test check setup ($n)"
ret=0
......
# Transaction ID
1122
# Standard query
0000
# Questions: 1, Additional: 1
0001 0000 0000 0001
# QNAME: isc.org
03 69 73 63 03 6F 72 67 00
# Type: A (Host Address)
0001
# Class: IN
0001
# Specially crafted TSIG Resource Record
# Name: "sha256"
06 73 68 61 32 35 36 00
# Type: TSIG (Transaction Signature)
00fa
# Class: ANY
00ff
# TTL: 0
00000000
# RdLen: 29
001d
# Algorithm Name: hmac-sha256
0b 68 6D 61 63 2D 73 68 61 32 35 36 00
# Time Signed: Jan 1, 1970 01:00:00.000000000 CET
00 00 00 00 00 00
# Fudge: 300
012c
# MAC Size: 0; MAC: empty
0000
# Original ID: 0
0000
# Error: BADSIG
0010
# Other Data Length: 0
0000
......@@ -212,5 +212,14 @@ ret=0
$KEYGEN -a hmac-sha256 -b 128 -n host example.net > keygen.out3 2>&1 && ret=1
grep "unknown algorithm" keygen.out3 > /dev/null || ret=1
echo_i "check that a 'BADTIME' response with 'QR=0' is handled as a request"
ret=0
$PERL ../packet.pl -a 10.53.0.1 -p ${PORT} -t tcp < badtime > /dev/null
$DIG -p ${PORT} @10.53.0.1 version.bind txt ch > dig.out.verify || ret=1
grep "status: NOERROR" dig.out.verify > /dev/null || ret=1
if [ $ret -eq 1 ] ; then
echo_i "failed"; status=1
fi
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1
......@@ -3476,9 +3476,7 @@ Tuning
``max-recursion-queries``
Sets the maximum number of iterative queries that may be sent while
servicing a recursive query. If more queries are sent, the recursive
query is terminated and returns SERVFAIL. Queries to look up top
level domains such as "com" and "net" and the DNS root zone are
exempt from this limitation. The default is 75.
query is terminated and returns SERVFAIL. The default is 75.
``notify-delay``
The delay, in seconds, between sending sets of notify messages for a
......
......@@ -14,7 +14,16 @@ Notes for BIND 9.17.2
Security Fixes
~~~~~~~~~~~~~~
- None.
- To prevent exhaustion of server resources by a maliciously configured
domain, the number of recursive queries that can be triggered by a
request before aborting recursion has been further limited. Root and
top-level domain servers are no longer exempt from the
``max-recursion-queries`` limit. Fetches for missing name server
address records are limited to 4 for any domain. This issue was
disclosed in CVE-2020-8616. [GL #1388]
- Replaying a TSIG BADTIME response as a request could trigger an
assertion failure. This was disclosed in CVE-2020-8617. [GL #1703]
Known Issues
~~~~~~~~~~~~
......
......@@ -440,6 +440,7 @@ log_quota(dns_adbentry_t *entry, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3);
#define FIND_GLUEOK(fn) (((fn)->options & DNS_ADBFIND_GLUEOK) != 0)
#define FIND_HAS_ADDRS(fn) (!ISC_LIST_EMPTY((fn)->list))
#define FIND_RETURNLAME(fn) (((fn)->options & DNS_ADBFIND_RETURNLAME) != 0)
#define FIND_NOFETCH(fn) (((fn)->options & DNS_ADBFIND_NOFETCH) != 0)
/*
* These are currently used on simple unsigned ints, so they are
......@@ -3234,7 +3235,9 @@ fetch:
} else {
have_address = false;
}
if (wanted_fetches != 0 && !(FIND_AVOIDFETCHES(find) && have_address)) {
if (wanted_fetches != 0 && !(FIND_AVOIDFETCHES(find) && have_address) &&
!FIND_NOFETCH(find))
{
/*
* We're missing at least one address family. Either the
* caller hasn't instructed us to avoid fetches, or we don't
......
......@@ -205,6 +205,10 @@ struct dns_adbfind {
* lame for this query.
*/
#define DNS_ADBFIND_OVERQUOTA 0x00000400
/*%
* Don't perform a fetch even if there are no address records available.
*/
#define DNS_ADBFIND_NOFETCH 0x00000800
/*%
* The answers to queries come back as a list of these.
......
......@@ -183,6 +183,14 @@
#define DEFAULT_MAX_QUERIES 75
#endif /* ifndef DEFAULT_MAX_QUERIES */
/*
* After NS_FAIL_LIMIT attempts to fetch a name server address,
* if the number of addresses in the NS RRset exceeds NS_RR_LIMIT,
* stop trying to fetch, in order to avoid wasting resources.
*/
#define NS_FAIL_LIMIT 4
#define NS_RR_LIMIT 5
/* Number of hash buckets for zone counters */
#ifndef RES_DOMAIN_BUCKETS
#define RES_DOMAIN_BUCKETS 523
......@@ -3465,7 +3473,7 @@ sort_finds(dns_adbfindlist_t *findlist, unsigned int bias) {
static void
findname(fetchctx_t *fctx, const dns_name_t *name, in_port_t port,
unsigned int options, unsigned int flags, isc_stdtime_t now,
bool *overquota, bool *need_alternate) {
bool *overquota, bool *need_alternate, unsigned int *no_addresses) {
dns_adbaddrinfo_t *ai;
dns_adbfind_t *find;
dns_resolver_t *res;
......@@ -3562,6 +3570,9 @@ findname(fetchctx_t *fctx, const dns_name_t *name, in_port_t port,
{
*need_alternate = true;
}
if (no_addresses != NULL) {
(*no_addresses)++;
}
} else {
if ((find->options & DNS_ADBFIND_OVERQUOTA) != 0) {
if (overquota != NULL) {
......@@ -3616,6 +3627,7 @@ fctx_getaddresses(fetchctx_t *fctx, bool badcache) {
dns_rdata_ns_t ns;
bool need_alternate = false;
bool all_spilled = true;
unsigned int no_addresses = 0;
FCTXTRACE5("getaddresses", "fctx->depth=", fctx->depth);
......@@ -3792,8 +3804,13 @@ normal_nses:
continue;
}
if (no_addresses > NS_FAIL_LIMIT &&
dns_rdataset_count(&fctx->nameservers) > NS_RR_LIMIT)
{
stdoptions |= DNS_ADBFIND_NOFETCH;
}
findname(fctx, &ns.name, 0, stdoptions, 0, now, &overquota,
&need_alternate);
&need_alternate, &no_addresses);
if (!overquota) {
all_spilled = false;
......@@ -3818,7 +3835,7 @@ normal_nses:
if (!a->isaddress) {
findname(fctx, &a->_u._n.name, a->_u._n.port,
stdoptions, FCTX_ADDRINFO_FORWARDER,
now, NULL, NULL);
now, NULL, NULL, NULL);
continue;
}
if (isc_sockaddr_pf(&a->_u.addr) != family) {
......@@ -4264,16 +4281,14 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) {
return;
}
if (dns_name_countlabels(&fctx->domain) > 2) {
result = isc_counter_increment(fctx->qc);
if (result != ISC_R_SUCCESS) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3),
"exceeded max queries resolving '%s'",
fctx->info);
fctx_done(fctx, DNS_R_SERVFAIL, __LINE__);
return;
}
result = isc_counter_increment(fctx->qc);
if (result != ISC_R_SUCCESS) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3),
"exceeded max queries resolving '%s'",
fctx->info);
fctx_done(fctx, DNS_R_SERVFAIL, __LINE__);
return;
}
fctx_increference(fctx);
......
......@@ -1360,8 +1360,8 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
goto cleanup_context;
}
msg->verified_sig = 1;
} else if (tsig.error != dns_tsigerror_badsig &&
tsig.error != dns_tsigerror_badkey)
} else if (!response || (tsig.error != dns_tsigerror_badsig &&
tsig.error != dns_tsigerror_badkey))
{
tsig_log(msg->tsigkey, 2, "signature was empty");
return (DNS_R_TSIGVERIFYFAILURE);
......@@ -1409,7 +1409,7 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
}
}
if (tsig.error != dns_rcode_noerror) {
if (response && tsig.error != dns_rcode_noerror) {
msg->tsigstatus = tsig.error;
if (tsig.error == dns_tsigerror_badtime) {
ret = DNS_R_CLOCKSKEW;
......
......@@ -863,6 +863,7 @@
./bin/tests/system/tools/clean.sh SH 2017,2018,2019,2020
./bin/tests/system/tools/setup.sh SH 2019,2020
./bin/tests/system/tools/tests.sh SH 2017,2018,2019,2020
./bin/tests/system/tsig/badtime X 2020
./bin/tests/system/tsig/clean.sh SH 2005,2006,2007,2012,2014,2016,2018,2019,2020
./bin/tests/system/tsig/setup.sh SH 2016,2017,2018,2019,2020
./bin/tests/system/tsig/tests.sh SH 2005,2006,2007,2011,2012,2016,2018,2019,2020
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment