import CS git bind-9.11.36-16.el8_10.8

This commit is contained in:
AlmaLinux RelEng Bot 2026-06-07 23:24:51 -04:00
parent 5e15a3310c
commit 3bc8ad52b2
3 changed files with 899 additions and 1 deletions

View File

@ -0,0 +1,375 @@
From 7c2afb490391a308733da1c37730328477bd80d3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= <ondrej@isc.org>
Date: Wed, 18 Mar 2026 00:10:35 +0100
Subject: [PATCH] Fix GSS-API context leak in TKEY negotiation
Reject multi-round GSS-API negotiation (GSS_S_CONTINUE_NEEDED) in
dst_gssapi_acceptctx(). Each call to gss_accept_sec_context()
allocates a context inside the GSS library; without this fix, the
context handle was passed back to process_gsstkey() which did not
store it persistently, leaking it on every incomplete negotiation.
An unauthenticated attacker could exhaust server memory by sending
repeated TKEY queries with GSSAPI tokens, each leaking one GSS
context. The leaked memory is allocated by the GSS library via
malloc(), bypassing BIND's memory accounting.
In practice, Kerberos/SPNEGO (the only mechanism used with BIND)
completes in a single round, so rejecting continuation does not
affect real-world deployments. See RFC 3645 Section 4.1.3.
(cherry picked from commit 3883058bf284de2889e4e3676767e58ad91a0ae3)
(cherry picked from commit e3c74f19c6b3b29ec649062f95bf1df5688a0799)
Fix output token and GSS context leaks in TKEY/GSS-API error paths
In dst_gssapi_acceptctx(), rename outtoken to outtokenp (matching BIND
convention for output pointer parameters) and free the allocated output
token buffer on error in the cleanup path.
In process_gsstkey(), route the empty-principal error path through
cleanup via CLEANUP() instead of returning early, so that the output
token, GSS context, and TSIG key are all freed consistently by the
existing cleanup block.
(cherry picked from commit f2240d2d06a1a68b622bd6b00a52c6fe4274426d)
(cherry picked from commit f2f1c0cb244a6d9e2fd8550a38bd2465856abce3)
---
lib/dns/gssapictx.c | 127 ++++++++++++++++++++---------------
lib/dns/include/dst/gssapi.h | 17 ++---
lib/dns/tkey.c | 50 +++++++-------
3 files changed, 104 insertions(+), 90 deletions(-)
diff --git a/lib/dns/gssapictx.c b/lib/dns/gssapictx.c
index 482c25e1cc..a58c3071d4 100644
--- a/lib/dns/gssapictx.c
+++ b/lib/dns/gssapictx.c
@@ -594,7 +594,14 @@ dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken,
0, NULL, gintokenp,
NULL, &gouttoken, &ret_flags, NULL);
- if (gret != GSS_S_COMPLETE && gret != GSS_S_CONTINUE_NEEDED) {
+ switch (gret) {
+ case GSS_S_COMPLETE:
+ result = ISC_R_SUCCESS;
+ break;
+ case GSS_S_CONTINUE_NEEDED:
+ result = DNS_R_CONTINUE;
+ break;
+ default:
gss_err_message(mctx, gret, minor, err_message);
if (err_message != NULL && *err_message != NULL)
gss_log(3, "Failure initiating security context: %s",
@@ -619,14 +626,10 @@ dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken,
RETERR(isc_buffer_copyregion(outtoken, &r));
}
- if (gret == GSS_S_COMPLETE)
- result = ISC_R_SUCCESS;
- else
- result = DNS_R_CONTINUE;
-
- out:
- if (gouttoken.length != 0U)
+out:
+ if (gouttoken.length != 0U) {
(void)gss_release_buffer(&minor, &gouttoken);
+ }
(void)gss_release_name(&minor, &gname);
return (result);
}
@@ -634,7 +637,7 @@ dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken,
isc_result_t
dst_gssapi_acceptctx(gss_cred_id_t cred,
const char *gssapi_keytab,
- isc_region_t *intoken, isc_buffer_t **outtoken,
+ isc_region_t *intoken, isc_buffer_t **outtokenp,
gss_ctx_id_t *ctxout, dns_name_t *principal,
isc_mem_t *mctx) {
isc_region_t r;
@@ -647,15 +650,11 @@ dst_gssapi_acceptctx(gss_cred_id_t cred,
isc_result_t result;
char buf[1024];
- REQUIRE(outtoken != NULL && *outtoken == NULL);
+ REQUIRE(outtokenp != NULL && *outtokenp == NULL);
+ REQUIRE(*ctxout == NULL);
REGION_TO_GBUFFER(*intoken, gintoken);
- if (*ctxout == NULL)
- context = GSS_C_NO_CONTEXT;
- else
- context = *ctxout;
-
if (gssapi_keytab != NULL) {
#if defined(ISC_PLATFORM_GSSAPI_KRB5_HEADER) || defined(WIN32)
gret = gsskrb5_register_acceptor_identity(gssapi_keytab);
@@ -697,8 +696,15 @@ dst_gssapi_acceptctx(gss_cred_id_t cred,
switch (gret) {
case GSS_S_COMPLETE:
- case GSS_S_CONTINUE_NEEDED:
break;
+ /*
+ * RFC 3645 4.1.3: we don't handle GSS_S_CONTINUE_NEEDED
+ * Multi-round GSS-API negotiation is not supported.
+ */
+ case GSS_S_CONTINUE_NEEDED:
+ gss_log(3, "multi-round GSS-API negotiation not supported");
+ (void)gss_delete_sec_context(&minor, &context, NULL);
+ /* FALLTHROUGH */
case GSS_S_DEFECTIVE_TOKEN:
case GSS_S_DEFECTIVE_CREDENTIAL:
case GSS_S_BAD_SIG:
@@ -711,7 +717,7 @@ dst_gssapi_acceptctx(gss_cred_id_t cred,
case GSS_S_BAD_MECH:
case GSS_S_FAILURE:
result = DNS_R_INVALIDTKEY;
- /* fall through */
+ /* FALLTHROUGH */
default:
gss_log(3, "failed gss_accept_sec_context: %s",
gss_error_tostring(gret, minor, buf, sizeof(buf)));
@@ -722,55 +728,70 @@ dst_gssapi_acceptctx(gss_cred_id_t cred,
}
if (gouttoken.length > 0U) {
- RETERR(isc_buffer_allocate(mctx, outtoken,
+ RETERR(isc_buffer_allocate(mctx, outtokenp,
(unsigned int)gouttoken.length));
GBUFFER_TO_REGION(gouttoken, r);
- RETERR(isc_buffer_copyregion(*outtoken, &r));
+ result = isc_buffer_copyregion(*outtokenp, &r);
+ if (result != ISC_R_SUCCESS) {
+ goto out;
+ }
(void)gss_release_buffer(&minor, &gouttoken);
}
- if (gret == GSS_S_COMPLETE) {
- gret = gss_display_name(&minor, gname, &gnamebuf, NULL);
- if (gret != GSS_S_COMPLETE) {
- gss_log(3, "failed gss_display_name: %s",
- gss_error_tostring(gret, minor,
- buf, sizeof(buf)));
- RETERR(ISC_R_FAILURE);
- }
+ INSIST(gret == GSS_S_COMPLETE);
- /*
- * Compensate for a bug in Solaris8's implementation
- * of gss_display_name(). Should be harmless in any
- * case, since principal names really should not
- * contain null characters.
- */
- if (gnamebuf.length > 0U &&
- ((char *)gnamebuf.value)[gnamebuf.length - 1] == '\0')
- gnamebuf.length--;
+ gret = gss_display_name(&minor, gname, &gnamebuf, NULL);
+ if (gret != GSS_S_COMPLETE) {
+ gss_log(3, "failed gss_display_name: %s",
+ gss_error_tostring(gret, minor, buf, sizeof(buf)));
+ result = ISC_R_FAILURE;
+ goto out;
+ }
- gss_log(3, "gss-api source name (accept) is %.*s",
- (int)gnamebuf.length, (char *)gnamebuf.value);
+ /*
+ * Compensate for a bug in Solaris8's implementation
+ * of gss_display_name(). Should be harmless in any
+ * case, since principal names really should not
+ * contain null characters.
+ */
+ if (gnamebuf.length > 0U &&
+ ((char *)gnamebuf.value)[gnamebuf.length - 1] == '\0')
+ {
+ gnamebuf.length--;
+ }
- GBUFFER_TO_REGION(gnamebuf, r);
- isc_buffer_init(&namebuf, r.base, r.length);
- isc_buffer_add(&namebuf, r.length);
+ gss_log(3, "gss-api source name (accept) is %.*s", (int)gnamebuf.length,
+ (char *)gnamebuf.value);
- RETERR(dns_name_fromtext(principal, &namebuf, dns_rootname,
- 0, NULL));
+ GBUFFER_TO_REGION(gnamebuf, r);
+ isc_buffer_init(&namebuf, r.base, r.length);
+ isc_buffer_add(&namebuf, r.length);
- if (gnamebuf.length != 0U) {
- gret = gss_release_buffer(&minor, &gnamebuf);
- if (gret != GSS_S_COMPLETE)
- gss_log(3, "failed gss_release_buffer: %s",
- gss_error_tostring(gret, minor, buf,
- sizeof(buf)));
- }
- } else
- result = DNS_R_CONTINUE;
+ result = dns_name_fromtext(principal, &namebuf, dns_rootname, 0, NULL);
+ if (result != ISC_R_SUCCESS) {
+ goto out;
+ }
*ctxout = context;
- out:
+out:
+ if (result != ISC_R_SUCCESS && *outtokenp != NULL) {
+ isc_buffer_free(outtokenp);
+ }
+
+ if (result != ISC_R_SUCCESS && context != GSS_C_NO_CONTEXT) {
+ (void)gss_delete_sec_context(&minor, &context, NULL);
+ }
+
+ if (gnamebuf.length != 0U) {
+ gret = gss_release_buffer(&minor, &gnamebuf);
+ if (gret != GSS_S_COMPLETE) {
+ gss_log(3, "failed gss_release_buffer: %s",
+ gss_error_tostring(gret, minor, buf,
+ sizeof(buf)));
+ }
+ }
+
if (gname != NULL) {
gret = gss_release_name(&minor, &gname);
if (gret != GSS_S_COMPLETE)
diff --git a/lib/dns/include/dst/gssapi.h b/lib/dns/include/dst/gssapi.h
index 8e31587871..bf1c4c959a 100644
--- a/lib/dns/include/dst/gssapi.h
+++ b/lib/dns/include/dst/gssapi.h
@@ -126,20 +126,17 @@ dst_gssapi_acceptctx(gss_cred_id_t cred,
* generated by gss_accept_sec_context() to be sent to the
* initiator
* 'context' is a valid pointer to receive the generated context handle.
- * On the initial call, it should be a pointer to NULL, which
- * will be allocated as a gss_ctx_id_t. Subsequent calls
- * should pass in the handle generated on the first call.
- * Call dst_gssapi_releasecred to delete the context and free
- * the memory.
*
* Requires:
- * 'outtoken' to != NULL && *outtoken == NULL.
+ * 'outtoken' != NULL && *outtoken == NULL.
+ * 'context' != NULL && *context == NULL.
*
* Returns:
- * ISC_R_SUCCESS msg was successfully updated to include the
- * query to be sent
- * DNS_R_CONTINUE transaction still in progress
- * other an error occurred while building the message
+ * ISC_R_SUCCESS msg was successfully updated to include
+ * the query to be sent
+ * DNS_R_INVALIDTKEY an error occurred while accepting the
+ * context
+ * ISC_R_FAILURE other error occurred
*/
isc_result_t
diff --git a/lib/dns/tkey.c b/lib/dns/tkey.c
index ae7a76cd3d..03bf521ee6 100644
--- a/lib/dns/tkey.c
+++ b/lib/dns/tkey.c
@@ -503,18 +503,9 @@ process_gsstkey(dns_message_t *msg, dns_name_t *name, dns_rdata_tkey_t *tkeyin,
return (ISC_R_SUCCESS);
}
- /*
- * XXXDCL need to check for key expiry per 4.1.1
- * XXXDCL need a way to check fully established, perhaps w/key_flags
- */
-
intoken.base = tkeyin->key;
intoken.length = tkeyin->keylen;
- result = dns_tsigkey_find(&tsigkey, name, &tkeyin->algorithm, ring);
- if (result == ISC_R_SUCCESS)
- gss_ctx = dst_key_getgssctx(tsigkey->key);
-
principal = dns_fixedname_initname(&fixed);
/*
@@ -523,25 +514,27 @@ process_gsstkey(dns_message_t *msg, dns_name_t *name, dns_rdata_tkey_t *tkeyin,
result = dst_gssapi_acceptctx(tctx->gsscred, tctx->gssapi_keytab,
&intoken, &outtoken, &gss_ctx,
principal, tctx->mctx);
- if (result == DNS_R_INVALIDTKEY) {
- if (tsigkey != NULL)
- dns_tsigkey_detach(&tsigkey);
+ if (result != ISC_R_SUCCESS) {
tkeyout->error = dns_tsigerror_badkey;
- tkey_log("process_gsstkey(): dns_tsigerror_badkey"); /* XXXSRA */
- return (ISC_R_SUCCESS);
- }
- if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS)
+ tkey_log("process_gsstkey(): dns_tsigerror_badkey");
+ result = ISC_R_SUCCESS;
goto failure;
+ }
+
/*
- * XXXDCL Section 4.1.3: Limit GSS_S_CONTINUE_NEEDED to 10 times.
+ * Multi-round GSS-API negotiation (GSS_S_CONTINUE_NEEDED) is
+ * rejected in dst_gssapi_acceptctx(), so if we reach here the
+ * negotiation is complete and the principal must be set.
*/
isc_stdtime_get(&now);
if (dns_name_countlabels(principal) == 0U) {
- if (tsigkey != NULL) {
- dns_tsigkey_detach(&tsigkey);
- }
+ tkeyout->error = dns_tsigerror_badkey;
+ tkey_log("process_gsstkey(): "
+ "completed context with empty principal");
+ result = ISC_R_SUCCESS;
+ goto failure;
} else if (tsigkey == NULL) {
#ifdef GSSAPI
OM_uint32 gret, minor, lifetime;
@@ -612,6 +605,10 @@ process_gsstkey(dns_message_t *msg, dns_name_t *name, dns_rdata_tkey_t *tkeyin,
return (ISC_R_SUCCESS);
failure:
+ if (dstkey == NULL && gss_ctx != NULL) {
+ dst_gssapi_deletectx(tctx->mctx, &gss_ctx);
+ }
+
if (tsigkey != NULL)
dns_tsigkey_detach(&tsigkey);
@@ -621,10 +618,10 @@ failure:
if (outtoken != NULL)
isc_buffer_free(&outtoken);
- tkey_log("process_gsstkey(): %s",
- isc_result_totext(result)); /* XXXSRA */
-
- return (result);
+ if (result != ISC_R_SUCCESS) {
+ tkey_log("process_gsstkey(): %s", isc_result_totext(result));
+ }
+ return result;
}
static isc_result_t
@@ -1521,9 +1518,8 @@ dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg,
&dstkey, NULL));
/*
- * XXXSRA This seems confused. If we got CONTINUE from initctx,
- * the GSS negotiation hasn't completed yet, so we can't sign
- * anything yet.
+ * GSS negotiation is complete (CONTINUE returned earlier).
+ * Create the TSIG key from the established context.
*/
RETERR(dns_tsigkey_createfromkey(tkeyname,
--
2.54.0

View File

@ -0,0 +1,512 @@
From de237c66c901b451e4957a28e0d953c57648eab9 Mon Sep 17 00:00:00 2001
From: Evan Hunt <each@isc.org>
Date: Tue, 3 Mar 2026 14:00:38 -0800
Subject: [PATCH] Disable recursion for non-IN classes
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Force recursion off, and set allow-recursion/allow-recursion-on ACLs
to none, for views with a class other than IN. Log a configuration
warning if recursion is explicitly enabled for a non-IN view.
This addresses YWH-PGM40640-74 and YWH-PGM40640-75 by preventing any
attempt at recursive processing in a class-CHAOS view, ensuring that
server addresses used for recursive queries and received in recursive
responses are of the expected format.
Fixes: isc-projects/bind9#5780
Fixes: isc-projects/bind9#5781
(cherry picked from commit 70532a37a1aec761e8a12444852866ce9d9d5fcc)
(cherry picked from commit cf0d5a4e385525e21f2ae39098b1ab90c1137a2a)
(cherry picked from commit c6b05d8449d94c74e85be70b822b7ad439abca40)
Disable UPDATE and NOTIFY for non-IN classes
Return NOTIMP for UPDATE and NOTIFY requests received for views with a
class other than IN. Only QUERY is now supported for non-IN views such
as CHAOS.
When running dns dns_rdata_tostruct() with types that are only defined
for class IN, ensure that the class is correct before proceeding.
Add an assertion that any zone being updated is of class IN. (Note
that previously, a DLZ zone could have its class value set incorrectly
to NONE; this has been fixed.)
This addresses YWH-PGM40640-70 and YWH-PGM40640-73 (as well as any
similar problems that might have occurred in the future) by minimizing
the code paths that can be reached by rdata classes other than IN, so it
is safe for the implementation to assume that rdatatypes that are only
defined for class IN, such as SVCB or WKS, have been parsed and
validated, and not accepted as unknown/opaque data.
Fixes: isc-projects/bind9#5777
Fixes: isc-projects/bind9#5779
(cherry picked from commit 9ae24c32bec16c0f64225ef04f34670018bf0765)
(cherry picked from commit a2ca2408b3ff031c426c5dc785f550c9d30bf4aa)
(cherry picked from commit f107b702c4ff4a68042d0dad8384544dd99954a8)
Validate DNS message CLASS early in request processing
Reject requests with unsupported or misused CLASS values before
further processing. Only IN, CH, HS, RESERVED0 (for DNS Cookies),
ANY (for TKEY negotiation), and NONE (for DNS UPDATE) are accepted;
all other classes return NOTIMP. Misuse of NONE or ANY outside
their allowed contexts returns FORMERR.
This adds further protection against bugs of the same general class
as YWH-PGM40640-70 and YWH-PGM40640-73.
(cherry picked from commit d41865a458b9ecd76be4097ac1bea1005cad72db)
(cherry picked from commit 1c8016c91c3674929f87cbe7ad09f3670e05ad4e)
(cherry picked from commit 6c50d4812c35fe982614cd53355c4048ab09267a)
Reject meta-classes in UPDATE and NOTIFY messages
NOTIFY and UPDATE messages must specify a data class in the
QUESTION/ZONE section. NONE and ANY are meta-classes and not
appropriate here. Return FORMERR if either is used.
Rejecting messages with a query class of NONE addresses YWH-PGM40640-72,
YWH-PGM40640-82, and YWH-PGM40640-83. Rejecting messages with a query
class of ANY addresses YWH-PGM40640-87, YWH-PGM40640-88, and
YWH-PGM40640-117.
Fixes: isc-projects/bind9#5778
Fixes: isc-projects/bind9#5782
Fixes: isc-projects/bind9#5783
Fixes: isc-projects/bind9#5797
Fixes: isc-projects/bind9#5798
Fixes: isc-projects/bind9#5853
(cherry picked from commit 7de5160517ae69196d1c323b8627b267cdd10761)
(cherry picked from commit 3c44de9e6252ec1c7742ef02ecc0d6cbf1cde5e9)
(cherry picked from commit f7d5fe628c220245a14397207893424f0b27ff53)
Skip "deny-answer-address" for non-IN addresses
Ensure that we don't attempt an ACL match for answer addresses
when handling a class-CHAOS zone. This is an additional line of
defense for YWH-PGM40640-74.
(cherry picked from commit 4cd3d8e6d866143ddc62df821a1007bf3ee7f083)
(cherry picked from commit fa60101e910346e64fa2a684b903fbcb84d8243b)
(cherry picked from commit c01d298f53b0ffbf38bf19867f368f60a9ea4ecf)
Pass empty string instead of NULL to ns_client_dumpmessage()
The two new call sites added by the CLASS-validation work passed NULL
as the reason, but ns_client_dumpmessage() bails out early on a NULL
reason — so the message dump never happened. The intent was to dump
the message and let the follow-up ns_client_log() carry the reason
text, so pass "" to suppress the prefix without short-circuiting the
dump.
(cherry picked from commit 8af39c360407a92ef31bf233b9df760d1bb9fb5f)
(cherry picked from commit 4d7e442c9aee72851f2b2d973273ebc92da42cf0)
%RH
Backport fixes.
---
bin/named/client.c | 56 +++++++++++++++++++++++++++++--
bin/named/server.c | 38 ++++++---------------
bin/named/update.c | 31 +++++++++--------
bin/tests/system/unknown/tests.sh | 12 +++----
lib/dns/adb.c | 2 +-
lib/dns/message.c | 11 ++++++
lib/dns/resolver.c | 13 +++++--
7 files changed, 109 insertions(+), 54 deletions(-)
diff --git a/bin/named/client.c b/bin/named/client.c
index ea121b301e..6990e02b03 100644
--- a/bin/named/client.c
+++ b/bin/named/client.c
@@ -40,6 +40,7 @@
#include <dns/dnstap.h>
#include <dns/cache.h>
#include <dns/edns.h>
+#include <dns/enumclass.h>
#include <dns/events.h>
#include <dns/message.h>
#include <dns/peer.h>
@@ -2829,7 +2830,9 @@ client_request(isc_task_t *task, isc_event_t *event) {
goto cleanup;
}
- if (client->message->rdclass == 0) {
+ char classbuf[DNS_RDATACLASS_FORMATSIZE];
+ switch (client->message->rdclass) {
+ case dns_rdataclass_reserved0:
if ((client->attributes & NS_CLIENTATTR_WANTCOOKIE) != 0 &&
client->message->opcode == dns_opcode_query &&
client->message->counts[DNS_SECTION_QUESTION] == 0U)
@@ -2851,6 +2854,44 @@ client_request(isc_task_t *task, isc_event_t *event) {
"message class could not be determined");
ns_client_error(client, notimp ? DNS_R_NOTIMP : DNS_R_FORMERR);
goto cleanup;
+ case dns_rdataclass_in:
+ break;
+ case dns_rdataclass_chaos:
+ break;
+ case dns_rdataclass_hs:
+ break;
+ case dns_rdataclass_none:
+ if (client->message->opcode != dns_opcode_update) {
+ ns_client_dumpmessage(client,
+ "message class NONE can be only "
+ "used in DNS updates");
+ ns_client_error(client, DNS_R_FORMERR);
+ return;
+ }
+ break;
+ case dns_rdataclass_any:
+ /*
+ * Required for TKEY negotiation.
+ */
+ if (client->message->tkey == 0) {
+ ns_client_dumpmessage(client,
+ "message class ANY can be only "
+ "used for TKEY negotiation");
+ ns_client_error(client, DNS_R_FORMERR);
+ return;
+ }
+ break;
+ default:
+ dns_rdataclass_format(client->message->rdclass, classbuf,
+ sizeof(classbuf));
+ ns_client_dumpmessage(client, "");
+ ns_client_log(client, NS_LOGCATEGORY_CLIENT,
+ NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1),
+ "message class could not be determined");
+ ns_client_dumpmessage(client, "message class could not be "
+ "determined");
+ ns_client_error(client, DNS_R_NOTIMP);
+ goto cleanup;
}
/*
@@ -2969,7 +3010,7 @@ client_request(isc_task_t *task, isc_event_t *event) {
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1),
"no matching view in class '%s'", classname);
- ns_client_dumpmessage(client, "no matching view in class");
+ ns_client_dumpmessage(client, "");
ns_client_error(client, notimp ? DNS_R_NOTIMP : DNS_R_REFUSED);
goto cleanup;
}
@@ -3149,11 +3190,19 @@ client_request(isc_task_t *task, isc_event_t *event) {
break;
case dns_opcode_update:
CTRACE("update");
+ if (client->view->rdclass != dns_rdataclass_in) {
+ ns_client_error(client, DNS_R_NOTIMP);
+ break;
+ }
ns_client_settimeout(client, 60);
ns_update_start(client, sigresult);
break;
case dns_opcode_notify:
CTRACE("notify");
+ if (client->view->rdclass != dns_rdataclass_in) {
+ ns_client_error(client, DNS_R_NOTIMP);
+ break;
+ }
ns_client_settimeout(client, 60);
ns_notify_start(client);
break;
@@ -4241,8 +4290,9 @@ ns_client_dumpmessage(ns_client_t *client, const char *reason) {
int len = 1024;
isc_result_t result;
- if (!isc_log_wouldlog(ns_g_lctx, ISC_LOG_DEBUG(1)))
+ if (!isc_log_wouldlog(ns_g_lctx, ISC_LOG_DEBUG(1)) || reason == NULL) {
return;
+ }
/*
* Note that these are multiline debug messages. We want a newline
diff --git a/bin/named/server.c b/bin/named/server.c
index 2086e41ca9..be521f6cf2 100644
--- a/bin/named/server.c
+++ b/bin/named/server.c
@@ -1756,6 +1756,7 @@ dlzconfigure_callback(dns_view_t *view, dns_dlzdb_t *dlzdb, dns_zone_t *zone) {
dns_rdataclass_t zclass = view->rdclass;
isc_result_t result;
+ dns_zone_setclass(zone, zclass);
result = dns_zonemgr_managezone(ns_g_server->zonemgr, zone);
if (result != ISC_R_SUCCESS)
return (result);
@@ -4170,32 +4171,14 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
CHECK(configure_alternates(config, view, alternates));
/*
- * We have default hints for class IN if we need them.
+ * We have default root hints for class IN if we need them.
+ * Each view gets its own rootdb so a priming response only
+ * writes into that view's copy. Other classes don't support
+ * recursion and don't need hints.
*/
if (view->rdclass == dns_rdataclass_in && view->hints == NULL)
dns_view_sethints(view, ns_g_server->in_roothints);
- /*
- * If we still have no hints, this is a non-IN view with no
- * "hints zone" configured. Issue a warning, except if this
- * is a root server. Root servers never need to consult
- * their hints, so it's no point requiring users to configure
- * them.
- */
- if (view->hints == NULL) {
- dns_zone_t *rootzone = NULL;
- (void)dns_view_findzone(view, dns_rootname, &rootzone);
- if (rootzone != NULL) {
- dns_zone_detach(&rootzone);
- need_hints = false;
- }
- if (need_hints)
- isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
- NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
- "no root hints for view '%s'",
- view->name);
- }
-
/*
* Configure the view's TSIG keys.
*/
@@ -4302,7 +4285,8 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
obj = NULL;
result = ns_config_get(maps, "recursion", &obj);
INSIST(result == ISC_R_SUCCESS);
- view->recursion = cfg_obj_asboolean(obj);
+ view->recursion = (view->rdclass == dns_rdataclass_in &&
+ cfg_obj_asboolean(obj));
obj = NULL;
result = ns_config_get(maps, "auth-nxdomain", &obj);
@@ -4409,10 +4393,10 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
"allow-query-cache", NULL, actx,
ns_g_mctx, &view->cacheacl));
- if (strcmp(view->name, "_bind") != 0 &&
- view->rdclass != dns_rdataclass_chaos)
- {
- /* named.conf only */
+ if (view->rdclass != dns_rdataclass_in) {
+ dns_acl_none(ns_g_mctx, &view->recursionacl);
+ dns_acl_none(ns_g_mctx, &view->recursiononacl);
+ } else {
CHECK(configure_view_acl(vconfig, config, NULL,
"allow-recursion", NULL, actx,
ns_g_mctx, &view->recursionacl));
diff --git a/bin/named/update.c b/bin/named/update.c
index 407ac38272..be469f8e91 100644
--- a/bin/named/update.c
+++ b/bin/named/update.c
@@ -1269,7 +1269,10 @@ replaces_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
dbsig.algorithm == updatesig.algorithm)
return (true);
}
- if (db_rr->type == dns_rdatatype_wks) {
+
+ if (db_rr->rdclass == dns_rdataclass_in &&
+ db_rr->type == dns_rdatatype_wks)
+ {
/*
* Compare the address and protocol fields only. These
* form the first five bytes of the RR data. Do a
@@ -1412,8 +1415,7 @@ add_rr_prepare_action(void *data, rr_t *rr) {
* 'rdata', and 'ttl', respectively.
*/
static void
-get_current_rr(dns_message_t *msg, dns_section_t section,
- dns_rdataclass_t zoneclass, dns_name_t **name,
+get_current_rr(dns_message_t *msg, dns_section_t section, dns_name_t **name,
dns_rdata_t *rdata, dns_rdatatype_t *covers,
dns_ttl_t *ttl, dns_rdataclass_t *update_class)
{
@@ -1430,7 +1432,7 @@ get_current_rr(dns_message_t *msg, dns_section_t section,
dns_rdataset_current(rdataset, rdata);
INSIST(dns_rdataset_next(rdataset) == ISC_R_NOMORE);
*update_class = rdata->rdclass;
- rdata->rdclass = zoneclass;
+ rdata->rdclass = dns_rdataclass_in;
}
/*%
@@ -1580,7 +1582,7 @@ send_update_event(ns_client_t *client, dns_zone_t *zone) {
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_ttl_t ttl;
dns_rdataclass_t update_class;
- get_current_rr(request, DNS_SECTION_UPDATE, zoneclass,
+ get_current_rr(request, DNS_SECTION_UPDATE,
&name, &rdata, &covers, &ttl, &update_class);
if (! dns_name_issubdomain(name, zonename))
@@ -1812,6 +1814,9 @@ send_update_event(ns_client_t *client, dns_zone_t *zone) {
CHECK(DNS_R_DROP);
}
+ /* Updates are only supported for class IN. */
+ INSIST(dns_zone_getclass(zone) == dns_rdataclass_in);
+
event = (update_event_t *)
isc_event_allocate(client->mctx, client, DNS_EVENT_UPDATE,
update_action, NULL, sizeof(*event));
@@ -2798,7 +2803,6 @@ update_action(isc_task_t *task, isc_event_t *event) {
isc_mem_t *mctx = client->mctx;
dns_rdatatype_t covers;
dns_message_t *request = client->message;
- dns_rdataclass_t zoneclass;
dns_name_t *zonename = NULL;
dns_ssutable_t *ssutable = NULL;
dns_fixedname_t tmpnamefixed;
@@ -2819,10 +2823,10 @@ update_action(isc_task_t *task, isc_event_t *event) {
CHECK(dns_zone_getdb(zone, &db));
zonename = dns_db_origin(db);
- zoneclass = dns_db_class(db);
dns_zone_getssutable(zone, &ssutable);
options = dns_zone_getoptions(zone);
+ INSIST(dns_zone_getclass(zone) == dns_rdataclass_in);
/*
* Get old and new versions now that queryacl has been checked.
*/
@@ -2843,8 +2847,8 @@ update_action(isc_task_t *task, isc_event_t *event) {
dns_rdataclass_t update_class;
bool flag;
- get_current_rr(request, DNS_SECTION_PREREQUISITE, zoneclass,
- &name, &rdata, &covers, &ttl, &update_class);
+ get_current_rr(request, DNS_SECTION_PREREQUISITE, &name, &rdata,
+ &covers, &ttl, &update_class);
if (ttl != 0)
PREREQFAILC(DNS_R_FORMERR,
@@ -2902,7 +2906,7 @@ update_action(isc_task_t *task, isc_event_t *event) {
"satisfied");
}
}
- } else if (update_class == zoneclass) {
+ } else if (update_class == dns_rdataclass_in) {
/* "temp<rr.name, rr.type> += rr;" */
result = temp_append(&temp, name, &rdata);
if (result != ISC_R_SUCCESS) {
@@ -2960,11 +2964,10 @@ update_action(isc_task_t *task, isc_event_t *event) {
dns_rdataclass_t update_class;
bool flag;
- get_current_rr(request, DNS_SECTION_UPDATE, zoneclass,
- &name, &rdata, &covers, &ttl, &update_class);
-
- if (update_class == zoneclass) {
+ get_current_rr(request, DNS_SECTION_UPDATE, &name,
+ &rdata, &covers, &ttl, &update_class);
+ if (update_class == dns_rdataclass_in) {
/*
* RFC1123 doesn't allow MF and MD in master zones.
*/
diff --git a/bin/tests/system/unknown/tests.sh b/bin/tests/system/unknown/tests.sh
index deb9a419ab..a6ceb7c69b 100644
--- a/bin/tests/system/unknown/tests.sh
+++ b/bin/tests/system/unknown/tests.sh
@@ -73,8 +73,8 @@ echo_i "querying for various representations of a CLASS10 TYPE1 record"
for i in 1 2
do
ret=0
- $DIG +short $DIGOPTS @10.53.0.1 a$i.example a class10 > dig.out || ret=1
- echo '\# 4 0A000001' | $DIFF - dig.out || ret=1
+ $DIG $DIGOPTS @10.53.0.1 a$i.example a class10 > dig.out || ret=1
+ grep -q "NOTIMP" dig.out || ret=1
if [ $ret != 0 ]
then
echo_i "#$i failed"
@@ -86,8 +86,8 @@ echo_i "querying for various representations of a CLASS10 TXT record"
for i in 1 2 3 4
do
ret=0
- $DIG +short $DIGOPTS @10.53.0.1 txt$i.example txt class10 > dig.out || ret=1
- echo '"hello"' | $DIFF - dig.out || ret=1
+ $DIG $DIGOPTS @10.53.0.1 txt$i.example txt class10 > dig.out || ret=1
+ grep -q "NOTIMP" dig.out || ret=1
if [ $ret != 0 ]
then
echo_i "#$i failed"
@@ -99,8 +99,8 @@ echo_i "querying for various representations of a CLASS10 TYPE123 record"
for i in 1 2
do
ret=0
- $DIG +short $DIGOPTS @10.53.0.1 unk$i.example type123 class10 > dig.out || ret=1
- echo '\# 1 00' | $DIFF - dig.out || ret=1
+ $DIG $DIGOPTS @10.53.0.1 unk$i.example type123 class10 > dig.out || ret=1
+ grep -q "NOTIMP" dig.out || ret=1
if [ $ret != 0 ]
then
echo_i "#$i failed"
diff --git a/lib/dns/adb.c b/lib/dns/adb.c
index e12c804f2b..25cfa32873 100644
--- a/lib/dns/adb.c
+++ b/lib/dns/adb.c
@@ -892,7 +892,7 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
INSIST(DNS_ADB_VALID(adb));
rdtype = rdataset->type;
- INSIST((rdtype == dns_rdatatype_a) || (rdtype == dns_rdatatype_aaaa));
+ REQUIRE(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa);
if (rdtype == dns_rdatatype_a)
findoptions = DNS_ADBFIND_INET;
else
diff --git a/lib/dns/message.c b/lib/dns/message.c
index 5603bcadf9..f9e3163d71 100644
--- a/lib/dns/message.c
+++ b/lib/dns/message.c
@@ -1179,6 +1179,17 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
rdtype = isc_buffer_getuint16(source);
rdclass = isc_buffer_getuint16(source);
+ /*
+ * Notify and update messages need to specify the data class.
+ */
+ if ((msg->opcode == dns_opcode_update ||
+ msg->opcode == dns_opcode_notify) &&
+ (rdclass == dns_rdataclass_none ||
+ rdclass == dns_rdataclass_any))
+ {
+ DO_ERROR(DNS_R_FORMERR);
+ }
+
/*
* If this class is different than the one we already read,
* this is an error.
diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c
index 1c704551aa..5331ea9dd2 100644
--- a/lib/dns/resolver.c
+++ b/lib/dns/resolver.c
@@ -6514,9 +6514,16 @@ is_answeraddress_allowed(dns_view_t *view, dns_name_t *name,
}
/*
- * Otherwise, search the filter list for a match for each address
- * record. If a match is found, the address should be filtered,
- * so should the entire answer.
+ * deny-answer-address doesn't apply to non-IN classes.
+ */
+ if (rdataset->rdclass != dns_rdataclass_in) {
+ return true;
+ }
+
+ /*
+ * Otherwise, search the filter list for a match for each
+ * address record. If a match is found, the address should be
+ * filtered, so should the entire answer.
*/
for (result = dns_rdataset_first(rdataset);
result == ISC_R_SUCCESS;
--
2.54.0

View File

@ -68,7 +68,7 @@ Summary: The Berkeley Internet Name Domain (BIND) DNS (Domain Name System) serv
Name: bind
License: MPLv2.0
Version: 9.11.36
Release: 16%{?PATCHVER:.%{PATCHVER}}%{?PREVER:.%{PREVER}}%{?dist}.7
Release: 16%{?PATCHVER:.%{PATCHVER}}%{?PREVER:.%{PREVER}}%{?dist}.8
Epoch: 32
Url: https://www.isc.org/downloads/bind/
#
@ -207,6 +207,11 @@ Patch213: bind-9.11-d-max-records-checkconf.patch
Patch214: bind-9.11-CVE-2025-40778.patch
# https://gitlab.isc.org/isc-projects/bind9/commit/e5357c1623da3842227d2c76468b76bc983584d6
Patch215: bind-9.11-CVE-2026-1519.patch
# https://gitlab.isc.org/isc-projects/bind9/commit/94a96c69193587b2c6df30055fbb0c1d00622a7d
Patch216: bind-9.11-CVE-2026-3039.patch
# https://gitlab.isc.org/isc-projects/bind9/commit/bba70f08b1818f697e8292b79270a464279adc23
# https://gitlab.isc.org/isc-projects/bind9/commit/befe1903d0aebfd69cb362c429afc1f9c1c89610
Patch217: bind-9.11-CVE-2026-5946.patch
# SDB patches
Patch11: bind-9.3.2b2-sdbsrc.patch
@ -637,6 +642,8 @@ are used for building ISC DHCP.
%patch -P 213 -p1 -b .records-checkconf
%patch -P 214 -p1 -b .CVE-2025-40778
%patch -P 215 -p1 -b .CVE-2026-1519
%patch -P 216 -p1 -b .CVE-2026-3039
%patch -P 217 -p1 -b .CVE-2026-5946
mkdir lib/dns/tests/testdata/dstrandom
cp -a %{SOURCE50} lib/dns/tests/testdata/dstrandom/random.data
@ -1689,6 +1696,10 @@ rm -rf ${RPM_BUILD_ROOT}
%endif
%changelog
* Wed May 27 2026 Petr Menšík <pemensik@redhat.com> - 32:9.11.36-16.8
- Fix GSS-API resource leak (CVE-2026-3039)
- Invalid handling of CLASS != IN (CVE-2026-5946)
* Fri Mar 27 2026 Petr Menšík <pemensik@redhat.com> - 32:9.11.36-16.7
- Denial of Service via maliciously crafted DNSSEC-validated zone
(CVE-2026-1519)