bind/bind-9.16-CVE-2024-1737.patch
Fedor Vorobev cf01b2a08d Fix masterformat, reclimit, and resolver tests
Some file changes were completely missing in the cherry-picks
of CVE-2024-1737 upstream test changes, as well as older backports
causing issues with the new version of bind.

Resolves: RHEL-6454
2026-07-07 14:38:41 +02:00

361 lines
13 KiB
Diff

From aed0e33be79d1d1b133208846d943503c4f2e6a8 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 | 83 +++++++++++++++++++++++++++++-
lib/dns/rdataslab.c | 12 +++++
lib/dns/zone.c | 13 -----
6 files changed, 100 insertions(+), 21 deletions(-)
diff --git a/bin/tests/system/resolver/tests.sh b/bin/tests/system/resolver/tests.sh
index fc05635e31..09fff0dd13 100755
--- a/bin/tests/system/resolver/tests.sh
+++ b/bin/tests/system/resolver/tests.sh
@@ -596,18 +596,17 @@ n=$((n + 1))
echo_i "check prefetch qtype * (${n})"
ret=0
dig_with_opts @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_with_opts @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 prefetch occurred;
-# note that only one record is prefetched, which is the AAAA record in this case,
+# note that only the first record is prefetched,
# because of the order of the records in the cache
dig_with_opts @10.53.0.5 fetchall.tld any >dig.out.3.${n} || ret=1
-ttl3=$(awk '/::1/ { print $2 }' dig.out.3.${n})
+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=$((status + ret))
diff --git a/configure b/configure
index 1b436d63eb..835cd94dff 100755
--- a/configure
+++ b/configure
@@ -12341,7 +12341,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 fb6f172eae..6db42501a2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -96,7 +96,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 3f06545aa1..d4c1829c26 100644
--- a/lib/dns/rbtdb.c
+++ b/lib/dns/rbtdb.c
@@ -990,6 +990,8 @@ prio_type(rbtdb_rdatatype_t type) {
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:
@@ -1002,6 +1004,22 @@ prio_type(rbtdb_rdatatype_t type) {
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);
@@ -6240,6 +6258,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.
*/
@@ -6251,7 +6293,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;
+ rdatasetheader_t *prioheader = NULL, *expireheader = NULL;
unsigned char *merged = NULL;
isc_result_t result;
bool header_nx;
@@ -6261,6 +6303,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.
@@ -6336,6 +6379,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename,
{
if (topheader->type == sigtype) {
sigheader = topheader;
+ break;
}
}
negtype = RBTDB_RDATATYPE_VALUE(covers, 0);
@@ -6398,6 +6442,12 @@ 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_type(topheader->type)) {
prioheader = topheader;
}
@@ -6755,6 +6805,12 @@ find_header:
/*
* No rdatasets of the given type exist at the node.
*/
+ if (!IS_CACHE(rbtdb) && overmaxtype(rbtdb, ntypes)) {
+ free_rdataset(rbtdb, rbtdb->common.mctx,
+ newheader);
+ return (ISC_R_QUOTA);
+ }
+
newheader->down = NULL;
if (prio_type(newheader->type)) {
@@ -6770,6 +6826,31 @@ find_header:
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 14c43818b8..d74e84ce4a 100644
--- a/lib/dns/rdataslab.c
+++ b/lib/dns/rdataslab.c
@@ -112,6 +112,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) {
@@ -156,6 +160,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);
}
@@ -524,6 +532,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 */
diff --git a/lib/dns/zone.c b/lib/dns/zone.c
index b457095907..53da95a7d7 100644
--- a/lib/dns/zone.c
+++ b/lib/dns/zone.c
@@ -2316,19 +2316,6 @@ zone_load(dns_zone_t *zone, unsigned int flags, bool locked) {
isc_result_totext(result));
goto cleanup;
}
- dns_db_settask(db, zone->task, zone->task);
-
- if (zone->type == dns_zone_primary ||
- zone->type == dns_zone_secondary || zone->type == dns_zone_mirror)
- {
- result = dns_db_setgluecachestats(db, zone->gluecachestats);
- if (result == ISC_R_NOTIMPLEMENTED) {
- result = ISC_R_SUCCESS;
- }
- if (result != ISC_R_SUCCESS) {
- goto cleanup;
- }
- }
if (!dns_db_ispersistent(db)) {
if (zone->masterfile != NULL) {
--
2.53.0