Add getrandom implementation [BZ #17252]
The emulation opens /dev/random and /dev/urandom (depending
on the flags), reads random bytes, and closes the descriptor
again.
The getrandom function is defined as a macro in such a way that
a direct attempt to define a getrandom function will either
fail to compile, or fail to interpose the __getrandom symbol.
The intent is that legacy implementations will not accidentally
preempt the implementation in glibc (which could well be used
by other libraries in the same process image).
2016-06-27 Florian Weimer <fweimer@redhat.com>
[BZ #17252]
* stdlib/sys/random.h: New file.
(headers): Add it.
* stdlib/Makefile (routines): Add getrandom.
(tests): Add tst-getrandom.
* stdlib/Versions (GLIBC_2.24): Add __getrandom.
* stdlib/getrandom.c: New file.
* stdlib/tst-getrandom.c: Likewise.
* sysdep/posix/getrandom.c: Likewise.
* sysdep/posix/getrandom_emulation.c: Likewise.
* sysdeps/unix/sysv/linux/getrandom.c: Likewise.
* sysdeps/unix/sysv/linux/kernel-features.h
(__ASSUME_GETRANDOM_SYSCALL): Define.
* manual/crypt.texi (Unpredictable Bytes): New section.
* manual/math.texi (Pseudo-Random Numbers): Add cross-reference.
* sysdeps/arm/nacl/libc.abilist: Add __getrandom.
* sysdeps/unix/sysv/linux/aarch64/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/alpha/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/arm/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/hppa/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/i386/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/ia64/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/microblaze/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/nios2/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist:
Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist:
Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist: Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/sh/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist: Likewise.
* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist: Likewise.
@@ -14,6 +14,10 @@ Version 2.24
unchanged). Linux 3.2 or later kernel headers are required on all
architectures.
+* The getrandom function and the <sys/random.h> header file have been added.
+ This function will use the Linux getrandom system call to obtain random
+ data if available.
+
* The pap_AN locale has been deleted. This has been deprecated for a long
time. It has been replaced by pap_AW & pap_CW, both of which have long
been included in previous releases.
@@ -45,6 +45,7 @@ encrypted authentication use normal DES.
* getpass:: Prompting the user for a password.
* crypt:: A one-way function for passwords.
* DES Encryption:: Routines for DES encryption.
+* Unpredictable Bytes:: Randomness for cryptography purposes.
@end menu
@node Legal Problems
@@ -428,3 +429,83 @@ each byte.
The @code{ecb_crypt}, @code{cbc_crypt}, and @code{des_setparity}
functions and their accompanying macros are all defined in the header
@file{rpc/des_crypt.h}.
+
+@node Unpredictable Bytes
+@section Generating Unpredictable Bytes
+
+Some cryptographic applications (such as session key generation) need
+unpredictable bytes.
+
+@comment sys/random.h
+@comment GNU
+@deftypefun ssize_t getrandom (void *@var{buffer}, size_t @var{length}, unsigned int @var{flags})
+@safety{@mtsafe{}@assafe{}@acsafe{}}
+
+This function writes @var{length} bytes of random data to the array
+starting at @var{buffer}. On success, this function returns the number
+of bytes which have been written to the buffer (which can be less than
+@var{length}). On error, @code{-1} is returned, and @code{errno} is
+updated accordingly.
+
+The @code{getrandom} function is declared in the header file
+@file{sys/random.h}. It is a GNU extension.
+
+The following flags are defined for the @var{flags} argument:
+
+@table @code
+@item GRND_RANDOM
+Use the blocking pool instead of the non-blocking pool to obtain
+randomness. By default, the non-blocking pool is used. The blocking
+pool corresponds to @file{/dev/random}, and the non-blocking pool to
+@file{/dev/urandom}.
+
+@item GRND_NONBLOCK
+Instead of blocking, return to the caller immediately if no data is
+available.
+@end table
+
+Even access to the non-blocking pool can block if the system has just
+booted and the pool has not yet been initialized.
+
+If the @var{flags} argument is zero, the @code{getrandom} implementation
+in @theglibc{} will only return once @var{length} bytes have been
+written to @var{buffer}, or there is an error (except @code{EINTR}), and
+such a function call is not a cancellation point.
+
+@strong{Note:} If the system lacks support for the @code{getrandom}
+system call, the @code{getrandom} function uses emulation based on the
+@file{/dev/random} and @file{/dev/urandom} device nodes. This results
+in additional failure scenarios, listed below as ``emulation only''.
+
+The @code{getrandom} function can fail with several errors, some of
+which are listed below. In addition, if @var{flags} is not zero, the
+function may not fill the buffer completely and return a value less than
+@var{length}.
+
+@table @code
+@item EAGAIN
+No random data was available and @code{GRND_NONBLOCK} was specified in
+@var{flags}.
+
+@item EFAULT
+The combination of @var{buffer} and @var{length} arguments specifies an
+invalid memory range.
+
+@item EINTR
+The system call was interrupted (only if @var{flags} is not zero).
+
+@item EINVAL
+The @var{flags} argument contains an invalid combination of flags.
+
+@item ENOENT
+@itemx EACCES
+The current file system namespace lacks the required device node, or the
+device node is inaccessible (emulation only).
+
+@item EMFILE
+@itemx ENFILE
+The random device node could not be opened due to process or system
+limits (emulation only).
+@end table
+
+@end deftypefun
@@ -1413,7 +1413,8 @@ is convenient when you are debugging a program, but it is unhelpful if
you want the program to behave unpredictably. If you want a different
pseudo-random series each time your program runs, you must specify a
different seed each time. For ordinary purposes, basing the seed on the
-current time works well.
+current time works well. For random numbers in cryptography,
+@pxref{Unpredictable Bytes}.
You can obtain repeatable sequences of numbers on a particular machine type
by specifying the same initial seed value for the random number
@@ -28,7 +28,7 @@ headers := stdlib.h bits/stdlib.h bits/stdlib-ldbl.h bits/stdlib-float.h \
errno.h sys/errno.h bits/errno.h \
ucontext.h sys/ucontext.h \
alloca.h fmtmsg.h \
- bits/stdlib-bsearch.h
+ bits/stdlib-bsearch.h sys/random.h
routines := \
atof atoi atol atoll \
@@ -45,7 +45,7 @@ routines := \
srand48 seed48 lcong48 \
drand48_r erand48_r lrand48_r nrand48_r mrand48_r jrand48_r \
srand48_r seed48_r lcong48_r \
- drand48-iter \
+ drand48-iter getrandom \
strtol strtoul strtoll strtoull \
strtol_l strtoul_l strtoll_l strtoull_l \
strtof strtod strtold \
@@ -77,7 +77,7 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \
tst-tininess tst-strtod-underflow tst-tls-atexit \
tst-setcontext3 tst-tls-atexit-nodelete \
tst-strtol-locale tst-strtod-nan-locale tst-strfmon_l \
- tst-quick_exit tst-thread-quick_exit
+ tst-quick_exit tst-thread-quick_exit tst-getrandom
tests-static := tst-secure-getenv
ifeq ($(have-cxx-thread_local),yes)
CFLAGS-tst-quick_exit.o = -std=c++11
@@ -111,6 +111,7 @@ libc {
}
GLIBC_2.24 {
quick_exit;
+ __getrandom;
}
GLIBC_PRIVATE {
# functions which have an additional interface since they are
new file mode 100644
@@ -0,0 +1,31 @@
+/* Stub for getrandom.
+ Copyright (C) 2016 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 <errno.h>
+#include <sys/random.h>
+
+/* Write LENGTH bytes of randomness starting at BUFFER. Returns the
+ number of bytes written, or -1 on error. */
+ssize_t
+__getrandom (void *buffer, size_t length, unsigned int flags)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+
+stub_warning (__getrandom)
new file mode 100644
@@ -0,0 +1,35 @@
+/* Interfaces for obtaining random bytes.
+ Copyright (C) 2016 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 _SYS_RANDOM_H
+#define _SYS_RANDOM_H 1
+
+/* Flags for use with getrandom. */
+#define GRND_NONBLOCK 1
+#define GRND_RANDOM 2
+
+/* Write LENGTH bytes of randomness starting at BUFFER. Returns the
+ number of bytes written, or -1 on error. */
+ssize_t __getrandom (void *__buffer, size_t __length, unsigned int __flags)
+ __THROW __wur;
+
+/* Prevent accidental interposition of the getrandom symbol. */
+#define getrandom(buffer, length, flags) \
+ (0 + __getrandom (buffer, length, flags))
+
+#endif /* _SYS_RANDOM_H */
new file mode 100644
@@ -0,0 +1,162 @@
+/* Tests for the getrandom function.
+ Copyright (C) 2016 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 <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/random.h>
+
+/* Set to true if any errors are encountered. */
+static bool errors;
+
+/* Test getrandom with a single buffer length. */
+static void
+test_length (char *buffer, size_t length, unsigned int flags)
+{
+ memset (buffer, 0, length);
+ strcpy (buffer + length, "123");
+ ssize_t ret = getrandom (buffer, length, flags);
+ if (ret < 0)
+ {
+ if (!((flags & GRND_RANDOM)
+ && (flags & GRND_NONBLOCK)
+ && errno != EAGAIN))
+ {
+ printf ("error: getrandom (%zu, 0x%x): %m\n", length, flags);
+ errors = true;
+ }
+ }
+ if (ret != length)
+ {
+ if (flags & GRND_RANDOM)
+ {
+ if (ret == 0 || ret > length)
+ {
+ printf ("error: getrandom (%zu, 0x%x) returned %zd\n",
+ length, flags, ret);
+ errors = true;
+ }
+ }
+ else
+ {
+ printf ("error: getrandom (%zu, 0x%x) returned %zd\n",
+ length, flags, ret);
+ errors = true;
+ }
+ }
+ if (length >= 7)
+ {
+ /* One spurious test failure in 2**56 is sufficiently
+ unlikely. */
+ int non_null = 0;
+ for (int i = 0; i < length; ++i)
+ non_null += buffer[i] != 0;
+ if (non_null == 0)
+ {
+ printf ("error: getrandom (%zu, 0x%x) returned all-zero bytes\n",
+ length, flags);
+ errors = true;
+ }
+ }
+ if (memcmp (buffer + length, "123", 4) != 0)
+ {
+ printf ("error: getrandom (%zu, 0x%x) wrote spurious bytes\n",
+ length, flags);
+ errors = true;
+ }
+}
+
+/* Call getrandom repeatedly to fill the buffer. */
+static bool
+getrandom_full (char *buffer, size_t length, unsigned int flags)
+{
+ char *end = buffer + length;
+ while (buffer < end)
+ {
+ ssize_t ret = getrandom (buffer, end - buffer, flags);
+ if (ret < 0)
+ {
+ printf ("error: getrandom (%zu, 0x%x): %m\n", length, flags);
+ errors = true;
+ return false;
+ }
+ buffer += ret;
+ }
+
+ return true;
+}
+
+static void
+test_flags (unsigned int flags)
+{
+ /* Test various lengths, but only for !GRND_RANDOM, to conserve
+ entropy. */
+ {
+ enum { max_length = 300 };
+ char buffer[max_length + 4];
+ if (flags & GRND_RANDOM)
+ test_length (buffer, 0, flags);
+ else
+ {
+ for (int length = 0; length <= 9; ++length)
+ test_length (buffer, length, flags);
+ test_length (buffer, 16, flags);
+ test_length (buffer, max_length, flags);
+ }
+ }
+
+ /* Test that getrandom returns different data. */
+ if (!(flags & GRND_NONBLOCK))
+ {
+ char buffer1[8];
+ memset (buffer1, 0, sizeof (buffer1));
+
+ char buffer2[8];
+ memset (buffer2, 0, sizeof (buffer2));
+
+ if (getrandom_full (buffer1, sizeof (buffer1), flags)
+ && getrandom_full (buffer2, sizeof (buffer2), flags))
+ {
+ if (memcmp (buffer1, buffer2, sizeof (buffer1)) == 0)
+ {
+ printf ("error: getrandom returns constant value\n");
+ errors = true;
+ }
+ }
+ }
+}
+
+static int
+do_test (void)
+{
+ for (int use_random = 0; use_random < 2; ++use_random)
+ for (int use_nonblock = 0; use_nonblock < 2; ++use_nonblock)
+ {
+ int flags = 0;
+ if (use_random)
+ flags |= GRND_RANDOM;
+ if (use_nonblock)
+ flags |= GRND_NONBLOCK;
+ test_flags (flags);
+ }
+ return errors;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
@@ -1840,4 +1840,5 @@ GLIBC_2.23 fts64_close F
GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
new file mode 100644
@@ -0,0 +1,27 @@
+/* Generic version of getrandom, based on emulation.
+ Copyright (C) 2016 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 "getrandom_emulation.c"
+
+/* Write LENGTH bytes of randomness starting at BUFFER. Returns the
+ number of bytes written, or -1 on error. */
+ssize_t
+__getrandom (void *buffer, size_t length, unsigned int flags)
+{
+ return getrandom_emulation (buffer, length, flags);
+}
new file mode 100644
@@ -0,0 +1,111 @@
+/* Emulation of the getrandom system call.
+ Copyright (C) 2016 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 <atomic.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libc-lock.h>
+#include <not-cancel.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <unistd.h>
+
+/* Support flags by this emulation. Additional flags will cause the
+ emulation to fail with EINVAL. */
+#define GETRANDOM_SUPPORTED_FLAGS (GRND_RANDOM | GRND_NONBLOCK)
+
+/* Open the device node for the random device requested by FLAGS.
+ Return -1 on error (and set errno), and the file descriptor on
+ success. */
+static int
+getrandom_open_fd (unsigned int flags)
+{
+ int open_flags = O_RDONLY | O_CLOEXEC;
+ if (flags & GRND_NONBLOCK)
+ open_flags |= O_NONBLOCK;
+ const char *device;
+ if (flags & GRND_RANDOM)
+ device = "/dev/random";
+ else
+ device = "/dev/urandom";
+ return open_not_cancel (device, open_flags, 0);
+}
+
+/* Attempt to read LENGTH bytes from FD, avoiding short reads.
+ Intended for getrandom calls without any flags. */
+static ssize_t
+getrandom_read_fd (int fd, void *buffer, size_t length)
+{
+ void *end = buffer + length;
+ while (buffer < end)
+ {
+ /* EINTR can occur without any flags during early userspace
+ initialization. */
+ ssize_t ret = TEMP_FAILURE_RETRY
+ (read_not_cancel (fd, buffer, end - buffer));
+ if (ret < 0)
+ /* Do not report the short read, return the error. */
+ return -1;
+ if (ret == 0)
+ __libc_fatal ("error: end of file on randomness device\n");
+ buffer += ret;
+ }
+ return length;
+}
+
+static void
+getrandom_close_fd (void *pfd)
+{
+ close_not_cancel_no_status (*(int *) pfd);
+}
+
+/* Write LENGTH bytes of randomness starting at BUFFER. Returns the
+ number of bytes written, or -1 on error. Implementation based on
+ emulation with /dev/urandom and /dev/random. */
+static ssize_t
+getrandom_emulation (void *buffer, size_t length, unsigned int flags)
+{
+ /* Check if any unsupported flags have been requested. */
+ if (flags & ~GETRANDOM_SUPPORTED_FLAGS)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ int fd = getrandom_open_fd (flags);
+ if (fd < 0)
+ return -1;
+
+ /* If flags is zero, avoid short reads. */
+ if (flags == 0)
+ {
+ ssize_t ret = getrandom_read_fd (fd, buffer, length);
+ close_not_cancel_no_status (fd);
+ return ret;
+ }
+ else
+ {
+ /* Some flags are set. Allow cancellation, and pass short reads
+ to the caller. */
+ ssize_t ret;
+ __libc_cleanup_push (getrandom_close_fd, &fd);
+ ret = __read (fd, buffer, length);
+ __libc_cleanup_pop (1);
+ return ret;
+ }
+}
@@ -2088,4 +2088,5 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
@@ -1999,6 +1999,7 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
@@ -89,6 +89,7 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
GLIBC_2.4 GLIBC_2.4 A
GLIBC_2.4 _Exit F
new file mode 100644
@@ -0,0 +1,164 @@
+/* Linux version of getrandom.
+ Copyright (C) 2016 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 <assert.h>
+#include <errno.h>
+#include <kernel-features.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/random.h>
+#include <sysdep-cancel.h>
+#include <unistd.h>
+
+#ifdef __NR_getrandom
+
+/* getrandom system call wrapper with no flags, and which can only
+ process INT_MAX bytes at a time, and retries on EINTR. */
+static int
+getrandom_syscall_intmax (void *buffer, size_t length)
+{
+ return TEMP_FAILURE_RETRY (INLINE_SYSCALL (getrandom, 3, buffer, length, 0));
+}
+
+/* getrandom system call wrapper with no flags, and which can process
+ all lengths and retries on EINTR. */
+static ssize_t
+getrandom_syscall_no_flags (void *buffer, size_t length)
+{
+ void *p = buffer;
+ void *end = buffer + length;
+
+ /* Execute the system call even for length == 0, so that we properly
+ report ENOSYS. Otherwise, the detection of system call
+ availability will not work. */
+ do
+ {
+ size_t to_get = end - p;
+ /* The system call returns an int, so it cannot process more
+ than INT_MAX bytes at a time. */
+ if (to_get > INT_MAX)
+ to_get = INT_MAX;
+ int getrandom_result = getrandom_syscall_intmax (p, to_get);
+ /* Stop on error. Do not report the short read, return the
+ error. */
+ if (getrandom_result < 0)
+ return -1;
+ /* If the system call returns 0 for some reason, we would enter
+ an infinite loop. */
+ assert (getrandom_result > 0 || length == 0);
+ p += getrandom_result;
+ }
+ while (p < end);
+
+ return length;
+}
+
+/* getrandom system call wrapper with special support for FLAGS == 0
+ (EINTR retry, arbitrary lengths). */
+static ssize_t
+getrandom_try_syscall (void *buffer, size_t length, unsigned int flags)
+{
+ if (flags == 0)
+ return getrandom_syscall_no_flags (buffer, length);
+ else
+ return SYSCALL_CANCEL (getrandom, buffer, length, flags);
+}
+
+/* Same as getrandom_try_syscall, but terminate the process on an
+ ENOSYS error. */
+static ssize_t
+getrandom_force_syscall (void *buffer, size_t length, unsigned int flags)
+{
+ ssize_t ret = getrandom_try_syscall (buffer, length, flags);
+ if (ret < 0 && ret == ENOSYS)
+ __libc_fatal ("error: getrandom system call failed with ENONSYS\n");
+ return ret;
+}
+
+# ifdef __ASSUME_GETRANDOM_SYSCALL
+/* Write LENGTH bytes of randomness starting at BUFFER. Returns the
+ number of bytes written, or -1 on error. This implementation uses
+ the system call unconditionally and terminates the process if it
+ fails with ENOSYS. */
+ssize_t
+__getrandom (void *buffer, size_t length, unsigned int flags)
+{
+ return getrandom_force_syscall (buffer, length, flags);
+}
+
+# else /* !__ASSUME_GETRANDOM_SYSCALL */
+# include "getrandom_emulation.c"
+
+/* Possible values: 0: not initialized, 1: system call present,
+ 2: system call missing. */
+static int have_getrandom;
+
+/* Write LENGTH bytes of randomness starting at BUFFER. Returns the
+ number of bytes written, or -1 on error. This implementation falls
+ back to emulation in case the system call is unavailable. */
+ssize_t
+__getrandom (void *buffer, size_t length, unsigned int flags)
+{
+ /* Relaxed MO means that we may issue some additional failing system
+ calls because concurrent calls to __getrandom are not
+ synchronized, but optimizing for repeated calls is more
+ important. */
+ switch (atomic_load_relaxed (&have_getrandom))
+ {
+ case 0:
+ /* Not yet initialized. */
+ {
+ ssize_t ret = getrandom_try_syscall (buffer, length, flags);
+ if (ret < 0 && errno == ENOSYS)
+ {
+ /* Record that the system call is missing and fall back to
+ emulation. */
+ atomic_store_relaxed (&have_getrandom, 2);
+ return getrandom_emulation (buffer, length, flags);
+ }
+ atomic_store_relaxed (&have_getrandom, 1);
+ return ret;
+ }
+ case 1:
+ /* System call is available. */
+ return getrandom_force_syscall (buffer, length, flags);
+ case 2:
+ /* System call is missing. */
+ return getrandom_emulation (buffer, length, flags);
+ }
+ abort ();
+}
+# endif /* __ASSUME_GETRANDOM_SYSCALL */
+
+#else /* !__NR_getrandom */
+
+/* The kernel headers do not mention the getrandom system call. We
+ can only perform emulation. */
+
+# include "getrandom_emulation.c"
+
+/* Write LENGTH bytes of randomness starting at BUFFER. Returns the
+ number of bytes written, or -1 on error. This implementation uses
+ emulation with device nodes. */
+ssize_t
+__getrandom (void *buffer, size_t length, unsigned int flags)
+{
+ return getrandom_emulation (buffer, length, flags);
+}
+
+#endif
@@ -1853,6 +1853,7 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
@@ -2011,6 +2011,7 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
@@ -1875,6 +1875,7 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
@@ -147,3 +147,8 @@
separate syscalls were only added later. */
#define __ASSUME_SENDMSG_SYSCALL 1
#define __ASSUME_RECVMSG_SYSCALL 1
+
+/* getrandom was added on many architectures in Linux 3.17. */
+#if __LINUX_KERNEL_VERSION >= 0x031100
+# define __ASSUME_GETRANDOM_SYSCALL
+#endif
@@ -90,6 +90,7 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
GLIBC_2.4 GLIBC_2.4 A
GLIBC_2.4 _Exit F
@@ -1967,6 +1967,7 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
@@ -2088,4 +2088,5 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
@@ -1942,6 +1942,7 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
@@ -1940,6 +1940,7 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
@@ -1938,6 +1938,7 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
@@ -1933,6 +1933,7 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
@@ -2129,4 +2129,5 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
@@ -1971,6 +1971,7 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
@@ -1976,6 +1976,7 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
@@ -2176,4 +2176,5 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
@@ -90,6 +90,7 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 _Exit F
@@ -1971,6 +1971,7 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
@@ -1872,6 +1872,7 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
@@ -1857,6 +1857,7 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
@@ -1963,6 +1963,7 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
@@ -1901,6 +1901,7 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
@@ -2095,4 +2095,5 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
@@ -2095,4 +2095,5 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
@@ -2095,4 +2095,5 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
@@ -1852,6 +1852,7 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F
GLIBC_2.3 GLIBC_2.3 A
GLIBC_2.3 __ctype_b_loc F
@@ -2095,4 +2095,5 @@ GLIBC_2.23 fts64_open F
GLIBC_2.23 fts64_read F
GLIBC_2.23 fts64_set F
GLIBC_2.24 GLIBC_2.24 A
+GLIBC_2.24 __getrandom F
GLIBC_2.24 quick_exit F