diff --git a/1-bugfix-for-CVE-2025-40780.patch b/1-bugfix-for-CVE-2025-40780.patch new file mode 100644 index 0000000000000000000000000000000000000000..65311fb56a37996179b024ca7bb12d8fe5bf6e0e --- /dev/null +++ b/1-bugfix-for-CVE-2025-40780.patch @@ -0,0 +1,329 @@ +From 8330b49fb90bfeae14b47b7983e9459cc2bbaffe Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= +Date: Tue, 19 Aug 2025 19:22:18 +0200 +Subject: [PATCH] Use cryptographically-secure pseudo-random generator + everywhere + +It was discovered in an upcoming academic paper that a xoshiro128** +internal state can be recovered by an external 3rd party allowing to +predict UDP ports and DNS IDs in the outgoing queries. This could lead +to an attacker spoofing the DNS answers with great efficiency and +poisoning the DNS cache. + +Change the internal random generator to system CSPRNG with buffering to +avoid excessive syscalls. + +Thanks Omer Ben Simhon and Amit Klein of Hebrew University of Jerusalem +for responsibly reporting this to us. Very cool research! + +(cherry picked from commit cffcab9d5f3e709002f331b72498fcc229786ae2) +--- + lib/isc/include/isc/random.h | 2 +- + lib/isc/random.c | 225 ++++++++++++++--------------------- + tests/isc/random_test.c | 4 +- + 3 files changed, 96 insertions(+), 135 deletions(-) + +diff --git a/lib/isc/include/isc/random.h b/lib/isc/include/isc/random.h +index 1e30d0c87d5..fd55343778a 100644 +--- a/lib/isc/include/isc/random.h ++++ b/lib/isc/include/isc/random.h +@@ -20,7 +20,7 @@ + #include + + /*! \file isc/random.h +- * \brief Implements wrapper around a non-cryptographically secure ++ * \brief Implements wrapper around a cryptographically secure + * pseudo-random number generator. + * + */ +diff --git a/lib/isc/random.c b/lib/isc/random.c +index fb0466953d1..6f37f5dedf1 100644 +--- a/lib/isc/random.c ++++ b/lib/isc/random.c +@@ -31,176 +31,135 @@ + */ + + #include +-#include +-#include +-#include ++#include + +-#include ++#include + #include +-#include + #include +-#include + #include + + #include "entropy_private.h" + +-/* +- * The specific implementation for PRNG is included as a C file +- * that has to provide a static variable named seed, and a function +- * uint32_t next(void) that provides next random number. +- * +- * The implementation must be thread-safe. +- */ +- +-/* +- * Two contestants have been considered: the xoroshiro family of the +- * functions by Villa&Blackman, and PCG by O'Neill. After +- * consideration, the xoshiro128starstar function has been chosen as +- * the uint32_t random number provider because it is very fast and has +- * good enough properties for our usage pattern. +- */ +- +-/* +- * Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) +- * +- * To the extent possible under law, the author has dedicated all +- * copyright and related and neighboring rights to this software to the +- * public domain worldwide. This software is distributed without any +- * warranty. +- * +- * See . +- */ ++#define ISC_RANDOM_BUFSIZE (ISC_OS_CACHELINE_SIZE / sizeof(uint32_t)) + +-/* +- * This is xoshiro128** 1.0, our 32-bit all-purpose, rock-solid generator. +- * It has excellent (sub-ns) speed, a state size (128 bits) that is large +- * enough for mild parallelism, and it passes all tests we are aware of. +- * +- * For generating just single-precision (i.e., 32-bit) floating-point +- * numbers, xoshiro128+ is even faster. +- * +- * The state must be seeded so that it is not everywhere zero. +- */ +-static thread_local uint32_t seed[4] = { 0 }; ++thread_local static uint32_t isc__random_pool[ISC_RANDOM_BUFSIZE]; ++thread_local static size_t isc__random_pos = ISC_RANDOM_BUFSIZE; + + static uint32_t +-rotl(const uint32_t x, int k) { +- return (x << k) | (x >> (32 - k)); +-} +- +-static uint32_t +-next(void) { +- uint32_t result_starstar, t; +- +- result_starstar = rotl(seed[0] * 5, 7) * 9; +- t = seed[1] << 9; +- +- seed[2] ^= seed[0]; +- seed[3] ^= seed[1]; +- seed[1] ^= seed[2]; +- seed[0] ^= seed[3]; +- +- seed[2] ^= t; +- +- seed[3] = rotl(seed[3], 11); +- +- return result_starstar; +-} +- +-static thread_local isc_once_t isc_random_once = ISC_ONCE_INIT; +- +-static void +-isc_random_initialize(void) { +- int useed[4] = { 0, 0, 0, 1 }; ++random_u32(void) { + #if FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* +- * Set a constant seed to help in problem reproduction should fuzzing +- * find a crash or a hang. The seed array must be non-zero else +- * xoshiro128starstar will generate an infinite series of zeroes. ++ * A fixed stream of numbers helps with problem reproduction when ++ * fuzzing. The first result needs to be non-zero as expected by ++ * random_test.c (it starts with ISC_RANDOM_BUFSIZE, see above). + */ +-#else /* if FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ +- isc_entropy_get(useed, sizeof(useed)); ++ return (uint32_t)(isc__random_pos++); + #endif /* if FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ +- memmove(seed, useed, sizeof(seed)); ++ ++ if (isc__random_pos == ISC_RANDOM_BUFSIZE) { ++ isc_entropy_get(isc__random_pool, sizeof(isc__random_pool)); ++ isc__random_pos = 0; ++ } ++ ++ return isc__random_pool[isc__random_pos++]; + } + + uint8_t + isc_random8(void) { +- RUNTIME_CHECK(isc_once_do(&isc_random_once, isc_random_initialize) == +- ISC_R_SUCCESS); +- return next() & 0xff; ++ return (uint8_t)random_u32(); + } + + uint16_t + isc_random16(void) { +- RUNTIME_CHECK(isc_once_do(&isc_random_once, isc_random_initialize) == +- ISC_R_SUCCESS); +- return next() & 0xffff; ++ return (uint16_t)random_u32(); + } + + uint32_t + isc_random32(void) { +- RUNTIME_CHECK(isc_once_do(&isc_random_once, isc_random_initialize) == +- ISC_R_SUCCESS); +- return next(); ++ return random_u32(); + } + + void + isc_random_buf(void *buf, size_t buflen) { +- int i; +- uint32_t r; +- +- REQUIRE(buf != NULL); +- REQUIRE(buflen > 0); +- +- RUNTIME_CHECK(isc_once_do(&isc_random_once, isc_random_initialize) == +- ISC_R_SUCCESS); ++ REQUIRE(buflen == 0 || buf != NULL); + +- for (i = 0; i + sizeof(r) <= buflen; i += sizeof(r)) { +- r = next(); +- memmove((uint8_t *)buf + i, &r, sizeof(r)); ++ if (buf == NULL || buflen == 0) { ++ return; + } +- r = next(); +- memmove((uint8_t *)buf + i, &r, buflen % sizeof(r)); +- return; ++ ++ isc_entropy_get(buf, buflen); + } + + uint32_t +-isc_random_uniform(uint32_t upper_bound) { +- /* Copy of arc4random_uniform from OpenBSD */ +- uint32_t r, min; +- +- RUNTIME_CHECK(isc_once_do(&isc_random_once, isc_random_initialize) == +- ISC_R_SUCCESS); +- +- if (upper_bound < 2) { +- return 0; +- } +- +-#if (ULONG_MAX > 0xffffffffUL) +- min = 0x100000000UL % upper_bound; +-#else /* if (ULONG_MAX > 0xffffffffUL) */ +- /* Calculate (2**32 % upper_bound) avoiding 64-bit math */ +- if (upper_bound > 0x80000000) { +- min = 1 + ~upper_bound; /* 2**32 - upper_bound */ +- } else { +- /* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */ +- min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound; +- } +-#endif /* if (ULONG_MAX > 0xffffffffUL) */ +- ++isc_random_uniform(uint32_t limit) { + /* +- * This could theoretically loop forever but each retry has +- * p > 0.5 (worst case, usually far better) of selecting a +- * number inside the range we need, so it should rarely need +- * to re-roll. ++ * Daniel Lemire's nearly-divisionless unbiased bounded random numbers. ++ * ++ * https://lemire.me/blog/?p=17551 ++ * ++ * The raw random number generator `next()` returns a 32-bit value. ++ * We do a 64-bit multiply `next() * limit` and treat the product as a ++ * 32.32 fixed-point value less than the limit. Our result will be the ++ * integer part (upper 32 bits), and we will use the fraction part ++ * (lower 32 bits) to determine whether or not we need to resample. + */ +- for (;;) { +- r = next(); +- if (r >= min) { +- break; ++ uint64_t num = (uint64_t)random_u32() * (uint64_t)limit; ++ /* ++ * In the fast path, we avoid doing a division in most cases by ++ * comparing the fraction part of `num` with the limit, which is ++ * a slight over-estimate for the exact resample threshold. ++ */ ++ if ((uint32_t)(num) < limit) { ++ /* ++ * We are in the slow path where we re-do the approximate test ++ * more accurately. The exact threshold for the resample loop ++ * is the remainder after dividing the raw RNG limit `1 << 32` ++ * by the caller's limit. We use a trick to calculate it ++ * within 32 bits: ++ * ++ * (1 << 32) % limit ++ * == ((1 << 32) - limit) % limit ++ * == (uint32_t)(-limit) % limit ++ * ++ * This division is safe: we know that `limit` is strictly ++ * greater than zero because of the slow-path test above. ++ */ ++ uint32_t residue = (uint32_t)(-limit) % limit; ++ /* ++ * Unless we get one of `N = (1 << 32) - residue` valid ++ * values, we reject the sample. This `N` is a multiple of ++ * `limit`, so our results will be unbiased; and `N` is the ++ * largest multiple that fits in 32 bits, so rejections are as ++ * rare as possible. ++ * ++ * There are `limit` possible values for the integer part of ++ * our fixed-point number. Each one corresponds to `N/limit` ++ * or `N/limit + 1` possible fraction parts. For our result to ++ * be unbiased, every possible integer part must have the same ++ * number of possible valid fraction parts. So, when we get ++ * the superfluous value in the `N/limit + 1` cases, we need ++ * to reject and resample. ++ * ++ * Because of the multiplication, the possible values in the ++ * fraction part are equally spaced by `limit`, with varying ++ * gaps at each end of the fraction's 32-bit range. We will ++ * choose a range of size `N` (a multiple of `limit`) into ++ * which valid fraction values must fall, with the rest of the ++ * 32-bit range covered by the `residue`. Lemire's paper says ++ * that exactly `N/limit` possible values spaced apart by ++ * `limit` will fit into our size `N` valid range, regardless ++ * of the size of the end gaps, the phase alignment of the ++ * values, or the position of the range. ++ * ++ * So, when a fraction value falls in the `residue` outside ++ * our valid range, it is superfluous, and we resample. ++ */ ++ while ((uint32_t)(num) < residue) { ++ num = (uint64_t)random_u32() * (uint64_t)limit; + } + } +- +- return r % upper_bound; ++ /* ++ * Return the integer part (upper 32 bits). ++ */ ++ return (uint32_t)(num >> 32); + } +diff --git a/tests/isc/random_test.c b/tests/isc/random_test.c +index ccba3170230..52f219bb3ab 100644 +--- a/tests/isc/random_test.c ++++ b/tests/isc/random_test.c +@@ -321,7 +321,9 @@ random_test(pvalue_func_t *func, isc_random_func test_func) { + } + break; + case ISC_RANDOM_BYTES: +- isc_random_buf(values, sizeof(values)); ++ for (i = 0; i < ARRAY_SIZE(values); i++) { ++ values[i] = isc_random32(); ++ } + break; + case ISC_RANDOM_UNIFORM: + uniform_values = (uint16_t *)values; +-- +GitLab + diff --git a/bind.spec b/bind.spec index d838d04eae2229589d5cd4a2ddf0b726668dac32..ff3af7c8f3e257a07aad3f163735faacfc217e06 100644 --- a/bind.spec +++ b/bind.spec @@ -1,4 +1,4 @@ -%define anolis_release 1 +%define anolis_release 2 %bcond_with SYSTEMTEST %bcond_without GSSTSIG @@ -41,6 +41,8 @@ Source2: https://downloads.isc.org/isc/bind9/%{version}/bind-%{version}.tar.xz. Source3: named.logrotate Source4: https://downloads.isc.org/isc/pgpkeys/codesign2021.txt Source16: named.conf + +Patch1: 1-bugfix-for-CVE-2025-40780.patch # Refresh by command: dig @a.root-servers.net. +tcp +norec # or from URL Source17: https://www.internic.net/domain/named.root @@ -290,7 +292,7 @@ in HTML and PDF format. %endif %prep -%autosetup -n %{name}-%{version} -N +%autosetup -p1 -n %{name}-%{version} -N # Common patches %autopatch -p1 -m 10 @@ -868,6 +870,9 @@ fi; %endif %changelog +* Thu Oct 30 2025 tomcruiseqi - 32:9.18.34-2 +- Fix CVE-2025-40780 + * Mon Feb 24 2025 yangxinyu - 32:9.18.34-1 - update to 9.18.34