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=dfcadc2085c8844b5836aff2b5ea51fb60c34868;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= --- diff --git a/configure b/configure index 30e65f1568d..835cd94dff7 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 -DDNS_RDATASET_MAX_RECORDS=5000" + 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 ffe087e6d7b..6db42501a24 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 -DDNS_RDATASET_MAX_RECORDS=5000" + [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 3f06545aa1e..b35e101b016 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -6240,6 +6240,10 @@ 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 */ + /* * write lock on rbtnode must be held. */ @@ -6261,6 +6265,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; /* * Add an rdatasetheader_t to a node. @@ -6325,6 +6330,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename, set_ttl(rbtdb, topheader, 0); mark_header_ancient(rbtdb, topheader); } + ntypes = 0; goto find_header; } /* @@ -6348,9 +6354,11 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename, * check for an extant non-ancient 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 && @@ -6395,9 +6403,11 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename, } } + ntypes = 0; for (topheader = rbtnode->data; topheader != NULL; topheader = topheader->next) { + ntypes++; if (prio_type(topheader->type)) { prioheader = topheader; } @@ -6755,6 +6765,13 @@ find_header: /* * 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)) {