From dfcadc2085c8844b5836aff2b5ea51fb60c34868 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= <ondrej@isc.org>
Date: Wed, 29 May 2024 08:43:39 +0200
Subject: [PATCH 2/3] 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>
 
Conflict:Context Adaptation
Reference:https://gitlab.isc.org/isc-projects/bind9/-/commit/5360c90612abf51deb4a80b30e1da84fd61212a5
 
---
 bind/bind-9.11.36/configure       |  2 +-
 bind/bind-9.11.36/configure.ac    |  2 +-
 bind/bind-9.11.36/lib/dns/rbtdb.c | 17 +++++++++++++++++
 3 files changed, 19 insertions(+), 2 deletions(-)
 
diff --git a/bind/bind-9.11.36/configure b/bind/bind-9.11.36/configure
index 736ff49..8e881e3 100755
--- a/bind/bind-9.11.36/configure
+++ b/bind/bind-9.11.36/configure
@@ -12185,7 +12185,7 @@ fi
 XTARGETS=
 case "$enable_developer" in
 yes)
-	STD_CDEFINES="$STD_CDEFINES -DISC_LIST_CHECKINIT=1 -DDNS_RDATASET_MAX_RECORDS=5000"
+	STD_CDEFINES="$STD_CDEFINES -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 "${enable_filter_aaaa+set}" = set || enable_filter_aaaa=yes
diff --git a/bind/bind-9.11.36/configure.ac b/bind/bind-9.11.36/configure.ac
index cc36b6c..0eab441 100644
--- a/bind/bind-9.11.36/configure.ac
+++ b/bind/bind-9.11.36/configure.ac
@@ -100,7 +100,7 @@ AC_ARG_ENABLE(developer,
 XTARGETS=
 case "$enable_developer" in
 yes)
-	STD_CDEFINES="$STD_CDEFINES -DISC_LIST_CHECKINIT=1 -DDNS_RDATASET_MAX_RECORDS=5000"
+	STD_CDEFINES="$STD_CDEFINES -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 "${enable_filter_aaaa+set}" = set || enable_filter_aaaa=yes
diff --git a/bind/bind-9.11.36/lib/dns/rbtdb.c b/bind/bind-9.11.36/lib/dns/rbtdb.c
index 3d76ca1..0cfef36 100644
--- a/bind/bind-9.11.36/lib/dns/rbtdb.c
+++ b/bind/bind-9.11.36/lib/dns/rbtdb.c
@@ -6190,6 +6190,10 @@ update_recordsandbytes(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 */
+
 /*
  * write lock on rbtnode must be held.
  */
@@ -6210,6 +6214,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
 	rbtdb_rdatatype_t negtype, sigtype;
 	dns_trust_t trust;
 	int idx;
+	uint32_t ntypes;
 
 	/*
 	 * Add an rdatasetheader_t to a node.
@@ -6272,6 +6277,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
 					set_ttl(rbtdb, topheader, 0);
 					mark_stale_header(rbtdb, topheader);
 				}
+				ntypes = 0;
 				goto find_header;
 			}
 			/*
@@ -6293,9 +6299,11 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
 			 * check for an extant non-stale NODATA ncache
 			 * entry which covers the same type as the RRSIG.
 			 */
+			ntypes = 0;
 			for (topheader = rbtnode->data;
 			     topheader != NULL;
 			     topheader = topheader->next) {
+				ntypes++;
 				if ((topheader->type ==
 					RBTDB_RDATATYPE_NCACHEANY) ||
 					(newheader->type == sigtype &&
@@ -6339,9 +6347,11 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
 		}
 	}
 
+	ntypes = 0;
 	for (topheader = rbtnode->data;
 	     topheader != NULL;
 	     topheader = topheader->next) {
+		ntypes++;
 		if (prio_type(topheader->type)) {
 			prioheader = topheader;
 		}
@@ -6700,6 +6710,13 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
 			/*
 			 * No rdatasets of the given type exist at the node.
 			 */
+
+			if (ntypes > DNS_RBTDB_MAX_RTYPES) {
+				free_rdataset(rbtdb, rbtdb->common.mctx,
+					      newheader);
+				return (ISC_R_QUOTA);
+			}
+
 			newheader->down = NULL;
 
 			if (prio_type(newheader->type)) {
-- 
2.33.0

