]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
stdlib: Add arc4random, arc4random_buf, and arc4random_uniform (BZ #4417)
authorAdhemerval Zanella Netto <adhemerval.zanella@linaro.org>
Thu, 21 Jul 2022 13:04:59 +0000 (10:04 -0300)
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>
Fri, 22 Jul 2022 14:58:27 +0000 (11:58 -0300)
The implementation is based on scalar Chacha20 with per-thread cache.
It uses getrandom or /dev/urandom as fallback to get the initial entropy,
and reseeds the internal state on every 16MB of consumed buffer.

To improve performance and lower memory consumption the per-thread cache
is allocated lazily on first arc4random functions call, and if the
memory allocation fails getentropy or /dev/urandom is used as fallback.
The cache is also cleared on thread exit iff it was initialized (so if
arc4random is not called it is not touched).

Although it is lock-free, arc4random is still not async-signal-safe
(the per thread state is not updated atomically).

The ChaCha20 implementation is based on RFC8439 [1], omitting the final
XOR of the keystream with the plaintext because the plaintext is a
stream of zeros.  This strategy is similar to what OpenBSD arc4random
does.

The arc4random_uniform is based on previous work by Florian Weimer,
where the algorithm is based on Jérémie Lumbroso paper Optimal Discrete
Uniform Generation from Coin Flips, and Applications (2013) [2], who
credits Donald E. Knuth and Andrew C. Yao, The complexity of nonuniform
random number generation (1976), for solving the general case.

The main advantage of this method is the that the unit of randomness is not
the uniform random variable (uint32_t), but a random bit.  It optimizes the
internal buffer sampling by initially consuming a 32-bit random variable
and then sampling byte per byte.  Depending of the upper bound requested,
it might lead to better CPU utilization.

Checked on x86_64-linux-gnu, aarch64-linux, and powerpc64le-linux-gnu.

Co-authored-by: Florian Weimer <fweimer@redhat.com>
Reviewed-by: Yann Droneaud <ydroneaud@opteya.com>
[1] https://datatracker.ietf.org/doc/html/rfc8439
[2] https://arxiv.org/pdf/1304.1916.pdf

55 files changed:
NEWS
include/stdlib.h
malloc/thread-freeres.c
nptl/allocatestack.c
stdlib/Makefile
stdlib/Versions
stdlib/arc4random.c [new file with mode: 0644]
stdlib/arc4random.h [new file with mode: 0644]
stdlib/arc4random_uniform.c [new file with mode: 0644]
stdlib/chacha20.c [new file with mode: 0644]
stdlib/stdlib.h
sysdeps/generic/not-cancel.h
sysdeps/generic/tls-internal-struct.h
sysdeps/generic/tls-internal.c
sysdeps/generic/tls-internal.h
sysdeps/mach/hurd/_Fork.c
sysdeps/mach/hurd/i386/libc.abilist
sysdeps/mach/hurd/not-cancel.h
sysdeps/nptl/_Fork.c
sysdeps/unix/sysv/linux/aarch64/libc.abilist
sysdeps/unix/sysv/linux/alpha/libc.abilist
sysdeps/unix/sysv/linux/arc/libc.abilist
sysdeps/unix/sysv/linux/arm/be/libc.abilist
sysdeps/unix/sysv/linux/arm/le/libc.abilist
sysdeps/unix/sysv/linux/csky/libc.abilist
sysdeps/unix/sysv/linux/hppa/libc.abilist
sysdeps/unix/sysv/linux/i386/libc.abilist
sysdeps/unix/sysv/linux/ia64/libc.abilist
sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
sysdeps/unix/sysv/linux/nios2/libc.abilist
sysdeps/unix/sysv/linux/not-cancel.h
sysdeps/unix/sysv/linux/or1k/libc.abilist
sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
sysdeps/unix/sysv/linux/sh/be/libc.abilist
sysdeps/unix/sysv/linux/sh/le/libc.abilist
sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
sysdeps/unix/sysv/linux/tls-internal.c
sysdeps/unix/sysv/linux/tls-internal.h
sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist

diff --git a/NEWS b/NEWS
index df882ec2438e38a070d24707e9a9860551e8add3..8420a65cd06874ee09518366b8fba746a557212a 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -60,6 +60,10 @@ Major new features:
   _GNU_SOURCE macro is defined and the C++20 __cpp_char8_t feature test macro
   is not defined (if __cpp_char8_t is defined, then char8_t is a builtin type).
 
+* The functions arc4random, arc4random_buf, and arc4random_uniform have been
+  added.  The functions use a pseudo-random number generator along with
+  entropy from the kernel.
+
 Deprecated and removed features, and other changes affecting compatibility:
 
 * Support for prelink will be removed in the next release; this includes
index 1c6f70b0820ced97ade127366db68de4f70928ec..cae7f7cdf8bfa8be3d9e92988a29fd276eee50d4 100644 (file)
@@ -144,6 +144,18 @@ libc_hidden_proto (__ptsname_r)
 libc_hidden_proto (grantpt)
 libc_hidden_proto (unlockpt)
 
+__typeof (arc4random) __arc4random;
+libc_hidden_proto (__arc4random);
+__typeof (arc4random_buf) __arc4random_buf;
+libc_hidden_proto (__arc4random_buf);
+__typeof (arc4random_uniform) __arc4random_uniform;
+libc_hidden_proto (__arc4random_uniform);
+extern void __arc4random_buf_internal (void *buffer, size_t len)
+     attribute_hidden;
+/* Called from the fork function to reinitialize the internal cipher state
+   in child process.  */
+extern void __arc4random_fork_subprocess (void) attribute_hidden;
+
 extern double __strtod_internal (const char *__restrict __nptr,
                                 char **__restrict __endptr, int __group)
      __THROW __nonnull ((1)) __wur;
index 38946521692bd27095a793d6e116a5b4eb0f14f2..b22e1d789f90c128fe9e239d301eb8685410f33e 100644 (file)
@@ -36,7 +36,7 @@ __libc_thread_freeres (void)
   __rpc_thread_destroy ();
 #endif
   call_function_static_weak (__res_thread_freeres);
-  __glibc_tls_internal_free ();
+  call_function_static_weak (__glibc_tls_internal_free);
   call_function_static_weak (__libc_dlerror_result_free);
 
   /* This should come last because it shuts down malloc for this
index 98f5f6dd85afe2e14b29600b4fdc565364b79671..219854f2cb5a78365a25b56155d5a7eb47fb8d59 100644 (file)
@@ -32,6 +32,7 @@
 #include <kernel-features.h>
 #include <nptl-stack.h>
 #include <libc-lock.h>
+#include <tls-internal.h>
 
 /* Default alignment of stack.  */
 #ifndef STACK_ALIGN
@@ -127,7 +128,7 @@ get_cached_stack (size_t *sizep, void **memp)
 
   result->exiting = false;
   __libc_lock_init (result->exit_lock);
-  result->tls_state = (struct tls_internal_t) { 0 };
+  memset (&result->tls_state, 0, sizeof result->tls_state);
 
   /* Clear the DTV.  */
   dtv_t *dtv = GET_DTV (TLS_TPADJ (result));
index d4a4d5679a73bfedb6f29f816eee5de0f672e02d..62f82532258c9342ed8212858ee929e3f9fef8e7 100644 (file)
@@ -53,6 +53,8 @@ routines := \
   a64l \
   abort \
   abs \
+  arc4random \
+  arc4random_uniform \
   at_quick_exit \
   atof \
   atoi \
index 5e9099a153631c803fa7e14e1b00b16061ad366a..d09a308fb5238d18b7c9f321d349afe6567da8d1 100644 (file)
@@ -136,6 +136,11 @@ libc {
     strtof32; strtof64; strtof32x;
     strtof32_l; strtof64_l; strtof32x_l;
   }
+  GLIBC_2.36 {
+    arc4random;
+    arc4random_buf;
+    arc4random_uniform;
+  }
   GLIBC_PRIVATE {
     # functions which have an additional interface since they are
     # are cancelable.
diff --git a/stdlib/arc4random.c b/stdlib/arc4random.c
new file mode 100644 (file)
index 0000000..65547e7
--- /dev/null
@@ -0,0 +1,208 @@
+/* Pseudo Random Number Generator based on ChaCha20.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <arc4random.h>
+#include <errno.h>
+#include <not-cancel.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/random.h>
+#include <tls-internal.h>
+
+/* arc4random keeps two counters: 'have' is the current valid bytes not yet
+   consumed in 'buf' while 'count' is the maximum number of bytes until a
+   reseed.
+
+   Both the initial seed and reseed try to obtain entropy from the kernel
+   and abort the process if none could be obtained.
+
+   The state 'buf' improves the usage of the cipher calls, allowing to call
+   optimized implementations (if the architecture provides it) and minimize
+   function call overhead.  */
+
+#include <chacha20.c>
+
+/* Called from the fork function to reset the state.  */
+void
+__arc4random_fork_subprocess (void)
+{
+  struct arc4random_state_t *state = __glibc_tls_internal ()->rand_state;
+  if (state != NULL)
+    {
+      explicit_bzero (state, sizeof (*state));
+      /* Force key init.  */
+      state->count = -1;
+    }
+}
+
+/* Return the current thread random state or try to create one if there is
+   none available.  In the case malloc can not allocate a state, arc4random
+   will try to get entropy with arc4random_getentropy.  */
+static struct arc4random_state_t *
+arc4random_get_state (void)
+{
+  struct arc4random_state_t *state = __glibc_tls_internal ()->rand_state;
+  if (state == NULL)
+    {
+      state = malloc (sizeof (struct arc4random_state_t));
+      if (state != NULL)
+       {
+         /* Force key initialization on first call.  */
+         state->count = -1;
+         __glibc_tls_internal ()->rand_state = state;
+       }
+    }
+  return state;
+}
+
+static void
+arc4random_getrandom_failure (void)
+{
+  __libc_fatal ("Fatal glibc error: cannot get entropy for arc4random\n");
+}
+
+static void
+arc4random_rekey (struct arc4random_state_t *state, uint8_t *rnd, size_t rndlen)
+{
+  chacha20_crypt (state->ctx, state->buf, state->buf, sizeof state->buf);
+
+  /* Mix optional user provided data.  */
+  if (rnd != NULL)
+    {
+      size_t m = MIN (rndlen, CHACHA20_KEY_SIZE + CHACHA20_IV_SIZE);
+      for (size_t i = 0; i < m; i++)
+       state->buf[i] ^= rnd[i];
+    }
+
+  /* Immediately reinit for backtracking resistance.  */
+  chacha20_init (state->ctx, state->buf, state->buf + CHACHA20_KEY_SIZE);
+  explicit_bzero (state->buf, CHACHA20_KEY_SIZE + CHACHA20_IV_SIZE);
+  state->have = sizeof (state->buf) - (CHACHA20_KEY_SIZE + CHACHA20_IV_SIZE);
+}
+
+static void
+arc4random_getentropy (void *rnd, size_t len)
+{
+  if (__getrandom_nocancel (rnd, len, GRND_NONBLOCK) == len)
+    return;
+
+  int fd = TEMP_FAILURE_RETRY (__open64_nocancel ("/dev/urandom",
+                                                 O_RDONLY | O_CLOEXEC));
+  if (fd != -1)
+    {
+      uint8_t *p = rnd;
+      uint8_t *end = p + len;
+      do
+       {
+         ssize_t ret = TEMP_FAILURE_RETRY (__read_nocancel (fd, p, end - p));
+         if (ret <= 0)
+           arc4random_getrandom_failure ();
+         p += ret;
+       }
+      while (p < end);
+
+      if (__close_nocancel (fd) == 0)
+       return;
+    }
+  arc4random_getrandom_failure ();
+}
+
+/* Check if the thread context STATE should be reseed with kernel entropy
+   depending of requested LEN bytes.  If there is less than requested,
+   the state is either initialized or reseeded, otherwise the internal
+   counter subtract the requested length.  */
+static void
+arc4random_check_stir (struct arc4random_state_t *state, size_t len)
+{
+  if (state->count <= len || state->count == -1)
+    {
+      uint8_t rnd[CHACHA20_KEY_SIZE + CHACHA20_IV_SIZE];
+      arc4random_getentropy (rnd, sizeof rnd);
+
+      if (state->count == -1)
+       chacha20_init (state->ctx, rnd, rnd + CHACHA20_KEY_SIZE);
+      else
+       arc4random_rekey (state, rnd, sizeof rnd);
+
+      explicit_bzero (rnd, sizeof rnd);
+
+      /* Invalidate the buf.  */
+      state->have = 0;
+      memset (state->buf, 0, sizeof state->buf);
+      state->count = CHACHA20_RESEED_SIZE;
+    }
+  else
+    state->count -= len;
+}
+
+void
+__arc4random_buf (void *buffer, size_t len)
+{
+  struct arc4random_state_t *state = arc4random_get_state ();
+  if (__glibc_unlikely (state == NULL))
+    {
+      arc4random_getentropy (buffer, len);
+      return;
+    }
+
+  arc4random_check_stir (state, len);
+  while (len > 0)
+    {
+      if (state->have > 0)
+       {
+         size_t m = MIN (len, state->have);
+         uint8_t *ks = state->buf + sizeof (state->buf) - state->have;
+         memcpy (buffer, ks, m);
+         explicit_bzero (ks, m);
+         buffer += m;
+         len -= m;
+         state->have -= m;
+       }
+      if (state->have == 0)
+       arc4random_rekey (state, NULL, 0);
+    }
+}
+libc_hidden_def (__arc4random_buf)
+weak_alias (__arc4random_buf, arc4random_buf)
+
+uint32_t
+__arc4random (void)
+{
+  uint32_t r;
+
+  struct arc4random_state_t *state = arc4random_get_state ();
+  if (__glibc_unlikely (state == NULL))
+    {
+      arc4random_getentropy (&r, sizeof (uint32_t));
+      return r;
+    }
+
+  arc4random_check_stir (state, sizeof (uint32_t));
+  if (state->have < sizeof (uint32_t))
+    arc4random_rekey (state, NULL, 0);
+  uint8_t *ks = state->buf + sizeof (state->buf) - state->have;
+  memcpy (&r, ks, sizeof (uint32_t));
+  memset (ks, 0, sizeof (uint32_t));
+  state->have -= sizeof (uint32_t);
+
+  return r;
+}
+libc_hidden_def (__arc4random)
+weak_alias (__arc4random, arc4random)
diff --git a/stdlib/arc4random.h b/stdlib/arc4random.h
new file mode 100644 (file)
index 0000000..cd39389
--- /dev/null
@@ -0,0 +1,48 @@
+/* Arc4random definition used on TLS.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _CHACHA20_H
+#define _CHACHA20_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+/* Internal ChaCha20 state.  */
+#define CHACHA20_STATE_LEN     16
+#define CHACHA20_BLOCK_SIZE    64
+
+/* Maximum number bytes until reseed (16 MB).  */
+#define CHACHA20_RESEED_SIZE   (16 * 1024 * 1024)
+
+/* Internal arc4random buffer, used on each feedback step so offer some
+   backtracking protection and to allow better used of vectorized
+   chacha20 implementations.  */
+#define CHACHA20_BUFSIZE        (8 * CHACHA20_BLOCK_SIZE)
+
+_Static_assert (CHACHA20_BUFSIZE >= CHACHA20_BLOCK_SIZE + CHACHA20_BLOCK_SIZE,
+               "CHACHA20_BUFSIZE < CHACHA20_BLOCK_SIZE + CHACHA20_BLOCK_SIZE");
+
+struct arc4random_state_t
+{
+  uint32_t ctx[CHACHA20_STATE_LEN];
+  size_t have;
+  size_t count;
+  uint8_t buf[CHACHA20_BUFSIZE];
+};
+
+#endif
diff --git a/stdlib/arc4random_uniform.c b/stdlib/arc4random_uniform.c
new file mode 100644 (file)
index 0000000..1326dfa
--- /dev/null
@@ -0,0 +1,140 @@
+/* Random pseudo generator number which returns a single 32 bit value
+   uniformly distributed but with an upper_bound.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <endian.h>
+#include <libc-lock.h>
+#include <stdlib.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 void
+random_bytes (uint32_t *result, uint32_t byte_count)
+{
+  *result = 0;
+  unsigned char *ptr = (unsigned char *) result;
+  if (__BYTE_ORDER == __BIG_ENDIAN)
+    ptr += 4 - byte_count;
+  __arc4random_buf (ptr, byte_count);
+}
+
+uint32_t
+__arc4random_uniform (uint32_t n)
+{
+  if (n <= 1)
+    /* There is no valid return value for a zero limit, and 0 is the
+       only possible result for limit 1.  */
+    return 0;
+
+  /* The bits variable serves as a source for bits.  Prefetch the
+     minimum number of bytes needed.  */
+  uint32_t count = byte_count (n);
+  uint32_t bits_length = count * CHAR_BIT;
+  uint32_t bits;
+  random_bytes (&bits, count);
+
+  /* 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 than 33 bits.  This ensures the code is 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)
+        {
+          /* Overwrite the least significant byte.  */
+         random_bytes (&bits, 1);
+         bits_length = CHAR_BIT;
+        }
+
+      /* 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.  */
+    }
+}
+libc_hidden_def (__arc4random_uniform)
+weak_alias (__arc4random_uniform, arc4random_uniform)
diff --git a/stdlib/chacha20.c b/stdlib/chacha20.c
new file mode 100644 (file)
index 0000000..c47b841
--- /dev/null
@@ -0,0 +1,187 @@
+/* Generic ChaCha20 implementation (used on arc4random).
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <array_length.h>
+#include <endian.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+/* 32-bit stream position, then 96-bit nonce.  */
+#define CHACHA20_IV_SIZE       16
+#define CHACHA20_KEY_SIZE      32
+
+#define CHACHA20_STATE_LEN     16
+
+/* The ChaCha20 implementation is based on RFC8439 [1], omitting the final
+   XOR of the keystream with the plaintext because the plaintext is a
+   stream of zeros.  */
+
+enum chacha20_constants
+{
+  CHACHA20_CONSTANT_EXPA = 0x61707865U,
+  CHACHA20_CONSTANT_ND_3 = 0x3320646eU,
+  CHACHA20_CONSTANT_2_BY = 0x79622d32U,
+  CHACHA20_CONSTANT_TE_K = 0x6b206574U
+};
+
+static inline uint32_t
+read_unaligned_32 (const uint8_t *p)
+{
+  uint32_t r;
+  memcpy (&r, p, sizeof (r));
+  return r;
+}
+
+static inline void
+write_unaligned_32 (uint8_t *p, uint32_t v)
+{
+  memcpy (p, &v, sizeof (v));
+}
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+# define read_unaligned_le32(p) __builtin_bswap32 (read_unaligned_32 (p))
+# define set_state(v)          __builtin_bswap32 ((v))
+#else
+# define read_unaligned_le32(p) read_unaligned_32 ((p))
+# define set_state(v)          (v)
+#endif
+
+static inline void
+chacha20_init (uint32_t *state, const uint8_t *key, const uint8_t *iv)
+{
+  state[0]  = CHACHA20_CONSTANT_EXPA;
+  state[1]  = CHACHA20_CONSTANT_ND_3;
+  state[2]  = CHACHA20_CONSTANT_2_BY;
+  state[3]  = CHACHA20_CONSTANT_TE_K;
+
+  state[4]  = read_unaligned_le32 (key + 0 * sizeof (uint32_t));
+  state[5]  = read_unaligned_le32 (key + 1 * sizeof (uint32_t));
+  state[6]  = read_unaligned_le32 (key + 2 * sizeof (uint32_t));
+  state[7]  = read_unaligned_le32 (key + 3 * sizeof (uint32_t));
+  state[8]  = read_unaligned_le32 (key + 4 * sizeof (uint32_t));
+  state[9]  = read_unaligned_le32 (key + 5 * sizeof (uint32_t));
+  state[10] = read_unaligned_le32 (key + 6 * sizeof (uint32_t));
+  state[11] = read_unaligned_le32 (key + 7 * sizeof (uint32_t));
+
+  state[12] = read_unaligned_le32 (iv + 0 * sizeof (uint32_t));
+  state[13] = read_unaligned_le32 (iv + 1 * sizeof (uint32_t));
+  state[14] = read_unaligned_le32 (iv + 2 * sizeof (uint32_t));
+  state[15] = read_unaligned_le32 (iv + 3 * sizeof (uint32_t));
+}
+
+static inline uint32_t
+rotl32 (unsigned int shift, uint32_t word)
+{
+  return (word << (shift & 31)) | (word >> ((-shift) & 31));
+}
+
+static void
+state_final (const uint8_t *src, uint8_t *dst, uint32_t v)
+{
+#ifdef CHACHA20_XOR_FINAL
+  v ^= read_unaligned_32 (src);
+#endif
+  write_unaligned_32 (dst, v);
+}
+
+static inline void
+chacha20_block (uint32_t *state, uint8_t *dst, const uint8_t *src)
+{
+  uint32_t x0, x1, x2, x3, x4, x5, x6, x7;
+  uint32_t x8, x9, x10, x11, x12, x13, x14, x15;
+
+  x0 = state[0];
+  x1 = state[1];
+  x2 = state[2];
+  x3 = state[3];
+  x4 = state[4];
+  x5 = state[5];
+  x6 = state[6];
+  x7 = state[7];
+  x8 = state[8];
+  x9 = state[9];
+  x10 = state[10];
+  x11 = state[11];
+  x12 = state[12];
+  x13 = state[13];
+  x14 = state[14];
+  x15 = state[15];
+
+  for (int i = 0; i < 20; i += 2)
+    {
+#define QROUND(_x0, _x1, _x2, _x3)                     \
+  do {                                                 \
+   _x0 = _x0 + _x1; _x3 = rotl32 (16, (_x0 ^ _x3));    \
+   _x2 = _x2 + _x3; _x1 = rotl32 (12, (_x1 ^ _x2));    \
+   _x0 = _x0 + _x1; _x3 = rotl32 (8,  (_x0 ^ _x3));    \
+   _x2 = _x2 + _x3; _x1 = rotl32 (7,  (_x1 ^ _x2));    \
+  } while(0)
+
+      QROUND (x0, x4, x8,  x12);
+      QROUND (x1, x5, x9,  x13);
+      QROUND (x2, x6, x10, x14);
+      QROUND (x3, x7, x11, x15);
+
+      QROUND (x0, x5, x10, x15);
+      QROUND (x1, x6, x11, x12);
+      QROUND (x2, x7, x8,  x13);
+      QROUND (x3, x4, x9,  x14);
+    }
+
+  state_final (&src[0], &dst[0], set_state (x0 + state[0]));
+  state_final (&src[4], &dst[4], set_state (x1 + state[1]));
+  state_final (&src[8], &dst[8], set_state (x2 + state[2]));
+  state_final (&src[12], &dst[12], set_state (x3 + state[3]));
+  state_final (&src[16], &dst[16], set_state (x4 + state[4]));
+  state_final (&src[20], &dst[20], set_state (x5 + state[5]));
+  state_final (&src[24], &dst[24], set_state (x6 + state[6]));
+  state_final (&src[28], &dst[28], set_state (x7 + state[7]));
+  state_final (&src[32], &dst[32], set_state (x8 + state[8]));
+  state_final (&src[36], &dst[36], set_state (x9 + state[9]));
+  state_final (&src[40], &dst[40], set_state (x10 + state[10]));
+  state_final (&src[44], &dst[44], set_state (x11 + state[11]));
+  state_final (&src[48], &dst[48], set_state (x12 + state[12]));
+  state_final (&src[52], &dst[52], set_state (x13 + state[13]));
+  state_final (&src[56], &dst[56], set_state (x14 + state[14]));
+  state_final (&src[60], &dst[60], set_state (x15 + state[15]));
+
+  state[12]++;
+}
+
+static void
+chacha20_crypt (uint32_t *state, uint8_t *dst, const uint8_t *src,
+               size_t bytes)
+{
+  while (bytes >= CHACHA20_BLOCK_SIZE)
+    {
+      chacha20_block (state, dst, src);
+
+      bytes -= CHACHA20_BLOCK_SIZE;
+      dst += CHACHA20_BLOCK_SIZE;
+      src += CHACHA20_BLOCK_SIZE;
+    }
+
+  if (__glibc_unlikely (bytes != 0))
+    {
+      uint8_t stream[CHACHA20_BLOCK_SIZE];
+      chacha20_block (state, stream, src);
+      memcpy (dst, stream, bytes);
+      explicit_bzero (stream, sizeof stream);
+    }
+}
index bf7cd438e1d6e11500210c30bfe7f82f7ae4d5f7..3a630a0ce8b53dca0a00a80b1b15876e38736805 100644 (file)
@@ -533,6 +533,19 @@ 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));
+
+/* Return a random integer between zero and 2**32-1 (inclusive).  */
+extern __uint32_t arc4random (void)
+     __THROW __wur;
+
+/* Fill the buffer with random data.  */
+extern void arc4random_buf (void *__buf, size_t __size)
+     __THROW __nonnull ((1));
+
+/* Return a random number between zero (inclusive) and the specified
+   limit (exclusive).  */
+extern __uint32_t arc4random_uniform (__uint32_t __upper_bound)
+     __THROW __wur;
 # endif        /* Use misc.  */
 #endif /* Use misc or X/Open.  */
 
