Compare commits

...

No commits in common. 'c9' and 'c9-beta' have entirely different histories.
c9 ... c9-beta

@ -1,4 +1,4 @@
From e9e7069ede766fa5c881517bdae74e2fc6682398 Mon Sep 17 00:00:00 2001
From e645046202006750f87531e21e3ff7c26fba3466 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
Date: Wed, 30 Jan 2019 14:37:17 +0100
Subject: [PATCH] Create feature-test in source directory
@ -6,27 +6,16 @@ Subject: [PATCH] Create feature-test in source directory
Feature-test tool is used in system tests to test compiled in changes.
Because we build more variants of named with different configuration,
compile feature-test for each of them this way.
Make gsstsig test supported
---
bin/named/Makefile.in | 14 ++++++++++++--
bin/named/Makefile.in | 12 +++++++++++-
bin/tests/system/conf.sh.in | 2 +-
2 files changed, 13 insertions(+), 3 deletions(-)
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/bin/named/Makefile.in b/bin/named/Makefile.in
index debb906adc..dd894fe934 100644
index 37053a7..ed9add2 100644
--- a/bin/named/Makefile.in
+++ b/bin/named/Makefile.in
@@ -56,7 +56,7 @@ CINCLUDES = -I${srcdir}/include -I${srcdir}/unix/include -I. \
${LIBXML2_CFLAGS} \
${MAXMINDDB_CFLAGS}
-CDEFINES = @CONTRIB_DLZ@
+CDEFINES = @USE_GSSAPI@ @CONTRIB_DLZ@
CWARNINGS =
@@ -93,7 +93,7 @@ NOSYMLIBS = ${NSLIBS} ${DNSLIBS} ${BIND9LIBS} \
@@ -91,7 +91,7 @@ NOSYMLIBS = ${NSLIBS} ${DNSLIBS} ${BIND9LIBS} \
SUBDIRS = unix
@ -35,7 +24,7 @@ index debb906adc..dd894fe934 100644
GEOIP2LINKOBJS = geoip.@O@
@@ -156,6 +156,16 @@ named@EXEEXT@: ${OBJS} ${DEPLIBS}
@@ -154,6 +154,16 @@ named@EXEEXT@: ${OBJS} ${DEPLIBS}
export BASEOBJS="${OBJS} ${UOBJS}"; \
${FINALBUILDCMD}
@ -53,10 +42,10 @@ index debb906adc..dd894fe934 100644
rm -f ${TARGETS} ${OBJS}
diff --git a/bin/tests/system/conf.sh.in b/bin/tests/system/conf.sh.in
index 9a61622143..f69c5be334 100644
index 7934930..e84fde2 100644
--- a/bin/tests/system/conf.sh.in
+++ b/bin/tests/system/conf.sh.in
@@ -38,7 +38,7 @@ DELV=$TOP/bin/delv/delv
@@ -37,7 +37,7 @@ DELV=$TOP/bin/delv/delv
DIG=$TOP/bin/dig/dig
DNSTAPREAD=$TOP/bin/tools/dnstap-read
DSFROMKEY=$TOP/bin/dnssec/dnssec-dsfromkey
@ -66,5 +55,5 @@ index 9a61622143..f69c5be334 100644
HOST=$TOP/bin/dig/host
IMPORTKEY=$TOP/bin/dnssec/dnssec-importkey
--
2.45.2
2.26.2

@ -1,88 +0,0 @@
From d258422d3e653621ce6340ba9af0153f8d4e8c07 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= <ondrej@isc.org>
Date: Sun, 11 Feb 2024 00:49:32 +0100
Subject: [PATCH] Test case insensitive matching in isc_ht hash table
implementation
The case insensitive matching in isc_ht was basically completely broken
as only the hashvalue computation was case insensitive, but the key
comparison was always case sensitive.
Import only test part from upstream.
(cherry picked from commit 175655b771fd17b06dfb8cfb29eaadf0f3b6a8b5)
(cherry picked from upstream commit f493a8394102b0aeb101d5dc2f963004c8741175)
---
lib/isc/tests/ht_test.c | 53 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)
diff --git a/lib/isc/tests/ht_test.c b/lib/isc/tests/ht_test.c
index 74d95c1..65502b5 100644
--- a/lib/isc/tests/ht_test.c
+++ b/lib/isc/tests/ht_test.c
@@ -334,9 +334,62 @@ isc_ht_iterator_test(void **state) {
test_ht_iterator();
}
+static void
+isc_ht_case(void **state) {
+ UNUSED(state);
+
+ isc_ht_t *ht = NULL;
+ void *f = NULL;
+ isc_result_t result = ISC_R_UNSET;
+
+ unsigned char lower[16] = { "test case" };
+ unsigned char same[16] = { "test case" };
+ unsigned char upper[16] = { "TEST CASE" };
+ unsigned char mixed[16] = { "tEsT CaSe" };
+
+ isc_ht_init(&ht, test_mctx, 8, ISC_HT_CASE_SENSITIVE);
+ assert_non_null(ht);
+
+ result = isc_ht_add(ht, lower, 16, (void *)lower);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_ht_add(ht, same, 16, (void *)same);
+ assert_int_equal(result, ISC_R_EXISTS);
+
+ result = isc_ht_add(ht, upper, 16, (void *)upper);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_ht_find(ht, mixed, 16, &f);
+ assert_int_equal(result, ISC_R_NOTFOUND);
+ assert_null(f);
+
+ isc_ht_destroy(&ht);
+ assert_null(ht);
+
+ isc_ht_init(&ht, test_mctx, 8, ISC_HT_CASE_INSENSITIVE);
+ assert_non_null(ht);
+
+ result = isc_ht_add(ht, lower, 16, (void *)lower);
+ assert_int_equal(result, ISC_R_SUCCESS);
+
+ result = isc_ht_add(ht, same, 16, (void *)same);
+ assert_int_equal(result, ISC_R_EXISTS);
+
+ result = isc_ht_add(ht, upper, 16, (void *)upper);
+ assert_int_equal(result, ISC_R_EXISTS);
+
+ result = isc_ht_find(ht, mixed, 16, &f);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_ptr_equal(f, &lower);
+
+ isc_ht_destroy(&ht);
+ assert_null(ht);
+}
+
int
main(void) {
const struct CMUnitTest tests[] = {
+ cmocka_unit_test(isc_ht_case),
cmocka_unit_test(isc_ht_20),
cmocka_unit_test(isc_ht_8),
cmocka_unit_test(isc_ht_1),
--
2.43.0

@ -1,75 +0,0 @@
From aa1b0fc4b24d26233db30c85ae3609e54e9fa6d2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= <ondrej@isc.org>
Date: Sun, 11 Feb 2024 09:13:43 +0100
Subject: [PATCH] Add a system test for mixed-case data for the same owner
We were missing a test where a single owner name would have multiple
types with a different case. The generated RRSIGs and NSEC records will
then have different case than the signed records and message parser have
to cope with that and treat everything as the same owner.
(cherry picked from commit a114042059ecbbc94ae0f604ca681323a75af480)
(cherry picked from upstream commit b9c10a194da3358204f5ba7d91e55332db435614)
---
bin/tests/system/dnssec/ns3/secure.example.db.in | 5 +++++
bin/tests/system/dnssec/ns3/sign.sh | 4 +++-
bin/tests/system/dnssec/tests.sh | 15 +++++++++++++++
3 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/bin/tests/system/dnssec/ns3/secure.example.db.in b/bin/tests/system/dnssec/ns3/secure.example.db.in
index 27f2b24..599566e 100644
--- a/bin/tests/system/dnssec/ns3/secure.example.db.in
+++ b/bin/tests/system/dnssec/ns3/secure.example.db.in
@@ -45,3 +45,8 @@ rrsigonly A 10.0.0.29
cnameandkey CNAME @
cnamenokey CNAME @
dnameandkey DNAME @
+
+mixedcase A 10.0.0.30
+mixedCASE TXT "mixed case"
+MIXEDcase AAAA 2002::
+mIxEdCaSe LOC 37 52 56.788 N 121 54 55.02 W 1120m 10m 100m 10m
diff --git a/bin/tests/system/dnssec/ns3/sign.sh b/bin/tests/system/dnssec/ns3/sign.sh
index 80d412e..d94f382 100644
--- a/bin/tests/system/dnssec/ns3/sign.sh
+++ b/bin/tests/system/dnssec/ns3/sign.sh
@@ -86,7 +86,9 @@ keyname=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone
cat "$infile" "$cnameandkey.key" "$dnameandkey.key" "$keyname.key" > "$zonefile"
-"$SIGNER" -P -o "$zone" "$zonefile" > /dev/null
+"$SIGNER" -P -D -o "$zone" "$zonefile" >/dev/null
+cat "$zonefile" "$zonefile".signed >"$zonefile".tmp
+mv "$zonefile".tmp "$zonefile".signed
zone=bogus.example.
infile=bogus.example.db.in
diff --git a/bin/tests/system/dnssec/tests.sh b/bin/tests/system/dnssec/tests.sh
index fe95c8d..0c03970 100644
--- a/bin/tests/system/dnssec/tests.sh
+++ b/bin/tests/system/dnssec/tests.sh
@@ -762,6 +762,21 @@ n=$((n+1))
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
+echo_i "checking mixed-case positive validation ($n)"
+ret=0
+for type in a txt aaaa loc; do
+ dig_with_opts +noauth mixedcase.secure.example. \
+ @10.53.0.3 $type >dig.out.$type.ns3.test$n || ret=1
+ dig_with_opts +noauth mixedcase.secure.example. \
+ @10.53.0.4 $type >dig.out.$type.ns4.test$n || ret=1
+ digcomp --lc dig.out.$type.ns3.test$n dig.out.$type.ns4.test$n || ret=1
+ grep "status: NOERROR" dig.out.$type.ns4.test$n >/dev/null || ret=1
+ grep "flags:.*ad.*QUERY" dig.out.$type.ns4.test$n >/dev/null || ret=1
+done
+n=$((n + 1))
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status + ret))
+
echo_i "checking multi-stage positive validation NSEC/NSEC3 ($n)"
ret=0
dig_with_opts +noauth a.nsec3.example. \
--
2.43.0

File diff suppressed because it is too large Load Diff

