diff --git a/bind-9.18-CVE-2025-40780.patch b/bind-9.18-CVE-2025-40780.patch new file mode 100644 index 0000000..62fd7bb --- /dev/null +++ b/bind-9.18-CVE-2025-40780.patch @@ -0,0 +1,361 @@ +From e2bfe1eec2f492224df85a04099d4505c9698965 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) +(cherry picked from commit 8330b49fb90bfeae14b47b7983e9459cc2bbaffe) +--- + lib/isc/include/isc/random.h | 2 +- + lib/isc/random.c | 189 ++++++++++++++++++----------------- + lib/isc/tests/random_test.c | 4 +- + lib/isc/xoshiro128starstar.c | 61 ----------- + 4 files changed, 103 insertions(+), 153 deletions(-) + delete mode 100644 lib/isc/xoshiro128starstar.c + +diff --git a/lib/isc/include/isc/random.h b/lib/isc/include/isc/random.h +index 556e747..2c16472 100644 +--- a/lib/isc/include/isc/random.h ++++ b/lib/isc/include/isc/random.h +@@ -18,7 +18,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 753453f..57430ac 100644 +--- a/lib/isc/random.c ++++ b/lib/isc/random.c +@@ -29,131 +29,140 @@ + */ + + #include +-#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. ++/* from lib/isc/include/isc/os.h in 9.18 */ ++/*%< ++ * Hardcode the L1 cacheline size of the CPU to 64, this is checked in ++ * the os.c library constructor if operating system provide means to ++ * get the L1 cacheline size using sysconf(). + */ ++#define ISC_OS_CACHELINE_SIZE 64 + +-/* +- * 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. +- */ +-#include "xoshiro128starstar.c" + +-ISC_THREAD_LOCAL isc_once_t isc_random_once = ISC_ONCE_INIT; ++#define ISC_RANDOM_BUFSIZE (ISC_OS_CACHELINE_SIZE / sizeof(uint32_t)) ++ISC_THREAD_LOCAL uint32_t isc__random_pool[ISC_RANDOM_BUFSIZE]; ++ISC_THREAD_LOCAL size_t isc__random_pos = ISC_RANDOM_BUFSIZE; + +-static void +-isc_random_initialize(void) { +- int useed[4] = { 0, 0, 0, 1 }; ++static uint32_t ++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. +- */ +-#else /* if FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ +- isc_entropy_get(useed, sizeof(useed)); +-#endif /* if FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ +- memmove(seed, useed, sizeof(seed)); ++ * 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). ++ return (uint32_t)(isc__random_pos++); ++#endif ++ 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); +- +- for (i = 0; i + sizeof(r) <= buflen; i += sizeof(r)) { +- r = next(); +- memmove((uint8_t *)buf + i, &r, sizeof(r)); ++ REQUIRE(buflen == 0 || buf != NULL); ++ 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/lib/isc/tests/random_test.c b/lib/isc/tests/random_test.c +index 7161cd9..f47137d 100644 +--- a/lib/isc/tests/random_test.c ++++ b/lib/isc/tests/random_test.c +@@ -345,7 +345,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; +diff --git a/lib/isc/xoshiro128starstar.c b/lib/isc/xoshiro128starstar.c +deleted file mode 100644 +index 9cdc258..0000000 +--- a/lib/isc/xoshiro128starstar.c ++++ /dev/null +@@ -1,61 +0,0 @@ +-/* +- * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC") +- * +- * This Source Code Form is subject to the terms of the Mozilla Public +- * License, v. 2.0. If a copy of the MPL was not distributed with this +- * file, you can obtain one at https://mozilla.org/MPL/2.0/. +- * +- * See the COPYRIGHT file distributed with this work for additional +- * information regarding copyright ownership. +- */ +- +-/* +- * 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 . +- */ +- +-#include +- +-#include +- +-/* +- * 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. +- */ +-ISC_THREAD_LOCAL uint32_t seed[4] = { 0 }; +- +-static inline uint32_t +-rotl(const uint32_t x, int k) { +- return ((x << k) | (x >> (32 - k))); +-} +- +-static inline 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); +-} +-- +2.51.0 + diff --git a/bind9.16.spec b/bind9.16.spec index 2d81e6a..aab5054 100644 --- a/bind9.16.spec +++ b/bind9.16.spec @@ -62,7 +62,7 @@ Summary: The Berkeley Internet Name Domain (BIND) DNS (Domain Name System) serv Name: bind9.16 License: MPLv2.0 Version: 9.16.23 -Release: 0.22%{?dist}.3 +Release: 0.22%{?dist}.4 Epoch: 32 Url: https://www.isc.org/downloads/bind/ # @@ -174,6 +174,8 @@ Patch215: bind-9.18-CVE-2024-11187-pre-test.patch Patch216: bind-9.18-CVE-2024-11187.patch # https://gitlab.isc.org/isc-projects/bind9/commit/8924adca613ca9daea63786563cce6fdbd742c56 Patch217: bind-9.16-update-b.root-servers.net.patch +# https://gitlab.isc.org/isc-projects/bind9/commit/8330b49fb90bfeae14b47b7983e9459cc2bbaffe +Patch225: bind-9.18-CVE-2025-40780.patch %{?systemd_ordering} Requires: coreutils @@ -1253,6 +1255,9 @@ fi; %endif %changelog +* Wed Oct 29 2025 Petr Menšík - 32:9.16.23-0.22.4 +- Prevent cache poisoning due to weak PRNG (CVE-2025-40780) + * Wed Aug 13 2025 Petr Menšík - Update addresses of b.root-servers.net (RHEL-18449) - 32:9.16.23-0.22.3