index 2104efeb5446b8c74afd83163f2dff244c2ee7e1..acceb9b67fae2a91a2cecc3581095e008e856f1f 100644 (file)
@@ -48,5 +48,7 @@
   (void) __writev (fd, iov, n)
 #define __fcntl64_nocancel(fd, cmd, ...) \
   __fcntl64 (fd, cmd, __VA_ARGS__)
+#define __getrandom_nocancel(buf, size, flags) \
+  __getrandom (buf, size, flags)
 
 #endif /* NOT_CANCEL_H  */
index d76c715a96214ff6a9739954c403658d1fd53c66..a91915831b0e080afcc3c3f5c2c226276d41536f 100644 (file)
@@ -23,6 +23,7 @@ struct tls_internal_t
 {
   char *strsignal_buf;
   char *strerror_l_buf;
+  struct arc4random_state_t *rand_state;
 };
 
 #endif
index 898c20b61c57fc66dbb66ab800d040e09c4c54e1..8a0f37d509fde74932654c03dc7132a378394d33 100644 (file)
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
+#include <stdlib/arc4random.h>
+#include <string.h>
 #include <tls-internal.h>
 
 __thread struct tls_internal_t __tls_internal;
+
+void
+__glibc_tls_internal_free (void)
+{
+  free (__tls_internal.strsignal_buf);
+  free (__tls_internal.strerror_l_buf);
+
+  if (__tls_internal.rand_state != NULL)
+    {
+      /* Clear any lingering random state prior so if the thread stack is
+        cached it won't leak any data.  */
+      explicit_bzero (__tls_internal.rand_state,
+                     sizeof (*__tls_internal.rand_state));
+      free (__tls_internal.rand_state);
+    }
+}
index acb8ac9abea04312a683effc1f56442fa562465c..3f53e4a1fa236427de59c5795b52b9d8877d6986 100644 (file)
@@ -30,11 +30,6 @@ __glibc_tls_internal (void)
   return &__tls_internal;
 }
 
