diff mbox

arc4random implementation

Message ID 811dad4f-e4d0-6eec-51f5-19b28d145bd5@redhat.com
State New, archived
Headers show

Commit Message

Florian Weimer June 21, 2018, noon UTC
I rebased the patch on current master.

Additional changes: I added a missing TEMP_FAILURE_RETRY to the 
/dev/urandom-based reseeding.  I changed the x86 hardware implementation 
not to us a separate flag variable, so this implementation doesn't need 
any CPU-specific state after all.

Thanks,
Florian
diff mbox

Patch

Subject: [PATCH] Add arc4random, arc4random_buf, arc4random_uniform [BZ #4417]
To: libc-alpha@sourceware.org

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

	[BZ #4417]
	Add arc4random, arc4random_buf, arc4random_uniform.
	* LICENSES: Mention libgcrypt.
	* stdlib/Makefile (headers): Add bits/arc4random.h.
	(routines): Add arc4random, arc4random_buf, arc4random_uniform,
	arc4random-thread, arc4random-forkdetect arc4random-reseed,
	arc4random-aes.
	(tests): Add tst-arc4random-fork, tst-arc4random-thread.
	(tests-arc4random-internal): New variable.
	(tests-internal, tests-static): Add tst-arc4random-aes,
	tst-arc4random-forkdetect, tst-arc4random-stats.
	* stdlib/Versions (GLIBC_2.28): Export arc4random, arc4random_buf,
	arc4random_uniform.
	(GLIBC_PRIVATE): Export __libc_arc4random_buf,
	__libc_arc4random_uniform.
	* stdlib/stdlib.h [__USE_MISC]: Include <bits/arc4random.h>.
	* stdlib/sys/random.h: Likewise.
	* sysdeps/generic/Makefile [$(subdir) == stdlib] (sysdep_routines):
	Add arc4random-cpu, arc4random-kernel.
	* sysdeps/nptl/fork.c (__libc_fork): Call
	__arc4random_after_fork_reinit.
	* sysdeps/mach/hurd/fork.c (__fork): Likewise.
	* sysdeps/x86/cpu-features.h (bit_cpu_RDRAND, bit_cpu_AES)
	(index_cpu_RDRAND, index_cpu_AES, reg_RDRAND, reg_AES): Define.
	* include/bits/arc4random.h: New file.
	* stdlib/arc4random-aes.c: Likewise.
	* stdlib/arc4random-forkdetect.c: Likewise.
	* stdlib/arc4random-forkdetect.h: Likewise.
	* stdlib/arc4random-private.h: Likewise.
	* stdlib/arc4random-reseed.c: Likewise.
	* stdlib/arc4random-thread.h: Likewise.
	* stdlib/arc4random.c: Likewise.
	* stdlib/arc4random_buf.c: Likewise.
	* stdlib/arc4random_uniform.c: Likewise.
	* stdlib/bits/arc4random.h: Likewise.
	* stdlib/tst-arc4random-aes.c: Likewise.
	* stdlib/tst-arc4random-fork.c: Likewise.
	* stdlib/tst-arc4random-forkdetect.c: Likewise.
	* stdlib/tst-arc4random-stats.c: Likewise.
	* stdlib/tst-arc4random-thread.c: Likewise.
	* sysdeps/generic/arc4random-cpu-data.h: Likewise.
	* sysdeps/generic/arc4random-cpu.c: Likewise.
	* sysdeps/generic/arc4random-cpu.h: Likewise.
	* sysdeps/generic/arc4random-kernel.c: Likewise.
	* sysdeps/generic/arc4random-kernel.h: Likewise.
	* sysdeps/unix/sysv/linux/arc4random-kernel.c: Likewise.
	* sysdeps/unix/sysv/linux/arc4random-kernel.h: Likewise.
	* sysdeps/x86/arc4random-cpu.c: Likewise.
	* sysdeps/x86/arc4random-cpu.h: Likewise.
	* sysdeps/**/libc*.abilist: Add arc4random, arc4random_buf,
	arc4random_uniform.

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