230 lines
7.4 KiB
Diff
230 lines
7.4 KiB
Diff
Downstream-only patch to add arc4random to support/ for use in qsort
|
|
testing.
|
|
|
|
The arc4random implementation is up-to-date with upstream commit
|
|
2642002380aafb71a1d3b569b6d7ebeab3284816, with minor changes to keep
|
|
everything self-contained within support infrastructure. Unlike the
|
|
upstream version, this implementation is a cancellation point.
|
|
Included atomic.h needed by arc4random.
|
|
|
|
diff -Nrup a/support/Makefile b/support/Makefile
|
|
--- a/support/Makefile 2026-03-30 09:17:27.259848607 -0400
|
|
+++ b/support/Makefile 2026-03-30 09:15:31.748426860 -0400
|
|
@@ -39,6 +39,8 @@ libsupport-routines = \
|
|
resolv_response_context_free \
|
|
resolv_test \
|
|
set_fortify_handler \
|
|
+ support-arc4random \
|
|
+ support-arc4random_uniform \
|
|
support-xfstat \
|
|
support-xstat \
|
|
support_become_root \
|
|
diff -Nrup a/support/support-arc4random.c b/support/support-arc4random.c
|
|
--- a/support/support-arc4random.c 1969-12-31 19:00:00.000000000 -0500
|
|
+++ b/support/support-arc4random.c 2026-03-30 12:05:14.721241229 -0400
|
|
@@ -0,0 +1,100 @@
|
|
+/* Pseudo Random Number Generator
|
|
+ Copyright (C) 2022-2025 Free Software Foundation, Inc.
|
|
+ This file is part of the GNU C Library.
|
|
+
|
|
+ The GNU C Library is free software; you can redistribute it and/or
|
|
+ modify it under the terms of the GNU Lesser General Public
|
|
+ License as published by the Free Software Foundation; either
|
|
+ version 2.1 of the License, or (at your option) any later version.
|
|
+
|
|
+ The GNU C Library is distributed in the hope that it will be useful,
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+ Lesser General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU Lesser General Public
|
|
+ License along with the GNU C Library; if not, see
|
|
+ <https://www.gnu.org/licenses/>. */
|
|
+
|
|
+#include <errno.h>
|
|
+#include <not-cancel.h>
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <sys/mman.h>
|
|
+#include <sys/param.h>
|
|
+#include <sys/random.h>
|
|
+#include <poll.h>
|
|
+#include <atomic.h>
|
|
+
|
|
+static void
|
|
+arc4random_getrandom_failure (void)
|
|
+{
|
|
+ __libc_fatal ("Fatal glibc error: cannot get entropy for arc4random\n");
|
|
+}
|
|
+
|
|
+void
|
|
+arc4random_buf (void *p, size_t n)
|
|
+{
|
|
+ static int seen_initialized;
|
|
+ ssize_t l;
|
|
+ int fd;
|
|
+
|
|
+ if (n == 0)
|
|
+ return;
|
|
+
|
|
+ for (;;)
|
|
+ {
|
|
+ l = TEMP_FAILURE_RETRY (getrandom (p, n, 0));
|
|
+ if (l > 0)
|
|
+ {
|
|
+ if ((size_t) l == n)
|
|
+ return; /* Done reading, success. */
|
|
+ p = (uint8_t *) p + l;
|
|
+ n -= l;
|
|
+ continue; /* Interrupted by a signal; keep going. */
|
|
+ }
|
|
+ else if (l < 0 && errno == ENOSYS)
|
|
+ break; /* No syscall, so fallback to /dev/urandom. */
|
|
+ arc4random_getrandom_failure ();
|
|
+ }
|
|
+
|
|
+ if (atomic_load_relaxed (&seen_initialized) == 0)
|
|
+ {
|
|
+ /* Poll /dev/random as an approximation of RNG initialization. */
|
|
+ struct pollfd pfd = { .events = POLLIN };
|
|
+ pfd.fd = TEMP_FAILURE_RETRY (
|
|
+ __open64_nocancel ("/dev/random", O_RDONLY | O_CLOEXEC | O_NOCTTY));
|
|
+ if (pfd.fd < 0)
|
|
+ arc4random_getrandom_failure ();
|
|
+ if (TEMP_FAILURE_RETRY (poll (&pfd, 1, -1)) < 0)
|
|
+ arc4random_getrandom_failure ();
|
|
+ if (__close_nocancel (pfd.fd) < 0)
|
|
+ arc4random_getrandom_failure ();
|
|
+ atomic_store_relaxed (&seen_initialized, 1);
|
|
+ }
|
|
+
|
|
+ fd = TEMP_FAILURE_RETRY (
|
|
+ __open64_nocancel ("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOCTTY));
|
|
+ if (fd < 0)
|
|
+ arc4random_getrandom_failure ();
|
|
+ for (;;)
|
|
+ {
|
|
+ l = TEMP_FAILURE_RETRY (__read_nocancel (fd, p, n));
|
|
+ if (l <= 0)
|
|
+ arc4random_getrandom_failure ();
|
|
+ if ((size_t) l == n)
|
|
+ break; /* Done reading, success. */
|
|
+ p = (uint8_t *) p + l;
|
|
+ n -= l;
|
|
+ }
|
|
+ if (__close_nocancel (fd) < 0)
|
|
+ arc4random_getrandom_failure ();
|
|
+}
|
|
+
|
|
+uint32_t
|
|
+arc4random (void)
|
|
+{
|
|
+ uint32_t r;
|
|
+ arc4random_buf (&r, sizeof (r));
|
|
+ return r;
|
|
+}
|
|
diff -Nrup a/support/support-arc4random_uniform.c b/support/support-arc4random_uniform.c
|
|
--- a/support/support-arc4random_uniform.c 1969-12-31 19:00:00.000000000 -0500
|
|
+++ b/support/support-arc4random_uniform.c 2026-03-30 09:15:31.748993540 -0400
|
|
@@ -0,0 +1,70 @@
|
|
+/* Random pseudo generator number which returns a single 32 bit value
|
|
+ uniformly distributed but with an upper_bound.
|
|
+ Copyright (C) 2022-2025 Free Software Foundation, Inc.
|
|
+ This file is part of the GNU C Library.
|
|
+
|
|
+ The GNU C Library is free software; you can redistribute it and/or
|
|
+ modify it under the terms of the GNU Lesser General Public
|
|
+ License as published by the Free Software Foundation; either
|
|
+ version 2.1 of the License, or (at your option) any later version.
|
|
+
|
|
+ The GNU C Library is distributed in the hope that it will be useful,
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+ Lesser General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU Lesser General Public
|
|
+ License along with the GNU C Library; if not, see
|
|
+ <https://www.gnu.org/licenses/>. */
|
|
+
|
|
+#include <stdlib.h>
|
|
+#include <sys/param.h>
|
|
+#include <support/support.h>
|
|
+
|
|
+/* Return a uniformly distributed random number less than N. The algorithm
|
|
+ calculates a mask being the lowest power of two bounding the upper bound
|
|
+ N, successively queries new random values, and rejects values outside of
|
|
+ the request range.
|
|
+
|
|
+ For reject values, it also tries if the remaining entropy could fit on
|
|
+ the asked range after range adjustment.
|
|
+
|
|
+ The algorithm avoids modulo and divide operations, which might be costly
|
|
+ depending on the architecture. */
|
|
+uint32_t
|
|
+arc4random_uniform (uint32_t n)
|
|
+{
|
|
+ if (n <= 1)
|
|
+ /* There is no valid return value for a zero limit, and 0 is the
|
|
+ only possible result for limit 1. */
|
|
+ return 0;
|
|
+
|
|
+ /* Powers of two are easy. */
|
|
+ if (powerof2 (n))
|
|
+ return arc4random () & (n - 1);
|
|
+
|
|
+ /* mask is the smallest power of 2 minus 1 number larger than n. */
|
|
+ int z = __builtin_clz (n);
|
|
+ uint32_t mask = ~UINT32_C(0) >> z;
|
|
+ int bits = CHAR_BIT * sizeof (uint32_t) - z;
|
|
+
|
|
+ while (1)
|
|
+ {
|
|
+ uint32_t value = arc4random ();
|
|
+
|
|
+ /* Return if the lower power of 2 minus 1 satisfy the condition. */
|
|
+ uint32_t r = value & mask;
|
|
+ if (r < n)
|
|
+ return r;
|
|
+
|
|
+ /* Otherwise check if remaining bits of entropy provides fits in the
|
|
+ bound. */
|
|
+ for (int bits_left = z; bits_left >= bits; bits_left -= bits)
|
|
+ {
|
|
+ value >>= bits;
|
|
+ r = value & mask;
|
|
+ if (r < n)
|
|
+ return r;
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff -Nrup a/support/support.h b/support/support.h
|
|
--- a/support/support.h 2026-03-30 09:17:27.259975554 -0400
|
|
+++ b/support/support.h 2026-03-30 09:19:25.546023987 -0400
|
|
@@ -24,6 +24,7 @@
|
|
#define SUPPORT_H
|
|
|
|
#include <stdbool.h>
|
|
+#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include <sys/cdefs.h>
|
|
/* For mode_t. */
|
|
@@ -130,6 +131,18 @@ extern void support_copy_file (const cha
|
|
|
|
extern ssize_t support_copy_file_range (int, off64_t *, int, off64_t *,
|
|
size_t, unsigned int);
|
|
+/* Return a random integer between zero and 2**32-1 (inclusive). */
|
|
+extern uint32_t arc4random (void)
|
|
+ __THROW __wur;
|
|
+
|
|
+/* Fill the buffer with random data. */
|
|
+extern void arc4random_buf (void *__buf, size_t __size)
|
|
+ __THROW __nonnull ((1));
|
|
+
|
|
+/* Return a random number between zero (inclusive) and the specified
|
|
+ limit (exclusive). */
|
|
+extern uint32_t arc4random_uniform (__uint32_t __upper_bound)
|
|
+ __THROW __wur;
|
|
|
|
__END_DECLS
|
|
|