-static inline void
-__glibc_tls_internal_free (void)
-{
-  free (__tls_internal.strsignal_buf);
-  free (__tls_internal.strerror_l_buf);
-}
+extern void __glibc_tls_internal_free (void) attribute_hidden;
 
 #endif
index e60b86fab12d1c897a56427e914846f67b9f74a4..667068c8cf3eaef405fb64d85bd661a54de8a028 100644 (file)
@@ -662,6 +662,8 @@ retry:
       _hurd_malloc_fork_child ();
       call_function_static_weak (__malloc_fork_unlock_child);
 
+      call_function_static_weak (__arc4random_fork_subprocess);
+
       /* Run things that want to run in the child task to set up.  */
       RUN_HOOK (_hurd_fork_child_hook, ());
 
index 66fb0e28fa25d4db5c76f044fd523d02b009346a..4e3200ef555874b9380ae02f6fdd665de0396e7a 100644 (file)
@@ -2289,6 +2289,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 close_range F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 mbrtoc8 F
 GLIBC_2.4 __confstr_chk F
index 6ec92ced844d273e0d495e540a290e41f8c54ba3..9a3a7ed59a03c81b3053be15d8e504f8041a7c3a 100644 (file)
@@ -74,6 +74,9 @@ __typeof (__fcntl) __fcntl_nocancel;
 #define __fcntl64_nocancel(...) \
   __fcntl_nocancel (__VA_ARGS__)
 
