This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] arc4random implementation


The attached patch provides an implementation of arc4random, arc4random_buf, and arc4random_uniform.

I believe it is reasonably complete, except for the documentation. I will submit that part once Zack's cryptography changes have been added to the manual, to avoid conflicts. More statistical tests would make sense as well, but the tricky part will be to weigh run time of the test against an extremely low false positive rate (e.g., a one-in-1024 chance of failure, as it happens with some statistical tests, would not be acceptable).

For fork detection, there are two modes, depending on the availability of MADV_WIPEONFORK support in the kernel.

The MADV_WIPEONFORK implementation is much simpler and has the advantage that it avoids deadlocks even if direct clone/fork system calls are performed in multi-threaded processes. It also avoids repeated mmap calls, which can fail due to OOM.

The fallback implementation uses two counters (one in a MAP_PRIVATE mapping, one in a MAP_SHARED mapping) for fork detection. It relies heavily on locking. Direct fork/clone system calls from multi-threaded processes can result in deadlocks, but the detection algorithm was designed in such a way that it would still work with such direct system calls. stdlib/arc4random-forkdetect.c and stdlib/tst-arc4random-forkdetect.c have the gory details.

As the source for randomness, the Linux getrandom system call, a CPU randomness source, and /dev/urandom are used, in that order. The idea is to give the kernel a chance to implement a particular randomness policy, before switching to the CPU generator. The /dev/urandom fallback is a bit of a wart and may of course fail in a chroot environment, but I don't see a way to avoid it.

Since arc4random cannot report failure, there are various situations in which the process may be terminated in response to calling arc4random (OOM, lack of /dev/urandom). For this reason, it is currently not advisable to use this implementation within glibc itself. If we want to change that, we need to perform the first seed using AT_RANDOM, which is always available (unlike getrandom or /dev/urandom).

The implementation has sysdeps hooks for the randomness generation (kernel and CPU) and the AES key schedule and block operation (CPU only). As a proof of concept, the CPU parts are implemented for x86. (These parts could conceivably be committed separately.)

The generator will not pass certification due to lack of periodic reseeding and backtrack protection. Adding reseeding should be easy enough in a follow-up patch. Efficient backtrack protection would probably need per-thread key schedules, so around 160 extra bytes of TLS data. It also needs more frequent reseeding. I think these aspects could be corrected in response to a review for certification, if that ever happens.

Thanks,
Florian
Subject: [PATCH] Add arc4random, arc4random_buf, arc4random_uniform
To: libc-alpha@sourceware.org

2018-05-31  Florian Weimer  <fweimer@redhat.com>

	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 e2a6f45121..43b37a697a 100644
--- a/NEWS
+++ b/NEWS
@@ -41,6 +41,8 @@ Major new features:
   NI_IDN_ALLOW_UNASSIGNED, NI_IDN_USE_STD3_ASCII_RULES) have been
   deprecated.  They no longer have any effect.
 
+* The functions arc4random, arc4random_buf, arc4random_uniform are provided.
+
 Deprecated and removed features, and other changes affecting compatibility:
 
 * The nonstandard header files <libio.h> and <_G_config.h> are no longer
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/scripts/update-abilist.sh b/scripts/update-abilist.sh
index 68d469b3e5..28953bfe28 100644
--- a/scripts/update-abilist.sh
+++ b/scripts/update-abilist.sh
@@ -20,9 +20,12 @@
 set -e
 export LC_ALL=C
 
-if [ $# -lt 3 ]; then
+if [ $# -lt 2 ]; then
   echo "usage: $0 OLD-FILE NEW-FILE FILES-TO-BE-PATCHED..." 1>&2
   exit 2
+elif [ $# -eq 2 ]; then
+  echo "info: no files to patch" 1>&2
+  exit 0
 fi
 
 old_file="$1"
diff --git a/stdlib/Makefile b/stdlib/Makefile
index bf1fbd4a3a..b914b9cf65 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-makecontext-align test-bz22786 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
@@ -238,3 +252,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..284562db4b
--- /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 = __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-data.h b/sysdeps/x86/arc4random-cpu-data.h
new file mode 100644
index 0000000000..74b6526b60
--- /dev/null
+++ b/sysdeps/x86/arc4random-cpu-data.h
@@ -0,0 +1,29 @@
+/* CPU support for arc4random, type definitions.  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_DATA_H
+#define _ARC4RANDOM_CPU_DATA_H
+
+/* Use a separate flag for the support status.  This ensures that we
+   do not switch implementations after process/VM migration.  */
+struct arc4random_cpu_data
+{
+  bool aesni;
+};
+
+#endif /* _ARC4RANDOM_CPU_DATA_H */
diff --git a/sysdeps/x86/arc4random-cpu.c b/sysdeps/x86/arc4random-cpu.c
new file mode 100644
index 0000000000..8cb73a0f5f
--- /dev/null
+++ b/sysdeps/x86/arc4random-cpu.c
@@ -0,0 +1,156 @@
+/* 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))
+    {
+      data->cpu.aesni = false;
+      return false;
+    }
+
+  data->cpu.aesni = true;
+
+  /* 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)
+{
+  if (!data->cpu.aesni)
+    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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]