bind/backport-CVE-2024-11187.patch
2025-02-19 16:41:23 +08:00

311 lines
11 KiB
Diff

From fa7b7973e36056440dd688c7f312c89600d4f8cf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= <ondrej@isc.org>
Date: Thu, 14 Nov 2024 10:37:29 +0100
Subject: [PATCH] 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.
Also, don't append any additional data to type=ANY queries. The
answer to ANY is already big enough.
(cherry picked from commit a1982cf1bb95c818aa7b58988b5611dec80f2408)
Conflict:Context adaptation
Reference:https://downloads.isc.org/isc/bind9/9.18.33/patches/0001-CVE-2024-11187.patch
---
bin/tests/system/additional/tests.sh | 2 +-
bin/tests/system/resolver/ns4/named.noaa | 5 -----
bin/tests/system/resolver/tests.sh | 8 ++++++++
lib/dns/include/dns/rdataset.h | 10 +++++++++-
lib/dns/rbtdb.c | 2 +-
lib/dns/rdataset.c | 7 ++++++-
lib/dns/resolver.c | 16 ++++++++++------
lib/isc/include/isc/result.h | 3 ++-
lib/isc/result.c | 6 ++++--
lib/ns/query.c | 13 +++++++++----
10 files changed, 50 insertions(+), 22 deletions(-)
delete mode 100644 bin/tests/system/resolver/ns4/named.noaa
diff --git a/bin/tests/system/additional/tests.sh b/bin/tests/system/additional/tests.sh
index 025f11f..539484c 100644
--- a/bin/tests/system/additional/tests.sh
+++ b/bin/tests/system/additional/tests.sh
@@ -260,7 +260,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: 2, ADDITIONAL: 2" dig.out.$n > /dev/null || 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
diff --git a/bin/tests/system/resolver/ns4/named.noaa b/bin/tests/system/resolver/ns4/named.noaa
deleted file mode 100644
index 3b121ad..0000000
--- 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 https://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 6c69c11..87b444d 100755
--- a/bin/tests/system/resolver/tests.sh
+++ b/bin/tests/system/resolver/tests.sh
@@ -289,6 +289,10 @@ done
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
+stop_server ns4
+touch ns4/named.noaa
+start_server --noclean --restart --port ${PORT} ns4 || ret=1
+
n=`expr $n + 1`
echo_i "RT21594 regression test check setup ($n)"
ret=0
@@ -316,6 +320,10 @@ grep "status: NOERROR" dig.ns5.out.${n} > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
+stop_server ns4
+rm ns4/named.noaa
+start_server --noclean --restart --port ${PORT} ns4 || ret=1
+
n=`expr $n + 1`
echo_i "RT21594 regression test NXDOMAIN answers ($n)"
ret=0
diff --git a/lib/dns/include/dns/rdataset.h b/lib/dns/include/dns/rdataset.h
index f2585ef..cba2234 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,7 +441,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.
@@ -458,10 +461,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 a6da874..e20aef7 100644
--- a/lib/dns/rbtdb.c
+++ b/lib/dns/rbtdb.c
@@ -10568,7 +10568,7 @@ no_glue:
maybe_rehash_gluetable(rbtversion);
idx = hash_32(hash, rbtversion->glue_table_bits);
- (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 bf9e7af..19a0051 100644
--- a/lib/dns/rdataset.c
+++ b/lib/dns/rdataset.c
@@ -576,7 +576,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 +589,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 cc8c9ab..2f932be 100644
--- a/lib/dns/resolver.c
+++ b/lib/dns/resolver.c
@@ -8944,7 +8944,7 @@ rctx_answer_any(respctx_t *rctx) {
rdataset->trust = rctx->trust;
(void)dns_rdataset_additionaldata(rdataset, check_related,
- rctx);
+ rctx, 0);
}
return (ISC_R_SUCCESS);
@@ -8991,7 +8991,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, rctx);
+ (void)dns_rdataset_additionaldata(rctx->ardataset, check_related, rctx, 0);
for (sigrdataset = ISC_LIST_HEAD(rctx->aname->list);
sigrdataset != NULL;
@@ -9197,7 +9197,7 @@ rctx_authority_positive(respctx_t *rctx) {
* to this rdataset.
*/
(void)dns_rdataset_additionaldata(
- rdataset, check_related, rctx);
+ rdataset, check_related, rctx, 0);
done = true;
}
}
@@ -9701,8 +9701,12 @@ rctx_referral(respctx_t *rctx) {
*/
INSIST(rctx->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(rctx->ns_rdataset, check_related,
- rctx);
+ rctx, 0);
#if CHECK_FOR_GLUE_IN_ANSWER
/*
* Look in the answer section for "glue" that is incorrectly
@@ -9715,7 +9719,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);
@@ -9825,7 +9829,7 @@ again:
if (CHASE(rdataset)) {
rdataset->attributes &= ~DNS_RDATASETATTR_CHASE;
(void)dns_rdataset_additionaldata(
- rdataset, check_related, rctx);
+ rdataset, check_related, rctx, 0);
rescan = true;
}
}
diff --git a/lib/isc/include/isc/result.h b/lib/isc/include/isc/result.h
index 21071c7..2b14d66 100644
--- a/lib/isc/include/isc/result.h
+++ b/lib/isc/include/isc/result.h
@@ -90,9 +90,10 @@
#define ISC_R_IPV4PREFIX 69 /*%< IPv4 prefix */
#define ISC_R_TLSERROR 70 /*%< TLS error */
#define ISC_R_HTTP2ALPNERROR 71 /*%< ALPN for HTTP/2 failed */
+#define DNS_R_TOOMANYRECORDS 72 /*%< too many records */
/*% Not a result code: the number of results. */
-#define ISC_R_NRESULTS 72
+#define ISC_R_NRESULTS 73
ISC_LANG_BEGINDECLS
diff --git a/lib/isc/result.c b/lib/isc/result.c
index 72e7a3c..a038b6e 100644
--- a/lib/isc/result.c
+++ b/lib/isc/result.c
@@ -102,7 +102,8 @@ static const char *description[ISC_R_NRESULTS] = {
"default", /*%< 68 */
"IPv4 prefix", /*%< 69 */
"TLS error", /*%< 70 */
- "ALPN for HTTP/2 failed" /*%< 71 */
+ "ALPN for HTTP/2 failed", /*%< 71 */
+ "too many records" /*%< 72 */
};
static const char *identifier[ISC_R_NRESULTS] = { "ISC_R_SUCCESS",
@@ -176,7 +177,8 @@ static const char *identifier[ISC_R_NRESULTS] = { "ISC_R_SUCCESS",
"ISC_R_DEFAULT",
"ISC_R_IPV4PREFIX",
"ISC_R_TLSERROR",
- "ISC_R_HTTP2ALPNERROR" };
+ "ISC_R_HTTP2ALPNERROR",
+ "DNS_R_TOOMANYRECODES" };
#define ISC_RESULT_RESULTSET 2
#define ISC_RESULT_UNAVAILABLESET 3
diff --git a/lib/ns/query.c b/lib/ns/query.c
index 520203f..15e321f 100644
--- a/lib/ns/query.c
+++ b/lib/ns/query.c
@@ -2031,7 +2031,8 @@ addname:
*/
if (trdataset != NULL && dns_rdatatype_followadditional(type)) {
eresult = dns_rdataset_additionaldata(
- trdataset, query_additional_cb, qctx);
+ trdataset, query_additional_cb, qctx,
+ DNS_RDATASET_MAXADDITIONAL);
}
cleanup:
@@ -2122,7 +2123,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");
}
@@ -2148,7 +2150,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
@@ -2203,7 +2206,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
--
2.33.0