File bind-9.16.6-CVE-2024-11187.patch of Package bind.37308

commit d6672b00793ac84ea905d8755bb15fd883a72c00
Author: Nicki Křížek <nicki@isc.org>
Date:   Mon Jan 20 16:17:08 2025 +0000

    [9.16] [CVE-2024-11187] sec: usr: Limit the additional processing for large RDATA sets
    
    When answering queries, don't add data to the additional section if the answer has more than 13 names in the RDATA. This limits the number of lookups into the database(s) during a single client query, reducing query processing load.
    
    Backport of MR !750
    
    See isc-projects/bind9#5034
    
    Merge branch '5034-security-limit-additional-9.16' into 'bind-9.16-release'
    
    See merge request isc-private/bind9!760

diff --git a/bin/tests/system/additional/tests.sh b/bin/tests/system/additional/tests.sh
index 51c09fc99d..ab18644234 100644
--- a/bin/tests/system/additional/tests.sh
+++ b/bin/tests/system/additional/tests.sh
@@ -259,10 +259,11 @@ dotests
 n=`expr $n + 1`
 echo_i "testing with 'minimal-any no;' ($n)"
 ret=0
-$DIG $DIGOPTS -t ANY www.rt.example @10.53.0.1 > dig.out.$n || ret=1
-grep "ANSWER: 3, AUTHORITY: 2, ADDITIONAL: 2" dig.out.$n > /dev/null || ret=1
-if [ $ret -eq 1 ] ; then
-    echo_i "failed"; status=$((status+1))
+$DIG $DIGOPTS -t ANY www.rt.example @10.53.0.1 >dig.out.$n || ret=1
+grep "ANSWER: 3, AUTHORITY: 2, ADDITIONAL: 1" dig.out.$n >/dev/null || ret=1
+if [ $ret -eq 1 ]; then
+  echo_i "failed"
+  status=$((status + 1))
 fi
 
 echo_i "reconfiguring server: minimal-any yes"
diff --git a/bin/tests/system/resolver/ns4/named.noaa b/bin/tests/system/resolver/ns4/named.noaa
deleted file mode 100644
index 0f215fcdc2..0000000000
--- a/bin/tests/system/resolver/ns4/named.noaa
+++ /dev/null
@@ -1,5 +0,0 @@
-Copyright (C) Internet Systems Consortium, Inc. ("ISC")
-
-See COPYRIGHT in the source root or http://isc.org/copyright.html for terms.
-
-Add -T noaa.
diff --git a/bin/tests/system/resolver/tests.sh b/bin/tests/system/resolver/tests.sh
index 2692b22c30..1cb6f91dab 100755
--- a/bin/tests/system/resolver/tests.sh
+++ b/bin/tests/system/resolver/tests.sh
@@ -290,7 +290,11 @@ done
 if [ $ret != 0 ]; then echo_i "failed"; fi
 status=`expr $status + $ret`
 
-n=`expr $n + 1`
+stop_server ns4
+touch ns4/named.noaa
+start_server --noclean --restart --port ${PORT} ns4 || ret=1
+
+n=$((n + 1))
 echo_i "RT21594 regression test check setup ($n)"
 ret=0
 # Check that "aa" is not being set by the authoritative server.
@@ -326,7 +330,11 @@ grep "status: NXDOMAIN" dig.ns5.out.${n} > /dev/null || ret=1
 if [ $ret != 0 ]; then echo_i "failed"; fi
 status=`expr $status + $ret`
 
-n=`expr $n + 1`
+stop_server ns4
+rm ns4/named.noaa
+start_server --noclean --restart --port ${PORT} ns4 || ret=1
+
+n=$((n + 1))
 echo_i "check that replacement of additional data by a negative cache no data entry clears the additional RRSIGs ($n)"
 ret=0
 $DIG $DIGOPTS +tcp mx example.net @10.53.0.7 > dig.ns7.out.${n} || ret=1
diff --git a/lib/dns/include/dns/rdataset.h b/lib/dns/include/dns/rdataset.h
index 05877f77c7..f4fdc198a5 100644
--- a/lib/dns/include/dns/rdataset.h
+++ b/lib/dns/include/dns/rdataset.h
@@ -53,6 +53,8 @@
 #include <dns/rdatastruct.h>
 #include <dns/types.h>
 
