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.
diff --git a/support/Makefile b/support/Makefile
index d6d03c2ed3af3e6d..bffcb06d7185d674 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -41,6 +41,8 @@ libsupport-routines = \
resolv_response_context_free \
resolv_test \
set_fortify_handler \
+ support-arc4random \
+ support-arc4random_uniform \
support-open-dev-null-range \
support_become_root \
support_can_chroot \
diff --git a/support/support-arc4random.c b/support/support-arc4random.c
new file mode 100644
index 0000000000000000..c4462b098c68cef5
--- /dev/null
+++ b/support/support-arc4random.c
@@ -0,0 +1,99 @@
+/* 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
+ . */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+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 --git a/support/support-arc4random_uniform.c b/support/support-arc4random_uniform.c
new file mode 100644
index 0000000000000000..20108e7409cca81b
--- /dev/null
+++ b/support/support-arc4random_uniform.c
@@ -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
+ . */
+
+#include
+#include
+#include
+
+/* 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 --git a/support/support.h b/support/support.h
index b69f588e2edce6be..ed7862daf9e4120a 100644
--- a/support/support.h
+++ b/support/support.h
@@ -220,6 +220,19 @@ void support_stack_free (struct support_stack *stack);
The returned value is the lowest file descriptor number. */
int support_open_dev_null_range (int num, int flags, mode_t mode);
+/* 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
#endif /* SUPPORT_H */