From df90026a8c8e918c79044b22adb365ed700966bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= Date: Wed, 19 Aug 2026 16:21:32 +0200 Subject: [PATCH] [9.18] [CVE-2026-5950] sec: usr: Avoid unbounded recursion loop A bug during bad server handling could cause the resolver to enter an infinite loop, continuously sending queries to an upstream server with no exit condition, until the resolver query timeout was hit. This has been fixed. ISC would like to thank Billy Baraja (BielraX) for bringing this issue to our attention. Closes isc-projects/bind9#5804 Resolves: RHEL-189756 CVE: CVE-2026-5950 --- bind-9.18-CVE-2026-5950.patch | 160 ++++++++++++++++++++++++++++++++++ bind.spec | 7 +- 2 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 bind-9.18-CVE-2026-5950.patch diff --git a/bind-9.18-CVE-2026-5950.patch b/bind-9.18-CVE-2026-5950.patch new file mode 100644 index 0000000..28c5922 --- /dev/null +++ b/bind-9.18-CVE-2026-5950.patch @@ -0,0 +1,160 @@ +From f4db107023d6385d77d43bffea0e662b8919ad2c Mon Sep 17 00:00:00 2001 +From: Colin Vidal +Date: Tue, 7 Apr 2026 22:18:10 +0200 +Subject: [PATCH] Refactor incrementing query counters + +Move the logic incrementing the query counter and the global query +counter into a dedicated helper function. + +(cherry picked from commit 05d6da2de54c093689e675e81ae898ee41220666) +(cherry picked from commit 9ebfca2af824a60ea072292ffb1ab01ff87c7fa7) + +rctx_resend() increment query counters + +Calls to `rctx_resend()` are done internally within the resolver, in +flow which are not supposed to happens more than once. For instance, +if some query fails, and a specific flag "F" wasn't set, then set the +flag and try again. This wouldn't occur more than once because if the +query fails the next attempt, the flag "F" would be set already, so the +resolver would move to the next server (or give up). + +However, a subtle bug missing checking a flag, for instance, could lead +to an unbounded loop re-trying to query the same server. This is now +impossible as `rctx_resend()` also increment the query counters (so if +such case occurs, it would stop once the maximum limit is reached). + +The dns_resstatscounter_retry are also only incremented if the +`fctx_query()` succeeds, similar to as is done in `fctx_try()`. + +(cherry picked from commit f3e74304889a2e8b69c8e88fc9a383589decda32) +(cherry picked from commit d3ba533080e31de98986f3beff70d7c330ba9f89) +--- + lib/dns/resolver.c | 81 ++++++++++++++++++++++++++++++---------------- + 1 file changed, 54 insertions(+), 27 deletions(-) + +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index 40480c5e3e..f5b91d044b 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -68,6 +68,13 @@ + #include + #include + ++#define CHECK(op) \ ++ do { \ ++ result = (op); \ ++ if (result != ISC_R_SUCCESS) \ ++ goto cleanup; \ ++ } while (0) ++ + /* Detailed logging of fctx attach/detach */ + #ifndef FCTX_TRACE + #undef FCTX_TRACE +@@ -4133,6 +4140,39 @@ fctx_nextaddress(fetchctx_t *fctx) { + return addrinfo; + } + ++static isc_result_t ++incr_query_counters(fetchctx_t *fctx) { ++ isc_result_t result; ++ ++ result = isc_counter_increment(fctx->qc); ++#if WANT_QUERYTRACE ++ FCTXTRACE5("query", "max-recursion-queries, querycount=", ++ isc_counter_used(fctx->qc)); ++#endif ++ if (result != ISC_R_SUCCESS) { ++ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, ++ DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3), ++ "exceeded max queries resolving '%s' " ++ "(max-recursion-queries, querycount=%u)", ++ fctx->info, isc_counter_used(fctx->qc)); ++ } else if (fctx->gqc != NULL) { ++ result = isc_counter_increment(fctx->gqc); ++#if WANT_QUERYTRACE ++ FCTXTRACE5("query", "max-query-count, querycount=", ++ isc_counter_used(fctx->gqc)); ++#endif ++ if (result != ISC_R_SUCCESS) { ++ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, ++ DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3), ++ "exceeded global max queries resolving " ++ "'%s' (max-query-count, querycount=%u)", ++ fctx->info, isc_counter_used(fctx->gqc)); ++ } ++ } ++ ++ return result; ++} ++ + static void + fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) { + isc_result_t result; +@@ -4287,31 +4327,11 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) { + return; + } + +- result = isc_counter_increment(fctx->qc); +- if (result != ISC_R_SUCCESS) { +- isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, +- DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3), +- "exceeded max queries resolving '%s' " +- "(max-recursion-queries, querycount=%u)", +- fctx->info, isc_counter_used(fctx->qc)); +- fctx_done_detach(&fctx, DNS_R_SERVFAIL); +- return; +- } +- +- if (fctx->gqc != NULL) { +- result = isc_counter_increment(fctx->gqc); +- if (result != ISC_R_SUCCESS) { +- isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, +- DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3), +- "exceeded global max queries resolving " +- "'%s' (max-query-count, querycount=%u)", +- fctx->info, isc_counter_used(fctx->gqc)); +- fctx_done_detach(&fctx, DNS_R_SERVFAIL); +- return; +- } +- } ++ CHECK(incr_query_counters(fctx)); + + result = fctx_query(fctx, addrinfo, fctx->options); ++ ++cleanup: + if (result != ISC_R_SUCCESS) { + fctx_done_detach(&fctx, result); + } else if (retrying) { +@@ -10072,9 +10092,9 @@ rctx_nextserver(respctx_t *rctx, dns_message_t *message, + * rctx_resend(): + * + * Resend the query, probably with the options changed. Calls +- * fctx_query(), passing rctx->retryopts (which is based on +- * query->options, but may have been updated since the last time +- * fctx_query() was called). ++ * fctx_query(), unless query counter limits are hit, passing ++ * rctx->retryopts (which is based on query->options, but may have ++ * been updated since the last time fctx_query() was called). + */ + static void + rctx_resend(respctx_t *rctx, dns_adbaddrinfo_t *addrinfo) { +@@ -10082,8 +10102,15 @@ rctx_resend(respctx_t *rctx, dns_adbaddrinfo_t *addrinfo) { + isc_result_t result; + + FCTXTRACE("resend"); +- inc_stats(fctx->res, dns_resstatscounter_retry); ++ ++ CHECK(incr_query_counters(fctx)); ++ + result = fctx_query(fctx, addrinfo, rctx->retryopts); ++ if (result == ISC_R_SUCCESS) { ++ inc_stats(fctx->res, dns_resstatscounter_retry); ++ } ++ ++cleanup: + if (result != ISC_R_SUCCESS) { + fctx_done_detach(&rctx->fctx, result); + } +-- +2.55.0 + diff --git a/bind.spec b/bind.spec index ab9cb1b..b3527bd 100644 --- a/bind.spec +++ b/bind.spec @@ -80,7 +80,7 @@ License: MPL-2.0 AND ISC AND MIT AND BSD-3-Clause AND BSD-2-Clause # Before rebasing bind, ensure bind-dyndb-ldap is ready to be rebuild and use side-tag with it. # Updating just bind will cause freeipa-dns-server package to be uninstallable. Version: 9.18.33 -Release: 25%{?dist} +Release: 26%{?dist} Epoch: 32 Url: https://www.isc.org/downloads/bind/ # @@ -189,6 +189,8 @@ Patch242: bind-9.18-CVE-2026-11331-test.patch Patch243: bind-9.18-CVE-2026-11721-test.patch # https://gitlab.isc.org/isc-projects/bind9/commit/1a4986e2533f87e80eb21da3f06708d335aff1e2 Patch244: bind-9.18-CVE-2026-11721-fix2.patch +# https://gitlab.isc.org/isc-projects/bind9/commit/43d173797e3c781c7e38d879c3c765f01cc09c59 +Patch245: bind-9.18-CVE-2026-5950.patch %{?systemd_ordering} # https://fedoraproject.org/wiki/Changes/RPMSuportForSystemdSysusers @@ -992,6 +994,9 @@ fi; %endif %changelog +* Wed Aug 19 2026 Petr Menšík - 32:9.18.33-26 +- Avoid unbounded recursion loop (CVE-2026-5950) + * Mon Jul 27 2026 RHEL Packaging Agent - 32:9.18.33-25 - Validate NSEC3 signer matches owning zone (CVE-2026-10723)