File bind-9.11-CVE-2024-11187.patch of Package bind.37287
commit bc748d21378fbe3e8314dec9efbd365c0de563df
Author: Nicki Křížek <nicki@isc.org>
Date: Mon Jan 20 16:17:36 2025 +0000
[9.11] [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.11' into 'bind-9.11-release'
See merge request isc-private/bind9!761
diff --git a/bin/named/query.c b/bin/named/query.c
index 61894283a6..b39e93bbf9 100644
--- a/bin/named/query.c
+++ b/bin/named/query.c
@@ -1803,7 +1803,8 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
*/
eresult = dns_rdataset_additionaldata(trdataset,
query_addadditional,
- client);
+ client,
+ DNS_RDATASET_MAXADDITIONAL);
}
cleanup:
@@ -2398,7 +2399,7 @@ query_addrdataset(ns_client_t *client, dns_name_t *fname,
rdataset->rdclass);
rdataset->attributes |= DNS_RDATASETATTR_LOADORDER;
- if (NOADDITIONAL(client))
+ if (NOADDITIONAL(client) || client->query.qtype == dns_rdatatype_any)
return;
/*
@@ -2409,7 +2410,8 @@ query_addrdataset(ns_client_t *client, dns_name_t *fname,
additionalctx.client = client;
additionalctx.rdataset = rdataset;
(void)dns_rdataset_additionaldata(rdataset, query_addadditional2,
- &additionalctx);
+ &additionalctx,
+ DNS_RDATASET_MAXADDITIONAL);
CTRACE(ISC_LOG_DEBUG(3), "query_addrdataset: done");
}
diff --git a/bin/tests/system/additional/tests.sh b/bin/tests/system/additional/tests.sh
index 1353f1210c..cbf9f353a0 100644
--- a/bin/tests/system/additional/tests.sh
+++ b/bin/tests/system/additional/tests.sh
@@ -261,7 +261,7 @@ 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: 1, ADDITIONAL: 2" dig.out.$n > /dev/null || ret=1
+grep "ANSWER: 3, AUTHORITY: 1, ADDITIONAL: 1" dig.out.$n > /dev/null || ret=1
if [ $ret -eq 1 ] ; then
echo_i "failed"; status=`expr status + 1`
fi
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 9ca70dae0c..8e0369a94a 100755
--- a/bin/tests/system/resolver/tests.sh
+++ b/bin/tests/system/resolver/tests.sh
@@ -282,6 +282,10 @@ done
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
+$PERL $SYSTEMTESTTOP/stop.pl resolver ns4
+touch ns4/named.noaa
+$PERL $SYSTEMTESTTOP/start.pl --noclean --restart --port ${PORT} resolver ns4 || ret=1
+
n=`expr $n + 1`
echo_i "RT21594 regression test check setup ($n)"
ret=0
@@ -318,6 +322,10 @@ grep "status: NXDOMAIN" dig.ns5.out.${n} > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
+$PERL $SYSTEMTESTTOP/stop.pl resolver ns4
+rm ns4/named.noaa
+$PERL $SYSTEMTESTTOP/start.pl --noclean --restart --port ${PORT} resolver ns4 || ret=1
+
n=`expr $n + 1`
echo_i "check that replacement of additional data by a negative cache no data entry clears the additional RRSIGs ($n)"
ret=0
diff --git a/lib/dns/include/dns/rdataset.h b/lib/dns/include/dns/rdataset.h
index 5295d8e4d7..50995da2d3 100644
--- a/lib/dns/include/dns/rdataset.h
+++ b/lib/dns/include/dns/rdataset.h
@@ -53,6 +53,8 @@
#include <dns/types.h>
#include <dns/rdatastruct.h>
+#define DNS_RDATASET_MAXADDITIONAL 13
+
ISC_LANG_BEGINDECLS
typedef enum {
@@ -471,7 +473,8 @@ dns_rdataset_towirepartial(dns_rdataset_t *rdataset,
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);
/*%<
* For each rdata in rdataset, call 'add' for each name and type in the
* rdata which is subject to additional section processing.
@@ -490,10 +493,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/rdataset.c b/lib/dns/rdataset.c
index a2ac36f839..43651b006c 100644
--- a/lib/dns/rdataset.c
+++ b/lib/dns/rdataset.c
@@ -28,6 +28,7 @@
#include <dns/ncache.h>
#include <dns/rdata.h>
#include <dns/rdataset.h>
+#include <dns/result.h>
static const char *trustnames[] = {
"none",
@@ -607,7 +608,8 @@ dns_rdataset_towire(dns_rdataset_t *rdataset,
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;
@@ -620,6 +622,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 0fccdd2174..c7cb854eba 100644
--- a/lib/dns/resolver.c
+++ b/lib/dns/resolver.c
@@ -6415,7 +6415,7 @@ chase_additional(fetchctx_t *fctx) {
rdataset->attributes &= ~DNS_RDATASETATTR_CHASE;
(void)dns_rdataset_additionaldata(rdataset,
check_related,
- fctx);
+ fctx, 0);
rescan = true;
}
}
@@ -7049,8 +7049,11 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
*/
INSIST(ns_rdataset != NULL);
FCTX_ATTR_SET(fctx, FCTX_ATTR_GLUING);
+ /*
+ * Mark the glue records in the additional section to be cached.
+ */
(void)dns_rdataset_additionaldata(ns_rdataset, check_related,
- fctx);
+ fctx, 0);
#if CHECK_FOR_GLUE_IN_ANSWER
/*
* Look in the answer section for "glue" that is incorrectly
@@ -7063,7 +7066,7 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
(fctx->type == dns_rdatatype_aaaa ||
fctx->type == dns_rdatatype_a))
(void)dns_rdataset_additionaldata(ns_rdataset,
- check_answer, fctx);
+ check_answer, fctx, 0);
#endif
FCTX_ATTR_CLR(fctx, FCTX_ATTR_GLUING);
/*
@@ -7302,7 +7305,7 @@ answer_response(fetchctx_t *fctx) {
rdataset->trust = trust;
(void)dns_rdataset_additionaldata(rdataset,
check_related,
- fctx);
+ fctx, 0);
}
} else if (aname != NULL) {
if (!validinanswer(ardataset, fctx))
@@ -7327,7 +7330,7 @@ answer_response(fetchctx_t *fctx) {
ardataset->attributes |= DNS_RDATASETATTR_CACHE;
ardataset->trust = trust;
(void)dns_rdataset_additionaldata(ardataset, check_related,
- fctx);
+ fctx, 0);
for (sigrdataset = ISC_LIST_HEAD(aname->list);
sigrdataset != NULL;
sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) {
@@ -7487,7 +7490,7 @@ answer_response(fetchctx_t *fctx) {
(void)dns_rdataset_additionaldata(
rdataset,
check_related,
- fctx);
+ fctx, 0);
done = true;
}
}