This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [PATCH] arc4random implementation
- From: Florian Weimer <fweimer at redhat dot com>
- To: libc-alpha at sourceware dot org
- Date: Thu, 21 Jun 2018 14:00:22 +0200
- Subject: Re: [PATCH] arc4random implementation
- References: <6edcc7d8-56fd-ab1f-8f65-0ed12f45618f@redhat.com>
I rebased the patch on current master.
Additional changes: I added a missing TEMP_FAILURE_RETRY to the
/dev/urandom-based reseeding. I changed the x86 hardware implementation
not to us a separate flag variable, so this implementation doesn't need
any CPU-specific state after all.
Thanks,
Florian
Subject: [PATCH] Add arc4random, arc4random_buf, arc4random_uniform [BZ #4417]
To: libc-alpha@sourceware.org
2018-05-31 Florian Weimer <fweimer@redhat.com>
[BZ #4417]
Add arc4random, arc4random_buf, arc4random_uniform.
* LICENSES: Mention libgcrypt.
* stdlib/Makefile (headers): Add bits/arc4random.h.
(routines): Add arc4random, arc4random_buf, arc4random_uniform,
arc4random-thread, arc4random-forkdetect arc4random-reseed,
arc4random-aes.
(tests): Add tst-arc4random-fork, tst-arc4random-thread.
(tests-arc4random-internal): New variable.
(tests-internal, tests-static): Add tst-arc4random-aes,
tst-arc4random-forkdetect, tst-arc4random-stats.
* stdlib/Versions (GLIBC_2.28): Export arc4random, arc4random_buf,
arc4random_uniform.
(GLIBC_PRIVATE): Export __libc_arc4random_buf,
__libc_arc4random_uniform.
* stdlib/stdlib.h [__USE_MISC]: Include <bits/arc4random.h>.
* stdlib/sys/random.h: Likewise.
* sysdeps/generic/Makefile [$(subdir) == stdlib] (sysdep_routines):
Add arc4random-cpu, arc4random-kernel.
* sysdeps/nptl/fork.c (__libc_fork): Call
__arc4random_after_fork_reinit.
* sysdeps/mach/hurd/fork.c (__fork): Likewise.
* sysdeps/x86/cpu-features.h (bit_cpu_RDRAND, bit_cpu_AES)
(index_cpu_RDRAND, index_cpu_AES, reg_RDRAND, reg_AES): Define.
* include/bits/arc4random.h: New file.
* stdlib/arc4random-aes.c: Likewise.
* stdlib/arc4random-forkdetect.c: Likewise.
* stdlib/arc4random-forkdetect.h: Likewise.
* stdlib/arc4random-private.h: Likewise.
* stdlib/arc4random-reseed.c: Likewise.
* stdlib/arc4random-thread.h: Likewise.
* stdlib/arc4random.c: Likewise.
* stdlib/arc4random_buf.c: Likewise.
* stdlib/arc4random_uniform.c: Likewise.
* stdlib/bits/arc4random.h: Likewise.
* stdlib/tst-arc4random-aes.c: Likewise.
* stdlib/tst-arc4random-fork.c: Likewise.
* stdlib/tst-arc4random-forkdetect.c: Likewise.
* stdlib/tst-arc4random-stats.c: Likewise.
* stdlib/tst-arc4random-thread.c: Likewise.
* sysdeps/generic/arc4random-cpu-data.h: Likewise.
* sysdeps/generic/arc4random-cpu.c: Likewise.
* sysdeps/generic/arc4random-cpu.h: Likewise.
* sysdeps/generic/arc4random-kernel.c: Likewise.
* sysdeps/generic/arc4random-kernel.h: Likewise.
* sysdeps/unix/sysv/linux/arc4random-kernel.c: Likewise.
* sysdeps/unix/sysv/linux/arc4random-kernel.h: Likewise.
* sysdeps/x86/arc4random-cpu.c: Likewise.
* sysdeps/x86/arc4random-cpu.h: Likewise.
* sysdeps/**/libc*.abilist: Add arc4random, arc4random_buf,
arc4random_uniform.
diff --git a/LICENSES b/LICENSES
index b29efe0108..1f12e1b121 100644
--- a/LICENSES
+++ b/LICENSES
@@ -398,3 +398,59 @@ Copyright 2001 by Stephen L. Moshier <moshier@na-net.ornl.gov>
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see
<http://www.gnu.org/licenses/>. */
+
+stdlib/arc4random-aes.c imports code from libgcrypt, with the
+following notices:
+
+Rijndael (AES) for GnuPG
+Copyright (C) 2000, 2001, 2002, 2003, 2007,
+ 2008, 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of Libgcrypt.
+
+Libgcrypt 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.
+
+Libgcrypt 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 this program; if not, see <http://www.gnu.org/licenses/>.
+******************************************************************
+The code here is based on the optimized implementation taken from
+http://www.esat.kuleuven.ac.be/~rijmen/rijndael/ on Oct 2, 2000,
+which carries this notice:
+------------------------------------------
+rijndael-alg-fst.c v2.3 April '2000
+
+Optimised ANSI C code
+
+authors: v1.0: Antoon Bosselaers
+ v2.0: Vincent Rijmen
+ v2.3: Paulo Barreto
+
+This code is placed in the public domain.
+------------------------------------------
+
+rijndael-tables.h - Rijndael (AES) for GnuPG,
+Copyright (C) 2000, 2001, 2002, 2003, 2007,
+ 2008 Free Software Foundation, Inc.
+
+This file is part of Libgcrypt.
+
+Libgcrypt 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.
+
+Libgcrypt 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 this program; if not, see <http://www.gnu.org/licenses/>.
diff --git a/NEWS b/NEWS
index d51fa09544..f64300a0be 100644
--- a/NEWS
+++ b/NEWS
@@ -24,6 +24,8 @@ Major new features:
- fdiv, fdivl, ddivl and corresponding fMdivfN, fMdivfNx, fMxdivfN and
fMxdivfNx functions.
+* The functions arc4random, arc4random_buf, arc4random_uniform are provided.
+
* Nominative and genitive month names are now supported for the following
languages: Catalan, Czech, Scottish Gaelic, Upper Sorbian, and Walloon.
The Catalan and Greek languages now support abbreviated alternative
diff --git a/include/bits/arc4random.h b/include/bits/arc4random.h
new file mode 100644
index 0000000000..c6bcb0eb76
--- /dev/null
+++ b/include/bits/arc4random.h
@@ -0,0 +1,37 @@
+/* Wrapper header for <stdlib/bits/arc4random.h>.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdlib/bits/arc4random.h>
+
+#ifndef _ISOMAC
+__typeof__ (arc4random) __libc_arc4random;
+libc_hidden_proto (__libc_arc4random)
+
+__typeof__ (arc4random_buf) __libc_arc4random_buf;
+libc_hidden_proto (__libc_arc4random_buf)
+
+__typeof__ (arc4random_uniform) __libc_arc4random_uniform;
+libc_hidden_proto (__libc_arc4random_uniform)
+
+/* Called from the glibc fork function to reinitialize the subsystem
+ lock in the child process. This avoids deadlocks if fork is called
+ in multi-threaded processes. Fork detection is handled by other
+ means; see arc4random-forkdetect.h. */
+void __arc4random_after_fork_reinit (void) attribute_hidden;
+
+#endif
diff --git a/stdlib/Makefile b/stdlib/Makefile
index 808a8ceab7..2d6ccfb090 100644
--- a/stdlib/Makefile
+++ b/stdlib/Makefile
@@ -29,7 +29,7 @@ headers := stdlib.h bits/stdlib.h bits/stdlib-ldbl.h bits/stdlib-float.h \
ucontext.h sys/ucontext.h \
alloca.h fmtmsg.h \
bits/stdlib-bsearch.h sys/random.h bits/stdint-intn.h \
- bits/stdint-uintn.h
+ bits/stdint-uintn.h bits/arc4random.h
routines := \
atof atoi atol atoll \
@@ -57,7 +57,10 @@ routines := \
a64l l64a \
rpmatch strfmon strfmon_l getsubopt xpg_basename fmtmsg \
strtoimax strtoumax wcstoimax wcstoumax \
- getcontext setcontext makecontext swapcontext
+ getcontext setcontext makecontext swapcontext \
+ arc4random arc4random_buf arc4random_uniform arc4random-forkdetect \
+ arc4random-reseed arc4random-aes
+
aux = grouping groupingwc tens_in_limb
# These routines will be omitted from the libc shared object.
@@ -84,12 +87,23 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \
tst-cxa_atexit tst-on_exit test-atexit-race \
test-at_quick_exit-race test-cxa_atexit-race \
test-on_exit-race test-dlclose-exit-race \
- tst-makecontext-align test-bz22786 tst-strtod-nan-sign
+ tst-makecontext-align test-bz22786 tst-strtod-nan-sign \
+ tst-arc4random-fork tst-arc4random-thread
tests-internal := tst-strtod1i tst-strtod3 tst-strtod4 tst-strtod5i \
tst-tls-atexit tst-tls-atexit-nodelete
tests-static := tst-secure-getenv
+# Thse arc4random tests access hidden symbols, so they need to be
+# internal, statically linked tests.
+tests-arc4random-internal = \
+ tst-arc4random-aes \
+ tst-arc4random-forkdetect \
+ tst-arc4random-stats \
+
+tests-internal += $(tests-arc4random-internal)
+tests-static += $(tests-arc4random-internal)
+
ifeq ($(build-hardcoded-path-in-tests),yes)
tests += tst-empty-env
endif
@@ -239,3 +253,6 @@ $(objpfx)tst-setcontext3.out: tst-setcontext3.sh $(objpfx)tst-setcontext3
$(evaluate-test)
$(objpfx)tst-makecontext: $(libdl)
+$(objpfx)tst-arc4random-fork: $(shared-thread-library)
+$(objpfx)tst-arc4random-forkdetect: $(static-thread-library)
+$(objpfx)tst-arc4random-thread: $(shared-thread-library)
diff --git a/stdlib/Versions b/stdlib/Versions
index a2dfa322ed..c624f4c2fc 100644
--- a/stdlib/Versions
+++ b/stdlib/Versions
@@ -139,6 +139,9 @@ libc {
strtof32; strtof64; strtof32x;
strtof32_l; strtof64_l; strtof32x_l;
}
+ GLIBC_2.28 {
+ arc4random; arc4random_buf; arc4random_uniform;
+ }
GLIBC_PRIVATE {
# functions which have an additional interface since they are
# are cancelable.
@@ -149,5 +152,6 @@ libc {
__libc_secure_getenv;
__call_tls_dtors;
__strtof_nan; __strtod_nan; __strtold_nan;
+ __libc_arc4random_buf; __libc_arc4random_uniform;
}
}
diff --git a/stdlib/arc4random-aes.c b/stdlib/arc4random-aes.c
new file mode 100644
index 0000000000..04a150ab57
--- /dev/null
+++ b/stdlib/arc4random-aes.c
@@ -0,0 +1,407 @@
+/* AES implementation for arc4random.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <arc4random-private.h>
+#include <endian.h>
+
+/* Forward declarations for the code imported from libcrypt. */
+static void do_setkey (struct arc4random_data *,
+ const unsigned char *);
+static void
+do_encrypt_fn (const struct arc4random_data *data,
+ struct arc4random_block *b,
+ const struct arc4random_block *a);
+static const uint32_t encT[256];
+static const uint32_t rcon[30];
+
+void
+__arc4random_schedule (struct arc4random_data *data,
+ const unsigned char *key)
+{
+ if (__arc4random_cpu_schedule (data, key))
+ return;
+ do_setkey (data, key);
+}
+
+void
+__arc4random_block (const struct arc4random_data *data,
+ struct arc4random_personalization personalization,
+ struct arc4random_block *output)
+{
+ if (__arc4random_cpu_block (data, personalization, output))
+ return;
+
+ union
+ {
+ struct arc4random_personalization personalization;
+ struct arc4random_block block;
+ } u;
+ u.personalization = personalization;
+ do_encrypt_fn (data, output, &u.block);
+}
+
+/* Reimplemented helper functions used by the code imported from
+ libgcrypt below. */
+
+static inline uint32_t
+le_bswap32 (uint32_t value)
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ return __builtin_bswap32 (value);
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+ return value;
+#else
+# error invalid __BYTE_ORDER
+#endif
+}
+
+static inline uint32_t
+rol (uint32_t value, unsigned int shift)
+{
+ return (value << (shift & 31)) | (value >> ((32 - shift) & 31));
+}
+
+/* The do_setkey and do_encrypt_fn functions are based on rijndael.c
+ from libgcrypt 1.8.1, which has the following copyright
+ information. */
+
+/* Rijndael (AES) for GnuPG
+ * Copyright (C) 2000, 2001, 2002, 2003, 2007,
+ * 2008, 2011, 2012 Free Software Foundation, Inc.
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt 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.
+ *
+ * Libgcrypt 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 this program; if not, see <http://www.gnu.org/licenses/>.
+ *******************************************************************
+ * The code here is based on the optimized implementation taken from
+ * http://www.esat.kuleuven.ac.be/~rijmen/rijndael/ on Oct 2, 2000,
+ * which carries this notice:
+ *------------------------------------------
+ * rijndael-alg-fst.c v2.3 April '2000
+ *
+ * Optimised ANSI C code
+ *
+ * authors: v1.0: Antoon Bosselaers
+ * v2.0: Vincent Rijmen
+ * v2.3: Paulo Barreto
+ *
+ * This code is placed in the public domain.
+ *------------------------------------------
+ *
+ * The SP800-38a document is available at:
+ * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
+ *
+ */
+
+static void
+do_setkey (struct arc4random_data *data, const unsigned char *key)
+{
+ enum { KC = 4, keylen = 16 };
+ const unsigned char *sbox = ((const unsigned char *) encT) + 1;
+ union
+ {
+ unsigned char tk[KC][4];
+ uint32_t tk_u32[KC];
+ } u;
+ int rconpointer = 0;
+
+ typedef uint32_t unaligned_uint32_t __attribute__ ((aligned (1)));
+ const unaligned_uint32_t *key32 = (const unaligned_uint32_t *) key;
+
+ for (int j = 0; j < KC; ++j)
+ u.tk_u32[j] = key32[j];
+
+ int r = 0;
+ int t = 0;
+ /* Copy values into round key array. */
+ for (int j = 0; j < KC && r < arc4random_aes_rounds + 1; )
+ {
+ for (; j < KC && t < 4; j++, t++)
+ data->generic[r][t] = le_bswap32 (u.tk_u32[j]);
+ if (t == 4)
+ {
+ r++;
+ t = 0;
+ }
+ }
+
+ while (r < arc4random_aes_rounds + 1)
+ {
+ /* While not enough round key material calculated calculate
+ new values. */
+ u.tk[0][0] ^= sbox[u.tk[KC - 1][1] * 4];
+ u.tk[0][1] ^= sbox[u.tk[KC - 1][2] * 4];
+ u.tk[0][2] ^= sbox[u.tk[KC - 1][3] * 4];
+ u.tk[0][3] ^= sbox[u.tk[KC - 1][0] * 4];
+ u.tk[0][0] ^= rcon[rconpointer++];
+
+ for (int j = 1; j < KC; j++)
+ u.tk_u32[j] ^= u.tk_u32[j - 1];
+
+ /* Copy values into round key array. */
+ for (int j = 0; j < KC && r < arc4random_aes_rounds + 1; )
+ {
+ for (; j < KC && t < 4; j++, t++)
+ data->generic[r][t] = le_bswap32 (u.tk_u32[j]);
+ if (t == 4)
+ {
+ r++;
+ t = 0;
+ }
+ }
+ }
+}
+
+static void
+do_encrypt_fn (const struct arc4random_data *data,
+ struct arc4random_block *b,
+ const struct arc4random_block *a)
+{
+ const unsigned char *sbox = ((const unsigned char *)encT) + 1;
+ int r;
+ uint32_t sa[4];
+ uint32_t sb[4];
+
+ sb[0] = le_bswap32 (a->data[0]);
+ sb[1] = le_bswap32 (a->data[1]);
+ sb[2] = le_bswap32 (a->data[2]);
+ sb[3] = le_bswap32 (a->data[3]);
+
+ sa[0] = sb[0] ^ data->generic[0][0];
+ sa[1] = sb[1] ^ data->generic[0][1];
+ sa[2] = sb[2] ^ data->generic[0][2];
+ sa[3] = sb[3] ^ data->generic[0][3];
+
+ sb[0] = rol (encT[(uint8_t) (sa[0] >> (0 * 8))], (0 * 8));
+ sb[3] = rol (encT[(uint8_t) (sa[0] >> (1 * 8))], (1 * 8));
+ sb[2] = rol (encT[(uint8_t) (sa[0] >> (2 * 8))], (2 * 8));
+ sb[1] = rol (encT[(uint8_t) (sa[0] >> (3 * 8))], (3 * 8));
+ sa[0] = data->generic[1][0] ^ sb[0];
+
+ sb[1] ^= rol (encT[(uint8_t) (sa[1] >> (0 * 8))], (0 * 8));
+ sa[0] ^= rol (encT[(uint8_t) (sa[1] >> (1 * 8))], (1 * 8));
+ sb[3] ^= rol (encT[(uint8_t) (sa[1] >> (2 * 8))], (2 * 8));
+ sb[2] ^= rol (encT[(uint8_t) (sa[1] >> (3 * 8))], (3 * 8));
+ sa[1] = data->generic[1][1] ^ sb[1];
+
+ sb[2] ^= rol (encT[(uint8_t) (sa[2] >> (0 * 8))], (0 * 8));
+ sa[1] ^= rol (encT[(uint8_t) (sa[2] >> (1 * 8))], (1 * 8));
+ sa[0] ^= rol (encT[(uint8_t) (sa[2] >> (2 * 8))], (2 * 8));
+ sb[3] ^= rol (encT[(uint8_t) (sa[2] >> (3 * 8))], (3 * 8));
+ sa[2] = data->generic[1][2] ^ sb[2];
+
+ sb[3] ^= rol (encT[(uint8_t) (sa[3] >> (0 * 8))], (0 * 8));
+ sa[2] ^= rol (encT[(uint8_t) (sa[3] >> (1 * 8))], (1 * 8));
+ sa[1] ^= rol (encT[(uint8_t) (sa[3] >> (2 * 8))], (2 * 8));
+ sa[0] ^= rol (encT[(uint8_t) (sa[3] >> (3 * 8))], (3 * 8));
+ sa[3] = data->generic[1][3] ^ sb[3];
+
+ for (r = 2; r < arc4random_aes_rounds; r++)
+ {
+ sb[0] = rol (encT[(uint8_t) (sa[0] >> (0 * 8))], (0 * 8));
+ sb[3] = rol (encT[(uint8_t) (sa[0] >> (1 * 8))], (1 * 8));
+ sb[2] = rol (encT[(uint8_t) (sa[0] >> (2 * 8))], (2 * 8));
+ sb[1] = rol (encT[(uint8_t) (sa[0] >> (3 * 8))], (3 * 8));
+ sa[0] = data->generic[r][0] ^ sb[0];
+
+ sb[1] ^= rol (encT[(uint8_t) (sa[1] >> (0 * 8))], (0 * 8));
+ sa[0] ^= rol (encT[(uint8_t) (sa[1] >> (1 * 8))], (1 * 8));
+ sb[3] ^= rol (encT[(uint8_t) (sa[1] >> (2 * 8))], (2 * 8));
+ sb[2] ^= rol (encT[(uint8_t) (sa[1] >> (3 * 8))], (3 * 8));
+ sa[1] = data->generic[r][1] ^ sb[1];
+
+ sb[2] ^= rol (encT[(uint8_t) (sa[2] >> (0 * 8))], (0 * 8));
+ sa[1] ^= rol (encT[(uint8_t) (sa[2] >> (1 * 8))], (1 * 8));
+ sa[0] ^= rol (encT[(uint8_t) (sa[2] >> (2 * 8))], (2 * 8));
+ sb[3] ^= rol (encT[(uint8_t) (sa[2] >> (3 * 8))], (3 * 8));
+ sa[2] = data->generic[r][2] ^ sb[2];
+
+ sb[3] ^= rol (encT[(uint8_t) (sa[3] >> (0 * 8))], (0 * 8));
+ sa[2] ^= rol (encT[(uint8_t) (sa[3] >> (1 * 8))], (1 * 8));
+ sa[1] ^= rol (encT[(uint8_t) (sa[3] >> (2 * 8))], (2 * 8));
+ sa[0] ^= rol (encT[(uint8_t) (sa[3] >> (3 * 8))], (3 * 8));
+ sa[3] = data->generic[r][3] ^ sb[3];
+
+ r++;
+
+ sb[0] = rol (encT[(uint8_t) (sa[0] >> (0 * 8))], (0 * 8));
+ sb[3] = rol (encT[(uint8_t) (sa[0] >> (1 * 8))], (1 * 8));
+ sb[2] = rol (encT[(uint8_t) (sa[0] >> (2 * 8))], (2 * 8));
+ sb[1] = rol (encT[(uint8_t) (sa[0] >> (3 * 8))], (3 * 8));
+ sa[0] = data->generic[r][0] ^ sb[0];
+
+ sb[1] ^= rol (encT[(uint8_t) (sa[1] >> (0 * 8))], (0 * 8));
+ sa[0] ^= rol (encT[(uint8_t) (sa[1] >> (1 * 8))], (1 * 8));
+ sb[3] ^= rol (encT[(uint8_t) (sa[1] >> (2 * 8))], (2 * 8));
+ sb[2] ^= rol (encT[(uint8_t) (sa[1] >> (3 * 8))], (3 * 8));
+ sa[1] = data->generic[r][1] ^ sb[1];
+
+ sb[2] ^= rol (encT[(uint8_t) (sa[2] >> (0 * 8))], (0 * 8));
+ sa[1] ^= rol (encT[(uint8_t) (sa[2] >> (1 * 8))], (1 * 8));
+ sa[0] ^= rol (encT[(uint8_t) (sa[2] >> (2 * 8))], (2 * 8));
+ sb[3] ^= rol (encT[(uint8_t) (sa[2] >> (3 * 8))], (3 * 8));
+ sa[2] = data->generic[r][2] ^ sb[2];
+
+ sb[3] ^= rol (encT[(uint8_t) (sa[3] >> (0 * 8))], (0 * 8));
+ sa[2] ^= rol (encT[(uint8_t) (sa[3] >> (1 * 8))], (1 * 8));
+ sa[1] ^= rol (encT[(uint8_t) (sa[3] >> (2 * 8))], (2 * 8));
+ sa[0] ^= rol (encT[(uint8_t) (sa[3] >> (3 * 8))], (3 * 8));
+ sa[3] = data->generic[r][3] ^ sb[3];
+ }
+
+ /* Last round is special. */
+
+ sb[0] = (sbox[(uint8_t) (sa[0] >> (0 * 8)) * 4]) << (0 * 8);
+ sb[3] = (sbox[(uint8_t) (sa[0] >> (1 * 8)) * 4]) << (1 * 8);
+ sb[2] = (sbox[(uint8_t) (sa[0] >> (2 * 8)) * 4]) << (2 * 8);
+ sb[1] = (sbox[(uint8_t) (sa[0] >> (3 * 8)) * 4]) << (3 * 8);
+ sa[0] = data->generic[r][0] ^ sb[0];
+
+ sb[1] ^= (sbox[(uint8_t) (sa[1] >> (0 * 8)) * 4]) << (0 * 8);
+ sa[0] ^= (sbox[(uint8_t) (sa[1] >> (1 * 8)) * 4]) << (1 * 8);
+ sb[3] ^= (sbox[(uint8_t) (sa[1] >> (2 * 8)) * 4]) << (2 * 8);
+ sb[2] ^= (sbox[(uint8_t) (sa[1] >> (3 * 8)) * 4]) << (3 * 8);
+ sa[1] = data->generic[r][1] ^ sb[1];
+
+ sb[2] ^= (sbox[(uint8_t) (sa[2] >> (0 * 8)) * 4]) << (0 * 8);
+ sa[1] ^= (sbox[(uint8_t) (sa[2] >> (1 * 8)) * 4]) << (1 * 8);
+ sa[0] ^= (sbox[(uint8_t) (sa[2] >> (2 * 8)) * 4]) << (2 * 8);
+ sb[3] ^= (sbox[(uint8_t) (sa[2] >> (3 * 8)) * 4]) << (3 * 8);
+ sa[2] = data->generic[r][2] ^ sb[2];
+
+ sb[3] ^= (sbox[(uint8_t) (sa[3] >> (0 * 8)) * 4]) << (0 * 8);
+ sa[2] ^= (sbox[(uint8_t) (sa[3] >> (1 * 8)) * 4]) << (1 * 8);
+ sa[1] ^= (sbox[(uint8_t) (sa[3] >> (2 * 8)) * 4]) << (2 * 8);
+ sa[0] ^= (sbox[(uint8_t) (sa[3] >> (3 * 8)) * 4]) << (3 * 8);
+ sa[3] = data->generic[r][3] ^ sb[3];
+
+ b->data[0] = le_bswap32 (sa[0]);
+ b->data[1] = le_bswap32 (sa[1]);
+ b->data[2] = le_bswap32 (sa[2]);
+ b->data[3] = le_bswap32 (sa[3]);
+}
+
+
+/* The encT table is derived from the rijndael-tables.h file in
+ libgcrypt 1.8.1. */
+
+/* rijndael-tables.h - Rijndael (AES) for GnuPG,
+ * Copyright (C) 2000, 2001, 2002, 2003, 2007,
+ * 2008 Free Software Foundation, Inc.
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt 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.
+ *
+ * Libgcrypt 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 this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+static const uint32_t encT[256] =
+ {
+ 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6,
+ 0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591,
+ 0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56,
+ 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec,
+ 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa,
+ 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb,
+ 0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45,
+ 0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b,
+ 0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c,
+ 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83,
+ 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9,
+ 0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a,
+ 0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d,
+ 0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f,
+ 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df,
+ 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea,
+ 0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34,
+ 0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b,
+ 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d,
+ 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413,
+ 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1,
+ 0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6,
+ 0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972,
+ 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85,
+ 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed,
+ 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511,
+ 0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe,
+ 0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b,
+ 0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05,
+ 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1,
+ 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142,
+ 0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf,
+ 0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3,
+ 0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e,
+ 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a,
+ 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6,
+ 0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3,
+ 0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b,
+ 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428,
+ 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad,
+ 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14,
+ 0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8,
+ 0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4,
+ 0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2,
+ 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda,
+ 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949,
+ 0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf,
+ 0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810,
+ 0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c,
+ 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697,
+ 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e,
+ 0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f,
+ 0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc,
+ 0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c,
+ 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969,
+ 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27,
+ 0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122,
+ 0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433,
+ 0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9,
+ 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5,
+ 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a,
+ 0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0,
+ 0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e,
+ 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c
+ };
+
+static const uint32_t rcon[30] =
+ {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
+ 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
+ 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91
+ };
diff --git a/stdlib/arc4random-forkdetect.c b/stdlib/arc4random-forkdetect.c
new file mode 100644
index 0000000000..6b9208bbed
--- /dev/null
+++ b/stdlib/arc4random-forkdetect.c
@@ -0,0 +1,520 @@
+/* Fork detection support for arc4random.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+
+/* Fork detection comes in two major modes:
+
+ If the kernel supports MADV_WIPEONFORK, fork_detect_data will point
+ to a private mapping which is cleared on fork. The not_forked
+ member is set to 1 during initialization, and the kernel will set
+ it to zero on fork. The forkdetect_pre_wipeonfork function will
+ check this value and reseed if necessary (setting not_forked to
+ non-zero again). forkdetect_post_wipeonfork only checks for
+ concurrent reseeding (which is not actually performed by the
+ current implementation; this may change in the future based on
+ certification requirements). The advantage of MADV_WIPEONFORK mode
+ is that no lock is needed in the common case, and, after
+ initialization, as long as the kernel has a working getrandom
+ implementation, arc4random cannot fail and terminate the process
+ due to a memory-allocation failure.
+
+ Without MADV_WIPEONFORK support, things are considerably more
+ difficult. fork_detect_data points to a MAP_SHARED mapping. Fork
+ detection is performed by comparing the two values of
+ fork_detect_counter, one in the MAP_SHARED mapping (as a struct
+ member) and one as a global data variable in this file (in a
+ MAP_PRIVATE mapping). The counter is incremented while the
+ subsystem lock (arc4random_lock) is acquired. Atomic memory
+ access is used for the counter in the shared mapping. If the
+ counter values diverge, it means that some other process has
+ incremented the counter in the shared mapping, and we need to
+ reseed. Upon reseeding, the shared mapping is replaced with a new
+ MAP_SHARED mapping (in remap_reseed), and the fork detection
+ counter is reset to zero. Both forkdetect_pre_shared and
+ forkdetect_post_shared need to check and increment the fork
+ detection counter. This covers the case of a concurrent fork in a
+ multi-threaded program:
+
+ Thread A Thread B Subprocess
+
+ arc4random called
+ â?¦
+ pre function called
+ fork
+ arc4random called
+ â?¦
+ pre function called
+ (a)
+ â?¦ (compute randomness)
+ post function called
+ (b)
+
+ The counter increment at (a) allows the post function at (b) to
+ detect counter divergence and trigger reseeding in thread A of the
+ parent process. tst-arc4random-forkdetect simulates various cases
+ of such interleaved executions.
+
+ A minor variant occurs in both shared and wipe-on-fork mode because
+ reseed_counter is 64 bits, so a lock is needed if 64-bit atomics
+ are not avaliable. In MAP_SHARED mode, accesses always occur under
+ the subsystem lock, arc4random_lock.
+
+ For the MAP_SHARED mode, only a 32-bit counter is used on the
+ shared mapping, plus an overflow check to trigger reseeding (see
+ FORK_DETECT_COUNTER_LIMIT). This construction is used with 64-bit
+ atomics available as well, to keep the 32-bit and 64-bit
+ implementations consistent.
+
+ In MADV_WIPEONFORK mode, arc4random_lock is not used. See
+ fork_detect_lock below. Instead, the lock is located in the
+ MADV_WIPEONFORK memory, so that the kernel resets it on fork. (In
+ MAP_SHARED mode, resetting the lock on fork will only happen when
+ the glibc fork function is called, not for direct system calls;
+ this can lead to deadlocks in the subprocess if a multi-threaded
+ process forks with a direct system call, and the subprocess calls
+ arc4random.)
+
+ As an optimization, the AES key schedule (in struct
+ arc4random_data) is stored in the mapping as well because it would
+ be a waste to perform a separate allocation for it. Concurrent
+ writes to the key schedule during reseeding may cause
+ __arc4random_block to operate on bad data, but the pre/post retry
+ loop will retry the computation in case of such reseeding. */
+
+#include <allocate_once.h>
+#include <arc4random-forkdetect.h>
+#include <arc4random-private.h>
+#include <arc4random-thread.h>
+#include <assert.h>
+#include <atomic.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/mman.h>
+
+/* Non-zero if MADV_WIPEONFORK is used for fork detection.
+ Initialized by fork_detect_alloc below. Used as a boolean.
+ (Atomic memory access requires the int type.) */
+static int wipeonfork_mode;
+
+/* The subsystem lock. Not always used; see fork_detect_lock
+ below. */
+__libc_lock_define_initialized (static, arc4random_lock)
+
+/* Definition for the declaration in <arc4random-thread.h>. */
+__thread struct arc4random_perthread __arc4random_perthread;
+
+struct fork_detect_data
+{
+ /* This should be aligned on a page boundary. */
+ struct arc4random_data data;
+
+ /* False in MADV_WIPEONFORK mode after fork, otherwise true. Not a
+ boolean due to atomic memory access. */
+ int not_forked;
+
+ /* Lock used in MADV_WIPEONFORK mode, in preference of
+ arc4random_lock. The advantage is that it is automatically
+ reinitialized by the kernel on fork. */
+ __libc_lock_define (, lock);
+
+ uint32_t fork_detect_counter; /* For !wipeonfork_mode mode. */
+};
+
+/* Used with allocate_once. Pointer to the magic mapped data used for
+ fork detection. */
+static void *fork_detect_data;
+
+/* Used to detect concurrent reseeding in
+ __arc4random_forkdetect_post. With wipeonfork_mode and 64-bit
+ atomics support, atomic memory accesses are used. Otherwise, the
+ subsystem lock (see fork_detect_lock) needs to be acquired around
+ accesses. (Writes happen during reseeding, which always acquires
+ the lock.) */
+static uint64_t reseed_counter;
+
+/* Used to assign unique numbers to individual threads calling
+ arc4random. Atomic access with 64-bit atomics; without them, the
+ subsystem lock is needed around access. */
+static uint64_t previous_thread_id;
+
+/* Used with !wipeonfork_mode to detect forks. Protected by the
+ arc4random_lock subsystem lock. */
+static uint32_t fork_detect_counter;
+
+/* Limit of a 32-bit fork counter value, to prevent overflow. (Can be
+ reduced for testing.) */
+#define FORK_DETECT_COUNTER_LIMIT 0XFFFFFFFEU
+
+/* Value for fork_detect_counter which forces reseeding because it
+ will never equal the counter on the shared page. */
+#define FORK_DETECT_COUNTER_RESEED 0XFFFFFFFFU
+
+/* Called to report mmap-related failures. */
+static void
+__attribute__ ((noreturn))
+mmap_failure (void)
+{
+ __libc_fatal ("Fatal glibc error: Cannot allocate memory for arc4random\n");
+}
+
+/* Lock the subsystem lock. This arc4random_lock in shared mode,
+ and the lock on the (private) mapping in wipe-on-fork mode. */
+static inline void
+fork_detect_lock (struct fork_detect_data *fd_data)
+{
+ if (wipeonfork_mode)
+ __libc_lock_lock (fd_data->lock);
+ else
+ __libc_lock_lock (arc4random_lock);
+}
+
+/* Undo the efect of fork_detect_lock. */
+static inline void
+fork_detect_unlock (struct fork_detect_data *fd_data)
+{
+ if (wipeonfork_mode)
+ __libc_lock_unlock (fd_data->lock);
+ else
+ __libc_lock_unlock (arc4random_lock);
+}
+
+/* Used with allocate_once. */
+static void
+fork_detect_free (void *unused, void *ptr)
+{
+ if (__munmap (ptr, sizeof (struct fork_detect_data)) != 0)
+ mmap_failure ();
+}
+
+/* Used with allocate_once. Attempts to allocate a MAP_PRIVATE
+ mapping and set MADV_WIPEONFORK on it. If that fails, use a
+ MAP_SHARED mapping. Initializes wipeonfork_mode as a side
+ effect. */
+static void *
+fork_detect_alloc (void *unused)
+{
+ void *ptr;
+#ifdef MADV_WIPEONFORK
+ /* First attempt a private mapping with MADV_WIPEONFORK. */
+ ptr = __mmap (NULL, sizeof (struct fork_detect_data),
+ PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ if (ptr == MAP_FAILED)
+ mmap_failure ();
+ {
+ int ret = __madvise (ptr, sizeof (struct fork_detect_data),
+ MADV_WIPEONFORK);
+ if (ret == 0)
+ {
+ /* Kernel supports fork detection. */
+
+ /* Relaxed MO store due to potentially racing writes from
+ parallel invocation of fork_detect_alloc. */
+ atomic_store_relaxed (&wipeonfork_mode, 1);
+
+ /* Atomic access for consistency. */
+ struct fork_detect_data *fd_data = ptr;
+ atomic_store_relaxed (&fd_data->not_forked, 1);
+
+ /* fd_data->lock is implicitly zero-initialized. */
+
+ __arc4random_reseed (&fd_data->data);
+ return fd_data;
+ }
+ else if (errno == EINVAL)
+ {
+ /* Kernel does not support MADV_WIPEONFORK. We need to use a
+ MAP_SHARED page for the detection. */
+ fork_detect_free (NULL, ptr);
+ /* Fall through to MAP_SHARED allocation below. */
+ }
+ else
+ mmap_failure ();
+ }
+#endif
+
+ ptr = __mmap (NULL, sizeof (struct fork_detect_data),
+ PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
+ if (ptr == MAP_FAILED)
+ mmap_failure ();
+
+ struct fork_detect_data *fd_data = ptr;
+ __arc4random_reseed (&fd_data->data);
+ return fd_data;
+}
+
+/* Perform the reseeding: Obtain randomness and perform the key
+ schedule (stored in FD_DATA->data). Invalidate the per-thread
+ cache. Must be called with the subsystem lock acquired; see
+ fork_detect_lock. */
+static void
+reseed (struct arc4random_forkdetect *fd,
+ struct fork_detect_data *fd_data)
+{
+ /* This may concurrently write to the arc4random data, but we ensure
+ that reads are consistent with help from the reseed_counter. */
+ __arc4random_reseed (&fd_data->data);
+
+ /* The caller has obtained a lock, but with 64-bit atomics, we still
+ need to synchronize with the acquire MO load in
+ forkdetect_pre_wipeonfork and forkdetect_post_wipeonfork. */
+#if __HAVE_64B_ATOMICS
+ fd->reseed_counter = atomic_load_relaxed (&reseed_counter) + 1;
+ if (fd->reseed_counter == 0)
+ __libc_fatal ("Fatal glibc error: arc4random reseed counter overflow\n");
+ atomic_store_release (&reseed_counter, fd->reseed_counter);
+#else
+ fd->reseed_counter = ++reseed_counter;
+#endif
+
+ /* Discard the thread cache. */
+ __arc4random_thread_discard_cache ();
+}
+
+/* Create a new shared mapping in place of the old one and initialize
+ it. This is fork MAP_SHARED-based fork detection after an
+ arc4random operation in another process has been detected (because
+ of counter divergence). The caller must have acquired the system
+ lock; see fork_detect_lock. */
+static void
+remap_reseed (struct arc4random_forkdetect *fd,
+ struct fork_detect_data *fd_data)
+{
+ assert (!wipeonfork_mode);
+ void *ptr = __mmap (fd_data, sizeof (struct fork_detect_data),
+ PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_SHARED | MAP_FIXED, -1, 0);
+ if (ptr != fd_data)
+ mmap_failure ();
+ /* The mmap call above replaced the shared fork detection counter
+ with zero. Adjust the local counter. */
+ fork_detect_counter = 0;
+ reseed (fd, fd_data);
+}
+
+/* Pre-function for wipeonfork_mode. */
+static void
+forkdetect_pre_wipeonfork (struct arc4random_forkdetect *fd,
+ struct fork_detect_data *fd_data)
+{
+ /* Synchronizes with the release MO store in below. Alternatively,
+ if a fork happened before a call to this function, the value will
+ be zero, too. */
+ if (!atomic_load_acquire (&fd_data->not_forked))
+ /* This indicates that the page was wiped on fork. We need to
+ reseed. */
+ {
+ fork_detect_lock (fd_data);
+ if (atomic_load_relaxed (&fd_data->not_forked))
+ /* Double-checked locking optimization. Another thread
+ performed reseeding. No need to redo it. Fall through
+ to the code below. */
+ fork_detect_unlock (fd_data);
+ else
+ {
+ /* Actually perform the reseeding. */
+ reseed (fd, fd_data);
+
+ /* Synchronizes with the acquired MO load above. */
+ atomic_store_release (&fd_data->not_forked, 1);
+
+ fork_detect_unlock (fd_data);
+ return;
+ }
+ }
+
+ /* Copy the reseed counter. */
+#if __HAVE_64B_ATOMICS
+ /* Synchronizes with the release MO store in reseed. */
+ fd->reseed_counter = atomic_load_acquire (&reseed_counter);
+#else
+ fork_detect_lock (fd_data);
+ fd->reseed_counter = reseed_counter;
+ fork_detect_unlock (fd_data);
+#endif
+}
+
+/* Post-function for wipeonfork_mode. */
+static bool
+forkdetect_post_wipeonfork (struct arc4random_forkdetect *fd,
+ struct fork_detect_data *fd_data)
+{
+ uint64_t local_reseed_counter;
+#if __HAVE_64B_ATOMICS
+ /* Synchronizes with the release MO store in reseed. */
+ local_reseed_counter = atomic_load_acquire (&reseed_counter);
+#else
+ fork_detect_lock (fd_data);
+ local_reseed_counter = reseed_counter;
+ fork_detect_unlock (fd_data);
+#endif
+
+ /* Retry in case of concurrent reseeding (after discarding the
+ per-thread cache). */
+ if (local_reseed_counter != fd->reseed_counter)
+ {
+ fd->reseed_counter = local_reseed_counter;
+ __arc4random_thread_discard_cache ();
+ return true;
+ }
+ else
+ return false;
+}
+
+/* Pre-function for !wipeonfork_mode. */
+static void
+forkdetect_pre_shared (struct arc4random_forkdetect *fd,
+ struct fork_detect_data *fd_data)
+{
+ fork_detect_lock (fd_data);
+
+ /* Increment the non-shared counter. */
+ uint32_t local_old = fork_detect_counter++;
+
+ /* Atomically increment the counter on the shared page, but guard
+ against overflow. */
+ uint32_t shared_old = atomic_load_relaxed (&fd_data->fork_detect_counter);
+ do
+ if (shared_old != local_old || shared_old == FORK_DETECT_COUNTER_LIMIT)
+ {
+ /* The counters diverged or are about to overflow. We must
+ reseed. */
+ remap_reseed (fd, fd_data);
+ fork_detect_unlock (fd_data);
+ return;
+ }
+ /* Retry if the values are not equal. */
+ while (!atomic_compare_exchange_weak_relaxed
+ (&fd_data->fork_detect_counter, &shared_old, shared_old + 1));
+
+ fd->reseed_counter = reseed_counter;
+ fork_detect_unlock (fd_data);
+}
+
+/* Post-function for !wipeonfork_mode. */
+static bool
+forkdetect_post_shared (struct arc4random_forkdetect *fd,
+ struct fork_detect_data *fd_data)
+{
+ /* Detect current random number generator use by other
+ processes. */
+ struct arc4random_forkdetect fd2;
+ forkdetect_pre_shared (&fd2, fd_data);
+
+ if (fd2.reseed_counter != fd->reseed_counter)
+ {
+ /* Concurrent reseeding happened in another thread. Update the
+ reseed counter for the next attempt, discard the thread
+ cache, and try again. */
+ fd->reseed_counter = fd2.reseed_counter;
+ __arc4random_thread_discard_cache ();
+ return true;
+ }
+ else
+ /* No fork detected, no reseeding observed. Use the computed
+ result. */
+ return false;
+}
+
+/* Use previous_thread_id to compute a thread ID for the current
+ thread, if necessary. */
+static void
+assign_thread_id (struct fork_detect_data *fd_data)
+{
+ if (__arc4random_perthread.personalization.thread_id != 0)
+ /* Thread ID has already been assigned. */
+ return;
+
+ uint64_t new_id;
+#if __HAVE_64B_ATOMICS
+ /* Should be atomic_add_fetch_relaxed, but it is missing. */
+ new_id = atomic_fetch_add_relaxed (&previous_thread_id, 1) + 1;
+#else
+ fork_detect_lock (fd_data);
+ new_id = ++previous_thread_id;
+ fork_detect_unlock (fd_data);
+#endif
+
+ if (new_id == 0)
+ __libc_fatal ("Fatal glibc error: arc4random thread counter overflow\n");
+
+ __arc4random_perthread.personalization.thread_id = new_id;
+}
+
+struct arc4random_data *
+__arc4random_forkdetect_pre (struct arc4random_forkdetect *fd)
+{
+ struct fork_detect_data *fd_data = allocate_once
+ (&fork_detect_data, fork_detect_alloc, fork_detect_free, NULL);
+ assign_thread_id (fd_data);
+
+ if (wipeonfork_mode)
+ forkdetect_pre_wipeonfork (fd, fd_data);
+ else
+ forkdetect_pre_shared (fd, fd_data);
+ return &fd_data->data;
+}
+
+bool
+__arc4random_forkdetect_post (struct arc4random_forkdetect *fd)
+{
+ /* Use relaxed MO for consistency. allocate_once has been called
+ before from this thread, via __arc4random_forkdetect_pre, so
+ initialization has happened. */
+ struct fork_detect_data *fd_data = atomic_load_relaxed (&fork_detect_data);
+
+
+ /* wipeonfork_mode has been initialized by the preceeding call to
+ __arc4random_forkdetect_pre. */
+ if (wipeonfork_mode)
+ return forkdetect_post_wipeonfork (fd, fd_data);
+ else
+ return forkdetect_post_shared (fd, fd_data);
+}
+
+void
+__arc4random_after_fork_reinit (void)
+{
+ /* We are single-threaded at this point, and the current thread is
+ the only running thread. */
+
+ /* Use relaxed MO load for consistency. */
+ struct fork_detect_data *fd_data = atomic_load_relaxed (&fork_detect_data);
+ if (fd_data == NULL)
+ /* The arc4random subsystem has not been initialized yet, so there
+ is nothing to do. */
+ return;
+
+ if (!wipeonfork_mode)
+ {
+ /* In MAP_SHARED mode, the kernel has not reset the subsystem
+ lock for us. Do it now, and also force reseeding in the
+ subprocess. (We could try to acquire the lock and reset only
+ if we fail, but always reseeding makes the behavior more
+ consistent in both modes.) */
+ __libc_lock_init (arc4random_lock);
+ fork_detect_counter = FORK_DETECT_COUNTER_RESEED;
+ }
+
+ /* We are reseeding in the subprocess, which means that we can reset
+ the thread number and reseed counter. Without 64-bit atomics,
+ the state of the 64-bit counters previous_thread_id,
+ reseed_counter could be corrupted. */
+ previous_thread_id = 1;
+ __arc4random_perthread.personalization.thread_id = 1;
+ reseed_counter = 0;
+}
diff --git a/stdlib/arc4random-forkdetect.h b/stdlib/arc4random-forkdetect.h
new file mode 100644
index 0000000000..a7b94bb863
--- /dev/null
+++ b/stdlib/arc4random-forkdetect.h
@@ -0,0 +1,53 @@
+/* Fork detection support for arc4random.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _ARC4RANDOM_FORKDETECT
+#define _ARC4RANDOM_FORKDETECT
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/* Internal randomness-generating functions need to be wrapped in
+ calls to __arc4random_forkdetect_pre and
+ __arc4random_forkdetect_post like this:
+
+ struct arc4random_forkdetect fd;
+ struct arc4random_data *data = __arc4random_forkdetect_pre (&fd);
+
+ do
+ ...
+ while (__arc4random_forkdetect_post (&fd));
+
+ This ensures that the randomness-generating process is restarted if
+ a fork (or reseeding) operating is detected.
+
+ The data pointer can be passed to __arc4random_buf_internal (which
+ does not perform fork detection on its own). */
+
+struct arc4random_forkdetect
+{
+ /* For internal use in arc4random-forkdetect.c only. */
+ uint64_t reseed_counter;
+};
+
+struct arc4random_data *__arc4random_forkdetect_pre
+ (struct arc4random_forkdetect *) attribute_hidden;
+bool __arc4random_forkdetect_post (struct arc4random_forkdetect *)
+ attribute_hidden;
+
+#endif /* _ARC4RANDOM_FORKDETECT */
diff --git a/stdlib/arc4random-private.h b/stdlib/arc4random-private.h
new file mode 100644
index 0000000000..b2d4f2230d
--- /dev/null
+++ b/stdlib/arc4random-private.h
@@ -0,0 +1,110 @@
+/* Declarations and definitions used by the arc4random implementation.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _ARC4RANDOM_PRIVATE_H
+#define _ARC4RANDOM_PRIVATE_H
+
+#include <libc-lock.h>
+#include <stdint.h>
+
+#include <arc4random-cpu-data.h>
+
+/* AES-128 is specified to use 10 rounds. */
+enum { arc4random_aes_rounds = 10 };
+
+/* AES-128 produces output blocks of 16 bytes. */
+enum { arc4random_block_size = 16 };
+
+/* AES-128 has a key size of 16 bytes. */
+enum { arc4random_key_size = 16 };
+
+/* Output from AES. */
+struct arc4random_block
+{
+ uint32_t data[4];
+};
+_Static_assert (sizeof (struct arc4random_block) == arc4random_block_size,
+ "AES-128 block size must match struct arc4random_block");
+
+/* Key schedule for AES-128. Global data shared by the entire
+ process. */
+struct arc4random_data
+{
+ /* AES key schedule. Increase alignment to help with concurrent
+ read access. */
+ uint32_t generic[arc4random_aes_rounds + 1][4]
+ __attribute__ ((aligned (128)));
+
+ struct arc4random_cpu_data cpu;
+};
+
+/* Generate a key and initialize the key schedule in *DATA. */
+void __arc4random_reseed (struct arc4random_data *data) attribute_hidden;
+
+/* Initialize the AES-128 key schedule, either DATA->generic or
+ DATA->cpu, depending on CPU support. KEY must point to 16 bytes of
+ key material. This is only supposed to be called by
+ __arc4random_reseed. */
+void __arc4random_schedule (struct arc4random_data *data,
+ const unsigned char *key)
+ attribute_hidden;
+
+/* The data which is encrypted using AES-128. */
+struct arc4random_personalization
+{
+ /* Unique number assigned to this thread. Note that the ID is *not*
+ necessarily unique across threads in different processes.
+ Therefore, it is still necessary to ensure divergence of the
+ random bit streams by other means. */
+ uint64_t thread_id;
+
+ /* The block number within a single thread. This must be advanced
+ each time a new block of randomness is obtained. */
+ uint64_t block_number;
+};
+_Static_assert (sizeof (struct arc4random_personalization)
+ == arc4random_block_size,
+ "personalization size matches AES-128 block size");
+
+/* Computes one block of random data and stores it in *OUTPUT. Can
+ use DATA->cpu if it has been initialized by the CPU-specific
+ code. */
+void __arc4random_block (const struct arc4random_data *data,
+ const struct arc4random_personalization,
+ struct arc4random_block *output)
+ attribute_hidden;
+
+/* Include these last, so that the inline function implementations can
+ use the above. */
+#include <arc4random-cpu.h>
+#include <arc4random-kernel.h>
+
+/* POSIX-based fallback implementation of key generation, using
+ /dev/urandom. For use in __arc4random_reseed. */
+void __arc4random_fallback_generate_key (unsigned char *key) attribute_hidden;
+
+
+/* Use personalization data for the current thread to compute random
+ bytes and store them in the range [buffer, end). Fork detection
+ needs to be performed by the caller. */
+void __arc4random_buf_internal (struct arc4random_data *data,
+ unsigned char *buffer, unsigned char *end)
+ attribute_hidden;
+
+
+#endif /* _ARC4RANDOM_PRIVATE_H */
diff --git a/stdlib/arc4random-reseed.c b/stdlib/arc4random-reseed.c
new file mode 100644
index 0000000000..a1a417daf5
--- /dev/null
+++ b/stdlib/arc4random-reseed.c
@@ -0,0 +1,58 @@
+/* Reseeding the arc4random generator.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <arc4random-private.h>
+#include <fcntl.h>
+#include <not-cancel.h>
+#include <stdio.h>
+#include <unistd.h>
+
+void
+__arc4random_fallback_generate_key (unsigned char *key)
+{
+ int fd = __open_nocancel ("/dev/urandom", O_RDONLY);
+ if (fd < 0)
+ __libc_fatal ("Fatal glibc error: cannot open /dev/urandom\n");
+
+ unsigned char *p = key;
+ unsigned char *end = key + arc4random_key_size;
+ do
+ {
+ ssize_t ret = TEMP_FAILURE_RETRY (__read_nocancel (fd, p, end - p));
+ if (ret <= 0)
+ __libc_fatal ("Fatal glibc error: cannot read from /dev/urandom\n");
+ p += ret;
+ }
+ while (p < end);
+
+ if (__close_nocancel (fd) != 0)
+ __libc_fatal ("Fatal glibc error: cannot close /dev/urandom\n");
+}
+
+void
+__arc4random_reseed (struct arc4random_data *data)
+{
+ unsigned char key[arc4random_key_size];
+ /* Prefer the kernel and CPU generators before fallback via
+ /dev/urandon. */
+ if (!(__arc4random_kernel_generate_key (key)
+ || __arc4random_cpu_generate_key (key)))
+ __arc4random_fallback_generate_key (key);
+
+ __arc4random_schedule (data, key);
+}
diff --git a/stdlib/arc4random-thread.h b/stdlib/arc4random-thread.h
new file mode 100644
index 0000000000..1ca5fff02b
--- /dev/null
+++ b/stdlib/arc4random-thread.h
@@ -0,0 +1,67 @@
+/* Multi-threading support for arc4random.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _ARC4RANDOM_THREAD_H
+#define _ARC4RANDOM_THREAD_H
+
+#include <arc4random-private.h>
+
+/* Subystem lock used to protect internal data structures (fork
+ detection, thread number). */
+__libc_lock_define (extern, __arc4random_lock attribute_hidden)
+
+/* Per-thread data used by the arc4random subsystem. */
+struct arc4random_perthread
+{
+ /* Data to make AES-128 output thread-specific. */
+ struct arc4random_personalization personalization;
+
+ /* Cached output from AES-128. */
+ struct
+ {
+ unsigned char unused_bytes;
+ unsigned char bytes[arc4random_block_size - 1];
+ } cache;
+};
+
+extern __thread struct arc4random_perthread __arc4random_perthread
+ attribute_tls_model_ie attribute_hidden;
+
+/* Slow path for __arc4random_thread_init below. */
+void __arc4random_thread_init_slow (void) attribute_hidden;
+
+/* Assign the per-thread personalization number in the
+ __arc4random_perthread.personalization.thread_id field of the
+ current thread. */
+static inline void
+__arc4random_thread_init (void)
+{
+ if (__arc4random_perthread.personalization.thread_id == 0)
+ __arc4random_thread_init_slow ();
+}
+
+/* Discard the data in the per-thread cache. Needs to be called after
+ reseeding (on all threads eventually). */
+static inline void
+__arc4random_thread_discard_cache (void)
+{
+ /* Mark all bytes as used. */
+ __arc4random_perthread.cache.unused_bytes = 0;
+}
+
+#endif /* _ARC4RANDOM_THREAD_H */
diff --git a/stdlib/arc4random.c b/stdlib/arc4random.c
new file mode 100644
index 0000000000..57800b8822
--- /dev/null
+++ b/stdlib/arc4random.c
@@ -0,0 +1,31 @@
+/* Unpredictable random numbers between 0 and 2**-31 (inclusive).
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdlib.h>
+
+_Static_assert (sizeof (unsigned int) == 4, "32-bit unsigned int");
+
+unsigned int
+__libc_arc4random (void)
+{
+ unsigned int result;
+ __libc_arc4random_buf (&result, sizeof (result));
+ return result;
+}
+libc_hidden_def (__libc_arc4random)
+weak_alias (__libc_arc4random, arc4random)
diff --git a/stdlib/arc4random_buf.c b/stdlib/arc4random_buf.c
new file mode 100644
index 0000000000..6b294951b0
--- /dev/null
+++ b/stdlib/arc4random_buf.c
@@ -0,0 +1,79 @@
+/* Fill a buffer with unpredictable random numbers.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <arc4random-forkdetect.h>
+#include <arc4random-private.h>
+#include <arc4random-thread.h>
+#include <ldsodefs.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+void
+__arc4random_buf_internal (struct arc4random_data *data,
+ unsigned char *buffer, unsigned char *end)
+{
+ while (buffer < end)
+ {
+ if (__arc4random_perthread.cache.unused_bytes == 0)
+ {
+ /* No cached data. Replenish it by computing another
+ block. */
+ struct arc4random_block block;
+ ++__arc4random_perthread.personalization.block_number;
+ __arc4random_block (data, __arc4random_perthread.personalization,
+ &block);
+
+ _Static_assert (sizeof (__arc4random_perthread.cache)
+ == sizeof (block), "padding in cache");
+ memcpy (&__arc4random_perthread.cache, &block, sizeof (block));
+
+ /* One byte goes into the buffer, so that the next iteration
+ of the loop uses the else branch below. Use the byte in
+ the unused_bytes position for that (which needs to be
+ initialized). */
+ *buffer = __arc4random_perthread.cache.unused_bytes;
+ ++buffer;
+ _Static_assert (sizeof (block) <= 256, "block size");
+ __arc4random_perthread.cache.unused_bytes = sizeof (block) - 1;
+ }
+ else
+ {
+ size_t to_copy = end - buffer;
+ if (to_copy > __arc4random_perthread.cache.unused_bytes)
+ to_copy = __arc4random_perthread.cache.unused_bytes;
+ memcpy (buffer, __arc4random_perthread.cache.bytes, to_copy);
+ buffer += to_copy;
+ __arc4random_perthread.cache.unused_bytes -= to_copy;
+ }
+ }
+}
+
+void
+__libc_arc4random_buf (void *buffer, size_t length)
+{
+ struct arc4random_forkdetect fd;
+ struct arc4random_data *data = __arc4random_forkdetect_pre (&fd);
+
+ do
+ __arc4random_buf_internal (data, buffer, buffer + length);
+ while (__arc4random_forkdetect_post (&fd));
+}
+libc_hidden_def (__libc_arc4random_buf)
+weak_alias (__libc_arc4random_buf, arc4random_buf)
diff --git a/stdlib/arc4random_uniform.c b/stdlib/arc4random_uniform.c
new file mode 100644
index 0000000000..2ac5f720d9
--- /dev/null
+++ b/stdlib/arc4random_uniform.c
@@ -0,0 +1,159 @@
+/* An unpredictable number up to a certain limit.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <arc4random-forkdetect.h>
+#include <arc4random-private.h>
+#include <sys/param.h>
+
+/* Return the number of bytes which cover values up to the limit. */
+__attribute__ ((const))
+static uint32_t
+byte_count (uint32_t n)
+{
+ if (n <= (1U << 8))
+ return 1;
+ else if (n <= (1U << 16))
+ return 2;
+ else if (n <= (1U << 24))
+ return 3;
+ else
+ return 4;
+}
+
+/* Fill the lower bits of the result with randomness, according to the
+ number of bytes requested. */
+static uint32_t
+random_bytes (struct arc4random_data *data, uint32_t byte_count)
+{
+ uint32_t result = 0;
+ unsigned char *ptr = (unsigned char *) &result;
+ if (__BYTE_ORDER == __BIG_ENDIAN)
+ ptr += 4 - byte_count;
+ __arc4random_buf_internal (data, ptr, ptr + byte_count);
+ return result;
+}
+
+static uint32_t
+compute_uniform (struct arc4random_data *data, 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;
+
+ /* The bits variable serves as a source for bits. Prefetch the
+ minimum number of bytes needed. */
+ uint32_t bits;
+ uint32_t bits_length;
+ {
+ unsigned count = byte_count (n);
+ bits = random_bytes (data, count);
+ bits_length = count * 8;
+ }
+
+ /* Powers of two are easy. */
+ if (powerof2 (n))
+ return bits & (n - 1);
+
+ /* The general case. This algorithm follows Jérémie Lumbroso,
+ Optimal Discrete Uniform Generation from Coin Flips, and
+ Applications (2013), who credits Donald E. Knuth and Andrew
+ C. Yao, The complexity of nonuniform random number generation
+ (1976), for solving the general case.
+
+ The implementation below unrolls the initialization stage of the
+ loop, where v is less than n. */
+
+ /* Use 64-bit variables even though the intermediate results are
+ never larger that 33 bits. This ensures the code easier to
+ compile on 64-bit architectures. */
+ uint64_t v;
+ uint64_t c;
+
+ /* Initialize v and c. v is the smallest power of 2 which is larger
+ than n.*/
+ {
+ uint32_t log2p1 = 32 - __builtin_clz (n);
+ v = 1ULL << log2p1;
+ c = bits & (v - 1);
+ bits >>= log2p1;
+ bits_length -= log2p1;
+ }
+
+ /* At the start of the loop, c is uniformly distributed within the
+ half-open interval [0, v), and v < 2n < 2**33. */
+ while (true)
+ {
+ if (v >= n)
+ {
+ /* If the candidate is less than n, accept it. */
+ if (c < n)
+ /* c is uniformly distributed on [0, n). */
+ return c;
+ else
+ {
+ /* c is uniformly distributed on [n, v). */
+ v -= n;
+ c -= n;
+ /* The distribution was shifted, so c is uniformly
+ distributed on [0, v) again. */
+ }
+ }
+ /* v < n here. */
+
+ /* Replenish the bit source if necessary. */
+ if (bits_length == 0)
+ {
+ unsigned char *target = (unsigned char *) &bits;
+ /* Overwrite the least significant byte. */
+ if (__BYTE_ORDER == __BIG_ENDIAN)
+ target += 3;
+ __arc4random_buf_internal (data, target, target + 1);
+ bits_length = 8;
+ }
+
+ /* Double the range. No overflow because v < n < 2**32. */
+ v *= 2;
+ /* v < 2n here. */
+
+ /* Extract a bit and append it to c. c remains less than v and
+ thus 2**33. */
+ c = (c << 1) | (bits & 1);
+ bits >>= 1;
+ --bits_length;
+
+ /* At this point, c is uniformly distributed on [0, v) again,
+ and v < 2n < 2**33. */
+ }
+}
+
+uint32_t
+__libc_arc4random_uniform (uint32_t n)
+{
+ uint32_t result;
+ struct arc4random_forkdetect fd;
+ struct arc4random_data *data = __arc4random_forkdetect_pre (&fd);
+
+ do
+ result = compute_uniform (data, n);
+ while (__arc4random_forkdetect_post (&fd));
+
+ return result;
+}
+libc_hidden_def (__libc_arc4random_uniform)
+weak_alias (__libc_arc4random_uniform, arc4random_uniform)
diff --git a/stdlib/bits/arc4random.h b/stdlib/bits/arc4random.h
new file mode 100644
index 0000000000..5b8f9a5273
--- /dev/null
+++ b/stdlib/bits/arc4random.h
@@ -0,0 +1,31 @@
+/* arc4random interfaces.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#if ! (defined (_STDLIB_H) || defined (_SYS_RANDOM_H))
+# error "Never use <bits/arc4random.h> directly; include <stdlib.h> instead."
+#endif
+
+/* Return a random integer between zero and 2**31-1 (inclusive). */
+extern unsigned int arc4random (void) __THROW __wur;
+
+/* Fill the buffer with random data. */
+extern void arc4random_buf (void *, size_t) __THROW __nonnull ((1));
+
+/* Return a random number between zero (inclusive) and the specified
+ limit (exclusive). */
+extern unsigned int arc4random_uniform (unsigned int) __THROW __wur;
diff --git a/stdlib/stdlib.h b/stdlib/stdlib.h
index 6b1ead31e0..fc9e565c1c 100644
--- a/stdlib/stdlib.h
+++ b/stdlib/stdlib.h
@@ -532,6 +532,9 @@ extern int seed48_r (unsigned short int __seed16v[3],
extern int lcong48_r (unsigned short int __param[7],
struct drand48_data *__buffer)
__THROW __nonnull ((1, 2));
+
+# include <bits/arc4random.h>
+
# endif /* Use misc. */
#endif /* Use misc or X/Open. */
diff --git a/stdlib/sys/random.h b/stdlib/sys/random.h
index 056312ca3b..9f69693b12 100644
--- a/stdlib/sys/random.h
+++ b/stdlib/sys/random.h
@@ -37,6 +37,8 @@ ssize_t getrandom (void *__buffer, size_t __length,
success or -1 on error. */
int getentropy (void *__buffer, size_t __length) __wur;
+#include <bits/arc4random.h>
+
__END_DECLS
#endif /* _SYS_RANDOM_H */
diff --git a/stdlib/tst-arc4random-aes.c b/stdlib/tst-arc4random-aes.c
new file mode 100644
index 0000000000..c5ff2e0a83
--- /dev/null
+++ b/stdlib/tst-arc4random-aes.c
@@ -0,0 +1,70 @@
+/* Test for low-level AES-128 routines for the arc4random PRNG.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+/* This test uses a test vector to make sure that the low-level
+ AES-128 generator produces the expected result. */
+
+#include <arc4random-private.h>
+#include <stdio.h>
+#include <string.h>
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+ static const unsigned char at_random[16]
+ = { 1, 2, 3, 4, 5, 6, 7, 8,
+ 131, 132, 133, 134, 135, 136, 137, 138};
+ TEST_COMPARE (sizeof (at_random), arc4random_key_size);
+
+ /* Test overall version. */
+
+ struct arc4random_data data;
+ memset (&data, 0, sizeof (data));
+ __arc4random_schedule (&data, at_random);
+
+ struct arc4random_personalization personalization;
+ const char *personalization_data
+ = "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0"
+ "\x00\x01\x02\x03\x04\x05\x06\x07";
+ _Static_assert (sizeof (personalization) == 16, "sizeof (personalization)");
+ memcpy (&personalization, personalization_data, sizeof (personalization));
+ struct arc4random_block result;
+ __arc4random_block (&data, personalization, &result);
+
+ const char *expected
+ = "\xa8\x0b\xa2\x8a\xdd\x9ew\\\000aK\xdc/\xa7\xd5\x16";
+ TEST_COMPARE_BLOB (&result, sizeof (result), expected, 16);
+
+ /* Test CPU-specific version. */
+
+ memset (&data, 0, sizeof (data));
+ if (__arc4random_cpu_schedule (&data, at_random))
+ {
+ puts ("info: CPU support active");
+ memcpy (&personalization, personalization_data, sizeof (personalization));
+ TEST_VERIFY (__arc4random_cpu_block (&data, personalization, &result));
+ TEST_COMPARE_BLOB (&result, sizeof (result), expected, 16);
+ }
+ else
+ puts ("info: CPU support not active");
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/stdlib/tst-arc4random-fork.c b/stdlib/tst-arc4random-fork.c
new file mode 100644
index 0000000000..6cfb2345b2
--- /dev/null
+++ b/stdlib/tst-arc4random-fork.c
@@ -0,0 +1,172 @@
+/* Test that subprocesses generate distinct streams of randomness.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+/* Collect random data from subprocesses and check that all the
+ results are unique. */
+
+#include <array_length.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xthread.h>
+#include <support/xunistd.h>
+#include <unistd.h>
+
+/* Perform multiple runs. The subsequent runs start with an
+ already-initialized random number generator. (The number 1500 was
+ seen to reproduce failures reliable in case of a race condition in
+ the fork detection code.) */
+enum { runs = 1500 };
+
+/* One hundred processes in total. This should be high enough to
+ expose any issues, but low enough not to tax the overall system too
+ much. */
+enum { subprocesses = 49 };
+
+/* The total number of processes. */
+enum { processes = subprocesses + 1 };
+
+/* Number of bytes of randomness to generate per process. Large
+ enough to make false positive duplicates extremely unlikely. */
+enum { random_size = 16 };
+
+/* Generated bytes of randomness. */
+struct result
+{
+ unsigned char bytes[random_size];
+};
+
+/* Shared across all processes. */
+static struct shared_data
+{
+ pthread_barrier_t barrier;
+ struct result results[runs][processes];
+} *shared_data;
+
+/* Invoked to collect data from a subprocess. */
+static void
+subprocess (int run, int process_index)
+{
+ xpthread_barrier_wait (&shared_data->barrier);
+ arc4random_buf (shared_data->results[run][process_index].bytes, random_size);
+}
+
+/* Used to sort the results. */
+struct index
+{
+ int run;
+ int process_index;
+};
+
+/* Used to sort an array of struct index values. */
+static int
+index_compare (const void *left1, const void *right1)
+{
+ const struct index *left = left1;
+ const struct index *right = right1;
+
+ return memcmp (shared_data->results[left->run][left->process_index].bytes,
+ shared_data->results[right->run][right->process_index].bytes,
+ random_size);
+}
+
+static int
+do_test (void)
+{
+ shared_data = support_shared_allocate (sizeof (*shared_data));
+ {
+ pthread_barrierattr_t attr;
+ xpthread_barrierattr_init (&attr);
+ xpthread_barrierattr_setpshared (&attr, PTHREAD_PROCESS_SHARED);
+ xpthread_barrier_init (&shared_data->barrier, &attr, processes);
+ xpthread_barrierattr_destroy (&attr);
+ }
+
+ /* Collect random data. */
+ for (int run = 0; run < runs; ++run)
+ {
+ if (run == runs / 2)
+ {
+ /* In the middle, desynchronize the block cache by consuming
+ an odd number of bytes. */
+ char buf;
+ arc4random_buf (&buf, 1);
+ }
+
+ pid_t pids[subprocesses];
+ for (int process_index = 0; process_index < subprocesses;
+ ++process_index)
+ {
+ pids[process_index] = xfork ();
+ if (pids[process_index] == 0)
+ {
+ subprocess (run, process_index);
+ _exit (0);
+ }
+ }
+
+ /* Trigger all subprocesses. Also add data from the parent
+ process. */
+ subprocess (run, subprocesses);
+
+ for (int process_index = 0; process_index < subprocesses;
+ ++process_index)
+ {
+ int status;
+ xwaitpid (pids[process_index], &status, 0);
+ if (status != 0)
+ FAIL_EXIT1 ("subprocess index %d (PID %d) exit status %d\n",
+ process_index, (int) pids[process_index], status);
+ }
+ }
+
+ /* Check for duplicates. */
+ struct index indexes[runs * processes];
+ for (int run = 0; run < runs; ++run)
+ for (int process_index = 0; process_index < processes; ++process_index)
+ indexes[run * processes + process_index]
+ = (struct index) { .run = run, .process_index = process_index };
+ qsort (indexes, array_length (indexes), sizeof (indexes[0]), index_compare);
+ for (size_t i = 1; i < array_length (indexes); ++i)
+ {
+ if (index_compare (indexes + i - 1, indexes + i) == 0)
+ {
+ support_record_failure ();
+ unsigned char *bytes
+ = shared_data->results[indexes[i].run]
+ [indexes[i].process_index].bytes;
+ char *quoted = support_quote_blob (bytes, random_size);
+ printf ("error: duplicate randomness data: \"%s\"\n"
+ " run %d, subprocess %d\n"
+ " run %d, subprocess %d\n",
+ quoted, indexes[i - 1].run, indexes[i - 1].process_index,
+ indexes[i].run, indexes[i].process_index);
+ free (quoted);
+ }
+ }
+
+ xpthread_barrier_destroy (&shared_data->barrier);
+ support_shared_free (shared_data);
+ shared_data = NULL;
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/stdlib/tst-arc4random-forkdetect.c b/stdlib/tst-arc4random-forkdetect.c
new file mode 100644
index 0000000000..63f998ffc3
--- /dev/null
+++ b/stdlib/tst-arc4random-forkdetect.c
@@ -0,0 +1,437 @@
+/* Low-level tests fork arc4random fork detection.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+/* This test attempts to cover interleaving of the pre and post
+ fork-detect functions in a parent process and a subprocess. The
+ behavior depends on the internals of the fork detection
+ implementation (MAP_SHARED mode vs MADV_WIPEONFORK mode), and
+ adjustments will be needed to this test if glibc initializes the
+ arc4random subsystem as part of process startup.
+
+ The test is not multi-threaded and assumes that
+ __arc4random_after_fork_reinit is not called during fork for such
+ processes. */
+
+#include <arc4random-forkdetect.h>
+#include <arc4random-thread.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/support.h>
+#include <support/test-driver.h>
+#include <support/xthread.h>
+#include <support/xunistd.h>
+
+/* Test without interference from another process. */
+static void
+test_quiet (void *unused)
+{
+ struct arc4random_forkdetect fd;
+
+ /* Some arbitrary number of invocations. Low enough to finish
+ quickly, and not to trigger reseeding. */
+ for (int i = 0; i < 100; ++i)
+ {
+ memset (&fd, 0xcc, sizeof (fd));
+ TEST_VERIFY (__arc4random_forkdetect_pre (&fd) != NULL);
+ TEST_COMPARE (fd.reseed_counter, 0);
+ TEST_VERIFY (!__arc4random_forkdetect_post (&fd));
+ TEST_COMPARE (fd.reseed_counter, 0);
+ }
+
+ /* Inject a different reseed counter and check that
+ __arc4random_forkdetect_post indicates a re-run of the randomness
+ generation. This simulates concurrent reseeding by another
+ thread. */
+ memset (&fd, 0xcc, sizeof (fd));
+ TEST_VERIFY (__arc4random_forkdetect_pre (&fd) != NULL);
+ TEST_COMPARE (fd.reseed_counter, 0);
+ fd.reseed_counter = -1;
+ /* Indicate that the cache has data. */
+ __arc4random_perthread.cache.unused_bytes = 1;
+ TEST_VERIFY (__arc4random_forkdetect_post (&fd));
+ TEST_COMPARE (fd.reseed_counter, 0);
+ /* The cache must have been consumed. */
+ TEST_COMPARE (__arc4random_perthread.cache.unused_bytes, 0);
+}
+
+/* Data allocated using support_shared_allocate, for passing data back
+ and forth between processes. */
+struct shared_data
+{
+ /* Used to pass back data from test_noninterleaved_subprocess_1. */
+ uint64_t uninterleaved_reseed_counter_subprocess;
+
+ /* Used to serialize execution between parent process and
+ subprocess. */
+ pthread_barrier_t barrier;
+
+ /* If true, MAP_SHARED mode, otherwise MADV_WIPEONFORK mode. */
+ bool shared_mode;
+
+ /* Used to pass along data for certain tests. */
+ int test_mode;
+};
+
+/* Helper for test_noninterleaved_subprocess below. */
+static void
+test_noninterleaved_subprocess_1 (void *closure)
+{
+ struct shared_data *shared_data = closure;
+
+ struct arc4random_forkdetect fd;
+ memset (&fd, 0xcc, sizeof (fd));
+ TEST_VERIFY (__arc4random_forkdetect_pre (&fd) != NULL);
+ shared_data->uninterleaved_reseed_counter_subprocess = fd.reseed_counter;
+ TEST_VERIFY (!__arc4random_forkdetect_post (&fd));
+ TEST_COMPARE (fd.reseed_counter,
+ shared_data->uninterleaved_reseed_counter_subprocess);
+}
+
+/* Test sequential execution in two processes. */
+static void
+test_noninterleaved_subprocess (void *closure)
+{
+ struct shared_data *shared_data = closure;
+
+ struct arc4random_forkdetect fd;
+ memset (&fd, 0xcc, sizeof (fd));
+ TEST_VERIFY (__arc4random_forkdetect_pre (&fd) != NULL);
+ TEST_COMPARE (fd.reseed_counter, 0);
+ TEST_VERIFY (!__arc4random_forkdetect_post (&fd));
+ TEST_COMPARE (fd.reseed_counter, 0);
+
+ support_isolate_in_subprocess (test_noninterleaved_subprocess_1,
+ shared_data);
+
+ memset (&fd, 0xcc, sizeof (fd));
+ TEST_VERIFY (__arc4random_forkdetect_pre (&fd) != NULL);
+ shared_data->shared_mode = fd.reseed_counter != 0;
+ if (shared_data->shared_mode)
+ {
+ TEST_COMPARE (fd.reseed_counter, 1);
+ TEST_COMPARE (shared_data->uninterleaved_reseed_counter_subprocess, 0);
+ }
+ else
+ {
+ TEST_COMPARE (fd.reseed_counter, 0);
+ TEST_COMPARE (shared_data->uninterleaved_reseed_counter_subprocess, 1);
+ }
+
+ TEST_VERIFY (!__arc4random_forkdetect_post (&fd));
+ if (shared_data->shared_mode)
+ TEST_COMPARE (fd.reseed_counter, 1);
+ else
+ TEST_COMPARE (fd.reseed_counter, 0);
+}
+
+/* Run a test where the parent process calls the pre function before
+ the subprocess. Three test modes:
+ 0: No initialization in parent.
+ 1: Pre function called in parent before fork.
+ 2: Pre and post function called in parent, and pre again after fork. */
+static void
+test_parent_first (void *closure)
+{
+ struct shared_data *shared_data = closure;
+ printf ("info: %s: test mode %d\n", __func__, shared_data->test_mode);
+
+ struct arc4random_forkdetect fd;
+ memset (&fd, 0xcc, sizeof (fd));
+
+ bool init_parent_after_fork;
+ bool subprocess_will_reseed;
+ bool parent_will_retry;
+
+ switch (shared_data->test_mode)
+ {
+ case 0:
+ /* Do not perform any initialization in the parent process
+ before the fork. This means that the subprocess will not
+ increment the reseed counter. */
+ init_parent_after_fork = true;
+ parent_will_retry = false;
+ subprocess_will_reseed = false;
+ break;
+ case 1:
+ /* Call the pre function function. */
+ init_parent_after_fork = false;
+ TEST_VERIFY (__arc4random_forkdetect_pre (&fd) != NULL);
+ TEST_COMPARE (fd.reseed_counter, 0);
+
+ if (shared_data->shared_mode)
+ {
+ /* In shared mapping mode, the subprocess sees consistent
+ counters after the fork, so it will not reseed. */
+ subprocess_will_reseed = false;
+ /* The parent will have to reseed in this case. */
+ parent_will_retry = true;
+ }
+ else
+ {
+ /* Without a shared mapping, the subprocess will see a wiped
+ mapping and reseed. */
+ subprocess_will_reseed = true;
+ /* This will not affect the parent. */
+ parent_will_retry = false;
+ }
+ break;
+ case 2:
+ /* Perform a full cycle to attain initialization. */
+ TEST_VERIFY (__arc4random_forkdetect_pre (&fd) != NULL);
+ TEST_COMPARE (fd.reseed_counter, 0);
+ TEST_VERIFY (__arc4random_forkdetect_pre (&fd) != NULL);
+ TEST_COMPARE (fd.reseed_counter, 0);
+ memset (&fd, 0xcc, sizeof (fd));
+ init_parent_after_fork = true;
+
+ /* The subprocess will either see a wiped mapping or diverged
+ counters, and will reseed. */
+ subprocess_will_reseed = true;
+ /* This does not affect the parent. */
+ parent_will_retry = false;
+ break;
+ default:
+ FAIL_EXIT1 ("%s: invalid test mode: %d",
+ __func__, shared_data->test_mode);
+ }
+
+ pid_t pid = xfork ();
+ if (pid != 0)
+ {
+ /* Parent process. */
+
+ if (init_parent_after_fork)
+ {
+ TEST_VERIFY (__arc4random_forkdetect_pre (&fd) != NULL);
+ TEST_COMPARE (fd.reseed_counter, 0);
+ }
+
+ /* Signal the subprocess. */
+ xpthread_barrier_wait (&shared_data->barrier);
+
+ /* Wait for the subprocess to execute the pre function. */
+ xpthread_barrier_wait (&shared_data->barrier);
+
+ if (parent_will_retry)
+ {
+ /* The subprocess did not reseed, so the parent has to. */
+ TEST_VERIFY (__arc4random_forkdetect_post (&fd));
+ TEST_COMPARE (fd.reseed_counter, 1);
+ TEST_VERIFY (!__arc4random_forkdetect_post (&fd));
+ TEST_COMPARE (fd.reseed_counter, 1);
+ }
+ else
+ {
+ /* The subprocess reseeded itself, replacing the shared
+ mapping (if it was shared in the place). This means that
+ the parent process does not need to reseed again,
+ irrespective of shared_data->shared_mode. */
+ TEST_VERIFY (!__arc4random_forkdetect_post (&fd));
+ TEST_COMPARE (fd.reseed_counter, 0);
+ }
+
+ /* Run post function in subprocess. */
+ xpthread_barrier_wait (&shared_data->barrier);
+
+ int status;
+ xwaitpid (pid, &status, 0);
+ TEST_COMPARE (status, 0);
+ }
+ else
+ {
+ /* Subprocess. Wait for parent to execute the pre function. */
+ xpthread_barrier_wait (&shared_data->barrier);
+
+ /* Pretend that there is some data in the cache that needs to be
+ discarded (when actually reseeding). */
+ if (subprocess_will_reseed)
+ __arc4random_perthread.cache.unused_bytes = 1;
+
+ TEST_VERIFY (__arc4random_forkdetect_pre (&fd) != NULL);
+ TEST_COMPARE (fd.reseed_counter, subprocess_will_reseed);
+
+ /* The cache is always empty at this point. */
+ TEST_COMPARE (__arc4random_perthread.cache.unused_bytes, 0);
+
+ /* Signal the parent. */
+ xpthread_barrier_wait (&shared_data->barrier);
+
+ /* Wait for parent to execute the post function. */
+ xpthread_barrier_wait (&shared_data->barrier);
+
+ /* The subprocess isolated itself from the parent through
+ reseeding. No retry needed. */
+ TEST_VERIFY (!__arc4random_forkdetect_post (&fd));
+ TEST_COMPARE (fd.reseed_counter, subprocess_will_reseed);
+
+ _exit (0);
+ }
+}
+
+/* Run a test where the subprocess process calls the pre function
+ before the parent. Four test modes:
+
+ 0: no initialization before fork, post in subprocess goes first
+ 1: initialization before fork, post in subprocess goes first
+ 2: no initialization before fork, post in parent goes first
+ 3: initialization before fork, post in parent goes first */
+static void
+test_subprocess_first (void *closure)
+{
+ struct shared_data *shared_data = closure;
+ printf ("info: %s: test mode %d\n", __func__, shared_data->test_mode);
+
+ struct arc4random_forkdetect fd;
+ memset (&fd, 0xcc, sizeof (fd));
+
+ bool subprocess_will_reseed;
+ bool parent_will_reseed;
+
+ TEST_VERIFY (shared_data->test_mode >= 0);
+ TEST_VERIFY (shared_data->test_mode <= 3);
+
+ if (shared_data->test_mode & 1)
+ {
+ /* Do not perform any initialization in the parent process.
+ Neither process will reseed because they will simply
+ initialize. */
+ subprocess_will_reseed = false;
+ parent_will_reseed = false;
+ }
+ else
+ {
+ /* Complete initialization in the parent process. */
+ TEST_VERIFY (__arc4random_forkdetect_pre (&fd) != NULL);
+ TEST_COMPARE (fd.reseed_counter, 0);
+ TEST_VERIFY (!__arc4random_forkdetect_post (&fd));
+ TEST_COMPARE (fd.reseed_counter, 0);
+ memset (&fd, 0xcc, sizeof (fd));
+
+ if (shared_data->shared_mode)
+ {
+ /* The subprocess will not reseed because it sees consistent
+ counters. */
+ subprocess_will_reseed = false;
+ /* But the parent will see counter divergence. */
+ parent_will_reseed = true;
+ }
+ else
+ {
+ /* The subprocess will see a wiped mapping. */
+ subprocess_will_reseed = true;
+ /* The parent process is not affected by this. */
+ parent_will_reseed = false;
+ }
+ }
+
+ pid_t pid = xfork ();
+ if (pid != 0)
+ {
+ /* Parent process. Wait for the pre function to run in the
+ subprocess. */
+ xpthread_barrier_wait (&shared_data->barrier);
+
+ /* When reseeding, pretend that there is some data in the cache
+ that needs to be invalidated. */
+ if (parent_will_reseed)
+ __arc4random_perthread.cache.unused_bytes = 1;
+ TEST_VERIFY (__arc4random_forkdetect_pre (&fd) != NULL);
+ TEST_COMPARE (fd.reseed_counter, parent_will_reseed);
+
+ /* The cache is always empty at this point. */
+ TEST_COMPARE (__arc4random_perthread.cache.unused_bytes, 0);
+
+ if (shared_data->test_mode & 2)
+ /* Signal the subprocess. */
+ xpthread_barrier_wait (&shared_data->barrier);
+
+ TEST_VERIFY (!__arc4random_forkdetect_post (&fd));
+ TEST_COMPARE (fd.reseed_counter, parent_will_reseed);
+
+ if (!(shared_data->test_mode & 2))
+ /* Signal the subprocess. */
+ xpthread_barrier_wait (&shared_data->barrier);
+
+ int status;
+ xwaitpid (pid, &status, 0);
+ TEST_COMPARE (status, 0);
+ }
+ else
+ {
+ /* When reseeding, pretend that there is some cached data to
+ invalidate. */
+ if (subprocess_will_reseed)
+ __arc4random_perthread.cache.unused_bytes = 1;
+
+ TEST_VERIFY (__arc4random_forkdetect_pre (&fd) != NULL);
+ TEST_COMPARE (fd.reseed_counter, subprocess_will_reseed);
+
+ /* The cache is always empty at this point. */
+ TEST_COMPARE (__arc4random_perthread.cache.unused_bytes, 0);
+
+ /* Signal the parent. */
+ xpthread_barrier_wait (&shared_data->barrier);
+
+ /* Wait for parent to execute the pre function in the
+ parent. */
+ xpthread_barrier_wait (&shared_data->barrier);
+
+ TEST_VERIFY (!__arc4random_forkdetect_post (&fd));
+ TEST_COMPARE (fd.reseed_counter, subprocess_will_reseed);
+
+ _exit (0);
+ }
+}
+
+static int
+do_test (void)
+{
+ struct shared_data *shared_data = support_shared_allocate (sizeof (*shared_data));
+ {
+ pthread_barrierattr_t attr;
+ xpthread_barrierattr_init (&attr);
+ xpthread_barrierattr_setpshared (&attr, PTHREAD_PROCESS_SHARED);
+ xpthread_barrier_init (&shared_data->barrier, &attr, 2);
+ xpthread_barrierattr_destroy (&attr);
+ }
+
+ support_isolate_in_subprocess (test_quiet, NULL);
+
+ support_isolate_in_subprocess (test_noninterleaved_subprocess, shared_data);
+ if (shared_data->shared_mode)
+ puts ("info: MAP_SHARED mode");
+ else
+ puts ("info: MADV_WIPEONFORK mode");
+
+ for (shared_data->test_mode = 0; shared_data->test_mode < 3;
+ ++shared_data->test_mode)
+ support_isolate_in_subprocess (test_parent_first, shared_data);
+
+ for (shared_data->test_mode = 0; shared_data->test_mode < 4;
+ ++shared_data->test_mode)
+ support_isolate_in_subprocess (test_subprocess_first, shared_data);
+
+ xpthread_barrier_destroy (&shared_data->barrier);
+ support_shared_free (shared_data);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/stdlib/tst-arc4random-stats.c b/stdlib/tst-arc4random-stats.c
new file mode 100644
index 0000000000..22ac1569a7
--- /dev/null
+++ b/stdlib/tst-arc4random-stats.c
@@ -0,0 +1,158 @@
+/* Statistical tests for arc4random-related functions.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <arc4random-private.h>
+#include <array_length.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+
+struct key
+{
+ unsigned char data[arc4random_key_size];
+};
+
+/* With 12,000 keys, the probability that a byte in a predetermined
+ position does not have a predetermined value in all generated keys
+ is about 4e-21. The probability that this happens with any of the
+ 16 * 256 possible byte position/values is 1.6e-17. This results in
+ an acceptably low false-positive rate. */
+enum { key_count = 12000 };
+
+static struct key keys[key_count];
+
+/* Used to perform the distribution check. */
+static int byte_counts[16][256];
+
+/* Bail out after this many failures. */
+enum { failure_limit = 100 };
+
+static void
+find_stuck_bytes (bool (*func) (unsigned char *key))
+{
+ memset (&keys, 0xcc, sizeof (keys));
+
+ int failures = 0;
+ for (int key = 0; key < key_count; ++key)
+ {
+ while (true)
+ {
+ if (func (keys[key].data))
+ break;
+ ++failures;
+ if (failures >= failure_limit)
+ {
+ printf ("warning: bailing out after %d failures\n", failures);
+ return;
+ }
+ }
+ }
+ printf ("info: key generation finished with %d failures\n", failures);
+
+ memset (&byte_counts, 0, sizeof (byte_counts));
+ for (int key = 0; key < key_count; ++key)
+ for (int pos = 0; pos < arc4random_key_size; ++pos)
+ ++byte_counts[pos][keys[key].data[pos]];
+
+ for (int pos = 0; pos < arc4random_key_size; ++pos)
+ for (int byte = 0; byte < 256; ++byte)
+ if (byte_counts[pos][byte] == 0)
+ {
+ support_record_failure ();
+ printf ("error: byte %d never appeared at position %d\n", byte, pos);
+ }
+}
+
+/* Test adapter for __arc4random_fallback_generate_key. */
+static bool
+generate_fallback (unsigned char *key)
+{
+ __arc4random_fallback_generate_key (key);
+ return true;
+}
+
+/* Test adapter for arc4random. */
+static bool
+generate_arc4random (unsigned char *key)
+{
+ uint32_t words[arc4random_key_size / 4];
+ _Static_assert (sizeof (words) == arc4random_key_size, "sizeof (words)");
+
+ for (int i = 0; i < array_length (words); ++i)
+ words[i] = arc4random ();
+ memcpy (key, &words, arc4random_key_size);
+ return true;
+}
+
+/* Test adapter for arc4random_buf. */
+static bool
+generate_arc4random_buf (unsigned char *key)
+{
+ arc4random_buf (key, arc4random_key_size);
+ return true;
+}
+
+/* Test adapter for arc4random_uniform. */
+static bool
+generate_arc4random_uniform (unsigned char *key)
+{
+ for (int i = 0; i < arc4random_key_size; ++i)
+ key[i] = arc4random_uniform (256);
+ return true;
+}
+
+/* Test adapter for arc4random_uniform with argument 257. This means
+ that byte 0 happens more often, but we do not perform such a
+ statistcal check, so the test will still pass */
+static bool
+generate_arc4random_uniform_257 (unsigned char *key)
+{
+ for (int i = 0; i < arc4random_key_size; ++i)
+ key[i] = arc4random_uniform (257);
+ return true;
+}
+
+static int
+do_test (void)
+{
+ puts ("info: CPU implementation test");
+ find_stuck_bytes (__arc4random_cpu_generate_key);
+
+ puts ("info: kernel implementation test");
+ find_stuck_bytes (__arc4random_kernel_generate_key);
+
+ puts ("info: POSIX fallback implementation test");
+ find_stuck_bytes (generate_fallback);
+
+ puts ("info: arc4random implementation test");
+ find_stuck_bytes (generate_arc4random);
+
+ puts ("info: arc4random_buf implementation test");
+ find_stuck_bytes (generate_arc4random_buf);
+
+ puts ("info: arc4random_uniform implementation test");
+ find_stuck_bytes (generate_arc4random_uniform);
+
+ puts ("info: arc4random_uniform implementation test (257 variant)");
+ find_stuck_bytes (generate_arc4random_uniform_257);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/stdlib/tst-arc4random-thread.c b/stdlib/tst-arc4random-thread.c
new file mode 100644
index 0000000000..b122eaa826
--- /dev/null
+++ b/stdlib/tst-arc4random-thread.c
@@ -0,0 +1,278 @@
+/* Test that threads generate distinct streams of randomness.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <array_length.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/support.h>
+#include <support/xthread.h>
+
+/* Number of arc4random_buf calls per thread. */
+enum { count_per_thread = 5000 };
+
+/* Number of threads computing randomness. */
+enum { inner_threads = 5 };
+
+/* Number of threads launching other threads. Chosen as to not to
+ overload the system. */
+enum { outer_threads = 7 };
+
+/* Number of launching rounds performed by the outer threads. */
+enum { outer_rounds = 10 };
+
+/* Maximum number of bytes generated in an arc4random call. */
+enum { max_size = 32 };
+
+/* Sizes generated by threads. Must be long enough to be unique with
+ high probability. */
+static const int sizes[] = { 12, 15, 16, 17, 24, 31, max_size };
+
+/* Data structure to capture randomness results. */
+struct blob
+{
+ unsigned int size;
+ int thread_id;
+ unsigned int index;
+ unsigned char bytes[max_size];
+};
+
+#define DYNARRAY_STRUCT dynarray_blob
+#define DYNARRAY_ELEMENT struct blob
+#define DYNARRAY_PREFIX dynarray_blob_
+#include <malloc/dynarray-skeleton.c>
+
+/* Sort blob elements by length first, then by comparing the data
+ member. */
+static int
+compare_blob (const void *left1, const void *right1)
+{
+ const struct blob *left = left1;
+ const struct blob *right = right1;
+
+ if (left->size != right->size)
+ /* No overflow due to limited range. */
+ return left->size - right->size;
+ return memcmp (left->bytes, right->bytes, left->size);
+}
+
+/* Used to store the global result. */
+static pthread_mutex_t global_result_lock = PTHREAD_MUTEX_INITIALIZER;
+static struct dynarray_blob global_result;
+
+/* Copy data to the global result, with locking. */
+static void
+copy_result_to_global (struct dynarray_blob *result)
+{
+ xpthread_mutex_lock (&global_result_lock);
+ size_t old_size = dynarray_blob_size (&global_result);
+ TEST_VERIFY_EXIT
+ (dynarray_blob_resize (&global_result,
+ old_size + dynarray_blob_size (result)));
+ memcpy (dynarray_blob_begin (&global_result) + old_size,
+ dynarray_blob_begin (result),
+ dynarray_blob_size (result) * sizeof (struct blob));
+ xpthread_mutex_unlock (&global_result_lock);
+}
+
+/* Used to assign unique thread IDs. Accessed atomically. */
+static int next_thread_id;
+
+static void *
+inner_thread (void *unused)
+{
+ /* Use local result to avoid global lock contention while generating
+ randomness. */
+ struct dynarray_blob result;
+ dynarray_blob_init (&result);
+
+ int thread_id = __atomic_fetch_add (&next_thread_id, 1, __ATOMIC_RELAXED);
+
+ /* Determine the sizes to be used by this thread. */
+ int size_slot = thread_id % (array_length (sizes) + 1);
+ bool switch_sizes = size_slot == array_length (sizes);
+ if (switch_sizes)
+ size_slot = 0;
+
+ /* Compute the random blobs. */
+ for (int i = 0; i < count_per_thread; ++i)
+ {
+ struct blob *place = dynarray_blob_emplace (&result);
+ TEST_VERIFY_EXIT (place != NULL);
+ place->size = sizes[size_slot];
+ place->thread_id = thread_id;
+ place->index = i;
+ arc4random_buf (place->bytes, place->size);
+
+ if (switch_sizes)
+ size_slot = (size_slot + 1) % array_length (sizes);
+ }
+
+ /* Store the blobs in the global result structure. */
+ copy_result_to_global (&result);
+
+ dynarray_blob_free (&result);
+
+ return NULL;
+}
+
+/* Launch the inner threads and wait for their termination. */
+static void *
+outer_thread (void *unused)
+{
+ for (int round = 0; round < outer_rounds; ++round)
+ {
+ pthread_t threads[inner_threads];
+
+ for (int i = 0; i < inner_threads; ++i)
+ threads[i] = xpthread_create (NULL, inner_thread, NULL);
+
+ for (int i = 0; i < inner_threads; ++i)
+ xpthread_join (threads[i]);
+ }
+
+ return NULL;
+}
+
+static bool termination_requested;
+
+/* Call arc4random_buf to fill one blob with 16 bytes. */
+static void *
+get_one_blob_thread (void *closure)
+{
+ struct blob *result = closure;
+ result->size = 16;
+ arc4random_buf (result->bytes, result->size);
+ return NULL;
+}
+
+/* Invoked from fork_thread to actually obtain randomness data. */
+static void
+fork_thread_subprocess (void *closure)
+{
+ struct blob *shared_result = closure;
+
+ pthread_t thr1 = xpthread_create
+ (NULL, get_one_blob_thread, shared_result + 1);
+ pthread_t thr2 = xpthread_create
+ (NULL, get_one_blob_thread, shared_result + 2);
+ get_one_blob_thread (shared_result);
+ xpthread_join (thr1);
+ xpthread_join (thr2);
+}
+
+/* Continuously fork subprocesses to obtain a little bit of
+ randomness. */
+static void *
+fork_thread (void *unused)
+{
+ struct dynarray_blob result;
+ dynarray_blob_init (&result);
+
+ /* Three blobs from each subprocess. */
+ struct blob *shared_result
+ = support_shared_allocate (3 * sizeof (*shared_result));
+
+ while (!__atomic_load_n (&termination_requested, __ATOMIC_RELAXED))
+ {
+ /* Obtain the results from a subprocess. */
+ support_isolate_in_subprocess (fork_thread_subprocess, shared_result);
+
+ for (int i = 0; i < 3; ++i)
+ {
+ struct blob *place = dynarray_blob_emplace (&result);
+ TEST_VERIFY_EXIT (place != NULL);
+ place->size = shared_result[i].size;
+ place->thread_id = -1;
+ place->index = i;
+ memcpy (place->bytes, shared_result[i].bytes, place->size);
+ }
+ }
+
+ support_shared_free (shared_result);
+
+ copy_result_to_global (&result);
+ dynarray_blob_free (&result);
+
+ return NULL;
+}
+
+/* Launch the outer threads and wait for their termination. */
+static void
+run_outer_threads (void)
+{
+ /* Special thread that continuously calls fork. */
+ pthread_t fork_thread_id = xpthread_create (NULL, fork_thread, NULL);
+
+ pthread_t threads[outer_threads];
+ for (int i = 0; i < outer_threads; ++i)
+ threads[i] = xpthread_create (NULL, outer_thread, NULL);
+
+ for (int i = 0; i < outer_threads; ++i)
+ xpthread_join (threads[i]);
+
+ __atomic_store_n (&termination_requested, true, __ATOMIC_RELAXED);
+ xpthread_join (fork_thread_id);
+}
+
+static int
+do_test (void)
+{
+ dynarray_blob_init (&global_result);
+ int expected_blobs
+ = count_per_thread * inner_threads * outer_threads * outer_rounds;
+ printf ("info: minimum of %d blob results expected\n", expected_blobs);
+
+ run_outer_threads ();
+
+ /* The forking thread delivers a non-deterministic number of
+ results, which is why expected_blobs is only a minimun number of
+ results. */
+ printf ("info: %zu blob results observed\n",
+ dynarray_blob_size (&global_result));
+ TEST_VERIFY (dynarray_blob_size (&global_result) >= expected_blobs);
+
+ /* Verify that there are no duplicates. */
+ qsort (dynarray_blob_begin (&global_result),
+ dynarray_blob_size (&global_result),
+ sizeof (struct blob), compare_blob);
+ struct blob *end = dynarray_blob_end (&global_result);
+ for (struct blob *p = dynarray_blob_begin (&global_result) + 1;
+ p < end; ++p)
+ {
+ if (compare_blob (p - 1, p) == 0)
+ {
+ support_record_failure ();
+ char *quoted = support_quote_blob (p->bytes, p->size);
+ printf ("error: duplicate blob: \"%s\" (%d bytes)\n",
+ quoted, (int) p->size);
+ printf (" first source: thread %d, index %u\n",
+ p[-1].thread_id, p[-1].index);
+ printf (" second source: thread %d, index %u\n",
+ p[0].thread_id, p[0].index);
+ free (quoted);
+ }
+ }
+
+ dynarray_blob_free (&global_result);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/generic/Makefile b/sysdeps/generic/Makefile
index d287bfafc6..065135de76 100644
--- a/sysdeps/generic/Makefile
+++ b/sysdeps/generic/Makefile
@@ -26,3 +26,8 @@ sysdep_routines += framestate unwind-pe
shared-only-routines += framestate unwind-pe
endif
endif
+
+ifeq ($(subdir),stdlib)
+sysdep_routines += arc4random-cpu
+sysdep_routines += arc4random-kernel
+endif
diff --git a/sysdeps/generic/arc4random-cpu-data.h b/sysdeps/generic/arc4random-cpu-data.h
new file mode 100644
index 0000000000..ed023e6526
--- /dev/null
+++ b/sysdeps/generic/arc4random-cpu-data.h
@@ -0,0 +1,25 @@
+/* CPU support for arc4random, type definitions. Generic version.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _ARC4RANDOM_CPU_DATA_H
+#define _ARC4RANDOM_CPU_DATA_H
+
+/* The generic version does not have any CPU-specific data. */
+struct arc4random_cpu_data { };
+
+#endif /* _ARC4RANDOM_CPU_DATA_H */
diff --git a/sysdeps/generic/arc4random-cpu.c b/sysdeps/generic/arc4random-cpu.c
new file mode 100644
index 0000000000..846b587721
--- /dev/null
+++ b/sysdeps/generic/arc4random-cpu.c
@@ -0,0 +1,20 @@
+/* CPU support for arc4random. Generic version.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+/* The generic implementation uses inline functions, so there is no
+ code here. */
diff --git a/sysdeps/generic/arc4random-cpu.h b/sysdeps/generic/arc4random-cpu.h
new file mode 100644
index 0000000000..978c790fc8
--- /dev/null
+++ b/sysdeps/generic/arc4random-cpu.h
@@ -0,0 +1,49 @@
+/* CPU support for arc4random. Generic version.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _ARC4RANDOM_CPU_H
+#define _ARC4RANDOM_CPU_H
+
+#include <stdbool.h>
+
+/* In the generic implementation, CPU-specific reseeding always
+ fails. */
+static inline bool
+__arc4random_cpu_generate_key (unsigned char *key)
+{
+ return false;
+}
+
+/* The generic implementation does nothing. */
+static inline bool
+__arc4random_cpu_schedule (struct arc4random_data *data,
+ const unsigned char *key)
+{
+ return false;
+}
+
+/* The generic implementation does nothing. */
+static inline bool
+__arc4random_cpu_block (const struct arc4random_data *data,
+ struct arc4random_personalization personalization,
+ struct arc4random_block *output)
+{
+ return false;
+}
+
+#endif /* _ARC4RANDOM_CPU_H */
diff --git a/sysdeps/generic/arc4random-kernel.c b/sysdeps/generic/arc4random-kernel.c
new file mode 100644
index 0000000000..d8d4ea715b
--- /dev/null
+++ b/sysdeps/generic/arc4random-kernel.c
@@ -0,0 +1,20 @@
+/* Kernel support for arc4random. Generic version.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+/* The generic implementation uses inline functions, so there is no
+ code here. */
diff --git a/sysdeps/generic/arc4random-kernel.h b/sysdeps/generic/arc4random-kernel.h
new file mode 100644
index 0000000000..0f9ac54647
--- /dev/null
+++ b/sysdeps/generic/arc4random-kernel.h
@@ -0,0 +1,30 @@
+/* Kernel support for arc4random. Generic version.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _ARC4RANDOM_KERNEL_H
+#define _ARC4RANDOM_KERNEL_H
+
+/* In the generic implementation, kernel-specific reseeding always
+ fails. */
+static inline bool
+__arc4random_kernel_generate_key (unsigned char *unused)
+{
+ return false;
+}
+
+#endif /* _ARC4RANDOM_KERNEL_H */
diff --git a/sysdeps/mach/hurd/fork.c b/sysdeps/mach/hurd/fork.c
index 2d1e64c8d1..57e1056602 100644
--- a/sysdeps/mach/hurd/fork.c
+++ b/sysdeps/mach/hurd/fork.c
@@ -642,6 +642,9 @@ __fork (void)
/* Forking clears the trace flag. */
__sigemptyset (&_hurdsig_traced);
+ /* Reinitialize the arc4random lock. */
+ call_function_static_weak (__arc4random_after_fork_reinit);
+
/* Release malloc locks. */
_hurd_malloc_fork_child ();
call_function_static_weak (__malloc_fork_unlock_child);
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index 2cb507052b..5dddcde5af 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2033,6 +2033,9 @@ GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
GLIBC_2.27 wcstof64x F
GLIBC_2.27 wcstof64x_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c
index ec56a827eb..92517d238a 100644
--- a/sysdeps/nptl/fork.c
+++ b/sysdeps/nptl/fork.c
@@ -120,6 +120,9 @@ __libc_fork (void)
/* Reset the lock state in the multi-threaded case. */
if (multiple_threads)
{
+ /* Reinitialize the arc4random lock. */
+ call_function_static_weak (__arc4random_after_fork_reinit);
+
/* Release malloc locks. */
call_function_static_weak (__malloc_fork_unlock_child);
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 80cdb98e1c..3934723139 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2131,3 +2131,6 @@ GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
GLIBC_2.27 wcstof64x F
GLIBC_2.27 wcstof64x_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index c761f61c43..3b879336a7 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2026,6 +2026,9 @@ GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
GLIBC_2.27 wcstof64x F
GLIBC_2.27 wcstof64x_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/arc4random-kernel.c b/sysdeps/unix/sysv/linux/arc4random-kernel.c
new file mode 100644
index 0000000000..0c58bda7a9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/arc4random-kernel.c
@@ -0,0 +1,38 @@
+/* Kernel support for arc4random. Linux version.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <arc4random-private.h>
+#include <sys/random.h>
+#include <sysdep.h>
+
+bool
+__arc4random_kernel_generate_key (unsigned char *key)
+{
+#ifdef __NR_getrandom
+ /* Use a direct system call to avoid cancellation. arc4random must
+ not block, so use GRND_NONBLOCK. */
+
+ INTERNAL_SYSCALL_DECL (err);
+ int ret = INTERNAL_SYSCALL (getrandom, err, 3, key, arc4random_key_size,
+ GRND_NONBLOCK);
+ if (!INTERNAL_SYSCALL_ERROR_P (ret, err) && ret == arc4random_key_size)
+ return true;
+
+#endif
+ return false;
+}
diff --git a/sysdeps/unix/sysv/linux/arc4random-kernel.h b/sysdeps/unix/sysv/linux/arc4random-kernel.h
new file mode 100644
index 0000000000..3568c9b030
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/arc4random-kernel.h
@@ -0,0 +1,24 @@
+/* Kernel support for arc4random. Linux version.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _ARC4RANDOM_KERNEL_H
+#define _ARC4RANDOM_KERNEL_H
+
+bool __arc4random_kernel_generate_key (unsigned char *) attribute_hidden;
+
+#endif /* _ARC4RANDOM_KERNEL_H */
diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
index 6aa58c3ca7..35a31bd85d 100644
--- a/sysdeps/unix/sysv/linux/arm/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
@@ -115,6 +115,9 @@ GLIBC_2.27 wcstof32x F
GLIBC_2.27 wcstof32x_l F
GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index d10695b7d3..532716fc58 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -1872,6 +1872,9 @@ GLIBC_2.27 wcstof32x F
GLIBC_2.27 wcstof32x_l F
GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 23092ab6d7..6e2dd0f9d0 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2037,6 +2037,9 @@ GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
GLIBC_2.27 wcstof64x F
GLIBC_2.27 wcstof64x_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 7bf259e86c..c243b08a81 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -1907,6 +1907,9 @@ GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
GLIBC_2.27 wcstof64x F
GLIBC_2.27 wcstof64x_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 4673bcd79b..70792dfac6 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -116,6 +116,9 @@ GLIBC_2.27 wcstof32x F
GLIBC_2.27 wcstof32x_l F
GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0x98
GLIBC_2.4 _IO_2_1_stdin_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 1f8ac40399..5eeb85c794 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -1981,6 +1981,9 @@ GLIBC_2.27 wcstof32x F
GLIBC_2.27 wcstof32x_l F
GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
index 09277f5954..4bc644436e 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
@@ -2122,3 +2122,6 @@ GLIBC_2.27 wcstof32x F
GLIBC_2.27 wcstof32x_l F
GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index f562e20f23..fc7feb00c1 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -1959,6 +1959,9 @@ GLIBC_2.27 wcstof32x F
GLIBC_2.27 wcstof32x_l F
GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index ceb7388829..9ecca7ae7e 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -1957,6 +1957,9 @@ GLIBC_2.27 wcstof32x F
GLIBC_2.27 wcstof32x_l F
GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 5765f487a2..434000aa16 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -1965,6 +1965,9 @@ GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
GLIBC_2.27 wcstof64x F
GLIBC_2.27 wcstof64x_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index a84bb45a38..dd5a9141d8 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -1961,6 +1961,9 @@ GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
GLIBC_2.27 wcstof64x F
GLIBC_2.27 wcstof64x_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index e43295986c..e476c6ac4c 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2163,3 +2163,6 @@ GLIBC_2.27 wcstof32x F
GLIBC_2.27 wcstof32x_l F
GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index a5f2b23068..12715d8598 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -1985,6 +1985,9 @@ GLIBC_2.27 wcstof32x F
GLIBC_2.27 wcstof32x_l F
GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index e4cbe36279..bbe72d56d4 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -1989,6 +1989,9 @@ GLIBC_2.27 wcstof32x F
GLIBC_2.27 wcstof32x_l F
GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
index 9869feb56b..8cee0565ec 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
@@ -2221,3 +2221,6 @@ GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
GLIBC_2.27 wcstof64x F
GLIBC_2.27 wcstof64x_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
index e526dc4627..7388b75a32 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
@@ -116,6 +116,9 @@ GLIBC_2.27 wcstof32x F
GLIBC_2.27 wcstof32x_l F
GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
GLIBC_2.3 _Exit F
GLIBC_2.3 _IO_2_1_stderr_ D 0xe0
GLIBC_2.3 _IO_2_1_stdin_ D 0xe0
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index e6319eef8d..50d9f8c768 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2093,3 +2093,6 @@ GLIBC_2.27 xdrstdio_create F
GLIBC_2.27 xencrypt F
GLIBC_2.27 xprt_register F
GLIBC_2.27 xprt_unregister F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 41cdda0c2e..df1747a916 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -1994,6 +1994,9 @@ GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
GLIBC_2.27 wcstof64x F
GLIBC_2.27 wcstof64x_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 8a756cf287..abe2ef27c5 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -1900,6 +1900,9 @@ GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
GLIBC_2.27 wcstof64x F
GLIBC_2.27 wcstof64x_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
index 999bddd1db..a0f324505c 100644
--- a/sysdeps/unix/sysv/linux/sh/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
@@ -1876,6 +1876,9 @@ GLIBC_2.27 wcstof32x F
GLIBC_2.27 wcstof32x_l F
GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 7c4296fc10..da4e91e914 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -1988,6 +1988,9 @@ GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
GLIBC_2.27 wcstof64x F
GLIBC_2.27 wcstof64x_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index dafe9d74b7..7f4c1b98d4 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -1930,6 +1930,9 @@ GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
GLIBC_2.27 wcstof64x F
GLIBC_2.27 wcstof64x_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index f72d494920..aa172dd463 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -1888,6 +1888,9 @@ GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
GLIBC_2.27 wcstof64x F
GLIBC_2.27 wcstof64x_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
GLIBC_2.3 __ctype_b_loc F
GLIBC_2.3 __ctype_tolower_loc F
GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 96c9fa050e..184021af09 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2139,3 +2139,6 @@ GLIBC_2.27 wcstof64 F
GLIBC_2.27 wcstof64_l F
GLIBC_2.27 wcstof64x F
GLIBC_2.27 wcstof64x_l F
+GLIBC_2.28 arc4random F
+GLIBC_2.28 arc4random_buf F
+GLIBC_2.28 arc4random_uniform F
diff --git a/sysdeps/x86/arc4random-cpu.c b/sysdeps/x86/arc4random-cpu.c
new file mode 100644
index 0000000000..59ae40d275
--- /dev/null
+++ b/sysdeps/x86/arc4random-cpu.c
@@ -0,0 +1,152 @@
+/* CPU support for arc4random. x86 version.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <arc4random-private.h>
+#include <cpu-features.h>
+#include <ldsodefs.h>
+
+/* This can be changed to "rdseed" for failure testing (on
+ implementations where the instruction occasionally fails). */
+#define RAND_INSTRUCTION "rdrand"
+
+bool
+__arc4random_cpu_generate_key (unsigned char *key)
+{
+ const struct cpu_features *cpu_features = __get_cpu_features ();
+ if (!CPU_FEATURES_CPU_P (cpu_features, RDRAND))
+ return false;
+
+ _Static_assert (arc4random_key_size == 16, "key size");
+
+ bool success;
+ uint32_t reg;
+ __asm__ (RAND_INSTRUCTION " %0\n\t"
+ "jnc 1f\n\t"
+ "movl %0, (%2)\n\t"
+ RAND_INSTRUCTION " %0\n\t"
+ "jnc 1f\n\t"
+ "movl %0, 4(%2)\n\t"
+ RAND_INSTRUCTION " %0\n\t"
+ "jnc 1f\n\t"
+ "movl %0, 8(%2)\n\t"
+ RAND_INSTRUCTION " %0\n\t"
+ "jnc 1f\n\t"
+ "movl %0, 12(%2)\n\t"
+ "mov $1, %%eax\n\t"
+ "jmp 2f\n\t"
+ "1:\n\t"
+ "xor %%eax, %%eax\n\t"
+ "2:\n\t"
+ : "=&r" (reg), "=a" (success)
+ : "r" (key)
+ : "cc", "memory");
+ return success;
+}
+
+/* Separate function to enable SSE2 register support in the
+ compiler. */
+static void
+__attribute__ ((target ("sse2")))
+sse2_schedule (struct arc4random_data *data, const unsigned char *key)
+{
+#define KEYGEN_ROUND(n, code) \
+ "aeskeygenassist $ " #code ", %%xmm0, %%xmm1\n\t" \
+ "pshufd $0xff, %%xmm1, %%xmm1\n\t" \
+ "movdqa %%xmm0, %%xmm2\n\t" \
+ "pslldq $4, %%xmm2\n\t" \
+ "pxor %%xmm2, %%xmm0\n\t" \
+ "pslldq $4, %%xmm2\n\t" \
+ "pxor %%xmm2, %%xmm0\n\t" \
+ "pslldq $4, %%xmm2\n\t" \
+ "pxor %%xmm2, %%xmm1\n\t" \
+ "pxor %%xmm1, %%xmm0\n\t" \
+ "movdqa %%xmm0, " #n " * 16(%1)\n\t"
+
+ asm ("movdqu (%0), %%xmm0\n\t"
+ "movdqa %%xmm0, 0x00(%1)\n\t"
+ KEYGEN_ROUND (1, 0x01)
+ KEYGEN_ROUND (2, 0x02)
+ KEYGEN_ROUND (3, 0x04)
+ KEYGEN_ROUND (4, 0x08)
+ KEYGEN_ROUND (5, 0x10)
+ KEYGEN_ROUND (6, 0x20)
+ KEYGEN_ROUND (7, 0x40)
+ KEYGEN_ROUND (8, 0x80)
+ KEYGEN_ROUND (9, 0x1b)
+ KEYGEN_ROUND (10, 0x36)
+ :
+ : "r" (key), "r" (&data->generic)
+ : "cc", "memory", "xmm0", "xmm1", "xmm2");
+#undef KEYGEN_ROUND
+}
+
+bool
+__arc4random_cpu_schedule (struct arc4random_data *data,
+ const unsigned char *key)
+{
+ const struct cpu_features *cpu_features = __get_cpu_features ();
+ if (!CPU_FEATURES_CPU_P (cpu_features, AES))
+ return false;
+
+ /* We could use the generic implementation because the data layout
+ is the same, but to avoid side-channel issues, we use
+ aeskeygenassist (which is also faster). */
+ sse2_schedule (data, key);
+
+ return true;
+}
+
+/* Separate function to enable SSE2 register support in the
+ compiler. */
+static void
+__attribute__ ((target ("sse2")))
+block_sse2 (const struct arc4random_data *data,
+ struct arc4random_personalization *personalization,
+ struct arc4random_block *output)
+{
+ __asm__ ("movdqu (%0), %%xmm0\n\t"
+ "pxor (%1), %%xmm0\n\t"
+ "aesenc 0x10(%1), %%xmm0\n\t"
+ "aesenc 0x20(%1), %%xmm0\n\t"
+ "aesenc 0x30(%1), %%xmm0\n\t"
+ "aesenc 0x40(%1), %%xmm0\n\t"
+ "aesenc 0x50(%1), %%xmm0\n\t"
+ "aesenc 0x60(%1), %%xmm0\n\t"
+ "aesenc 0x70(%1), %%xmm0\n\t"
+ "aesenc 0x80(%1), %%xmm0\n\t"
+ "aesenc 0x90(%1), %%xmm0\n\t"
+ "aesenclast 0xa0(%1), %%xmm0\n\t"
+ "movdqu %%xmm0, (%2)"
+ :
+ : "r" (personalization), "r" (&data->generic), "r" (output)
+ : "cc", "memory", "xmm0");
+}
+
+bool
+__arc4random_cpu_block (const struct arc4random_data *data,
+ struct arc4random_personalization personalization,
+ struct arc4random_block *output)
+{
+ const struct cpu_features *cpu_features = __get_cpu_features ();
+ if (!CPU_FEATURES_CPU_P (cpu_features, RDRAND))
+ return false;
+
+ block_sse2 (data, &personalization, output);
+
+ return true;
+}
diff --git a/sysdeps/x86/arc4random-cpu.h b/sysdeps/x86/arc4random-cpu.h
new file mode 100644
index 0000000000..eab2c3c157
--- /dev/null
+++ b/sysdeps/x86/arc4random-cpu.h
@@ -0,0 +1,33 @@
+/* CPU support for arc4random. x86 version.
+ Copyright (C) 2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _ARC4RANDOM_CPU_H
+#define _ARC4RANDOM_CPU_H
+
+#include <stdbool.h>
+
+/* These return true if the CPU supports AES instructions, and perform
+ the operation. */
+bool __arc4random_cpu_generate_key (unsigned char *key) attribute_hidden;
+bool __arc4random_cpu_schedule (struct arc4random_data *data,
+ const unsigned char *key) attribute_hidden;
+bool __arc4random_cpu_block (const struct arc4random_data *data,
+ struct arc4random_personalization personalization,
+ struct arc4random_block *output) attribute_hidden;
+
+#endif /* _ARC4RANDOM_CPU_H */
diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h
index 624e681e96..1493615e34 100644
--- a/sysdeps/x86/cpu-features.h
+++ b/sysdeps/x86/cpu-features.h
@@ -61,6 +61,8 @@
#define bit_cpu_LZCNT (1 << 5)
#define bit_cpu_MOVBE (1 << 22)
#define bit_cpu_POPCNT (1 << 23)
+#define bit_cpu_RDRAND (1 << 30)
+#define bit_cpu_AES (1 << 30)
/* COMMON_CPUID_INDEX_7. */
#define bit_cpu_BMI1 (1 << 3)
@@ -210,6 +212,8 @@ extern const struct cpu_features *__get_cpu_features (void)
# define index_cpu_IBT COMMON_CPUID_INDEX_7
# define index_cpu_SHSTK COMMON_CPUID_INDEX_7
# define index_cpu_FSRM COMMON_CPUID_INDEX_7
+# define index_cpu_RDRAND COMMON_CPUID_INDEX_1
+# define index_cpu_AES COMMON_CPUID_INDEX_1
# define reg_CX8 edx
# define reg_CMOV edx
@@ -242,6 +246,8 @@ extern const struct cpu_features *__get_cpu_features (void)
# define reg_IBT edx
# define reg_SHSTK ecx
# define reg_FSRM edx
+# define reg_RDRAND ecx
+# define reg_AES ecx
# define index_arch_Fast_Rep_String FEATURE_INDEX_1
# define index_arch_Fast_Copy_Backward FEATURE_INDEX_1