@ -1,478 +0,0 @@
From c6e05ffc5fb784514ab54938867abaab41126c65 Mon Sep 17 00:00:00 2001
From: Petr Mensik <pemensik@redhat.com>
Date: Mon, 12 Feb 2024 21:09:51 +0100
Subject: [PATCH] Prevent increased CPU consumption in DNSSEC validator
KeyTrap - Extreme CPU consumption in DNSSEC validator. Preparing an
NSEC3 closest encloser proof can exhaust CPU resources.
6322. [security] Specific DNS answers could cause a denial-of-service
condition due to DNS validation taking a long time.
(CVE-2023-50387) [GL #4424]
Resolves: CVE-2023-50387 CVE-2023-50868
---
lib/dns/dst_api.c | 27 +++++++++----
lib/dns/include/dns/validator.h | 1 +
lib/dns/include/dst/dst.h | 4 ++
lib/dns/resolver.c | 4 +-
lib/dns/validator.c | 67 +++++++++++++++------------------
lib/isc/include/isc/netmgr.h | 3 ++
lib/isc/netmgr/netmgr-int.h | 1 +
lib/isc/netmgr/netmgr.c | 36 +++++++++++-------
lib/isc/netmgr/tcp.c | 6 +--
lib/isc/netmgr/tcpdns.c | 4 +-
lib/isc/netmgr/udp.c | 6 +--
11 files changed, 91 insertions(+), 68 deletions(-)
diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c
index 62600dd..3aafd7c 100644
--- a/lib/dns/dst_api.c
+++ b/lib/dns/dst_api.c
@@ -160,7 +160,8 @@ computeid(dst_key_t *key);
static isc_result_t
frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags,
unsigned int protocol, dns_rdataclass_t rdclass,
- isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp);
+ isc_buffer_t *source, isc_mem_t *mctx, bool no_rdata,
+ dst_key_t **keyp);
static isc_result_t
algorithm_status(unsigned int alg);
@@ -745,6 +746,13 @@ dst_key_todns(const dst_key_t *key, isc_buffer_t *target) {
isc_result_t
dst_key_fromdns(const dns_name_t *name, dns_rdataclass_t rdclass,
isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) {
+ return (dst_key_fromdns_ex(name, rdclass, source, mctx, false, keyp));
+}
+
+isc_result_t
+dst_key_fromdns_ex(const dns_name_t *name, dns_rdataclass_t rdclass,
+ isc_buffer_t *source, isc_mem_t *mctx, bool no_rdata,
+ dst_key_t **keyp) {
uint8_t alg, proto;
uint32_t flags, extflags;
dst_key_t *key = NULL;
@@ -775,7 +783,7 @@ dst_key_fromdns(const dns_name_t *name, dns_rdataclass_t rdclass,
}
result = frombuffer(name, alg, flags, proto, rdclass, source, mctx,
- &key);
+ no_rdata, &key);
if (result != ISC_R_SUCCESS) {
return (result);
}
@@ -796,7 +804,7 @@ dst_key_frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags,
REQUIRE(dst_initialized);
result = frombuffer(name, alg, flags, protocol, rdclass, source, mctx,
- &key);
+ false, &key);
if (result != ISC_R_SUCCESS) {
return (result);
}
@@ -2288,7 +2296,8 @@ computeid(dst_key_t *key) {
static isc_result_t
frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags,
unsigned int protocol, dns_rdataclass_t rdclass,
- isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) {
+ isc_buffer_t *source, isc_mem_t *mctx, bool no_rdata,
+ dst_key_t **keyp) {
dst_key_t *key;
isc_result_t ret;
@@ -2313,10 +2322,12 @@ frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags,
return (DST_R_UNSUPPORTEDALG);
}
- ret = key->func->fromdns(key, source);
- if (ret != ISC_R_SUCCESS) {
- dst_key_free(&key);
- return (ret);
+ if (!no_rdata) {
+ ret = key->func->fromdns(key, source);
+ if (ret != ISC_R_SUCCESS) {
+ dst_key_free(&key);
+ return (ret);
+ }
}
}
diff --git a/lib/dns/include/dns/validator.h b/lib/dns/include/dns/validator.h
index 4744014..fe97e41 100644
--- a/lib/dns/include/dns/validator.h
+++ b/lib/dns/include/dns/validator.h
@@ -148,6 +148,7 @@ struct dns_validator {
unsigned int authcount;
unsigned int authfail;
isc_stdtime_t start;
+ bool failed;
};
/*%
diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h
index f454ebb..36770b5 100644
--- a/lib/dns/include/dst/dst.h
+++ b/lib/dns/include/dst/dst.h
@@ -469,6 +469,10 @@ dst_key_tofile(const dst_key_t *key, int type, const char *directory);
*/
isc_result_t
+dst_key_fromdns_ex(const dns_name_t *name, dns_rdataclass_t rdclass,
+ isc_buffer_t *source, isc_mem_t *mctx, bool no_rdata,
+ dst_key_t **keyp);
+isc_result_t
dst_key_fromdns(const dns_name_t *name, dns_rdataclass_t rdclass,
isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp);
/*%<
diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c
index 7cbfbb2..be1d735 100644
--- a/lib/dns/resolver.c
+++ b/lib/dns/resolver.c
@@ -10613,8 +10613,8 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr,
* Since we have a pool of tasks we bind them to task queues
* to spread the load evenly
*/
- result = isc_task_create_bound(taskmgr, 0,
- &res->buckets[i].task, i);
+ result = isc_task_create_bound(
+ taskmgr, 0, &res->buckets[i].task, ISC_NM_TASK_SLOW(i));
if (result != ISC_R_SUCCESS) {
isc_mutex_destroy(&res->buckets[i].lock);
goto cleanup_buckets;
diff --git a/lib/dns/validator.c b/lib/dns/validator.c
index e54fc70..e416cc9 100644
--- a/lib/dns/validator.c
+++ b/lib/dns/validator.c
@@ -1098,8 +1098,8 @@ create_validator(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type,
* 'rdataset'. If found, build a dst_key_t for it and point val->key at
* it.
*
- * If val->key is already non-NULL, locate it in the rdataset and then
- * search past it for the *next* key that could have signed 'siginfo', then
+ * If val->key is already non-NULL, start searching from the next position in
+ * 'rdataset' to find the *next* key that could have signed 'siginfo', then
* set val->key to that.
*
* Returns ISC_R_SUCCESS if a possible matching key has been found,
@@ -1112,59 +1112,59 @@ select_signing_key(dns_validator_t *val, dns_rdataset_t *rdataset) {
isc_buffer_t b;
dns_rdata_t rdata = DNS_RDATA_INIT;
dst_key_t *oldkey = val->key;
- bool foundold;
+ bool no_rdata = false;
if (oldkey == NULL) {
- foundold = true;
+ result = dns_rdataset_first(rdataset);
} else {
- foundold = false;
+ dst_key_free(&oldkey);
val->key = NULL;
+ result = dns_rdataset_next(rdataset);
}
-
- result = dns_rdataset_first(rdataset);
if (result != ISC_R_SUCCESS) {
- goto failure;
+ goto done;
}
+
do {
dns_rdataset_current(rdataset, &rdata);
isc_buffer_init(&b, rdata.data, rdata.length);
isc_buffer_add(&b, rdata.length);
INSIST(val->key == NULL);
- result = dst_key_fromdns(&siginfo->signer, rdata.rdclass, &b,
- val->view->mctx, &val->key);
+ result = dst_key_fromdns_ex(&siginfo->signer, rdata.rdclass, &b,
+ val->view->mctx, no_rdata,
+ &val->key);
if (result == ISC_R_SUCCESS) {
if (siginfo->algorithm ==
(dns_secalg_t)dst_key_alg(val->key) &&
siginfo->keyid ==
(dns_keytag_t)dst_key_id(val->key) &&
+ (dst_key_flags(val->key) & DNS_KEYFLAG_REVOKE) ==
+ 0 &&
dst_key_iszonekey(val->key))
{
- if (foundold) {
- /*
- * This is the key we're looking for.
- */
- return (ISC_R_SUCCESS);
- } else if (dst_key_compare(oldkey, val->key)) {
- foundold = true;
- dst_key_free(&oldkey);
+ if (no_rdata) {
+ /* Retry with full key */
+ dns_rdata_reset(&rdata);
+ dst_key_free(&val->key);
+ no_rdata = false;
+ continue;
}
+ /* This is the key we're looking for. */
+ goto done;
}
dst_key_free(&val->key);
}
dns_rdata_reset(&rdata);
result = dns_rdataset_next(rdataset);
+ no_rdata = true;
} while (result == ISC_R_SUCCESS);
+done:
if (result == ISC_R_NOMORE) {
result = ISC_R_NOTFOUND;
}
-failure:
- if (oldkey != NULL) {
- dst_key_free(&oldkey);
- }
-
return (result);
}
@@ -1557,20 +1557,9 @@ validate_answer(dns_validator_t *val, bool resume) {
continue;
}
- do {
- isc_result_t tresult;
- vresult = verify(val, val->key, &rdata,
- val->siginfo->keyid);
- if (vresult == ISC_R_SUCCESS) {
- break;
- }
-
- tresult = select_signing_key(val, val->keyset);
- if (tresult != ISC_R_SUCCESS) {
- break;
- }
- } while (1);
+ vresult = verify(val, val->key, &rdata, val->siginfo->keyid);
if (vresult != ISC_R_SUCCESS) {
+ val->failed = true;
validator_log(val, ISC_LOG_DEBUG(3),
"failed to verify rdataset");
} else {
@@ -1607,9 +1596,13 @@ validate_answer(dns_validator_t *val, bool resume) {
} else {
validator_log(val, ISC_LOG_DEBUG(3),
"verify failure: %s",
- isc_result_totext(result));
+ isc_result_totext(vresult));
resume = false;
}
+ if (val->failed) {
+ result = ISC_R_NOMORE;
+ break;
+ }
}
if (result != ISC_R_NOMORE) {
validator_log(val, ISC_LOG_DEBUG(3),
diff --git a/lib/isc/include/isc/netmgr.h b/lib/isc/include/isc/netmgr.h
index be9fd56..dfabdc8 100644
--- a/lib/isc/include/isc/netmgr.h
+++ b/lib/isc/include/isc/netmgr.h
@@ -455,6 +455,9 @@ isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
* 'cb'.
*/
+#define ISC_NM_TASK_SLOW_OFFSET -2
+#define ISC_NM_TASK_SLOW(i) (ISC_NM_TASK_SLOW_OFFSET - 1 - i)
+
void
isc_nm_task_enqueue(isc_nm_t *mgr, isc_task_t *task, int threadid);
/*%<
diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h
index f7b54f9..70bb32d 100644
--- a/lib/isc/netmgr/netmgr-int.h
+++ b/lib/isc/netmgr/netmgr-int.h
@@ -673,6 +673,7 @@ struct isc_nm {
#ifdef NETMGR_TRACE
ISC_LIST(isc_nmsocket_t) active_sockets;
#endif
+ int nlisteners;
};
typedef enum isc_nmsocket_type {
diff --git a/lib/isc/netmgr/netmgr.c b/lib/isc/netmgr/netmgr.c
index 0ed3182..898de41 100644
--- a/lib/isc/netmgr/netmgr.c
+++ b/lib/isc/netmgr/netmgr.c
@@ -269,31 +269,34 @@ isc__nm_winsock_destroy(void) {
#endif /* WIN32 */
static void
-isc__nm_threadpool_initialize(uint32_t workers) {
+isc__nm_threadpool_initialize(uint32_t nworkers) {
char buf[11];
int r = uv_os_getenv("UV_THREADPOOL_SIZE", buf,
&(size_t){ sizeof(buf) });
if (r == UV_ENOENT) {
- snprintf(buf, sizeof(buf), "%" PRIu32, workers);
+ snprintf(buf, sizeof(buf), "%" PRIu32, nworkers);
uv_os_setenv("UV_THREADPOOL_SIZE", buf);
}
}
void
-isc__netmgr_create(isc_mem_t *mctx, uint32_t workers, isc_nm_t **netmgrp) {
+isc__netmgr_create(isc_mem_t *mctx, uint32_t nworkers, isc_nm_t **netmgrp) {
isc_nm_t *mgr = NULL;
char name[32];
- REQUIRE(workers > 0);
+ REQUIRE(nworkers > 0);
#ifdef WIN32
isc__nm_winsock_initialize();
#endif /* WIN32 */
- isc__nm_threadpool_initialize(workers);
+ isc__nm_threadpool_initialize(nworkers);
mgr = isc_mem_get(mctx, sizeof(*mgr));
- *mgr = (isc_nm_t){ .nworkers = workers };
+ *mgr = (isc_nm_t){
+ .nworkers = nworkers * 2,
+ .nlisteners = nworkers,
+ };
isc_mem_attach(mctx, &mgr->mctx);
isc_mutex_init(&mgr->lock);
@@ -334,11 +337,12 @@ isc__netmgr_create(isc_mem_t *mctx, uint32_t workers, isc_nm_t **netmgrp) {
isc_mempool_associatelock(mgr->evpool, &mgr->evlock);
isc_mempool_setfillcount(mgr->evpool, 32);
- isc_barrier_init(&mgr->pausing, workers);
- isc_barrier_init(&mgr->resuming, workers);
+ isc_barrier_init(&mgr->pausing, mgr->nworkers);
+ isc_barrier_init(&mgr->resuming, mgr->nworkers);
- mgr->workers = isc_mem_get(mctx, workers * sizeof(isc__networker_t));
- for (size_t i = 0; i < workers; i++) {
+ mgr->workers = isc_mem_get(mctx,
+ mgr->nworkers * sizeof(isc__networker_t));
+ for (int i = 0; i < mgr->nworkers; i++) {
int r;
isc__networker_t *worker = &mgr->workers[i];
*worker = (isc__networker_t){
@@ -373,7 +377,7 @@ isc__netmgr_create(isc_mem_t *mctx, uint32_t workers, isc_nm_t **netmgrp) {
mgr->workers_running++;
isc_thread_create(nm_thread, &mgr->workers[i], &worker->thread);
- snprintf(name, sizeof(name), "isc-net-%04zu", i);
+ snprintf(name, sizeof(name), "isc-net-%04d", i);
isc_thread_setname(worker->thread, name);
}
@@ -848,9 +852,15 @@ isc_nm_task_enqueue(isc_nm_t *nm, isc_task_t *task, int threadid) {
isc__networker_t *worker = NULL;
if (threadid == -1) {
- tid = (int)isc_random_uniform(nm->nworkers);
+ tid = (int)isc_random_uniform(nm->nlisteners);
+ } else if (threadid == ISC_NM_TASK_SLOW_OFFSET) {
+ tid = nm->nlisteners +
+ (int)isc_random_uniform(nm->nworkers - nm->nlisteners);
+ } else if (threadid < ISC_NM_TASK_SLOW_OFFSET) {
+ tid = nm->nlisteners + (ISC_NM_TASK_SLOW(threadid) %
+ (nm->nworkers - nm->nlisteners));
} else {
- tid = threadid % nm->nworkers;
+ tid = threadid % nm->nlisteners;
}
worker = &nm->workers[tid];
diff --git a/lib/isc/netmgr/tcp.c b/lib/isc/netmgr/tcp.c
index 5cca9f5..83bd2e2 100644
--- a/lib/isc/netmgr/tcp.c
+++ b/lib/isc/netmgr/tcp.c
@@ -321,7 +321,7 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
isc__nm_connectcb(sock, req, result, false);
} else {
isc__nmsocket_clearcb(sock);
- sock->tid = isc_random_uniform(mgr->nworkers);
+ sock->tid = isc_random_uniform(mgr->nlisteners);
isc__nm_connectcb(sock, req, result, true);
}
atomic_store(&sock->closed, true);
@@ -339,7 +339,7 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
isc__nm_put_netievent_tcpconnect(mgr, ievent);
} else {
atomic_init(&sock->active, false);
- sock->tid = isc_random_uniform(mgr->nworkers);
+ sock->tid = isc_random_uniform(mgr->nlisteners);
isc__nm_enqueue_ievent(&mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
}
@@ -435,7 +435,7 @@ isc_nm_listentcp(isc_nm_t *mgr, isc_sockaddr_t *iface,
#if defined(WIN32)
sock->nchildren = 1;
#else
- sock->nchildren = mgr->nworkers;
+ sock->nchildren = mgr->nlisteners;
#endif
children_size = sock->nchildren * sizeof(sock->children[0]);
sock->children = isc_mem_get(mgr->mctx, children_size);
diff --git a/lib/isc/netmgr/tcpdns.c b/lib/isc/netmgr/tcpdns.c
index 188790c..7f13ab2 100644
--- a/lib/isc/netmgr/tcpdns.c
+++ b/lib/isc/netmgr/tcpdns.c
@@ -305,7 +305,7 @@ isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
isc__nm_put_netievent_tcpdnsconnect(mgr, ievent);
} else {
atomic_init(&sock->active, false);
- sock->tid = isc_random_uniform(mgr->nworkers);
+ sock->tid = isc_random_uniform(mgr->nlisteners);
isc__nm_enqueue_ievent(&mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
}
@@ -404,7 +404,7 @@ isc_nm_listentcpdns(isc_nm_t *mgr, isc_sockaddr_t *iface,
#if defined(WIN32)
sock->nchildren = 1;
#else
- sock->nchildren = mgr->nworkers;
+ sock->nchildren = mgr->nlisteners;
#endif
children_size = sock->nchildren * sizeof(sock->children[0]);
sock->children = isc_mem_get(mgr->mctx, children_size);
diff --git a/lib/isc/netmgr/udp.c b/lib/isc/netmgr/udp.c
index a91c425..f2e161c 100644
--- a/lib/isc/netmgr/udp.c
+++ b/lib/isc/netmgr/udp.c
@@ -126,7 +126,7 @@ isc_nm_listenudp(isc_nm_t *mgr, isc_sockaddr_t *iface, isc_nm_recv_cb_t cb,
uv_os_sock_t fd = -1;
/*
- * We are creating mgr->nworkers duplicated sockets, one
+ * We are creating mgr->nlisteners duplicated sockets, one
* socket for each worker thread.
*/
sock = isc_mem_get(mgr->mctx, sizeof(isc_nmsocket_t));
@@ -136,7 +136,7 @@ isc_nm_listenudp(isc_nm_t *mgr, isc_sockaddr_t *iface, isc_nm_recv_cb_t cb,
#if defined(WIN32)
sock->nchildren = 1;
#else
- sock->nchildren = mgr->nworkers;
+ sock->nchildren = mgr->nlisteners;
#endif
children_size = sock->nchildren * sizeof(sock->children[0]);
@@ -795,7 +795,7 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
isc__nm_put_netievent_udpconnect(mgr, event);
} else {
atomic_init(&sock->active, false);
- sock->tid = isc_random_uniform(mgr->nworkers);
+ sock->tid = isc_random_uniform(mgr->nlisteners);
isc__nm_enqueue_ievent(&mgr->workers[sock->tid],
(isc__netievent_t *)event);
}
--
2.43.0

@ -1,111 +0,0 @@
From bef141d5795429cab745f29f7d080d1e2ea8f164 Mon Sep 17 00:00:00 2001
From: Petr Mensik <pemensik@redhat.com>
Date: Mon, 12 Feb 2024 20:33:41 +0100
Subject: [PATCH] Prevent assertion failure when nxdomain-redirect is used with
RFC 1918 reverse zones
6316. [security] Specific queries could trigger an assertion check with
nxdomain-redirect enabled. (CVE-2023-5517) [GL #4281]
---
lib/ns/query.c | 25 ++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/lib/ns/query.c b/lib/ns/query.c
index 4fe3e30..cc1d179 100644
--- a/lib/ns/query.c
+++ b/lib/ns/query.c
@@ -453,10 +453,10 @@ static void
query_addnxrrsetnsec(query_ctx_t *qctx);
static isc_result_t
-query_nxdomain(query_ctx_t *qctx, bool empty_wild);
+query_nxdomain(query_ctx_t *qctx, isc_result_t result);
static isc_result_t
-query_redirect(query_ctx_t *qctx);
+query_redirect(query_ctx_t *qctx, isc_result_t result);
static isc_result_t
query_ncache(query_ctx_t *qctx, isc_result_t result);
@@ -7262,8 +7262,7 @@ query_usestale(query_ctx_t *qctx, isc_result_t result) {
* result from the search.
*/
static isc_result_t
-query_gotanswer(query_ctx_t *qctx, isc_result_t res) {
- isc_result_t result = res;
+query_gotanswer(query_ctx_t *qctx, isc_result_t result) {
char errmsg[256];
CCTRACE(ISC_LOG_DEBUG(3), "query_gotanswer");
@@ -7333,16 +7332,16 @@ root_key_sentinel:
return (query_nodata(qctx, DNS_R_NXRRSET));
case DNS_R_EMPTYWILD:
- return (query_nxdomain(qctx, true));
+ return (query_nxdomain(qctx, DNS_R_EMPTYWILD));
case DNS_R_NXDOMAIN:
- return (query_nxdomain(qctx, false));
+ return (query_nxdomain(qctx, DNS_R_NXDOMAIN));
case DNS_R_COVERINGNSEC:
return (query_coveringnsec(qctx));
case DNS_R_NCACHENXDOMAIN:
- result = query_redirect(qctx);
+ result = query_redirect(qctx, result);
if (result != ISC_R_COMPLETE) {
return (result);
}
@@ -9155,10 +9154,10 @@ query_addnxrrsetnsec(query_ctx_t *qctx) {
* Handle NXDOMAIN and empty wildcard responses.
*/
static isc_result_t
-query_nxdomain(query_ctx_t *qctx, bool empty_wild) {
+query_nxdomain(query_ctx_t *qctx, isc_result_t result) {
dns_section_t section;
uint32_t ttl;
- isc_result_t result;
+ bool empty_wild = (result == DNS_R_EMPTYWILD);
CCTRACE(ISC_LOG_DEBUG(3), "query_nxdomain");
@@ -9167,7 +9166,7 @@ query_nxdomain(query_ctx_t *qctx, bool empty_wild) {
INSIST(qctx->is_zone || REDIRECT(qctx->client));
if (!empty_wild) {
- result = query_redirect(qctx);
+ result = query_redirect(qctx, result);
if (result != ISC_R_COMPLETE) {
return (result);
}
@@ -9253,7 +9252,7 @@ cleanup:
* redirecting, so query processing should continue past it.
*/
static isc_result_t
-query_redirect(query_ctx_t *qctx) {
+query_redirect(query_ctx_t *qctx, isc_result_t saved_result) {
isc_result_t result;
CCTRACE(ISC_LOG_DEBUG(3), "query_redirect");
@@ -9294,7 +9293,7 @@ query_redirect(query_ctx_t *qctx) {
SAVE(qctx->client->query.redirect.rdataset, qctx->rdataset);
SAVE(qctx->client->query.redirect.sigrdataset,
qctx->sigrdataset);
- qctx->client->query.redirect.result = DNS_R_NCACHENXDOMAIN;
+ qctx->client->query.redirect.result = saved_result;
dns_name_copynf(qctx->fname,
qctx->client->query.redirect.fname);
qctx->client->query.redirect.authoritative =
@@ -9908,7 +9907,7 @@ query_coveringnsec(query_ctx_t *qctx) {
* We now have the proof that we have an NXDOMAIN. Apply
* NXDOMAIN redirection if configured.
*/
- result = query_redirect(qctx);
+ result = query_redirect(qctx, DNS_R_COVERINGNSEC);
if (result != ISC_R_COMPLETE) {
redirected = true;
goto cleanup;
--
2.43.0

@ -1,37 +0,0 @@
From 61112d1ce39848e08ec133f280cf8f729cb70d16 Mon Sep 17 00:00:00 2001
From: Petr Mensik <pemensik@redhat.com>
Date: Mon, 12 Feb 2024 20:41:43 +0100
Subject: [PATCH] Prevent assertion failure if DNS64 and serve-stale is used
Enabling both DNS64 and serve-stale may cause an assertion failure
during recursive resolution.
6317. [security] Restore DNS64 state when handling a serve-stale timeout.
(CVE-2023-5679) [GL #4334]
Resolves: CVE-2023-5679
---
lib/ns/query.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/lib/ns/query.c b/lib/ns/query.c
index cc1d179..1993800 100644
--- a/lib/ns/query.c
+++ b/lib/ns/query.c
@@ -5983,6 +5983,13 @@ query_lookup_stale(ns_client_t *client) {
query_ctx_t qctx;
qctx_init(client, NULL, client->query.qtype, &qctx);
+ if (DNS64(client)) {
+ qctx.qtype = qctx.type = dns_rdatatype_a;
+ qctx.dns64 = true;
+ }
+ if (DNS64EXCLUDE(client)) {
+ qctx.dns64_exclude = true;
+ }
dns_db_attach(client->view->cachedb, &qctx.db);
client->query.attributes &= ~NS_QUERYATTR_RECURSIONOK;
client->query.dboptions |= DNS_DBFIND_STALETIMEOUT;
--
2.43.0

@ -1,52 +0,0 @@
From e91ab7758bed0cf3dcf8ed745f91063d7ec4011c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= <michal@isc.org>
Date: Thu, 4 Jan 2024 13:39:27 +0100
Subject: [PATCH] Fix map offsets in the "masterformat" system test
The "masterformat" system test attempts to check named-checkzone
behavior when it is fed corrupt map-format zone files. However, despite
the RBTDB and RBT structures having evolved over the years, the offsets
at which a valid map-format zone file is malformed by the "masterformat"
test have not been updated accordingly, causing the relevant checks to
introduce a different type of corruption than they were originally meant
to cause:
- the "bad node header" check originally mangled the 'type' member of
the rdatasetheader_t structure for cname.example.nil,
- the "bad node data" check originally mangled the 'serial' and
'rdh_ttl' members of the rdatasetheader_t structure for
aaaa.example.nil.
Update the offsets at which the map-format zone file is malformed at by
the "masterformat" system test so that the relevant checks fulfill their
original purpose again.
---
bin/tests/system/masterformat/tests.sh | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/bin/tests/system/masterformat/tests.sh b/bin/tests/system/masterformat/tests.sh
index 364a0d2..bb4e6ec 100755
--- a/bin/tests/system/masterformat/tests.sh
+++ b/bin/tests/system/masterformat/tests.sh
@@ -295,7 +295,7 @@ status=$((status+ret))
echo_i "checking corrupt map files fail to load (bad node header) ($n)"
ret=0
cp map.5 badmap
-stomp badmap 2754 2 99
+stomp badmap 3706 2 99
$CHECKZONE -D -f map -F text -o text.5 example.nil badmap > /dev/null
[ $? = 1 ] || ret=1
n=$((n+1))
@@ -305,7 +305,7 @@ status=$((status+ret))
echo_i "checking corrupt map files fail to load (bad node data) ($n)"
ret=0
cp map.5 badmap
-stomp badmap 2897 5 127
+stomp badmap 3137 5 127
$CHECKZONE -D -f map -F text -o text.5 example.nil badmap > /dev/null
[ $? = 1 ] || ret=1
n=$((n+1))
--
2.44.0

@ -1,283 +0,0 @@
From 6e08fef24d7ba491228a4083ea0f0e33253a1043 Mon Sep 17 00:00:00 2001
From: Petr Mensik <pemensik@redhat.com>
Date: Mon, 12 Feb 2024 20:48:57 +0100
Subject: [PATCH] Specific recursive query patterns may lead to an
out-of-memory condition
6319. [security] Query patterns that continuously triggered cache
database maintenance could exhaust all available memory
on the host running named. (CVE-2023-6516) [GL #4383]
Resolves: CVE-2023-6516
---
lib/dns/include/dns/rbt.h | 6 ++
lib/dns/mapapi | 2 +-
lib/dns/rbt.c | 1 +
lib/dns/rbtdb.c | 149 +++++++++++++++++++++++++-------------
4 files changed, 107 insertions(+), 51 deletions(-)
diff --git a/lib/dns/include/dns/rbt.h b/lib/dns/include/dns/rbt.h
index b67e602..69655b0 100644
--- a/lib/dns/include/dns/rbt.h
+++ b/lib/dns/include/dns/rbt.h
@@ -164,6 +164,12 @@ struct dns_rbtnode {
uint16_t locknum; /* note that this is not in the bitfield */
isc_refcount_t references;
/*@}*/
+
+ /*%
+ * This linked list is used to store nodes from which tree pruning can
+ * be started.
+ */
+ ISC_LINK(dns_rbtnode_t) prunelink;
};
typedef isc_result_t (*dns_rbtfindcallback_t)(dns_rbtnode_t *node,
diff --git a/lib/dns/mapapi b/lib/dns/mapapi
index 1b502d3..a46e190 100644
--- a/lib/dns/mapapi
+++ b/lib/dns/mapapi
@@ -13,4 +13,4 @@
# Whenever releasing a new major release of BIND9, set this value
# back to 1.0 when releasing the first alpha. Map files are *never*
# compatible across major releases.
-MAPAPI=3.0
+MAPAPI=4.0
diff --git a/lib/dns/rbt.c b/lib/dns/rbt.c
index 7f2c2d2..a220368 100644
--- a/lib/dns/rbt.c
+++ b/lib/dns/rbt.c
@@ -2283,6 +2283,7 @@ create_node(isc_mem_t *mctx, const dns_name_t *name, dns_rbtnode_t **nodep) {
HASHVAL(node) = 0;
ISC_LINK_INIT(node, deadlink);
+ ISC_LINK_INIT(node, prunelink);
LOCKNUM(node) = 0;
WILD(node) = 0;
diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c
index 75f97f5..2707507 100644
--- a/lib/dns/rbtdb.c
+++ b/lib/dns/rbtdb.c
@@ -515,6 +515,10 @@ struct dns_rbtdb {
*/
rbtnodelist_t *deadnodes;
+ /* List of nodes from which recursive tree pruning can be started from.
+ * Locked by tree_lock. */
+ rbtnodelist_t prunenodes;
+
/*
* Heaps. These are used for TTL based expiry in a cache,
* or for zone resigning in a zone DB. hmctx is the memory
@@ -1060,6 +1064,7 @@ free_rbtdb(dns_rbtdb_t *rbtdb, bool log, isc_event_t *event) {
unsigned int i;
isc_result_t result;
char buf[DNS_NAME_FORMATSIZE];
+ dns_rbtnode_t *node = NULL;
dns_rbt_t **treep;
isc_time_t start;
dns_dbonupdatelistener_t *listener, *listener_next;
@@ -1086,8 +1091,6 @@ free_rbtdb(dns_rbtdb_t *rbtdb, bool log, isc_event_t *event) {
* the overhead of unlinking all nodes here should be negligible.
*/
for (i = 0; i < rbtdb->node_lock_count; i++) {
- dns_rbtnode_t *node;
-
node = ISC_LIST_HEAD(rbtdb->deadnodes[i]);
while (node != NULL) {
ISC_LIST_UNLINK(rbtdb->deadnodes[i], node, deadlink);
@@ -1095,6 +1098,12 @@ free_rbtdb(dns_rbtdb_t *rbtdb, bool log, isc_event_t *event) {
}
}
+ node = ISC_LIST_HEAD(rbtdb->prunenodes);
+ while (node != NULL) {
+ ISC_LIST_UNLINK(rbtdb->prunenodes, node, prunelink);
+ node = ISC_LIST_HEAD(rbtdb->prunenodes);
+ }
+
if (event == NULL) {
rbtdb->quantum = (rbtdb->task != NULL) ? 100 : 0;
}
@@ -1934,19 +1943,32 @@ is_leaf(dns_rbtnode_t *node) {
node->left == NULL && node->right == NULL);
}
+/*%
+ * The tree lock must be held when this function is called as it reads and
+ * updates rbtdb->prunenodes.
+ */
static inline void
send_to_prune_tree(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
isc_rwlocktype_t locktype) {
- isc_event_t *ev;
- dns_db_t *db;
+ bool pruning_queued = (ISC_LIST_HEAD(rbtdb->prunenodes) != NULL);
+
+ INSIST(locktype == isc_rwlocktype_write);
- ev = isc_event_allocate(rbtdb->common.mctx, NULL, DNS_EVENT_RBTPRUNE,
- prune_tree, node, sizeof(isc_event_t));
new_reference(rbtdb, node, locktype);
- db = NULL;
- attach((dns_db_t *)rbtdb, &db);
- ev->ev_sender = db;
- isc_task_send(rbtdb->task, &ev);
+ INSIST(!ISC_LINK_LINKED(node, prunelink));
+ ISC_LIST_APPEND(rbtdb->prunenodes, node, prunelink);
+
+ if (!pruning_queued) {
+ isc_event_t *ev = NULL;
+ dns_db_t *db = NULL;
+
+ attach((dns_db_t *)rbtdb, &db);
+
+ ev = isc_event_allocate(rbtdb->common.mctx, NULL,
+ DNS_EVENT_RBTPRUNE, prune_tree, db,
+ sizeof(isc_event_t));
+ isc_task_send(rbtdb->task, &ev);
+ }
}
/*%
@@ -2220,17 +2242,26 @@ restore_locks:
}
/*
- * Prune the tree by recursively cleaning-up single leaves. In the worst
- * case, the number of iteration is the number of tree levels, which is at
- * most the maximum number of domain name labels, i.e, 127. In practice, this
- * should be much smaller (only a few times), and even the worst case would be
- * acceptable for a single event.
+ * Prune the tree by recursively cleaning up single leaves. Go through all
+ * nodes stored in the rbtdb->prunenodes list; for each of them, in the worst
+ * case, it will be necessary to traverse a number of tree levels equal to the
+ * maximum legal number of domain name labels (127); in practice, the number of
+ * tree levels to traverse will virtually always be much smaller (a few levels
+ * at most). While holding the tree lock throughout this entire operation is
+ * less than ideal, so is splitting the latter up by queueing a separate
+ * prune_tree() run for each node to start pruning from (as queueing requires
+ * allocating memory and can therefore potentially be exploited to exhaust
+ * available memory). Also note that actually freeing up the memory used by
+ * RBTDB nodes (which is what this function does) is essential to keeping cache
+ * memory use in check, so since the tree lock needs to be acquired anyway,
+ * freeing as many nodes as possible before the tree lock gets released is
+ * prudent.
*/
static void
prune_tree(isc_task_t *task, isc_event_t *event) {
- dns_rbtdb_t *rbtdb = event->ev_sender;
- dns_rbtnode_t *node = event->ev_arg;
- dns_rbtnode_t *parent;
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)event->ev_arg;
+ dns_rbtnode_t *node = NULL;
+ dns_rbtnode_t *parent = NULL;
unsigned int locknum;
UNUSED(task);
@@ -2238,44 +2269,60 @@ prune_tree(isc_task_t *task, isc_event_t *event) {
isc_event_free(&event);
RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
- locknum = node->locknum;
- NODE_LOCK(&rbtdb->node_locks[locknum].lock, isc_rwlocktype_write);
- do {
- parent = node->parent;
- decrement_reference(rbtdb, node, 0, isc_rwlocktype_write,
- isc_rwlocktype_write, true);
- if (parent != NULL && parent->down == NULL) {
- /*
- * node was the only down child of the parent and has
- * just been removed. We'll then need to examine the
- * parent. Keep the lock if possible; otherwise,
- * release the old lock and acquire one for the parent.
- */
- if (parent->locknum != locknum) {
- NODE_UNLOCK(&rbtdb->node_locks[locknum].lock,
- isc_rwlocktype_write);
- locknum = parent->locknum;
- NODE_LOCK(&rbtdb->node_locks[locknum].lock,
- isc_rwlocktype_write);
+ while ((node = ISC_LIST_HEAD(rbtdb->prunenodes)) != NULL) {
+ locknum = node->locknum;
+ NODE_LOCK(&rbtdb->node_locks[locknum].lock,
+ isc_rwlocktype_write);
+ do {
+ if (ISC_LINK_LINKED(node, prunelink)) {
+ ISC_LIST_UNLINK(rbtdb->prunenodes, node,
+ prunelink);
}
- /*
- * We need to gain a reference to the node before
- * decrementing it in the next iteration.
- */
- if (ISC_LINK_LINKED(parent, deadlink)) {
- ISC_LIST_UNLINK(rbtdb->deadnodes[locknum],
+ parent = node->parent;
+ decrement_reference(rbtdb, node, 0,
+ isc_rwlocktype_write,
+ isc_rwlocktype_write, true);
+
+ if (parent != NULL && parent->down == NULL) {
+ /*
+ * node was the only down child of the parent
+ * and has just been removed. We'll then need
+ * to examine the parent. Keep the lock if
+ * possible; otherwise, release the old lock and
+ * acquire one for the parent.
+ */
+ if (parent->locknum != locknum) {
+ NODE_UNLOCK(
+ &rbtdb->node_locks[locknum].lock,
+ isc_rwlocktype_write);
+ locknum = parent->locknum;
+ NODE_LOCK(
+ &rbtdb->node_locks[locknum].lock,
+ isc_rwlocktype_write);
+ }
+
+ /*
+ * We need to gain a reference to the node
+ * before decrementing it in the next iteration.
+ */
+ if (ISC_LINK_LINKED(parent, deadlink)) {
+ ISC_LIST_UNLINK(
+ rbtdb->deadnodes[locknum],
parent, deadlink);
+ }
+ new_reference(rbtdb, parent,
+ isc_rwlocktype_write);
+ } else {
+ parent = NULL;
}
- new_reference(rbtdb, parent, isc_rwlocktype_write);
- } else {
- parent = NULL;
- }
- node = parent;
- } while (node != NULL);
- NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, isc_rwlocktype_write);
+ node = parent;
+ } while (node != NULL);
+ NODE_UNLOCK(&rbtdb->node_locks[locknum].lock,
+ isc_rwlocktype_write);
+ }
RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
detach((dns_db_t **)&rbtdb);
@@ -8726,6 +8773,8 @@ dns_rbtdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type,
ISC_LIST_INIT(rbtdb->deadnodes[i]);
}
+ ISC_LIST_INIT(rbtdb->prunenodes);
+
rbtdb->active = rbtdb->node_lock_count;
for (i = 0; i < (int)(rbtdb->node_lock_count); i++) {
--
2.43.0

File diff suppressed because it is too large Load Diff

@ -1,27 +0,0 @@
From 7bc5e5abf5a3cd66f11cc649b6ecf4c39c92bd9e Mon Sep 17 00:00:00 2001
From: Petr Mensik <pemensik@redhat.com>
Date: Fri, 9 Aug 2024 12:32:20 +0200
Subject: [PATCH] fixup! Add test for not-loading and not-transfering huge
RRSets
---
bin/tests/system/conf.sh.common | 3 +++
1 file changed, 3 insertions(+)
diff --git a/bin/tests/system/conf.sh.common b/bin/tests/system/conf.sh.common
index 9fab00f..e617595 100644
--- a/bin/tests/system/conf.sh.common
+++ b/bin/tests/system/conf.sh.common
@@ -301,6 +301,9 @@ DISABLED_ALGORITHM=ECDSAP384SHA384
DISABLED_ALGORITHM_NUMBER=14
DISABLED_BITS=384
+# Default HMAC algorithm.
+export DEFAULT_HMAC=hmac-sha256
+
#
# Useful functions in test scripts
#
--
2.45.2

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,582 +0,0 @@
From a1c95d5fa479ac722f0cf758c494a37ffe1508c0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= <ondrej@isc.org>
Date: Sat, 25 May 2024 11:46:56 +0200
Subject: [PATCH] Add a limit to the number of RR types for single name
Previously, the number of RR types for a single owner name was limited
only by the maximum number of the types (64k). As the data structure
that holds the RR types for the database node is just a linked list, and
there are places where we just walk through the whole list (again and
again), adding a large number of RR types for a single owner named with
would slow down processing of such name (database node).
Add a configurable limit to cap the number of the RR types for a single
owner. This is enforced at the database (rbtdb, qpzone, qpcache) level
and configured with new max-types-per-name configuration option that
can be configured globally, per-view and per-zone.
(cherry picked from commit 00d16211d6368b99f070c1182d8c76b3798ca1db)
(cherry picked from commit 89f1779bc28b27adbd00325b974ede7a683f8632)
fix a memory leak that could occur when signing
when signatures were not added because of too many types already
existing at a node, the diff was not being cleaned up; this led to
a memory leak being reported at shutdown.
(cherry picked from commit 2825bdb1ae5be801e7ed603ba2455ed9a308f1f7)
(cherry picked from commit a080317de0efb7f6ffa12415a863729d416007d5)
Be smarter about refusing to add many RR types to the database
Instead of outright refusing to add new RR types to the cache, be a bit
smarter:
1. If the new header type is in our priority list, we always add either
positive or negative entry at the beginning of the list.
2. If the new header type is negative entry, and we are over the limit,
we mark it as ancient immediately, so it gets evicted from the cache
as soon as possible.
3. Otherwise add the new header after the priority headers (or at the
head of the list).
4. If we are over the limit, evict the last entry on the normal header
list.
(cherry picked from commit 57cd34441a1b4ecc9874a4a106c2c95b8d7a3120)
(cherry picked from commit 92a680a3ef708281267e4fd7b1e62b57c929447b)
Log error when update fails
The new "too many records" error can make an update fail without the
error being logged. This commit fixes that.
(cherry picked from commit 558923e5405894cf976d102f0d246a28bdbb400c)
(cherry picked from commit d72adf4b927d83a2a0ff8e431b911ec1df7aeb88)
---
bin/named/config.c | 1 +
bin/named/server.c | 9 +++++++++
bin/named/zoneconf.c | 8 ++++++++
bin/tests/system/dyndb/driver/db.c | 3 ++-
doc/arm/reference.rst | 12 ++++++++++++
lib/dns/cache.c | 12 ++++++++++++
lib/dns/db.c | 9 +++++++++
lib/dns/dnsrps.c | 3 ++-
lib/dns/ecdb.c | 3 ++-
lib/dns/include/dns/cache.h | 6 ++++++
lib/dns/include/dns/db.h | 11 +++++++++++
lib/dns/include/dns/view.h | 7 +++++++
lib/dns/include/dns/zone.h | 13 +++++++++++++
lib/dns/rbtdb.c | 28 +++++++++++++++++-----------
lib/dns/sdb.c | 3 ++-
lib/dns/sdlz.c | 3 ++-
lib/dns/view.c | 10 ++++++++++
lib/dns/zone.c | 16 ++++++++++++++++
lib/isccfg/namedconf.c | 3 +++
lib/ns/update.c | 15 ++++++++++++---
20 files changed, 156 insertions(+), 19 deletions(-)
diff --git a/bin/named/config.c b/bin/named/config.c
index 9cba6f588b..c9888ada65 100644
--- a/bin/named/config.c
+++ b/bin/named/config.c
@@ -218,6 +218,7 @@ options {\n\
max-records-per-type 100;\n\
max-refresh-time 2419200; /* 4 weeks */\n\
max-retry-time 1209600; /* 2 weeks */\n\
+ max-types-per-name 100;\n\
max-transfer-idle-in 60;\n\
max-transfer-idle-out 60;\n\
max-transfer-time-in 120;\n\
diff --git a/bin/named/server.c b/bin/named/server.c
index 7bf5f2664d..4cc69b54a1 100644
--- a/bin/named/server.c
+++ b/bin/named/server.c
@@ -5427,6 +5427,15 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
INSIST(result == ISC_R_SUCCESS);
dns_view_setmaxrrperset(view, cfg_obj_asuint32(obj));
+ /*
+ * This is used for the cache and also as a default value
+ * for zone databases.
+ */
+ obj = NULL;
+ result = named_config_get(maps, "max-types-per-name", &obj);
+ INSIST(result == ISC_R_SUCCESS);
+ dns_view_setmaxtypepername(view, cfg_obj_asuint32(obj));
+
obj = NULL;
result = named_config_get(maps, "max-recursion-depth", &obj);
INSIST(result == ISC_R_SUCCESS);
diff --git a/bin/named/zoneconf.c b/bin/named/zoneconf.c
index ae5cc656ee..f6e8c64866 100644
--- a/bin/named/zoneconf.c
+++ b/bin/named/zoneconf.c
@@ -1100,6 +1100,14 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
dns_zone_setmaxrrperset(zone, 0);
}
+ obj = NULL;
+ result = named_config_get(maps, "max-types-per-name", &obj);
+ INSIST(result == ISC_R_SUCCESS && obj != NULL);
+ dns_zone_setmaxtypepername(mayberaw, cfg_obj_asuint32(obj));
+ if (zone != mayberaw) {
+ dns_zone_setmaxtypepername(zone, 0);
+ }
+
if (raw != NULL && filename != NULL) {
#define SIGNED ".signed"
size_t signedlen = strlen(filename) + sizeof(SIGNED);
diff --git a/bin/tests/system/dyndb/driver/db.c b/bin/tests/system/dyndb/driver/db.c
index 6725a3bacd..c95fc8212b 100644
--- a/bin/tests/system/dyndb/driver/db.c
+++ b/bin/tests/system/dyndb/driver/db.c
@@ -593,7 +593,8 @@ static dns_dbmethods_t sampledb_methods = {
NULL, /* getservestalerefresh */
NULL, /* setgluecachestats */
NULL, /* adjusthashsize */
- NULL /* setmaxrrperset */
+ NULL, /* setmaxrrperset */
+ NULL /* setmaxtypepername */
};
/* Auxiliary driver functions. */
diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst
index b1983ef30d..a8a3c7911d 100644
--- a/doc/arm/reference.rst
+++ b/doc/arm/reference.rst
@@ -2902,6 +2902,18 @@ system.
a failure. If set to 0, there is no cap on RRset size. The default is
100.
+``max-types-per-name``
+ This sets the maximum number of resource record types that can be stored
+ for a single owner name in a database. When configured in ``options``
+ or ``view``, it controls the cache database, and also sets
+ the default value for zone databases, which can be overridden by setting
+ it at the ``zone`` level
+
+ If set to a positive value, any attempt to cache or to add to a zone an owner
+ name with more than the specified number of resource record types will result
+ in a failure. If set to 0, there is no cap on RR types number. The default is
+ 100.
+
``recursive-clients``
This sets the maximum number (a "hard quota") of simultaneous recursive lookups
the server performs on behalf of clients. The default is
diff --git a/lib/dns/cache.c b/lib/dns/cache.c
index 9f0412dbe7..0b474fc313 100644
--- a/lib/dns/cache.c
+++ b/lib/dns/cache.c
@@ -150,6 +150,7 @@ struct dns_cache {
/* Access to the on-disk cache file is also locked by 'filelock'. */
uint32_t maxrrperset;
+ uint32_t maxtypepername;
};
/***
@@ -178,6 +179,7 @@ cache_create_db(dns_cache_t *cache, dns_db_t **db) {
if (result == ISC_R_SUCCESS) {
dns_db_setservestalettl(*db, cache->serve_stale_ttl);
dns_db_setmaxrrperset(*db, cache->maxrrperset);
+ dns_db_setmaxtypepername(*db, cache->maxtypepername);
}
return (result);
}
@@ -1290,6 +1292,16 @@ dns_cache_setmaxrrperset(dns_cache_t *cache, uint32_t value) {
}
}
+void
+dns_cache_setmaxtypepername(dns_cache_t *cache, uint32_t value) {
+ REQUIRE(VALID_CACHE(cache));
+
+ cache->maxtypepername = value;
+ if (cache->db != NULL) {
+ dns_db_setmaxtypepername(cache->db, value);
+ }
+}
+
/*
* XXX: Much of the following code has been copied in from statschannel.c.
* We should refactor this into a generic function in stats.c that can be
diff --git a/lib/dns/db.c b/lib/dns/db.c
index 8439265a7f..18583d41c2 100644
--- a/lib/dns/db.c
+++ b/lib/dns/db.c
@@ -1131,3 +1131,12 @@ dns_db_setmaxrrperset(dns_db_t *db, uint32_t value) {
(db->methods->setmaxrrperset)(db, value);
}
}
+
+void
+dns_db_setmaxtypepername(dns_db_t *db, uint32_t value) {
+ REQUIRE(DNS_DB_VALID(db));
+
+ if (db->methods->setmaxtypepername != NULL) {
+ (db->methods->setmaxtypepername)(db, value);
+ }
+}
diff --git a/lib/dns/dnsrps.c b/lib/dns/dnsrps.c
index 539090d1bd..e1a1b21a8b 100644
--- a/lib/dns/dnsrps.c
+++ b/lib/dns/dnsrps.c
@@ -971,7 +971,8 @@ static dns_dbmethods_t rpsdb_db_methods = {
NULL, /* getservestalerefresh */
NULL, /* setgluecachestats */
NULL, /* adjusthashsize */
- NULL /* setmaxrrperset */
+ NULL, /* setmaxrrperset */
+ NULL /* setmaxtypepername */
};
static dns_rdatasetmethods_t rpsdb_rdataset_methods = {
diff --git a/lib/dns/ecdb.c b/lib/dns/ecdb.c
index bab5da5503..27d03b4e3a 100644
--- a/lib/dns/ecdb.c
+++ b/lib/dns/ecdb.c
@@ -560,7 +560,8 @@ static dns_dbmethods_t ecdb_methods = {
NULL, /* getservestalerefresh */
NULL, /* setgluecachestats */
NULL, /* adjusthashsize */
- NULL /* setmaxrrperset */
+ NULL, /* setmaxrrperset */
+ NULL /* setmaxtypepername */
};
static isc_result_t
diff --git a/lib/dns/include/dns/cache.h b/lib/dns/include/dns/cache.h
index 3fa2a891e0..72de21600a 100644
--- a/lib/dns/include/dns/cache.h
+++ b/lib/dns/include/dns/cache.h
@@ -343,6 +343,12 @@ dns_cache_setmaxrrperset(dns_cache_t *cache, uint32_t value);
* Set the maximum resource records per RRSet that can be cached.
*/
+void
+dns_cache_setmaxtypepername(dns_cache_t *cache, uint32_t value);
+/*%<
+ * Set the maximum resource record types per owner name that can be cached.
+ */
+
#ifdef HAVE_LIBXML2
int
dns_cache_renderxml(dns_cache_t *cache, void *writer0);
diff --git a/lib/dns/include/dns/db.h b/lib/dns/include/dns/db.h
index 732bfe473d..411881d48a 100644
--- a/lib/dns/include/dns/db.h
+++ b/lib/dns/include/dns/db.h
@@ -183,6 +183,7 @@ typedef struct dns_dbmethods {
isc_result_t (*setgluecachestats)(dns_db_t *db, isc_stats_t *stats);
isc_result_t (*adjusthashsize)(dns_db_t *db, size_t size);
void (*setmaxrrperset)(dns_db_t *db, uint32_t value);
+ void (*setmaxtypepername)(dns_db_t *db, uint32_t value);
} dns_dbmethods_t;
typedef isc_result_t (*dns_dbcreatefunc_t)(isc_mem_t *mctx,
@@ -1791,6 +1792,16 @@ dns_db_setmaxrrperset(dns_db_t *db, uint32_t value);
* is nonzero, then any subsequent attempt to add an rdataset with
* more than 'value' RRs will return ISC_R_NOSPACE.
*/
+
+void
+dns_db_setmaxtypepername(dns_db_t *db, uint32_t value);
+/*%<
+ * Set the maximum permissible number of RR types per owner name.
+ *
+ * If 'value' is nonzero, then any subsequent attempt to add an rdataset with a
+ * RR type that would exceed the number of already stored RR types will return
+ * ISC_R_NOSPACE.
+ */
ISC_LANG_ENDDECLS
#endif /* DNS_DB_H */
diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h
index 0d502f4dd2..0a72f58e98 100644
--- a/lib/dns/include/dns/view.h
+++ b/lib/dns/include/dns/view.h
@@ -187,6 +187,7 @@ struct dns_view {
uint32_t fail_ttl;
dns_badcache_t *failcache;
uint32_t maxrrperset;
+ uint32_t maxtypepername;
/*
* Configurable data for server use only,
@@ -1346,6 +1347,12 @@ dns_view_setmaxrrperset(dns_view_t *view, uint32_t value);
* Set the maximum resource records per RRSet that can be cached.
*/
+void
+dns_view_setmaxtypepername(dns_view_t *view, uint32_t value);
+/*%<
+ * Set the maximum resource record types per owner name that can be cached.
+ */
+
ISC_LANG_ENDDECLS
#endif /* DNS_VIEW_H */
diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h
index e902043357..6fca11f3fd 100644
--- a/lib/dns/include/dns/zone.h
+++ b/lib/dns/include/dns/zone.h
@@ -356,6 +356,19 @@ dns_zone_setmaxrrperset(dns_zone_t *zone, uint32_t maxrrperset);
*\li void
*/
+void
+dns_zone_setmaxtypepername(dns_zone_t *zone, uint32_t maxtypepername);
+/*%<
+ * Sets the maximum number of resource record types per owner name
+ * permitted in a zone. 0 implies unlimited.
+ *
+ * Requires:
+ *\li 'zone' to be valid initialised zone.
+ *
+ * Returns:
+ *\li void
+ */
+
void
dns_zone_setmaxttl(dns_zone_t *zone, uint32_t maxttl);
/*%<
diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c
index ca71bb9c03..ed5015c2d4 100644
--- a/lib/dns/rbtdb.c
+++ b/lib/dns/rbtdb.c
@@ -483,6 +483,7 @@ struct dns_rbtdb {
rbtdb_serial_t least_serial;
rbtdb_serial_t next_serial;
uint32_t maxrrperset;
+ uint32_t maxtypepername;
rbtdb_version_t *current_version;
rbtdb_version_t *future_version;
rbtdb_versionlist_t open_versions;
@@ -6222,19 +6223,13 @@ update_recordsandxfrsize(bool add, rbtdb_version_t *rbtversion,
RWUNLOCK(&rbtversion->rwlock, isc_rwlocktype_write);
}
-#ifndef DNS_RBTDB_MAX_RTYPES
-#define DNS_RBTDB_MAX_RTYPES 100
-#endif /* DNS_RBTDB_MAX_RTYPES */
-
static bool
overmaxtype(dns_rbtdb_t *rbtdb, uint32_t ntypes) {
- UNUSED(rbtdb);
-
- if (DNS_RBTDB_MAX_RTYPES == 0) {
+ if (rbtdb->maxtypepername == 0) {
return (false);
}
- return (ntypes >= DNS_RBTDB_MAX_RTYPES);
+ return (ntypes >= rbtdb->maxtypepername);
}
static bool
@@ -6794,7 +6789,7 @@ find_header:
if (!IS_CACHE(rbtdb) && overmaxtype(rbtdb, ntypes)) {
free_rdataset(rbtdb, rbtdb->common.mctx,
newheader);
- return (ISC_R_QUOTA);
+ return (DNS_R_TOOMANYRECORDS);
}
newheader->down = NULL;
@@ -8623,6 +8618,15 @@ setmaxrrperset(dns_db_t *db, uint32_t maxrrperset) {
rbtdb->maxrrperset = maxrrperset;
}
+static void
+setmaxtypepername(dns_db_t *db, uint32_t maxtypepername) {
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+
+ rbtdb->maxtypepername = maxtypepername;
+}
+
static dns_stats_t *
getrrsetstats(dns_db_t *db) {
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
@@ -8747,7 +8751,8 @@ static dns_dbmethods_t zone_methods = { attach,
NULL, /* getservestalerefresh */
setgluecachestats,
adjusthashsize,
- setmaxrrperset };
+ setmaxrrperset,
+ setmaxtypepername };
static dns_dbmethods_t cache_methods = { attach,
detach,
@@ -8800,7 +8805,8 @@ static dns_dbmethods_t cache_methods = { attach,
getservestalerefresh,
NULL,
adjusthashsize,
- setmaxrrperset };
+ setmaxrrperset,
+ setmaxtypepername };
isc_result_t
dns_rbtdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type,
diff --git a/lib/dns/sdb.c b/lib/dns/sdb.c
index 84cd324fb4..77a5834b76 100644
--- a/lib/dns/sdb.c
+++ b/lib/dns/sdb.c
@@ -1313,7 +1313,8 @@ static dns_dbmethods_t sdb_methods = {
NULL, /* getservestalerefresh */
NULL, /* setgluecachestats */
NULL, /* adjusthashsize */
- NULL /* setmaxrrperset */
+ NULL, /* setmaxrrperset */
+ NULL /* setmaxtypepername */
};
static isc_result_t
diff --git a/lib/dns/sdlz.c b/lib/dns/sdlz.c
index 60a1d23b3b..418a4a14ee 100644
--- a/lib/dns/sdlz.c
+++ b/lib/dns/sdlz.c
@@ -1285,7 +1285,8 @@ static dns_dbmethods_t sdlzdb_methods = {
NULL, /* getservestalerefresh */
NULL, /* setgluecachestats */
NULL, /* adjusthashsize */
- NULL /* setmaxrrperset */
+ NULL, /* setmaxrrperset */
+ NULL /* setmaxtypepername */
};
/*
diff --git a/lib/dns/view.c b/lib/dns/view.c
index a672aa8bc8..98579f03d9 100644
--- a/lib/dns/view.c
+++ b/lib/dns/view.c
@@ -871,6 +871,7 @@ dns_view_setcache(dns_view_t *view, dns_cache_t *cache, bool shared) {
INSIST(DNS_DB_VALID(view->cachedb));
dns_cache_setmaxrrperset(view->cache, view->maxrrperset);
+ dns_cache_setmaxtypepername(view->cache, view->maxtypepername);
}
bool
@@ -2555,3 +2556,12 @@ dns_view_setmaxrrperset(dns_view_t *view, uint32_t value) {
dns_cache_setmaxrrperset(view->cache, value);
}
}
+
+void
+dns_view_setmaxtypepername(dns_view_t *view, uint32_t value) {
+ REQUIRE(DNS_VIEW_VALID(view));
+ view->maxtypepername = value;
+ if (view->cache != NULL) {
+ dns_cache_setmaxtypepername(view->cache, value);
+ }
+}
diff --git a/lib/dns/zone.c b/lib/dns/zone.c
index 5c8d97ed18..e1fb9ab50b 100644
--- a/lib/dns/zone.c
+++ b/lib/dns/zone.c
@@ -277,6 +277,7 @@ struct dns_zone {
uint32_t maxrecords;
uint32_t maxrrperset;
+ uint32_t maxtypepername;
isc_sockaddr_t *masters;
isc_dscp_t *masterdscps;
@@ -9959,6 +9960,7 @@ cleanup:
}
dns_diff_clear(&_sig_diff);
+ dns_diff_clear(&post_diff);
for (i = 0; i < nkeys; i++) {
dst_key_free(&zone_keys[i]);
@@ -12168,6 +12170,16 @@ dns_zone_setmaxrrperset(dns_zone_t *zone, uint32_t val) {
}
}
+void
+dns_zone_setmaxtypepername(dns_zone_t *zone, uint32_t val) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ zone->maxtypepername = val;
+ if (zone->db != NULL) {
+ dns_db_setmaxtypepername(zone->db, val);
+ }
+}
+
static bool
notify_isqueued(dns_zone_t *zone, unsigned int flags, dns_name_t *name,
isc_sockaddr_t *addr, dns_tsigkey_t *key) {
@@ -14573,6 +14585,8 @@ ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) {
}
dns_db_settask(stub->db, zone->task);
dns_db_setmaxrrperset(stub->db, zone->maxrrperset);
+ dns_db_setmaxtypepername(stub->db,
+ zone->maxtypepername);
}
result = dns_db_newversion(stub->db, &stub->version);
@@ -17295,6 +17309,7 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, bool dump) {
zone_attachdb(zone, db);
dns_db_settask(zone->db, zone->task);
dns_db_setmaxrrperset(zone->db, zone->maxrrperset);
+ dns_db_setmaxtypepername(zone->db, zone->maxtypepername);
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED | DNS_ZONEFLG_NEEDNOTIFY);
return (ISC_R_SUCCESS);
@@ -23444,6 +23459,7 @@ dns_zone_makedb(dns_zone_t *zone, dns_db_t **dbp) {
dns_db_settask(db, zone->task);
dns_db_setmaxrrperset(db, zone->maxrrperset);
+ dns_db_setmaxtypepername(db, zone->maxtypepername);
*dbp = db;
diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c
index dce30537dd..ac9fc2af5e 100644
--- a/lib/isccfg/namedconf.c
+++ b/lib/isccfg/namedconf.c
@@ -2239,6 +2239,9 @@ static cfg_clausedef_t zone_clauses[] = {
{ "max-records-per-type", &cfg_type_uint32,
CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR |
CFG_ZONE_STUB | CFG_ZONE_STATICSTUB | CFG_ZONE_REDIRECT },
+ { "max-types-per-name", &cfg_type_uint32,
+ CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR |
+ CFG_ZONE_STUB | CFG_ZONE_STATICSTUB | CFG_ZONE_REDIRECT },
{ "max-refresh-time", &cfg_type_uint32,
CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR | CFG_ZONE_STUB },
{ "max-retry-time", &cfg_type_uint32,
diff --git a/lib/ns/update.c b/lib/ns/update.c
index c5ce1eaf09..0e0bdc9c03 100644
--- a/lib/ns/update.c
+++ b/lib/ns/update.c
@@ -3112,9 +3112,18 @@ update_action(isc_task_t *task, isc_event_t *event) {
dns_diff_clear(&ctx.add_diff);
goto failure;
}
- CHECK(update_one_rr(db, ver, &diff,
- DNS_DIFFOP_ADD,
- name, ttl, &rdata));
+ result = update_one_rr(
+ db, ver, &diff, DNS_DIFFOP_ADD,
+ name, ttl, &rdata);
+ if (result != ISC_R_SUCCESS) {
+ update_log(client, zone,
+ LOGLEVEL_PROTOCOL,
+ "adding an RR "
+ "failed: %s",
+ isc_result_totext(
+ result));
+ goto failure;
+ }
}
}
} else if (update_class == dns_rdataclass_any) {
--
2.45.2

@ -1,364 +0,0 @@
From c5357835c98b7b028f8a041b6976bb335c9a4056 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= <ondrej@isc.org>
Date: Fri, 1 Mar 2024 08:26:07 +0100
Subject: [PATCH] Add a limit to the number of RRs in RRSets
Previously, the number of RRs in the RRSets were internally unlimited.
As the data structure that holds the RRs is just a linked list, and
there are places where we just walk through all of the RRs, adding an
RRSet with huge number of RRs inside would slow down processing of said
RRSets.
The fix for end-of-life branches make the limit compile-time only for
simplicity and the limit can be changed at the compile time by adding
following define to CFLAGS:
-DDNS_RDATASET_MAX_RECORDS=<limit>
(cherry picked from commit c5c4d00c38530390c9e1ae4c98b65fbbadfe9e5e)
(cherry picked from commit fdabf4b9570a60688f9f7d1e88d885f7a3718bca)
Add a limit to the number of RR types for single name
Previously, the number of RR types for a single owner name was limited
only by the maximum number of the types (64k). As the data structure
that holds the RR types for the database node is just a linked list, and
there are places where we just walk through the whole list (again and
again), adding a large number of RR types for a single owner named with
would slow down processing of such name (database node).
Add a hard-coded limit (100) to cap the number of the RR types for a single
owner. The limit can be changed at the compile time by adding following
define to CFLAGS:
-DDNS_RBTDB_MAX_RTYPES=<limit>
(cherry picked from commit dfcadc2085c8844b5836aff2b5ea51fb60c34868)
Optimize the slabheader placement for certain RRTypes
Mark the infrastructure RRTypes as "priority" types and place them at
the beginning of the rdataslab header data graph. The non-priority
types either go right after the priority types (if any).
(cherry picked from commit 3ac482be7fd058d284e89873021339579fad0615)
(cherry picked from commit 8ef414a7f38a04cfc11df44adaedaf3126fa3878)
Expand the list of the priority types
Add HTTPS, SVCB, SRV, PTR, NAPTR, DNSKEY and TXT records to the list of
the priority types that are put at the beginning of the slabheader list
for faster access and to avoid eviction when there are more types than
the max-types-per-name limit.
(cherry picked from commit b27c6bcce894786a8e082eafd59eccbf6f2731cb)
(cherry picked from commit d56d2a32b861e81c2aaaabd309c4c58b629ede32)
Make the resolver qtype ANY test order agnostic
Instead of relying on a specific order of the RR types in the databases
pick the first RR type as returned from the cache.
(cherry picked from commit 58f660cf2b800963fa649bc9823a626009db3a7e)
(cherry picked from commit c5ebda6deb0997dc520b26fa0639891459de5cb6)
Be smarter about refusing to add many RR types to the database
Instead of outright refusing to add new RR types to the cache, be a bit
smarter:
1. If the new header type is in our priority list, we always add either
positive or negative entry at the beginning of the list.
2. If the new header type is negative entry, and we are over the limit,
we mark it as ancient immediately, so it gets evicted from the cache
as soon as possible.
3. Otherwise add the new header after the priority headers (or at the
head of the list).
4. If we are over the limit, evict the last entry on the normal header
list.
(cherry picked from commit 57cd34441a1b4ecc9874a4a106c2c95b8d7a3120)
(cherry picked from commit 26c9da5f2857b72077c17e06ac79f068c63782cc)
---
bin/tests/system/resolver/tests.sh | 9 ++-
configure | 2 +-
configure.ac | 2 +-
lib/dns/rbtdb.c | 125 ++++++++++++++++++++++++++++-
lib/dns/rdataslab.c | 12 +++
5 files changed, 144 insertions(+), 6 deletions(-)
diff --git a/bin/tests/system/resolver/tests.sh b/bin/tests/system/resolver/tests.sh
index 6c69c1104e..bd997a61a4 100755
--- a/bin/tests/system/resolver/tests.sh
+++ b/bin/tests/system/resolver/tests.sh
@@ -553,15 +553,20 @@ n=`expr $n + 1`
echo_i "check prefetch qtype * (${n})"
ret=0
$DIG $DIGOPTS @10.53.0.5 fetchall.tld any > dig.out.1.${n} || ret=1
-ttl1=`awk '/"A" "short" "ttl"/ { print $2 - 3 }' dig.out.1.${n}`
+ttl1=$(awk '/^fetchall.tld/ { print $2 - 3; exit }' dig.out.1.${n})
# sleep so we are in prefetch range
sleep ${ttl1:-0}
# trigger prefetch
$DIG $DIGOPTS @10.53.0.5 fetchall.tld any > dig.out.2.${n} || ret=1
-ttl2=`awk '/"A" "short" "ttl"/ { print $2 }' dig.out.2.${n}`
+ttl2=$(awk '/^fetchall.tld/ { print $2; exit }' dig.out.2.${n})
sleep 1
# check that the nameserver is still alive
$DIG $DIGOPTS @10.53.0.5 fetchall.tld any > dig.out.3.${n} || ret=1
+# note that only the first record is prefetched,
+# because of the order of the records in the cache
+$DIG $DIGOPTS @10.53.0.5 fetchall.tld any >dig.out.3.${n} || ret=1
+ttl3=$(awk '/^fetchall.tld/ { print $2; exit }' dig.out.3.${n})
+test "${ttl3:-0}" -gt "${ttl2:-1}" || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
diff --git a/configure b/configure
index ed2d4869e5..be0f60eaba 100755
--- a/configure
+++ b/configure
@@ -12295,7 +12295,7 @@ fi
XTARGETS=
if test "$enable_developer" = "yes"; then :
- STD_CDEFINES="$STD_CDEFINES -DISC_MEM_DEFAULTFILL=1 -DISC_LIST_CHECKINIT=1"
+ STD_CDEFINES="$STD_CDEFINES -DISC_MEM_DEFAULTFILL=1 -DISC_LIST_CHECKINIT=1 -DDNS_RDATASET_MAX_RECORDS=5000 -DDNS_RBTDB_MAX_RTYPES=5000"
test "${enable_fixed_rrset+set}" = set || enable_fixed_rrset=yes
test "${enable_querytrace+set}" = set || enable_querytrace=yes
test "${with_cmocka+set}" = set || with_cmocka=yes
diff --git a/configure.ac b/configure.ac
index 287de41369..3ff4bdd135 100644
--- a/configure.ac
+++ b/configure.ac
@@ -94,7 +94,7 @@ AC_ARG_ENABLE([developer],
XTARGETS=
AS_IF([test "$enable_developer" = "yes"],
- [STD_CDEFINES="$STD_CDEFINES -DISC_MEM_DEFAULTFILL=1 -DISC_LIST_CHECKINIT=1"
+ [STD_CDEFINES="$STD_CDEFINES -DISC_MEM_DEFAULTFILL=1 -DISC_LIST_CHECKINIT=1 -DDNS_RDATASET_MAX_RECORDS=5000 -DDNS_RBTDB_MAX_RTYPES=5000"
test "${enable_fixed_rrset+set}" = set || enable_fixed_rrset=yes
test "${enable_querytrace+set}" = set || enable_querytrace=yes
test "${with_cmocka+set}" = set || with_cmocka=yes
diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c
index 2707507bd7..e840c0665d 100644
--- a/lib/dns/rbtdb.c
+++ b/lib/dns/rbtdb.c
@@ -967,6 +967,48 @@ set_ttl(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, dns_ttl_t newttl) {
}
}
+static bool
+prio_type(rbtdb_rdatatype_t type) {
+ switch (type) {
+ case dns_rdatatype_soa:
+ case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_soa):
+ case dns_rdatatype_a:
+ case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_a):
+ case dns_rdatatype_mx:
+ case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_mx):
+ case dns_rdatatype_aaaa:
+ case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_aaaa):
+ case dns_rdatatype_nsec:
+ case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_nsec):
+ case dns_rdatatype_nsec3:
+ case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_nsec3):
+ case dns_rdatatype_ns:
+ case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_ns):
+ case dns_rdatatype_ds:
+ case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_ds):
+ case dns_rdatatype_cname:
+ case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_cname):
+ case dns_rdatatype_dname:
+ case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_dname):
+ case dns_rdatatype_svcb:
+ case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_svcb):
+ case dns_rdatatype_https:
+ case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_https):
+ case dns_rdatatype_dnskey:
+ case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_dnskey):
+ case dns_rdatatype_srv:
+ case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_srv):
+ case dns_rdatatype_txt:
+ case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_txt):
+ case dns_rdatatype_ptr:
+ case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_ptr):
+ case dns_rdatatype_naptr:
+ case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_naptr):
+ return (true);
+ }
+ return (false);
+}
+
/*%
* These functions allow the heap code to rank the priority of each
* element. It returns true if v1 happens "sooner" than v2.
@@ -6179,6 +6221,30 @@ update_recordsandxfrsize(bool add, rbtdb_version_t *rbtversion,
RWUNLOCK(&rbtversion->rwlock, isc_rwlocktype_write);
}
+#ifndef DNS_RBTDB_MAX_RTYPES
+#define DNS_RBTDB_MAX_RTYPES 100
+#endif /* DNS_RBTDB_MAX_RTYPES */
+
+static bool
+overmaxtype(dns_rbtdb_t *rbtdb, uint32_t ntypes) {
+ UNUSED(rbtdb);
+
+ if (DNS_RBTDB_MAX_RTYPES == 0) {
+ return (false);
+ }
+
+ return (ntypes >= DNS_RBTDB_MAX_RTYPES);
+}
+
+static bool
+prio_header(rdatasetheader_t *header) {
+ if (NEGATIVE(header) && prio_type(RBTDB_RDATATYPE_EXT(header->type))) {
+ return (true);
+ }
+
+ return (prio_type(header->type));
+}
+
/*
* write lock on rbtnode must be held.
*/
@@ -6190,6 +6256,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename,
rbtdb_changed_t *changed = NULL;
rdatasetheader_t *topheader = NULL, *topheader_prev = NULL;
rdatasetheader_t *header = NULL, *sigheader = NULL;
+ rdatasetheader_t *prioheader = NULL, *expireheader = NULL;
unsigned char *merged = NULL;
isc_result_t result;
bool header_nx;
@@ -6199,6 +6266,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename,
rbtdb_rdatatype_t negtype, sigtype;
dns_trust_t trust;
int idx;
+ uint32_t ntypes = 0;
/*
* Add an rdatasetheader_t to a node.
@@ -6272,6 +6340,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename,
topheader = topheader->next) {
if (topheader->type == sigtype) {
sigheader = topheader;
+ break;
}
}
negtype = RBTDB_RDATATYPE_VALUE(covers, 0);
@@ -6331,6 +6400,15 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename,
for (topheader = rbtnode->data; topheader != NULL;
topheader = topheader->next) {
+ if (IS_CACHE(rbtdb) && ACTIVE(topheader, now)) {
+ ++ntypes;
+ expireheader = topheader;
+ } else if (!IS_CACHE(rbtdb)) {
+ ++ntypes;
+ }
+ if (prio_header(topheader)) {
+ prioheader = topheader;
+ }
if (topheader->type == newheader->type ||
topheader->type == negtype) {
break;
@@ -6712,9 +6790,52 @@ find_header:
/*
* No rdatasets of the given type exist at the node.
*/
- newheader->next = rbtnode->data;
+ if (!IS_CACHE(rbtdb) && overmaxtype(rbtdb, ntypes)) {
+ free_rdataset(rbtdb, rbtdb->common.mctx,
+ newheader);
+ return (ISC_R_QUOTA);
+ }
+
newheader->down = NULL;
- rbtnode->data = newheader;
+
+ if (prio_header(newheader)) {
+ /* This is a priority type, prepend it */
+ newheader->next = rbtnode->data;
+ rbtnode->data = newheader;
+ } else if (prioheader != NULL) {
+ /* Append after the priority headers */
+ newheader->next = prioheader->next;
+ prioheader->next = newheader;
+ } else {
+ /* There were no priority headers */
+ newheader->next = rbtnode->data;
+ rbtnode->data = newheader;
+ }
+
+ if (IS_CACHE(rbtdb) && overmaxtype(rbtdb, ntypes)) {
+ if (expireheader == NULL) {
+ expireheader = newheader;
+ }
+ if (NEGATIVE(newheader) &&
+ !prio_header(newheader))
+ {
+ /*
+ * Add the new non-priority negative
+ * header to the database only
+ * temporarily.
+ */
+ expireheader = newheader;
+ }
+
+ set_ttl(rbtdb, expireheader, 0);
+ mark_header_ancient(rbtdb, expireheader);
+ /*
+ * FIXME: In theory, we should mark the RRSIG
+ * and the header at the same time, but there is
+ * no direct link between those two header, so
+ * we would have to check the whole list again.
+ */
+ }
}
}
diff --git a/lib/dns/rdataslab.c b/lib/dns/rdataslab.c
index 1d5e88f745..dda903819a 100644
--- a/lib/dns/rdataslab.c
+++ b/lib/dns/rdataslab.c
@@ -110,6 +110,10 @@ fillin_offsets(unsigned char *offsetbase, unsigned int *offsettable,
}
#endif /* if DNS_RDATASET_FIXED */
+#ifndef DNS_RDATASET_MAX_RECORDS
+#define DNS_RDATASET_MAX_RECORDS 100
+#endif /* DNS_RDATASET_MAX_RECORDS */
+
isc_result_t
dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
isc_region_t *region, unsigned int reservelen) {
@@ -154,6 +158,10 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
return (ISC_R_SUCCESS);
}
+ if (nitems > DNS_RDATASET_MAX_RECORDS) {
+ return (DNS_R_TOOMANYRECORDS);
+ }
+
if (nitems > 0xffff) {
return (ISC_R_NOSPACE);
}
@@ -520,6 +528,10 @@ dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab,
#endif /* if DNS_RDATASET_FIXED */
INSIST(ocount > 0 && ncount > 0);
+ if (ocount + ncount > DNS_RDATASET_MAX_RECORDS) {
+ return (DNS_R_TOOMANYRECORDS);
+ }
+
#if DNS_RDATASET_FIXED
oncount = ncount;
#endif /* if DNS_RDATASET_FIXED */
--
2.45.2

@ -1,318 +0,0 @@
From 34e92fc88943beeba76aa4e408951cb46d8cdb53 Mon Sep 17 00:00:00 2001
From: Petr Mensik <pemensik@redhat.com>
Date: Tue, 16 Jul 2024 19:49:09 +0200
Subject: [PATCH] Resolve CVE-2024-1975
6404. [security] Remove SIG(0) support from named as a countermeasure
for CVE-2024-1975. [GL #4480]
Resolves: CVE-2024-1975
---
bin/tests/system/tsiggss/authsock.pl | 5 ++
bin/tests/system/tsiggss/tests.sh | 12 ++--
bin/tests/system/upforwd/tests.sh | 21 +++---
doc/arm/general.rst | 6 +-
doc/arm/reference.rst | 4 +-
doc/arm/security.rst | 4 +-
lib/dns/message.c | 97 ++--------------------------
lib/ns/client.c | 7 ++
8 files changed, 43 insertions(+), 113 deletions(-)
diff --git a/bin/tests/system/tsiggss/authsock.pl b/bin/tests/system/tsiggss/authsock.pl
index ab3833d..0b231ee 100644
--- a/bin/tests/system/tsiggss/authsock.pl
+++ b/bin/tests/system/tsiggss/authsock.pl
@@ -31,6 +31,10 @@ if (!defined($path)) {
exit(1);
}
+# Enable output autoflush so that it's not lost when the parent sends TERM.
+select STDOUT;
+$| = 1;
+
unlink($path);
my $server = IO::Socket::UNIX->new(Local => $path, Type => SOCK_STREAM, Listen => 8) or
die "unable to create socket $path";
@@ -53,6 +57,7 @@ if ($timeout != 0) {
}
while (my $client = $server->accept()) {
+ printf("accept()\n");
$client->recv(my $buf, 8, 0);
my ($version, $req_len) = unpack('N N', $buf);
diff --git a/bin/tests/system/tsiggss/tests.sh b/bin/tests/system/tsiggss/tests.sh
index 632bb87..7977e49 100644
--- a/bin/tests/system/tsiggss/tests.sh
+++ b/bin/tests/system/tsiggss/tests.sh
@@ -116,7 +116,7 @@ status=$((status+ret))
echo_i "testing external update policy (CNAME) with auth sock ($n)"
ret=0
-$PERL ./authsock.pl --type=CNAME --path=ns1/auth.sock --pidfile=authsock.pid --timeout=120 > /dev/null 2>&1 &
+$PERL ./authsock.pl --type=CNAME --path=ns1/auth.sock --pidfile=authsock.pid --timeout=120 >authsock.log 2>&1 &
sleep 1
test_update $n testcname.example.nil. CNAME "86400 CNAME testdenied.example.nil" "testdenied" || ret=1
n=$((n+1))
@@ -130,17 +130,19 @@ n=$((n+1))
if [ "$ret" -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
-echo_i "testing external policy with SIG(0) key ($n)"
+echo_i "testing external policy with unsupported SIG(0) key ($n)"
ret=0
-$NSUPDATE -k ns1/Kkey.example.nil.*.private <<END > /dev/null 2>&1 || ret=1
+$NSUPDATE -d -k ns1/Kkey.example.nil.*.private <<END >nsupdate.out${n} 2>&1 || true
+debug
server 10.53.0.1 ${PORT}
zone example.nil
update add fred.example.nil 120 cname foo.bar.
send
END
output=`$DIG $DIGOPTS +short cname fred.example.nil.`
-[ -n "$output" ] || ret=1
-[ $ret -eq 0 ] || echo_i "failed"
+# update must have failed - SIG(0) signer is not supported
+[ -n "$output" ] && ret=1
+grep -F "signer=key.example.nil" authsock.log >/dev/null && ret=1
n=$((n+1))
if [ "$ret" -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
diff --git a/bin/tests/system/upforwd/tests.sh b/bin/tests/system/upforwd/tests.sh
index 20fc46f..c8fd54b 100644
--- a/bin/tests/system/upforwd/tests.sh
+++ b/bin/tests/system/upforwd/tests.sh
@@ -224,19 +224,22 @@ fi
if test -f keyname
then
- echo_i "checking update forwarding to with sig0 ($n)"
+ echo_i "checking update forwarding to with sig0 (expected to fail) ($n)"
ret=0
keyname=`cat keyname`
- $NSUPDATE -k $keyname.private -- - <<EOF
- local 10.53.0.1
- server 10.53.0.3 ${PORT}
- zone example2
- update add unsigned.example2. 600 A 10.10.10.1
- update add unsigned.example2. 600 TXT Foo
- send
+ # SIG(0) is removed, update is expected to fail.
+ {
+ $NSUPDATE -k $keyname.private -- - <<EOF
+ local 10.53.0.1
+ server 10.53.0.3 ${PORT}
+ zone example2
+ update add unsigned.example2. 600 A 10.10.10.1
+ update add unsigned.example2. 600 TXT Foo
+ send
EOF
+ } >nsupdate.out.$n 2>&1 && ret=1
$DIG -p ${PORT} unsigned.example2 A @10.53.0.1 > dig.out.ns1.test$n
- grep "status: NOERROR" dig.out.ns1.test$n > /dev/null || ret=1
+ grep "status: NOERROR" dig.out.ns1.test$n >/dev/null && ret=1
if [ $ret != 0 ] ; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
diff --git a/doc/arm/general.rst b/doc/arm/general.rst
index 225576b..0766dfe 100644
--- a/doc/arm/general.rst
+++ b/doc/arm/general.rst
@@ -534,10 +534,8 @@ than a non-authoritative response. This is considered a feature.
[2] CLASS ANY queries are not supported. This is considered a
feature.
-[3] When receiving a query signed with a SIG(0), the server is
-only able to verify the signature if it has the key in its local
-authoritative data; it cannot do recursion or validation to
-retrieve unknown keys.
+[3] Support for SIG(0) message verification was removed
+as part of the mitigation of CVE-2024-1975.
[4] Compliance is with loading and serving of A6 records only. A6 records were moved
to the experimental category by :rfc:`3363`.
diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst
index d4ee9d2..ad7ff27 100644
--- a/doc/arm/reference.rst
+++ b/doc/arm/reference.rst
@@ -5789,7 +5789,7 @@ The ``update-policy`` clause allows more fine-grained control over which
updates are allowed. It specifies a set of rules, in which each rule
either grants or denies permission for one or more names in the zone to
be updated by one or more identities. Identity is determined by the key
-that signed the update request, using either TSIG or SIG(0). In most
+that signed the update request, using either TSIG. In most
cases, ``update-policy`` rules only apply to key-based identities. There
is no way to specify update permissions based on the client source address.
@@ -5846,7 +5846,7 @@ field), and the type of the record to be updated matches the ``types``
field. Details for each rule type are described below.
The ``identity`` field must be set to a fully qualified domain name. In
-most cases, this represents the name of the TSIG or SIG(0) key that
+most cases, this represents the name of the TSIG key that
must be used to sign the update request. If the specified name is a
wildcard, it is subject to DNS wildcard expansion, and the rule may
apply to multiple identities. When a TKEY exchange has been used to
diff --git a/doc/arm/security.rst b/doc/arm/security.rst
index f7c8bd3..e3abfd1 100644
--- a/doc/arm/security.rst
+++ b/doc/arm/security.rst
@@ -32,7 +32,7 @@ Limiting access to the server by outside parties can help prevent
spoofing and denial of service (DoS) attacks against the server.
ACLs match clients on the basis of up to three characteristics: 1) The
-client's IP address; 2) the TSIG or SIG(0) key that was used to sign the
+client's IP address; 2) the TSIG key that was used to sign the
request, if any; and 3) an address prefix encoded in an EDNS
Client-Subnet option, if any.
@@ -73,7 +73,7 @@ and no queries at all from the networks specified in ``bogusnets``.
In addition to network addresses and prefixes, which are matched against
the source address of the DNS request, ACLs may include ``key``
-elements, which specify the name of a TSIG or SIG(0) key.
+elements, which specify the name of a TSIG key.
When BIND 9 is built with GeoIP support, ACLs can also be used for
geographic access restrictions. This is done by specifying an ACL
diff --git a/lib/dns/message.c b/lib/dns/message.c
index 1993b2e..04315bc 100644
--- a/lib/dns/message.c
+++ b/lib/dns/message.c
@@ -3287,109 +3287,24 @@ dns_message_dumpsig(dns_message_t *msg, char *txt1) {
isc_result_t
dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
- isc_buffer_t b, msgb;
+ isc_buffer_t msgb;
REQUIRE(DNS_MESSAGE_VALID(msg));
- if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL) {
+ if (msg->tsigkey == NULL && msg->tsig == NULL) {
return (ISC_R_SUCCESS);
}
INSIST(msg->saved.base != NULL);
isc_buffer_init(&msgb, msg->saved.base, msg->saved.length);
isc_buffer_add(&msgb, msg->saved.length);
- if (msg->tsigkey != NULL || msg->tsig != NULL) {
#ifdef SKAN_MSG_DEBUG
- dns_message_dumpsig(msg, "dns_message_checksig#1");
+ dns_message_dumpsig(msg, "dns_message_checksig#1");
#endif /* ifdef SKAN_MSG_DEBUG */
- if (view != NULL) {
- return (dns_view_checksig(view, &msgb, msg));
- } else {
- return (dns_tsig_verify(&msgb, msg, NULL, NULL));
- }
+ if (view != NULL) {
+ return (dns_view_checksig(view, &msgb, msg));
} else {
- dns_rdata_t rdata = DNS_RDATA_INIT;
- dns_rdata_sig_t sig;
- dns_rdataset_t keyset;
- isc_result_t result;
-
- result = dns_rdataset_first(msg->sig0);
- INSIST(result == ISC_R_SUCCESS);
- dns_rdataset_current(msg->sig0, &rdata);
-
- /*
- * This can occur when the message is a dynamic update, since
- * the rdata length checking is relaxed. This should not
- * happen in a well-formed message, since the SIG(0) is only
- * looked for in the additional section, and the dynamic update
- * meta-records are in the prerequisite and update sections.
- */
- if (rdata.length == 0) {
- return (ISC_R_UNEXPECTEDEND);
- }
-
- result = dns_rdata_tostruct(&rdata, &sig, msg->mctx);
- if (result != ISC_R_SUCCESS) {
- return (result);
- }
-
- dns_rdataset_init(&keyset);
- if (view == NULL) {
- return (DNS_R_KEYUNAUTHORIZED);
- }
- result = dns_view_simplefind(view, &sig.signer,
- dns_rdatatype_key /* SIG(0) */, 0,
- 0, false, &keyset, NULL);
-
- if (result != ISC_R_SUCCESS) {
- /* XXXBEW Should possibly create a fetch here */
- result = DNS_R_KEYUNAUTHORIZED;
- goto freesig;
- } else if (keyset.trust < dns_trust_secure) {
- /* XXXBEW Should call a validator here */
- result = DNS_R_KEYUNAUTHORIZED;
- goto freesig;
- }
- result = dns_rdataset_first(&keyset);
- INSIST(result == ISC_R_SUCCESS);
- for (; result == ISC_R_SUCCESS;
- result = dns_rdataset_next(&keyset)) {
- dst_key_t *key = NULL;
-
- dns_rdata_reset(&rdata);
- dns_rdataset_current(&keyset, &rdata);
- isc_buffer_init(&b, rdata.data, rdata.length);
- isc_buffer_add(&b, rdata.length);
-
- result = dst_key_fromdns(&sig.signer, rdata.rdclass, &b,
- view->mctx, &key);
- if (result != ISC_R_SUCCESS) {
- continue;
- }
- if (dst_key_alg(key) != sig.algorithm ||
- dst_key_id(key) != sig.keyid ||
- !(dst_key_proto(key) == DNS_KEYPROTO_DNSSEC ||
- dst_key_proto(key) == DNS_KEYPROTO_ANY))
- {
- dst_key_free(&key);
- continue;
- }
- result = dns_dnssec_verifymessage(&msgb, msg, key);
- dst_key_free(&key);
- if (result == ISC_R_SUCCESS) {
- break;
- }
- }
- if (result == ISC_R_NOMORE) {
- result = DNS_R_KEYUNAUTHORIZED;
- }
-
- freesig:
- if (dns_rdataset_isassociated(&keyset)) {
- dns_rdataset_disassociate(&keyset);
- }
- dns_rdata_freestruct(&sig);
- return (result);
+ return (dns_tsig_verify(&msgb, msg, NULL, NULL));
}
}
diff --git a/lib/ns/client.c b/lib/ns/client.c
index 967e21b..87b8a18 100644
--- a/lib/ns/client.c
+++ b/lib/ns/client.c
@@ -2060,6 +2060,13 @@ ns__client_request(isc_nmhandle_t *handle, isc_result_t eresult,
ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
"request is signed by a nonauthoritative key");
+ } else if (result == DNS_R_NOTVERIFIEDYET &&
+ client->message->sig0 != NULL)
+ {
+ ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
+ NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
+ "request has a SIG(0) signature but its support "
+ "was removed (CVE-2024-1975)");
} else {
char tsigrcode[64];
isc_buffer_t b;
--
2.45.2

@ -1,40 +0,0 @@
From d249889a9c18df7792ca3cd8d97897e4fb5824b5 Mon Sep 17 00:00:00 2001
From: Aram Sargsyan <aram@isc.org>
Date: Wed, 31 Aug 2022 12:30:38 +0000
Subject: [PATCH] Add mctx attach/detach when creating/destroying a memory pool
This should make sure that the memory context is not destroyed
before the memory pool, which is using the context.
(cherry picked from commit e97c3eea954e055634b72c21325d2611e960ee94)
---
lib/isc/mem.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/lib/isc/mem.c b/lib/isc/mem.c
index f84d300..33ece7a 100644
--- a/lib/isc/mem.c
+++ b/lib/isc/mem.c
@@ -1656,7 +1656,8 @@ isc_mempool_create(isc_mem_t *mctx0, size_t size, isc_mempool_t **mpctxp) {
mpctx->common.impmagic = MEMPOOL_MAGIC;
mpctx->common.magic = ISCAPI_MPOOL_MAGIC;
mpctx->lock = NULL;
- mpctx->mctx = mctx;
+ mpctx->mctx = NULL;
+ isc_mem_attach((isc_mem_t *)mctx, (isc_mem_t **)&mpctx->mctx);
/*
* Mempools are stored as a linked list of element.
*/
@@ -1765,7 +1766,8 @@ isc_mempool_destroy(isc_mempool_t **mpctxp) {
mpctx->common.impmagic = 0;
mpctx->common.magic = 0;
- isc_mem_put((isc_mem_t *)mpctx->mctx, mpctx, sizeof(isc__mempool_t));
+ isc_mem_putanddetach((isc_mem_t **)&mpctx->mctx, mpctx,
+ sizeof(isc__mempool_t));
if (lock != NULL) {
UNLOCK(lock);
--
2.43.2

@ -1,66 +0,0 @@
From 103b09187466b2afbff7e204d166d21e2fbb057c Mon Sep 17 00:00:00 2001
From: Petr Mensik <pemensik@redhat.com>
Date: Wed, 21 Feb 2024 11:54:27 +0100
Subject: [PATCH] Downstream specific changes related to KeyTrap
Fix for CVE-2023-50387 introduced new additional thread. But because
isc_hp functions were removed from later bind 9.16 release, their
changes did not contain increase of hazard pointers max thread limit.
To prevent obscure memory corruption increase thread max size.
In addition place at least few INSISTs to check this is catched before
random memory overwrites begins. It would be quite difficult to track
without any check.
---
lib/isc/hp.c | 3 +++
lib/isc/managers.c | 5 +++--
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/lib/isc/hp.c b/lib/isc/hp.c
index 92d160b..5f9bbf7 100644
--- a/lib/isc/hp.c
+++ b/lib/isc/hp.c
@@ -138,6 +138,7 @@ isc_hp_destroy(isc_hp_t *hp) {
void
isc_hp_clear(isc_hp_t *hp) {
+ INSIST(tid() < isc__hp_max_threads);
for (int i = 0; i < hp->max_hps; i++) {
atomic_store_release(&hp->hp[tid()][i], 0);
}
@@ -152,6 +153,7 @@ uintptr_t
isc_hp_protect(isc_hp_t *hp, int ihp, atomic_uintptr_t *atom) {
uintptr_t n = 0;
uintptr_t ret;
+ INSIST(tid() < isc__hp_max_threads);
while ((ret = atomic_load(atom)) != n) {
atomic_store(&hp->hp[tid()][ihp], ret);
n = ret;
@@ -173,6 +175,7 @@ isc_hp_protect_release(isc_hp_t *hp, int ihp, atomic_uintptr_t ptr) {
void
isc_hp_retire(isc_hp_t *hp, uintptr_t ptr) {
+ INSIST(tid() < isc__hp_max_threads);
hp->rl[tid()]->list[hp->rl[tid()]->size++] = ptr;
INSIST(hp->rl[tid()]->size < isc__hp_max_retired);
diff --git a/lib/isc/managers.c b/lib/isc/managers.c
index c39a650..3bdca99 100644
--- a/lib/isc/managers.c
+++ b/lib/isc/managers.c
@@ -25,9 +25,10 @@ isc_managers_create(isc_mem_t *mctx, size_t workers, size_t quantum,
/*
* We have ncpus network threads, ncpus old network threads - make
- * it 4x just to be on the safe side.
+ * it 4x just to be on the safe side. One additional for slow netmgr
+ * thread.
*/
- isc_hp_init(4 * workers);
+ isc_hp_init(5 * workers);
REQUIRE(netmgrp != NULL && *netmgrp == NULL);
isc__netmgr_create(mctx, workers, &netmgr);
--
2.43.2

@ -1,33 +0,0 @@
From 7cc9fd1870e5264abd885ed2c419034945121d0f Mon Sep 17 00:00:00 2001
From: Petr Mensik <pemensik@redhat.com>
Date: Mon, 19 Feb 2024 22:13:52 +0100
Subject: [PATCH] Define variants to empty values
DNSSEC_VARIANT and NAMED_VARIANT are special Red Hat modifications to
allow testing or alternative rebuilds, with support for pkcs11 or sdb.
But undefined value breaks some tests, so define them to empty values.
That means normal build variant.
Required to pass upstream test suite cds test correctly.
---
bin/tests/system/conf.sh.in | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/bin/tests/system/conf.sh.in b/bin/tests/system/conf.sh.in
index 7b2b309..c2d6526 100644
--- a/bin/tests/system/conf.sh.in
+++ b/bin/tests/system/conf.sh.in
@@ -24,6 +24,10 @@ TMPDIR=${TMPDIR:-/tmp}
# This is not the windows build.
CYGWIN=""
+# RH specific, allow variants testing
+: ${DNSSEC_VARIANT:=}
+: ${NAMED_VARIANT:=}
+
# Load common values shared between windows and unix/linux.
. $TOP/bin/tests/system/conf.sh.common
--
2.43.2

@ -1,29 +0,0 @@
From 274463c5b71db87a615694889da23837ba48db9a Mon Sep 17 00:00:00 2001
From: Petr Mensik <pemensik@redhat.com>
Date: Tue, 16 Jul 2024 19:49:26 +0200
Subject: [PATCH] Resolve CVE-2024-4076
6403. [security] qctx-zversion was not being cleared when it should have
been leading to an assertion failure if it needed to be
reused. (CVE-2024-4076) [GL #4507]
Resolves: CVE-2024-4076
---
lib/ns/query.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/ns/query.c b/lib/ns/query.c
index 537d332..be4cbb6 100644
--- a/lib/ns/query.c
+++ b/lib/ns/query.c
@@ -5325,6 +5325,7 @@ qctx_freedata(query_ctx_t *qctx) {
ns_client_releasename(qctx->client, &qctx->zfname);
dns_db_detachnode(qctx->zdb, &qctx->znode);
dns_db_detach(&qctx->zdb);
+ qctx->zversion = NULL;
}
if (qctx->event != NULL && !qctx->client->nodetach) {
--
2.45.2

@ -33,9 +33,6 @@
%{_libdir}/bind %{_libdir}/named %{_datadir}/GeoIP /proc/sys/net/ipv4
%global selinuxbooleans named_write_master_zones=1
# BIND 9.16 does not work with fortify 3 level, make builds work on Fedora
%global _fortify_level 2
## The order of libs is important. See lib/Makefile.in for details
%define bind_export_libs isc dns isccfg irs
%{!?_export_dir:%global _export_dir /bind9-export/}
@ -54,7 +51,7 @@ Summary: The Berkeley Internet Name Domain (BIND) DNS (Domain Name System) serv
Name: bind
License: MPLv2.0
Version: 9.16.23
Release: 18%{?dist}.6
Release: 15%{?dist}
Epoch: 32
Url: https://www.isc.org/downloads/bind/
#
@ -138,41 +135,6 @@ Patch191: bind-9.16-CVE-2023-2911-3.patch
Patch192: bind-9.16-CVE-2023-3341.patch
# https://gitlab.isc.org/isc-projects/bind9/commit/8924adca613ca9daea63786563cce6fdbd742c56
Patch193: bind-9.16-update-b.root-servers.net.patch
Patch194: bind-9.16-CVE-2023-4408.patch
Patch195: bind-9.16-CVE-2023-5517.patch
Patch196: bind-9.16-CVE-2023-5679.patch
Patch197: bind-9.16-CVE-2023-6516.patch
Patch198: bind-9.16-CVE-2023-50387.patch
# https://gitlab.isc.org/isc-projects/bind9/commit/f493a8394102b0aeb101d5dc2f963004c8741175
Patch199: bind-9.16-CVE-2023-4408-test1.patch
# https://gitlab.isc.org/isc-projects/bind9/commit/b9c10a194da3358204f5ba7d91e55332db435614
Patch200: bind-9.16-CVE-2023-4408-test2.patch
# Downstream only change, fixes patch 171
Patch201: bind-9.16-system-test-cds.patch
# https://gitlab.isc.org/isc-projects/bind9/commit/32779aba8a0a5f852c611f44ecbeab5aab633e34
Patch202: bind-9.16-isc-mempool-attach.patch
# Downstream only change, complements patch 198
Patch203: bind-9.16-isc_hp-CVE-2023-50387.patch
# https://gitlab.isc.org/isc-projects/bind9/commit/1237d73cd1120b146ee699bbae7b2fe837cf2f98
Patch204: bind-9.16-CVE-2023-6516-test.patch
Patch205: bind-9.16-CVE-2024-1975.patch
# https://gitlab.isc.org/isc-projects/bind9/commit/26c9da5f2857b72077c17e06ac79f068c63782cc
# https://gitlab.isc.org/isc-projects/bind9/commit/c5ebda6deb0997dc520b26fa0639891459de5cb6
# https://gitlab.isc.org/isc-projects/bind9/commit/d56d2a32b861e81c2aaaabd309c4c58b629ede32
# https://gitlab.isc.org/isc-projects/bind9/commit/dfcadc2085c8844b5836aff2b5ea51fb60c34868
# https://gitlab.isc.org/isc-projects/bind9/commit/fdabf4b9570a60688f9f7d1e88d885f7a3718bca
# https://gitlab.isc.org/isc-projects/bind9/commit/8ef414a7f38a04cfc11df44adaedaf3126fa3878
Patch206: bind-9.16-CVE-2024-1737.patch
# https://gitlab.isc.org/isc-projects/bind9/commit/a61be8eef0ee0ca8fd8036ccb61c6f9b728158ce
Patch207: bind-9.18-CVE-2024-4076.patch
# https://gitlab.isc.org/isc-projects/bind9/commit/2f2f0a900b9baf5e6eba02a82e2fe9e967dc1760
Patch209: bind-9.16-CVE-2024-1737-records.patch
Patch210: bind-9.16-CVE-2024-1737-records-test.patch
# https://gitlab.isc.org/isc-projects/bind9/commit/3f1826f2f78792e95f56da7af3a35c46b4d6d9af
Patch211: bind-9.16-CVE-2024-1737-types.patch
Patch212: bind-9.16-CVE-2024-1737-types-test.patch
# backport issue fix
Patch213: bind-9.16-CVE-2024-1737-records-test2.patch
%{?systemd_ordering}
Requires: coreutils
@ -212,7 +174,6 @@ BuildRequires: softhsm
%if %{with SYSTEMTEST}
# bin/tests/system dependencies
BuildRequires: perl(Net::DNS) perl(Net::DNS::Nameserver) perl(Time::HiRes) perl(Getopt::Long)
BuildRequires: python-dns
# manual configuration requires this tool
BuildRequires: iproute
%endif
@ -495,25 +456,6 @@ in HTML and PDF format.
%patch191 -p1 -b .CVE-2023-2911-3
%patch192 -p1 -b .CVE-2023-3341
%patch193 -p1 -b .b.root-servers.net
%patch194 -p1 -b .CVE-2023-4408
%patch195 -p1 -b .CVE-2023-5517
%patch196 -p1 -b .CVE-2023-5679
%patch197 -p1 -b .CVE-2023-6516
%patch198 -p1 -b .CVE-2023-50387
%patch199 -p1
%patch200 -p1
%patch201 -p1 -b .test-variant-def
%patch202 -p1 -b .mempool-attach
%patch203 -p1 -b .isc_hp-CVE-2023-50387
%patch204 -p1 -b .CVE-2023-6516-test
%patch205 -p1 -b .CVE-2024-1975
%patch206 -p1 -b .CVE-2024-1737
%patch207 -p1 -b .CVE-2024-4076
%patch209 -p1 -b .CVE-2024-1737-records
%patch210 -p1 -b .CVE-2024-1737-records-test
%patch211 -p1 -b .CVE-2024-1737-types
%patch212 -p1 -b .CVE-2024-1737-types-test
%patch213 -p1 -b .CVE-2024-1737-records-test2
%if %{with PKCS11}
%patch135 -p1 -b .config-pkcs11
@ -614,11 +556,6 @@ export LIBDIR_SUFFIX
--enable-fixed-rrset \
--enable-full-report \
;
%if 0%{?bind_skip_parsetab}
sed -e 's/^TARGETS =/& #/' -i bin/python/isc/Makefile
%endif
%if %{with DNSTAP}
pushd lib
SRCLIB="../../../lib"
@ -1242,39 +1179,6 @@ fi;
%endif
%changelog
* Fri Aug 09 2024 Petr Menšík <pemensik@redhat.com> - 32:9.16.23-18.6
- Minor fix of reclimit test backport (CVE-2024-1737)
* Wed Aug 07 2024 Petr Menšík <pemensik@redhat.com> - 32:9.16.23-18.5
- Backport addition of max-records-per-type and max-records-per-type options
* Thu Jul 18 2024 Petr Menšík <pemensik@redhat.com> - 32:9.16.23-18.2
- Resolve CVE-2024-1975
- Resolve CVE-2024-1737
- Resolve CVE-2024-4076
- Add ability to change runtime limits for max types and records per name
* Mon Mar 25 2024 Petr Menšík <pemensik@redhat.com> - 32:9.16.23-18.1
- Rebuild with correct z-stream tag again
* Mon Mar 25 2024 Petr Menšík <pemensik@redhat.com> - 32:9.16.23-18
- Prevent crashing at masterformat system test (CVE-2023-6516)
* Mon Feb 19 2024 Petr Menšík <pemensik@redhat.com> - 32:9.16.23-17
- Import tests for large DNS messages fix
- Add downstream change complementing CVE-2023-50387
* Mon Feb 12 2024 Petr Menšík <pemensik@redhat.com> - 32:9.16.23-16
- Prevent increased CPU load on large DNS messages (CVE-2023-4408)
- Prevent assertion failure when nxdomain-redirect is used with
RFC 1918 reverse zones (CVE-2023-5517)
- Prevent assertion failure if DNS64 and serve-stale is used (CVE-2023-5679)
- Specific recursive query patterns may lead to an out-of-memory
condition (CVE-2023-6516)
- Prevent increased CPU consumption in DNSSEC validator (CVE-2023-50387
CVE-2023-50868)
* Thu Dec 07 2023 Petr Menšík <pemensik@redhat.com> - 32:9.16.23-15
- Update addresses of b.root-servers.net (RHEL-18188)

Loading…
Cancel
Save