+#define __getrandom_nocancel(buf, size, flags) \
+  __getrandom (buf, size, flags)
+
 #if IS_IN (libc)
 hidden_proto (__close_nocancel)
 hidden_proto (__close_nocancel_nostatus)
index dd568992e2520e2f5a03c1cd6db682a6d7802c58..7dc02569f6c054517e1d0600bb89ba2975b1b02b 100644 (file)
@@ -43,6 +43,8 @@ _Fork (void)
       self->robust_head.list = &self->robust_head;
       INTERNAL_SYSCALL_CALL (set_robust_list, &self->robust_head,
                             sizeof (struct robust_list_head));
+
+      call_function_static_weak (__arc4random_fork_subprocess);
     }
   return pid;
 }
index 516b029d30364236f30a6c3e64626bede7935daf..b66fadef4002bb5e9e0f608a364ec0ceadd49229 100644 (file)
@@ -2616,6 +2616,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index dde08899fe927019d0dffb5b88ec6d0801070640..f918bb2d483284b3f770b3b3bc8e18b324163cea 100644 (file)
@@ -2713,6 +2713,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index ade44d3029eb3e4d03756f378c139b2d45d193ac..093043a53312878ac595db77b53b429ff6219f73 100644 (file)
@@ -2377,6 +2377,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index 98b33708af5e5dbcb598106b67d36a250ac652eb..e0668a80cf88f928385a6918e4e46cbee47ad484 100644 (file)
@@ -496,6 +496,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index 05dbbe5bccb4ebd7ae5c239b6963598e913ba228..d28e7c60b78f15ffedfe4e3707c94d96ddea773b 100644 (file)
@@ -493,6 +493,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index 430a24349edbe76c19923cef59203426f3913e45..922b05062ff35122469e8396b64b763954e260af 100644 (file)
@@ -2652,6 +2652,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index de446165267ee6e34cc73632e01c0df8f1903c9f..412144f94c8fe165017ce302e0b97bfe09ac8a9f 100644 (file)
@@ -2601,6 +2601,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index 18b4fbf26eee2ef7b196ea6d5375967cf748c285..134393900a1e6be4653e172faa68735d143ea55b 100644 (file)
@@ -2785,6 +2785,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index a8e959d4171eb2a3581a91ec1c686e9154172e01..02c65b648271ca972e37d56ecd2f4ebe0d4374db 100644 (file)
@@ -2551,6 +2551,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index 3a7e4ef6e4f8d403ec63f5729ef2a160f14351f1..0604029c68f7d9dcbec9cbe215753e6333ab83bc 100644 (file)
@@ -497,6 +497,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index 864ad2cdf8c3d17f0892f1fed189203eb0e7dbc7..af2be5c80df72f3d4a4ac2e65515cbfe71e04080 100644 (file)
@@ -2728,6 +2728,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index 163058420d6fcf03c4034892034cf04d7a119e1b..e090b8d48fe5b0eb8ca3055f1cccaaedc1f527b6 100644 (file)
@@ -2701,6 +2701,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index a6debfda56fc294b3c534c65f08011f4563b9b9b..8c5b2db2431da3bef6d90205d4f0514123eb3281 100644 (file)
@@ -2698,6 +2698,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index 2b53d888de654bdfee314de7dda97736c3afd6b4..68847134a23ddace4bd7bc02ac488dcfea08c0e9 100644 (file)
@@ -2693,6 +2693,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index 849aae41304517aa40bddad25d867b160993acf0..daa44e64fa12a35437736036787463ca971c04ca 100644 (file)
@@ -2691,6 +2691,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index 37f6c1bf58d86bf438d286cf2d8507a093baff38..6169188c960257cb1fef701938726c17200aae44 100644 (file)
@@ -2699,6 +2699,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index ff1eb91e101523e782508e7a54d20b15d3ce85c5..2f7f1ccaf771ba920e8f570c685f7e835a0997c0 100644 (file)
@@ -2602,6 +2602,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index 361b91f547a75264decb75a236bd59cfaa616ef8..58e9b486b0f45b9f4fdd32b3b2bde53f848a02b4 100644 (file)
@@ -2740,6 +2740,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index 75b9e0ee1ebf9d1220a52fe6ee8a7959428381d8..2c58d5ae2fb0637616e146f6e16673258f56c05d 100644 (file)
@@ -67,6 +67,13 @@ __writev_nocancel_nostatus (int fd, const struct iovec *iov, int iovcnt)
   INTERNAL_SYSCALL_CALL (writev, fd, iov, iovcnt);
 }
 
