From: Ondřej Surý Date: Wed, 29 May 2024 06:43:39 +0000 (+0200) Subject: Add a limit to the number of RR types for single name X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3f10d6eff035702796ba82cd28b9f7cf9836e743;p=thirdparty%2Fbind9.git 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= (cherry picked from commit 538b843d84f49ba5125ff545e3d0cf1c8434a8f2) --- diff --git a/configure b/configure index 76de61f49a7..9174ad8e352 100755 --- a/configure +++ b/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/configure.ac b/configure.ac index be37b9f6313..fdbc160a1ba 100644 --- a/configure.ac +++ b/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/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index abe2d9b49c3..c83d5dcf1de 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -6200,6 +6200,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. */ @@ -6220,6 +6224,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. @@ -6282,6 +6287,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; } /* @@ -6303,9 +6309,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 && @@ -6349,9 +6357,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; } @@ -6710,6 +6720,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)) {