+#define DNS_RDATASET_MAXADDITIONAL 13
+
 ISC_LANG_BEGINDECLS
 
 typedef enum {
@@ -439,8 +441,9 @@ dns_rdataset_towirepartial(dns_rdataset_t *  rdataset,
  */
 
 isc_result_t
-dns_rdataset_additionaldata(dns_rdataset_t *	     rdataset,
-			    dns_additionaldatafunc_t add, void *arg);
+dns_rdataset_additionaldata(dns_rdataset_t	    *rdataset,
+			    dns_additionaldatafunc_t add, void *arg,
+			    size_t limit);
 /*%<
  * For each rdata in rdataset, call 'add' for each name and type in the
  * rdata which is subject to additional section processing.
@@ -459,10 +462,15 @@ dns_rdataset_additionaldata(dns_rdataset_t *	     rdataset,
  *\li	If a call to dns_rdata_additionaldata() is not successful, the
  *	result returned will be the result of dns_rdataset_additionaldata().
  *
+ *\li	If 'limit' is non-zero and the number of the rdatasets is larger
+ *	than 'limit', no additional data will be processed.
+ *
  * Returns:
  *
  *\li	#ISC_R_SUCCESS
  *
+ *\li	#DNS_R_TOOMANYRECORDS in case rdataset count is larger than 'limit'
+ *
  *\li	Any error that dns_rdata_additionaldata() can return.
  */
 
diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c
index 1f1bcc58b1..6933ca933c 100644
--- a/lib/dns/rbtdb.c
+++ b/lib/dns/rbtdb.c
@@ -10639,7 +10639,7 @@ no_glue:
 		      rbtversion->glue_table_size;
 	}
 
-	(void)dns_rdataset_additionaldata(rdataset, glue_nsdname_cb, &ctx);
+	(void)dns_rdataset_additionaldata(rdataset, glue_nsdname_cb, &ctx, 0);
 
 	cur = isc_mem_get(rbtdb->common.mctx, sizeof(*cur));
 
diff --git a/lib/dns/rdataset.c b/lib/dns/rdataset.c
index 8f44568a39..e9c3ec58c2 100644
--- a/lib/dns/rdataset.c
+++ b/lib/dns/rdataset.c
@@ -27,6 +27,7 @@
 #include <dns/ncache.h>
 #include <dns/rdata.h>
 #include <dns/rdataset.h>
+#include <dns/result.h>
 
 static const char *trustnames[] = {
 	"none",		  "pending-additional",
@@ -576,7 +577,8 @@ dns_rdataset_towire(dns_rdataset_t *rdataset, const dns_name_t *owner_name,
 
 isc_result_t
 dns_rdataset_additionaldata(dns_rdataset_t *rdataset,
-			    dns_additionaldatafunc_t add, void *arg) {
+			    dns_additionaldatafunc_t add, void *arg,
+			    size_t limit) {
 	dns_rdata_t rdata = DNS_RDATA_INIT;
 	isc_result_t result;
 
@@ -588,6 +590,10 @@ dns_rdataset_additionaldata(dns_rdataset_t *rdataset,
 	REQUIRE(DNS_RDATASET_VALID(rdataset));
 	REQUIRE((rdataset->attributes & DNS_RDATASETATTR_QUESTION) == 0);
 
+	if (limit != 0 && dns_rdataset_count(rdataset) > limit) {
+		return (DNS_R_TOOMANYRECORDS);
+	}
+
 	result = dns_rdataset_first(rdataset);
 	if (result != ISC_R_SUCCESS) {
 		return (result);
diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c
index 183552dc49..e6e317671f 100644
--- a/lib/dns/resolver.c
+++ b/lib/dns/resolver.c
@@ -8739,8 +8739,7 @@ rctx_answer_any(respctx_t *rctx) {
 		rdataset->attributes |= DNS_RDATASETATTR_CACHE;
 		rdataset->trust = rctx->trust;
 
-		(void)dns_rdataset_additionaldata(rdataset, check_related,
-						  fctx);
+		(void)dns_rdataset_additionaldata(rdataset, check_related, fctx, 0);
 	}
 
 	return (ISC_R_SUCCESS);
@@ -8787,7 +8786,7 @@ rctx_answer_match(respctx_t *rctx) {
 	rctx->ardataset->attributes |= DNS_RDATASETATTR_ANSWER;
 	rctx->ardataset->attributes |= DNS_RDATASETATTR_CACHE;
 	rctx->ardataset->trust = rctx->trust;
-	(void)dns_rdataset_additionaldata(rctx->ardataset, check_related, fctx);
+	(void)dns_rdataset_additionaldata(rctx->ardataset, check_related, fctx, 0);
 
 	for (sigrdataset = ISC_LIST_HEAD(rctx->aname->list);
 	     sigrdataset != NULL;
@@ -8992,7 +8991,7 @@ rctx_authority_positive(respctx_t *rctx) {
 					 * to this rdataset.
 					 */
 					(void)dns_rdataset_additionaldata(
-						rdataset, check_related, fctx);
+						rdataset, check_related, fctx, 0);
 					done = true;
 				}
 			}
@@ -9493,8 +9492,10 @@ rctx_referral(respctx_t *rctx) {
 	 */
 	INSIST(rctx->ns_rdataset != NULL);
 	FCTX_ATTR_SET(fctx, FCTX_ATTR_GLUING);
-	(void)dns_rdataset_additionaldata(rctx->ns_rdataset, check_related,
-					  fctx);
+	/*
+	 * Mark the glue records in the additional section to be cached.
+	 */
+	(void)dns_rdataset_additionaldata(rctx->ns_rdataset, check_related, fctx, 0);
 #if CHECK_FOR_GLUE_IN_ANSWER
 	/*
 	 * Look in the answer section for "glue" that is incorrectly
@@ -9507,7 +9508,7 @@ rctx_referral(respctx_t *rctx) {
 	    (fctx->type == dns_rdatatype_aaaa || fctx->type == dns_rdatatype_a))
 	{
 		(void)dns_rdataset_additionaldata(rctx->ns_rdataset,
-						  check_answer, fctx);
+						  check_answer, fctx, 0);
 	}
 #endif /* if CHECK_FOR_GLUE_IN_ANSWER */
 	FCTX_ATTR_CLR(fctx, FCTX_ATTR_GLUING);
@@ -9618,7 +9619,7 @@ again:
 			if (CHASE(rdataset)) {
 				rdataset->attributes &= ~DNS_RDATASETATTR_CHASE;
 				(void)dns_rdataset_additionaldata(
-					rdataset, check_related, fctx);
+					rdataset, check_related, fctx, 0);
 				rescan = true;
 			}
 		}
diff --git a/lib/ns/query.c b/lib/ns/query.c
index b2b9b935e4..9825d0f488 100644
--- a/lib/ns/query.c
+++ b/lib/ns/query.c
@@ -2022,7 +2022,8 @@ addname:
 		 * as well.
 		 */
 		eresult = dns_rdataset_additionaldata(
-			trdataset, query_additional_cb, qctx);
+			trdataset, query_additional_cb, qctx,
+			DNS_RDATASET_MAXADDITIONAL);
 	}
 
 cleanup:
@@ -2113,7 +2114,8 @@ regular:
 	 * Add other additional data if needed.
 	 * We don't care if dns_rdataset_additionaldata() fails.
 	 */
-	(void)dns_rdataset_additionaldata(rdataset, query_additional_cb, qctx);
+	(void)dns_rdataset_additionaldata(rdataset, query_additional_cb, qctx,
+					  DNS_RDATASET_MAXADDITIONAL);
 	CTRACE(ISC_LOG_DEBUG(3), "query_additional: done");
 }
 
@@ -2139,7 +2141,8 @@ query_addrrset(query_ctx_t *qctx, dns_name_t **namep,
 	 * To the current response for 'client', add the answer RRset
 	 * '*rdatasetp' and an optional signature set '*sigrdatasetp', with
 	 * owner name '*namep', to section 'section', unless they are
-	 * already there.  Also add any pertinent additional data.
+	 * already there.  Also add any pertinent additional data, unless
+	 * the query was for type ANY.
 	 *
 	 * If 'dbuf' is not NULL, then '*namep' is the name whose data is
 	 * stored in 'dbuf'.  In this case, query_addrrset() guarantees that
@@ -2190,7 +2193,9 @@ query_addrrset(query_ctx_t *qctx, dns_name_t **namep,
 	 */
 	query_addtoname(mname, rdataset);
 	query_setorder(qctx, mname, rdataset);
-	query_additional(qctx, rdataset);
+	if (qctx->qtype != dns_rdatatype_any) {
+		query_additional(qctx, rdataset);
+	}
 
 	/*
 	 * Note: we only add SIGs if we've added the type they cover, so
openSUSE Build Service is sponsored by