+static inline int
+__getrandom_nocancel (void *buf, size_t buflen, unsigned int flags)
+{
+  return INTERNAL_SYSCALL_CALL (getrandom, buf, buflen, flags);
+}
+
+
 /* Uncancelable fcntl.  */
 __typeof (__fcntl) __fcntl64_nocancel;
 
index cb916063779dcaa8cabdf02ce9c7042bea7a917b..ffdb8819d54e55a5ecb532295cd96b8ca48b0e76 100644 (file)
@@ -2123,6 +2123,9 @@ GLIBC_2.35 wprintf F
 GLIBC_2.35 write F
 GLIBC_2.35 writev F
 GLIBC_2.35 wscanf F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index 1264aff6ef49a4794de3ded60ca6c534aea6cdff..8c9ca32cbe146eaf32608a2a9184e0cf84dfcae5 100644 (file)
@@ -2755,6 +2755,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index f96d6e37b508806b97eb34450d9b8b12975a9967..08a6604aab6d49148701473aba4208e3dae02cda 100644 (file)
@@ -2788,6 +2788,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index e7082e1bd354487e5fc0dc3a64f83b9b958d1f09..849863e6399a691abc5626fce797b8a1239dd59f 100644 (file)
@@ -2510,6 +2510,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index 1032c7e46a9775e8c407773c472d9051cb824cca..b2ccee08c6b87301e49e28a4b38d8d6a6eb31f58 100644 (file)
@@ -2812,6 +2812,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index f932db7c22a3b678271fc232b03eb00c3df1304d..ff90d1bff2e95434be24b3b928869a0a2ae1b00c 100644 (file)
@@ -2379,6 +2379,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index ccc53b0bb859b90e23a82392dd4853997ae8ed34..f1017f6ec54561959bc3b7dce4db756db43b2bd8 100644 (file)
@@ -2579,6 +2579,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index dbf65010076cf71c863c713d48752fc90bc7d31c..009f22931ead890d59b2fcec3395612aa1a2be52 100644 (file)
@@ -2753,6 +2753,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index 98f08a01b6db78255b4d2b842215d12ee75af124..0e0b3df973aee2ac2f7484ebb6e17357c57e1e24 100644 (file)
@@ -2547,6 +2547,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index df11cc8f1382ba75ef090c398b8aff7650fe5b2b..afb5bc37b17f009c555bfd8e6a7caaef99201bd4 100644 (file)
@@ -2608,6 +2608,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index 4ee5513d183808d3515b4bcb8eda0bbf4e5593b6..2b53a3cf92305b8f9382f1a2cad00e49ad862736 100644 (file)
@@ -2605,6 +2605,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index 3cefa76871c3892fe3459269513ef16fffd3b32d..43b9844a99cc56a0676bb36d41d7d39bbdd556c8 100644 (file)
@@ -2748,6 +2748,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index e3ea5c438337f0d5185c7cbc8e4c0330f3498993..9ec4a0bc7fed2555d7406bfe8abc1657218fa9b3 100644 (file)
@@ -2574,6 +2574,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index 6e25b021ab50d9b5863c60a5d9cb68ccaae31a4b..0326ebb7676dc5361ff18e9562a55dd6116ddd51 100644 (file)
@@ -1 +1,38 @@
-/* Empty.  */
+/* Per-thread state.  Linux version.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdlib/arc4random.h>
+#include <string.h>
+#include <tls-internal.h>
+
+void
+__glibc_tls_internal_free (void)
+{
+  struct pthread *self = THREAD_SELF;
+  free (self->tls_state.strsignal_buf);
+  free (self->tls_state.strerror_l_buf);
+
+  if (self->tls_state.rand_state != NULL)
+    {
+      /* Clear any lingering random state prior so if the thread stack is
+         cached it won't leak any data.  */
+      explicit_bzero (self->tls_state.rand_state,
+                     sizeof (*self->tls_state.rand_state));
+      free (self->tls_state.rand_state);
+    }
+}
index f7a1a621352125e49eca1d127f361e18ec0c8608..ebc65d896a6e0195cd227863f5ebaa9c19965773 100644 (file)
@@ -28,11 +28,7 @@ __glibc_tls_internal (void)
   return &THREAD_SELF->tls_state;
 }
 
-static inline void
-__glibc_tls_internal_free (void)
-{
-  free (THREAD_SELF->tls_state.strsignal_buf);
-  free (THREAD_SELF->tls_state.strerror_l_buf);
-}
+/* Reset the arc4random TCB state on fork.  */
+extern void __glibc_tls_internal_free (void) attribute_hidden;
 
 #endif
index 2944bc783795da4447fc3c492e4ee535a09a8441..367c8d0a03b78ed18d669bc4692a7d50fc723f88 100644 (file)
@@ -2525,6 +2525,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F
index 47296193afc74995364e652cc4a104b05f6284e0..6a614efb628bffdf599d47a38f1863a511fda880 100644 (file)
@@ -2631,6 +2631,9 @@ GLIBC_2.35 __memcmpeq F
 GLIBC_2.35 _dl_find_object F
 GLIBC_2.35 epoll_pwait2 F
 GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
+GLIBC_2.36 arc4random F
+GLIBC_2.36 arc4random_buf F
+GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 fsconfig F
 GLIBC_2.36 fsmount F