public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 1/3] New string function explicit_bzero (from OpenBSD).
  2016-09-15 13:05 [PATCH 0/3] explicit_bzero again Zack Weinberg
@ 2016-09-15 13:05 ` Zack Weinberg
  2016-09-15 13:05   ` [PATCH 2/3] Add fortification and inline optimization of explicit_bzero Zack Weinberg
                     ` (3 more replies)
  0 siblings, 4 replies; 15+ messages in thread
From: Zack Weinberg @ 2016-09-15 13:05 UTC (permalink / raw)
  To: libc-alpha; +Cc: fweimer

explicit_bzero(s, n) is the same as memset(s, 0, n), except that the
compiler is not allowed to delete a call to explicit_bzero even if the
memory pointed to by 's' is dead after the call.  We achieve this effect
by defining it to call memset() and then a second function,

    extern void __glibc_read_memory (const void *, size_t)
       __attribute_noinline__;

which does nothing -- but the compiler is prevented from knowing that
it does nothing, and so the pointer "escapes" and the memory is not
treated as dead.  (Concretely, __glibc_read_memory is forced
out-of-line, defined in a file containing nothing else, and comments
in both string/read_memory.c and string/Makefile document that it must
not be subject to link-time optimization.)

There are two new tests: test-explicit_bzero.c verifies the
visible semantics in the same way as the existing test-bzero.c,
and tst-xbzero-opt.c verifies the not-being-optimized-out property.
The latter is conceptually based on a test written by Matthew Dempsky
for the OpenBSD regression suite.

	* string/explicit_bzero.c, string/read_memory.c: New routines.
	* string/test-explicit_bzero.c, string/tst-xbzero-opt.c: New tests.
	* string/Makefile (routines, strop-tests, tests): Add them.
	* string/test-memset.c: Add ifdeffage for testing explicit_bzero.
	* string/string.h [__USE_MISC]: Declare explicit_bzero.

	* manual/string.texi: Document explicit_bzero.

	* string/Versions [GLIBC_2.25]: Add explicit_bzero.

	* include/string.h: Hidden prototype for __glibc_read_memory.
	* sysdeps/arm/nacl/libc.abilist
	* sysdeps/unix/sysv/linux/aarch64/libc.abilist
	* sysdeps/unix/sysv/linux/alpha/libc.abilist
	* sysdeps/unix/sysv/linux/arm/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/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/powerpc/powerpc32/fpu/libc.abilist
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/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/libc.abilist
	* sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
	* sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
	* sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
	* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
	* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist:
	Add entry for explicit_bzero.
---
 include/string.h                                   |   3 +
 manual/string.texi                                 | 101 ++++++
 string/Makefile                                    |  12 +-
 string/Versions                                    |   4 +
 string/explicit_bzero.c                            |  30 ++
 string/read_memory.c                               |  40 +++
 string/string.h                                    |   4 +
 string/test-explicit_bzero.c                       |  20 ++
 string/test-memset.c                               |  10 +-
 string/tst-xbzero-opt.c                            | 383 +++++++++++++++++++++
 sysdeps/arm/nacl/libc.abilist                      |   1 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist       |   1 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist         |   1 +
 sysdeps/unix/sysv/linux/arm/libc.abilist           |   1 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist          |   1 +
 sysdeps/unix/sysv/linux/i386/libc.abilist          |   1 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist          |   1 +
 sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist |   1 +
 sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/microblaze/libc.abilist    |   1 +
 .../unix/sysv/linux/mips/mips32/fpu/libc.abilist   |   1 +
 .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist |   1 +
 .../unix/sysv/linux/mips/mips64/n32/libc.abilist   |   1 +
 .../unix/sysv/linux/mips/mips64/n64/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist         |   1 +
 .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist  |   1 +
 .../linux/powerpc/powerpc32/nofpu/libc.abilist     |   1 +
 .../sysv/linux/powerpc/powerpc64/libc-le.abilist   |   1 +
 .../unix/sysv/linux/powerpc/powerpc64/libc.abilist |   1 +
 sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist  |   1 +
 sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist  |   1 +
 sysdeps/unix/sysv/linux/sh/libc.abilist            |   1 +
 sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist |   1 +
 sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist |   1 +
 .../sysv/linux/tile/tilegx/tilegx32/libc.abilist   |   1 +
 .../sysv/linux/tile/tilegx/tilegx64/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist  |   1 +
 sysdeps/unix/sysv/linux/x86_64/64/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist    |   1 +
 39 files changed, 632 insertions(+), 4 deletions(-)
 create mode 100644 string/explicit_bzero.c
 create mode 100644 string/read_memory.c
 create mode 100644 string/test-explicit_bzero.c
 create mode 100644 string/tst-xbzero-opt.c

diff --git a/include/string.h b/include/string.h
index e145bfd..dc0edf3 100644
--- a/include/string.h
+++ b/include/string.h
@@ -99,6 +99,9 @@ libc_hidden_proto (memmem)
 extern __typeof (memmem) __memmem;
 libc_hidden_proto (__memmem)
 libc_hidden_proto (__ffs)
+extern void __glibc_read_memory (const void *s, size_t len)
+  __THROW __nonnull ((1)) __attribute_noinline__;
+libc_hidden_proto (__glibc_read_memory)
 
 libc_hidden_builtin_proto (memchr)
 libc_hidden_builtin_proto (memcpy)
diff --git a/manual/string.texi b/manual/string.texi
index bce81a7..fe4ca48 100644
--- a/manual/string.texi
+++ b/manual/string.texi
@@ -34,6 +34,8 @@ too.
 * Search Functions::            Searching for a specific element or substring.
 * Finding Tokens in a String::  Splitting a string into tokens by looking
 				 for delimiters.
+* Erasing Sensitive Data::      Clearing memory which contains sensitive
+                                 data, after it's no longer needed.
 * strfry::                      Function for flash-cooking a string.
 * Trivial Encryption::          Obscuring data.
 * Encode Binary Data::          Encoding and Decoding of Binary Data.
@@ -2375,6 +2377,105 @@ contains no '/' bytes, then "." is returned.  The prototype for this
 function can be found in @file{libgen.h}.
 @end deftypefun
 
+@node Erasing Sensitive Data
+@section Erasing Sensitive Data
+
+It is sometimes necessary to make sure that a block of data in memory
+is erased after use, even if no correct C program could access it
+again.  For instance, a cryptographic key should not be allowed to
+survive on the stack after the program is finished using it, because
+there might be a bug that causes junk stack data, including the key,
+to be revealed to the outside world.  @code{memset} and @code{bzero}
+are not safe to use for this, because the C compiler knows what they
+do, and can delete ``unnecessary'' calls to them.  For this situation,
+@theglibc{} provides @code{explicit_bzero}, which is functionally
+identical to @code{bzero}, except that the C compiler will @emph{not}
+delete apparently-unnecessary calls.
+
+@comment string.h
+@comment BSD
+@deftypefun void explicit_bzero (void *@var{block}, size_t @var{len})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+
+@code{explicit_bzero} writes zero into each of the first @var{len}
+bytes of the object beginning at @var{block}, just as @code{bzero}
+would.  The compiler will not delete a call to this function, even
+if the object beginning at @var{block} is never referred to again.
+
+@smallexample
+#include <string.h>
+
+extern void encrypt (const char *key, const char *in,
+                     char *out, size_t n);
+extern void genkey (const char *phrase, char *key);
+
+void encrypt_with_phrase (const char *phrase, const char *in,
+                          char *out, size_t n)
+@{
+  char key[16];
+  genkey (phrase, key);
+  encrypt (key, in, out, n);
+  explicit_bzero (key, 16);
+@}
+@end smallexample
+
+@noindent
+If @code{bzero} or @code{memset} had been used in this function, the C
+compiler might remove it as unnecessary, but it will not do this with
+@code{explicit_bzero}.
+
+@strong{Warning:} The @emph{only} optimization disabled by
+@code{explicit_bzero} is removal of ``unnecessary'' calls.  In all
+other respects, the compiler is allowed to optimize as it would for
+@code{memset}.  For instance, it may deduce that @var{block} cannot be
+a null pointer, and propagate this information both forward and
+backward in control flow.
+
+@strong{Warning:} The compiler is free to make additional copies of
+any object, or parts of it, in temporary storage areas (such as
+registers and ``scratch'' stack space).  @code{explicit_bzero} does
+not guarantee that temporary copies of sensitive data are destroyed.
+In fact, in some situations, using @code{explicit_bzero} will
+@emph{cause} creation of an additional copy, and only that copy will
+be cleared:
+
+@smallexample
+#include <string.h>
+
+struct key @{
+  unsigned long long low;
+  unsigned long long high;
+@};
+
+struct key get_key(void);
+void use_key(struct key);
+
+void
+with_clear(void)
+@{
+  struct key k;
+  k = get_key();
+  use_key(k);
+  explicit_bzero(&k, sizeof(k));
+@}
+@end smallexample
+
+@noindent
+Without the call to @code{explicit_bzero}, @var{k} might not need to
+be stored in memory: depending on the ABI, its value could be returned
+from @code{get_key} and passed to @code{use_key} using only CPU
+registers.  @code{explicit_bzero} operates on memory, so the compiler
+has to make a copy of @var{k} in memory for it, and the copy in the
+CPU registers remains intact.  This can occur for any variable whose
+address is only taken in a call to @code{explicit_bzero}, even if it
+might seem ``too large'' to be stored in registers.
+
+@strong{Portability Note:} This function first appeared in OpenBSD 5.5
+and has not been standardized.  @Theglibc{} declares this function in
+@file{string.h}, but on other systems it may be in @file{strings.h}
+instead.
+@end deftypefun
+
 @node strfry
 @section strfry
 
diff --git a/string/Makefile b/string/Makefile
index 69d3f80..0b6486e 100644
--- a/string/Makefile
+++ b/string/Makefile
@@ -41,20 +41,26 @@ routines	:= strcat strchr strcmp strcoll strcpy strcspn		\
 				     addsep replace)			\
 		   envz basename					\
 		   strcoll_l strxfrm_l string-inlines memrchr		\
-		   xpg-strerror strerror_l
+		   xpg-strerror strerror_l explicit_bzero
+
+# Attention future hackers trying to enable link-time optimization for
+# glibc: this file *must not* be subject to LTO.  It is added separately
+# to 'routines' to document this.  See comments in this file for details.
+routines	+= read_memory
 
 strop-tests	:= memchr memcmp memcpy memmove mempcpy memset memccpy	\
 		   stpcpy stpncpy strcat strchr strcmp strcpy strcspn	\
 		   strlen strncmp strncpy strpbrk strrchr strspn memmem	\
 		   strstr strcasestr strnlen strcasecmp strncasecmp	\
-		   strncat rawmemchr strchrnul bcopy bzero memrchr
+		   strncat rawmemchr strchrnul bcopy bzero memrchr	\
+		   explicit_bzero
 tests		:= tester inl-tester noinl-tester testcopy test-ffs	\
 		   tst-strlen stratcliff tst-svc tst-inlcall		\
 		   bug-strncat1 bug-strspn1 bug-strpbrk1 tst-bswap	\
 		   tst-strtok tst-strxfrm bug-strcoll1 tst-strfry	\
 		   bug-strtok1 $(addprefix test-,$(strop-tests))	\
 		   bug-envz1 tst-strxfrm2 tst-endian tst-svc2		\
-		   tst-strtok_r bug-strcoll2 tst-cmp
+		   tst-strtok_r bug-strcoll2 tst-cmp tst-xbzero-opt
 
 xtests = tst-strcoll-overflow
 
diff --git a/string/Versions b/string/Versions
index 475c1fd..a2c6e6e 100644
--- a/string/Versions
+++ b/string/Versions
@@ -82,4 +82,8 @@ libc {
   }
   GLIBC_2.24 {
   }
+  GLIBC_2.25 {
+    # e*
+    explicit_bzero;
+  }
 }
diff --git a/string/explicit_bzero.c b/string/explicit_bzero.c
new file mode 100644
index 0000000..a2b75be
--- /dev/null
+++ b/string/explicit_bzero.c
@@ -0,0 +1,30 @@
+/* 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 <features.h>
+#undef __USE_STRING_INLINES
+#define __NO_STRING_INLINES
+#include <string.h>
+
+/* Set LEN bytes of S to 0.  The compiler will not delete a call to
+   this function, even if S is dead after the call.  */
+void
+explicit_bzero (void *s, size_t len)
+{
+  memset (s, '\0', len);
+  __glibc_read_memory (s, len);
+}
diff --git a/string/read_memory.c b/string/read_memory.c
new file mode 100644
index 0000000..5347ee2
--- /dev/null
+++ b/string/read_memory.c
@@ -0,0 +1,40 @@
+/* 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 <string.h>
+
+/* This function is an optimization fence.  It doesn't do anything
+   itself, but calls to it prevent calls to explicit_bzero from being
+   optimized away.  In order to achieve this effect, this function
+   must never, under any circumstances, be inlined or subjected to
+   inter-procedural optimization.  string.h declares this function
+   with attributes that, in conjunction with the no-op asm insert, are
+   sufficient to prevent problems in the current (2016) generation of
+   compilers, but *only if* this file is *not* compiled with -flto.
+   At present, this is not an issue since glibc is never compiled with
+   -flto, but should that ever change, this file must be excepted.
+
+   The 'volatile' below is technically not necessary but is included
+   for explicitness.  */
+
+void
+internal_function
+__glibc_read_memory(const void *s, size_t len)
+{
+  asm volatile ("");
+}
+libc_hidden_def (__glibc_read_memory)
diff --git a/string/string.h b/string/string.h
index 57deaa4..89f5ab2 100644
--- a/string/string.h
+++ b/string/string.h
@@ -455,6 +455,10 @@ extern void bcopy (const void *__src, void *__dest, size_t __n)
 /* Set N bytes of S to 0.  */
 extern void bzero (void *__s, size_t __n) __THROW __nonnull ((1));
 
+/* As bzero, but the compiler will not delete a call to this
+   function, even if S is dead after the call.  */
+extern void explicit_bzero (void *__s, size_t __n) __THROW __nonnull ((1));
+
 /* Compare N bytes of S1 and S2 (same as memcmp).  */
 extern int bcmp (const void *__s1, const void *__s2, size_t __n)
      __THROW __attribute_pure__ __nonnull ((1, 2));
diff --git a/string/test-explicit_bzero.c b/string/test-explicit_bzero.c
new file mode 100644
index 0000000..5a4543b
--- /dev/null
+++ b/string/test-explicit_bzero.c
@@ -0,0 +1,20 @@
+/* Test and measure explicit_bzero.
+   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/>.  */
+#define TEST_EXPLICIT_BZERO
+#define TEST_BZERO
+#include "test-memset.c"
diff --git a/string/test-memset.c b/string/test-memset.c
index fee3bdf..7ca4f20 100644
--- a/string/test-memset.c
+++ b/string/test-memset.c
@@ -19,7 +19,11 @@
 
 #define TEST_MAIN
 #ifdef TEST_BZERO
-# define TEST_NAME "bzero"
+# ifdef TEST_EXPLICIT_BZERO
+#  define TEST_NAME "explicit_bzero"
+# else
+#  define TEST_NAME "bzero"
+# endif
 #else
 # ifndef WIDE
 #  define TEST_NAME "memset"
@@ -56,7 +60,11 @@ void builtin_bzero (char *, size_t);
 
 IMPL (simple_bzero, 0)
 IMPL (builtin_bzero, 0)
+#ifdef TEST_EXPLICIT_BZERO
+IMPL (explicit_bzero, 1)
+#else
 IMPL (bzero, 1)
+#endif
 
 void
 simple_bzero (char *s, size_t n)
diff --git a/string/tst-xbzero-opt.c b/string/tst-xbzero-opt.c
new file mode 100644
index 0000000..81eb5c1
--- /dev/null
+++ b/string/tst-xbzero-opt.c
@@ -0,0 +1,383 @@
+/* Test that explicit_bzero block clears are not optimized out.
+   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/>.  */
+
+/* This test is conceptually based on a test designed by Matthew
+   Dempsky for the OpenBSD regression suite:
+   <openbsd>/src/regress/lib/libc/explicit_bzero/explicit_bzero.c.
+   The basic idea is, we have a function that contains a
+   block-clearing operation (not necessarily explicit_bzero), after
+   which the block is dead, in the compiler-jargon sense.  Execute
+   that function from a signal handler running on an alternative
+   signal stack.  Then we have another pointer to the memory region
+   affected by the block clear -- namely, the sigaltstack buffer --
+   and can find out whether it actually happened.
+
+   The OpenBSD test cautions that some operating systems (e.g. Solaris
+   and OSX) wipe the signal stack upon returning to the normal stack,
+   so the test has to happen while still executing on the signal
+   stack.  This, of course, means that the buffer might be clobbered
+   by normal stack operations after the function with the block clear
+   returns (it has to return, so that the block is truly dead).  The
+   most straightforward way to deal with this is to have a large block
+   containing several copies of a byte pattern that is unlikely to
+   occur by chance, and check whether _any_ of them survives.  */
+
+#define _GNU_SOURCE 1
+
+#include <stdbool.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* The "byte pattern that is unlikely to occur by chance": the first
+   16 prime numbers (OEIS A000040).  */
+static const unsigned char test_pattern[16] =
+{
+  2, 3, 5, 7,  11, 13, 17, 19,  23, 29, 31, 37,  41, 43, 47, 53
+};
+
+#define PATTERN_SIZE (sizeof test_pattern)
+#define PATTERN_REPS 32
+#define TEST_BUFFER_SIZE (PATTERN_SIZE * PATTERN_REPS)
+
+static void
+fill_with_test_pattern (unsigned char *buf)
+{
+  for (unsigned int i = 0; i < PATTERN_REPS; i++)
+    memcpy (buf + i*PATTERN_SIZE, test_pattern, PATTERN_SIZE);
+}
+
+static unsigned int
+count_test_patterns (unsigned char *buf, size_t bufsiz)
+{
+  unsigned char *first = memmem (buf, bufsiz, test_pattern, PATTERN_SIZE);
+  if (!first)
+    return 0;
+  unsigned int cnt = 0;
+  for (unsigned int i = 0; i < PATTERN_REPS; i++)
+    {
+      unsigned char *p = first + i*PATTERN_SIZE;
+      if (p + PATTERN_SIZE - buf > bufsiz)
+        break;
+      if (memcmp (p, test_pattern, PATTERN_SIZE) == 0)
+        cnt++;
+    }
+  return cnt;
+}
+
+/* Global test state.  */
+static int failed_subtests;
+static bool this_subtest_failed;
+
+/* The signal stack is allocated with memalign.  */
+static unsigned char *signal_stack_buffer;
+#define SIGNAL_STACK_SIZE (SIGSTKSZ + TEST_BUFFER_SIZE)
+
+enum test_expectation { EXPECT_NONE, EXPECT_SOME, EXPECT_ALL };
+
+static void
+check_test_buffer (enum test_expectation expected,
+                   const char *label, const char *stage)
+{
+  unsigned int cnt = count_test_patterns (signal_stack_buffer,
+                                          SIGNAL_STACK_SIZE);
+  switch (expected)
+    {
+    case EXPECT_NONE:
+      if (cnt == 0)
+        {
+          printf ("PASS: %s/%s: expected 0 got %d\n", label, stage, cnt);
+          fflush (stdout);
+        }
+      else
+        {
+          printf ("FAIL: %s/%s: expected 0 got %d\n", label, stage, cnt);
+          fflush (stdout);
+          this_subtest_failed = true;
+          failed_subtests++;
+        }
+      break;
+
+    case EXPECT_SOME:
+      if (cnt > 0)
+        {
+          printf ("PASS: %s/%s: expected some got %d\n", label, stage, cnt);
+          fflush (stdout);
+        }
+      else
+        {
+          printf ("FAIL: %s/%s: expected some got 0\n", label, stage);
+          fflush (stdout);
+          this_subtest_failed = true;
+          failed_subtests++;
+        }
+      break;
+
+     case EXPECT_ALL:
+      if (cnt == PATTERN_REPS)
+        {
+          printf ("PASS: %s/%s: expected %d got %d\n", label, stage,
+                  PATTERN_REPS, cnt);
+          fflush (stdout);
+        }
+      else
+        {
+          printf ("FAIL: %s/%s: expected %d got %d\n", label, stage,
+                  PATTERN_REPS, cnt);
+          fflush (stdout);
+          this_subtest_failed = true;
+          failed_subtests++;
+        }
+      break;
+
+    default:
+      printf ("ERROR: %s/%s: invalid value for 'expected' = %d\n",
+              label, stage, (int)expected);
+      fflush (stdout);
+      this_subtest_failed = true;
+      failed_subtests++;
+    }
+}
+
+/* Always check the test buffer immediately after filling it; this
+   makes externally visible side effects depend on the buffer existing
+   and having been filled in.  */
+static void
+prepare_test_buffer (unsigned char *buf, const char *label)
+{
+  fill_with_test_pattern (buf);
+  check_test_buffer (EXPECT_ALL, label, "prepare");
+
+  unsigned char *loc = memmem (signal_stack_buffer, SIGNAL_STACK_SIZE,
+                               test_pattern, PATTERN_SIZE);
+  if (loc == buf)
+    {
+      printf ("PASS: %s/prepare: expected buffer location %p got %p\n",
+              label, buf, loc);
+      fflush (stdout);
+    }
+  else
+    {
+      printf ("FAIL: %s/prepare: expected buffer location %p got %p\n",
+              label, buf, loc);
+      fflush (stdout);
+      this_subtest_failed = true;
+      failed_subtests++;
+    }
+}
+
+/* There are three subtests, two of which are sanity checks.
+
+   In the "no_clear" case, we don't do anything to the test buffer
+   between preparing it and letting it go out of scope, and we expect
+   to find it.  This confirms that the test buffer does get filled in
+   and we can find it from the stack buffer.  In the "ordinary_clear"
+   case, we clear it using memset, and we expect to find it.  This
+   confirms that the compiler can optimize out block clears in this
+   context; if it can't, the real test might be succeeding for the
+   wrong reason.  Finally, the "explicit_clear" case uses
+   explicit_bzero and expects _not_ to find the test buffer, which is
+   the real test.  */
+
+static void
+setup_no_clear (void)
+{
+  unsigned char buf[TEST_BUFFER_SIZE];
+  prepare_test_buffer (buf, "no clear");
+}
+
+static void
+setup_ordinary_clear (void)
+{
+  unsigned char buf[TEST_BUFFER_SIZE];
+  prepare_test_buffer (buf, "ordinary clear");
+  if (this_subtest_failed)
+    return;
+  memset (buf, 0, TEST_BUFFER_SIZE);
+}
+
+static void
+setup_explicit_clear (void)
+{
+  unsigned char buf[TEST_BUFFER_SIZE];
+  prepare_test_buffer (buf, "explicit clear");
+  if (this_subtest_failed)
+    return;
+  explicit_bzero (buf, TEST_BUFFER_SIZE);
+}
+
+struct subtest
+{
+  void (*setup_subtest) (void);
+  const char *label;
+  enum test_expectation expected;
+};
+
+static const struct subtest subtests[] =
+{
+  { setup_no_clear,       "no clear",       EXPECT_SOME },
+  { setup_ordinary_clear, "ordinary clear", EXPECT_SOME },
+  { setup_explicit_clear, "explicit clear", EXPECT_NONE },
+  { 0,                    0,                -1          }
+};
+static const struct subtest *this_subtest;
+static bool this_subtest_complete;
+
+/* This function is called as a signal handler.  The signal is
+   triggered by a call to raise, therefore it is safe to do
+   non-async-signal-safe things within this function.
+
+   The this_subtest_complete flag addresses a race.  The outer loop
+   keeps SIGUSR1 blocked all the time, unblocking it only immediately
+   after setting up the appropriate conditions for a test and then
+   raising SIGUSR1 itself.  SIGUSR1 is not a real-time signal, so if
+   another process sends this process SIGUSR1 _before_ it's unblocked
+   by the outer loop, this function will only be called once.
+   However, if another process sends this process SIGUSR1 _while this
+   handler is already running_, that signal will be pending upon
+   return from this function, and will fire before the outer loop has
+   a chance to re-block SIGUSR1.  This is unavoidable; the workaround
+   is to arrange for this function not to do anything if it's called
+   several times in a row.  */
+static void
+do_subtest (int signo __attribute__ ((unused)))
+{
+  if (!this_subtest_complete)
+    {
+      this_subtest->setup_subtest ();
+      if (!this_subtest_failed)
+        check_test_buffer (this_subtest->expected,
+                           this_subtest->label,
+                           "test");
+      this_subtest_complete = true;
+    }
+}
+
+static int
+do_test (void)
+{
+  /* test-skeleton.c unconditionally sets stdout to be unbuffered.
+     vfprintf allocates a great deal of memory on the stack if called
+     with an unbuffered FILE*, overflowing the alt-stack.  This is
+     also why there is a call to fflush after every call to printf in
+     this file.  */
+  if (setvbuf (stdout, 0, _IOFBF, 0))
+    {
+      printf ("ERROR: restoring stdout buffering: %s\n", strerror (errno));
+      fflush (stdout);
+      return 2;
+    }
+
+  size_t page_alignment = sysconf (_SC_PAGESIZE);
+  if (page_alignment < sizeof (void *))
+    page_alignment = sizeof (void *);
+
+  void *p;
+  int err = posix_memalign (&p, page_alignment, SIGNAL_STACK_SIZE);
+  if (err || !p)
+    {
+      printf ("ERROR: allocating alt stack: %s\n", strerror (err));
+      fflush (stdout);
+      return 2;
+    }
+  signal_stack_buffer = p;
+
+  /* This program will malfunction if it receives SIGUSR1 signals at any
+     time other than when it's just sent one to itself.  Therefore, keep
+     it blocked most of the time.  */
+  sigset_t sigusr1_mask;
+  sigemptyset (&sigusr1_mask);
+  sigaddset (&sigusr1_mask, SIGUSR1);
+  if (sigprocmask (SIG_BLOCK, &sigusr1_mask, 0))
+    {
+      printf ("ERROR: block(SIGUSR1): %s\n", strerror (errno));
+      fflush (stdout);
+      return 2;
+    }
+
+  stack_t ss;
+  ss.ss_sp    = signal_stack_buffer;
+  ss.ss_flags = 0;
+  ss.ss_size  = SIGNAL_STACK_SIZE;
+  if (sigaltstack (&ss, 0))
+    {
+      printf ("ERROR: sigaltstack: %s\n", strerror (errno));
+      fflush (stdout);
+      return 2;
+    }
+
+  struct sigaction sa;
+  sigemptyset (&sa.sa_mask);
+  sigaddset (&sa.sa_mask, SIGUSR1);
+  sa.sa_handler = do_subtest;
+  sa.sa_flags = SA_RESTART | SA_ONSTACK;
+  if (sigaction (SIGUSR1, &sa, 0))
+    {
+      printf ("ERROR: sigaction(SIGUSR1): %s\n", strerror (errno));
+      fflush (stdout);
+      return 2;
+    }
+
+  /* We use kill instead of raise, because raise screws with the
+     signal mask, which we don't want.  */
+  pid_t self = getpid ();
+
+  this_subtest = subtests;
+  while (this_subtest->label)
+    {
+      this_subtest_complete = false;
+      this_subtest_failed = false;
+
+      /* Completely clear the signal stack between tests, so that junk
+         from previous tests cannot interfere with the current one.  */
+      memset (signal_stack_buffer, 0, SIGNAL_STACK_SIZE);
+
+      /* Raise SIGUSR1, then unblock it, then immediately block it
+         again.  This will trigger do_subtest to run _once_ on the
+         alternative stack, at the point of calling sigprocmask to
+         unblock the signal.  */
+      if (kill (self, SIGUSR1))
+        {
+          printf ("ERROR: raise(SIGUSR1): %s\n", strerror (errno));
+          fflush (stdout);
+          return 2;
+        }
+      if (sigprocmask (SIG_UNBLOCK, &sigusr1_mask, 0))
+        {
+          printf ("ERROR: unblock(SIGUSR1): %s\n", strerror (errno));
+          fflush (stdout);
+          return 2;
+        }
+      if (sigprocmask (SIG_BLOCK, &sigusr1_mask, 0))
+        {
+          printf ("ERROR: unblock(SIGUSR1): %s\n", strerror(errno));
+          fflush (stdout);
+          return 2;
+        }
+
+      this_subtest++;
+    }
+
+  return failed_subtests ? 1 : 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/sysdeps/arm/nacl/libc.abilist b/sysdeps/arm/nacl/libc.abilist
index 4d3b0b9..345246c 100644
--- a/sysdeps/arm/nacl/libc.abilist
+++ b/sysdeps/arm/nacl/libc.abilist
@@ -1843,6 +1843,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 gnu_dev_major F
 GLIBC_2.25 gnu_dev_makedev F
 GLIBC_2.25 gnu_dev_minor F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 2c2f49e..a6f076a 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2090,3 +2090,4 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 8afba47..6d67017 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2001,6 +2001,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
index de3bdf4..3f70b6c 100644
--- a/sysdeps/unix/sysv/linux/arm/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
@@ -91,6 +91,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.4 GLIBC_2.4 A
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 3261b93..8dd44b3 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -1855,6 +1855,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 6465a55..147d6c4 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2013,6 +2013,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 4536271..77d6743 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -1877,6 +1877,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 287d7a5..52e1d01 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -92,6 +92,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.4 GLIBC_2.4 A
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index c9229fa..6dfe8a1 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -1969,6 +1969,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
index 0409791..8fff289 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
@@ -2090,3 +2090,4 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index f31653e..7b9a1d6 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -1944,6 +1944,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_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 a56bd99..b1ca58e 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -1942,6 +1942,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_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 44552df..73542d1 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -1940,6 +1940,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_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 8d2a09d..66d53a1 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -1935,6 +1935,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 0443b92..9be8569 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2131,3 +2131,4 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index ba9a29a..590b6f0 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -1973,6 +1973,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_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 f19534c..f191e62 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -1978,6 +1978,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_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 f8de1ab..39fbee9 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
@@ -2178,3 +2178,4 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
index 6819133..8921048 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
@@ -92,6 +92,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 _Exit F
 GLIBC_2.3 _IO_2_1_stderr_ D 0xe0
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 4cd5d85..10109a8 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -1973,6 +1973,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_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 8cdb9df..10ad998 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -1874,6 +1874,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
index 69791b4..f7fd80d 100644
--- a/sysdeps/unix/sysv/linux/sh/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
@@ -1859,6 +1859,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index fce58a8..6a77cc9 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -1965,6 +1965,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 16ce739..da1bc47 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -1903,6 +1903,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
index f99c298..3cb4463 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
@@ -2097,3 +2097,4 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
index c601ab0..db16fa5 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
@@ -2097,3 +2097,4 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
index f99c298..3cb4463 100644
--- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
@@ -2097,3 +2097,4 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 8e6fa57..34bf69c 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -1854,6 +1854,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_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 1e12f48..c31daa8 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2097,3 +2097,4 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 explicit_bzero F
-- 
2.9.3

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 3/3] Use explicit_bzero where appropriate
  2016-09-15 13:05   ` [PATCH 2/3] Add fortification and inline optimization of explicit_bzero Zack Weinberg
@ 2016-09-15 13:05     ` Zack Weinberg
  0 siblings, 0 replies; 15+ messages in thread
From: Zack Weinberg @ 2016-09-15 13:05 UTC (permalink / raw)
  To: libc-alpha; +Cc: fweimer

I *believe* these are the only places where memset was being used
to clear buffers containing sensitive data.  The compiler probably
couldn't optimize *all* of them out but it seems best to change them all.

The legacy DES implementation wasn't bothering to clear its buffers,
so I added that, mostly for consistency's sake.

	* crypt/crypt-entry.c (__crypt_r): Clear key-dependent intermediate
	data before returning, using explicit_bzero.
	* crypt/md5-crypt.c (__md5_crypt_r): Likewise.
	* crypt/sha256-crypt.c (__sha256_crypt_r): Likewise.
	* crypt/sha512-crypt.c (__sha512_crypt_r): Likewise.
---
 crypt/crypt-entry.c  | 11 +++++++++++
 crypt/md5-crypt.c    |  8 ++++----
 crypt/sha256-crypt.c | 14 +++++++-------
 crypt/sha512-crypt.c | 14 +++++++-------
 4 files changed, 29 insertions(+), 18 deletions(-)

diff --git a/crypt/crypt-entry.c b/crypt/crypt-entry.c
index a7dfcca..09a5664 100644
--- a/crypt/crypt-entry.c
+++ b/crypt/crypt-entry.c
@@ -141,6 +141,17 @@ __crypt_r (const char *key, const char *salt,
    * And convert back to 6 bit ASCII
    */
   _ufc_output_conversion_r (res[0], res[1], salt, data);
+
+#ifdef _LIBC
+  /*
+   * Erase key-dependent intermediate data.  Data dependent only on
+   * the salt is not considered sensitive.
+   */
+  explicit_bzero (ktab, sizeof (ktab));
+  explicit_bzero (data->keysched, sizeof (data->keysched));
+  explicit_bzero (res, sizeof (res));
+#endif
+
   return data->crypt_3_buf;
 }
 weak_alias (__crypt_r, crypt_r)
diff --git a/crypt/md5-crypt.c b/crypt/md5-crypt.c
index 2243bc7..6125c7f 100644
--- a/crypt/md5-crypt.c
+++ b/crypt/md5-crypt.c
@@ -288,13 +288,13 @@ __md5_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
 #ifndef USE_NSS
   __md5_init_ctx (&ctx);
   __md5_finish_ctx (&ctx, alt_result);
-  memset (&ctx, '\0', sizeof (ctx));
-  memset (&alt_ctx, '\0', sizeof (alt_ctx));
+  explicit_bzero (&ctx, sizeof (ctx));
+  explicit_bzero (&alt_ctx, sizeof (alt_ctx));
 #endif
   if (copied_key != NULL)
-    memset (copied_key, '\0', key_len);
+    explicit_bzero (copied_key, key_len);
   if (copied_salt != NULL)
-    memset (copied_salt, '\0', salt_len);
+    explicit_bzero (copied_salt, salt_len);
 
   free (free_key);
   return buffer;
diff --git a/crypt/sha256-crypt.c b/crypt/sha256-crypt.c
index ca703de..6717e22 100644
--- a/crypt/sha256-crypt.c
+++ b/crypt/sha256-crypt.c
@@ -371,16 +371,16 @@ __sha256_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
 #ifndef USE_NSS
   __sha256_init_ctx (&ctx);
   __sha256_finish_ctx (&ctx, alt_result);
-  memset (&ctx, '\0', sizeof (ctx));
-  memset (&alt_ctx, '\0', sizeof (alt_ctx));
+  explicit_bzero (&ctx, sizeof (ctx));
+  explicit_bzero (&alt_ctx, sizeof (alt_ctx));
 #endif
-  memset (temp_result, '\0', sizeof (temp_result));
-  memset (p_bytes, '\0', key_len);
-  memset (s_bytes, '\0', salt_len);
+  explicit_bzero (temp_result, sizeof (temp_result));
+  explicit_bzero (p_bytes, key_len);
+  explicit_bzero (s_bytes, salt_len);
   if (copied_key != NULL)
-    memset (copied_key, '\0', key_len);
+    explicit_bzero (copied_key, key_len);
   if (copied_salt != NULL)
-    memset (copied_salt, '\0', salt_len);
+    explicit_bzero (copied_salt, salt_len);
 
   free (free_key);
   free (free_pbytes);
diff --git a/crypt/sha512-crypt.c b/crypt/sha512-crypt.c
index c42e5b7..1965191 100644
--- a/crypt/sha512-crypt.c
+++ b/crypt/sha512-crypt.c
@@ -393,16 +393,16 @@ __sha512_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
 #ifndef USE_NSS
   __sha512_init_ctx (&ctx);
   __sha512_finish_ctx (&ctx, alt_result);
-  memset (&ctx, '\0', sizeof (ctx));
-  memset (&alt_ctx, '\0', sizeof (alt_ctx));
+  explicit_bzero (&ctx, sizeof (ctx));
+  explicit_bzero (&alt_ctx, sizeof (alt_ctx));
 #endif
-  memset (temp_result, '\0', sizeof (temp_result));
-  memset (p_bytes, '\0', key_len);
-  memset (s_bytes, '\0', salt_len);
+  explicit_bzero (temp_result, sizeof (temp_result));
+  explicit_bzero (p_bytes, key_len);
+  explicit_bzero (s_bytes, salt_len);
   if (copied_key != NULL)
-    memset (copied_key, '\0', key_len);
+    explicit_bzero (copied_key, key_len);
   if (copied_salt != NULL)
-    memset (copied_salt, '\0', salt_len);
+    explicit_bzero (copied_salt, salt_len);
 
   free (free_key);
   free (free_pbytes);
-- 
2.9.3

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 0/3] explicit_bzero again
@ 2016-09-15 13:05 Zack Weinberg
  2016-09-15 13:05 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Zack Weinberg
  0 siblings, 1 reply; 15+ messages in thread
From: Zack Weinberg @ 2016-09-15 13:05 UTC (permalink / raw)
  To: libc-alpha; +Cc: fweimer

The implementation strategy is the same as in the previous iteration.
I have reorganized it again to make clearer what is and is not essential.
The first patch adds only an out-of-line definition of explicit_bzero,
plus tests.  The second patch exposes __glibc_read_memory to external
callers and uses that to define a fortify wrapper and a string2.h
optimization.  The third patch makes use of explicit_bzero in libcrypt,
which I believe to be the only current place where it's needed inside
glibc itself.

zw

Zack Weinberg (3):
  New string function explicit_bzero (from OpenBSD).
  Add fortification and inline optimization of explicit_bzero.
  Use explicit_bzero where appropriate

 crypt/crypt-entry.c                                |  11 +
 crypt/md5-crypt.c                                  |   8 +-
 crypt/sha256-crypt.c                               |  14 +-
 crypt/sha512-crypt.c                               |  14 +-
 debug/tst-chk1.c                                   |  28 ++
 include/string.h                                   |   2 +
 manual/string.texi                                 | 101 ++++++
 string/Makefile                                    |  12 +-
 string/Versions                                    |   7 +
 string/bits/string2.h                              |  13 +-
 string/bits/string3.h                              |   7 +
 string/explicit_bzero.c                            |  30 ++
 string/read_memory.c                               |  41 +++
 string/string.h                                    |   9 +
 string/test-explicit_bzero.c                       |  20 ++
 string/test-memset.c                               |  10 +-
 string/tst-xbzero-opt.c                            | 383 +++++++++++++++++++++
 sysdeps/arm/nacl/libc.abilist                      |   2 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist       |   2 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist         |   2 +
 sysdeps/unix/sysv/linux/arm/libc.abilist           |   2 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist          |   2 +
 sysdeps/unix/sysv/linux/i386/libc.abilist          |   2 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist          |   2 +
 sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist |   2 +
 sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist   |   2 +
 sysdeps/unix/sysv/linux/microblaze/libc.abilist    |   2 +
 .../unix/sysv/linux/mips/mips32/fpu/libc.abilist   |   2 +
 .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist |   2 +
 .../unix/sysv/linux/mips/mips64/n32/libc.abilist   |   2 +
 .../unix/sysv/linux/mips/mips64/n64/libc.abilist   |   2 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist         |   2 +
 .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist  |   2 +
 .../linux/powerpc/powerpc32/nofpu/libc.abilist     |   2 +
 .../sysv/linux/powerpc/powerpc64/libc-le.abilist   |   2 +
 .../unix/sysv/linux/powerpc/powerpc64/libc.abilist |   2 +
 sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist  |   2 +
 sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist  |   2 +
 sysdeps/unix/sysv/linux/sh/libc.abilist            |   2 +
 sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist |   2 +
 sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist |   2 +
 .../sysv/linux/tile/tilegx/tilegx32/libc.abilist   |   2 +
 .../sysv/linux/tile/tilegx/tilegx64/libc.abilist   |   2 +
 sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist  |   2 +
 sysdeps/unix/sysv/linux/x86_64/64/libc.abilist     |   2 +
 sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist    |   2 +
 46 files changed, 745 insertions(+), 23 deletions(-)
 create mode 100644 string/explicit_bzero.c
 create mode 100644 string/read_memory.c
 create mode 100644 string/test-explicit_bzero.c
 create mode 100644 string/tst-xbzero-opt.c

-- 
2.9.3

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 2/3] Add fortification and inline optimization of explicit_bzero.
  2016-09-15 13:05 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Zack Weinberg
@ 2016-09-15 13:05   ` Zack Weinberg
  2016-09-15 13:05     ` [PATCH 3/3] Use explicit_bzero where appropriate Zack Weinberg
  2016-09-15 15:38   ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Paul Eggert
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 15+ messages in thread
From: Zack Weinberg @ 2016-09-15 13:05 UTC (permalink / raw)
  To: libc-alpha; +Cc: fweimer

By exposing __glibc_read_memory to external callers, we can write a
fortify wrapper for explicit_bzero in terms of __memset_chk and
__glibc_read_memory.  There is no out-of-line __bzero_chk defined in
libc.so, so I see no need to add an out-of-line __explicit_bzero_chk
either.

We can also add a bits/string2.h macro that optimizes explicit_bzero
to memset + __glibc_read_memory, thus allowing the compiler to use
intrinsic code generation for memset.  I think this is worth doing
because it partially addresses the problem pointed out in the manual,
where explicit_bzero might _cause_ sensitive data to be copied out of
registers onto the stack.  With memset visible to the compiler, it
will just clear a scratch area on the stack and then call
__glibc_read_memory; it won't copy the sensitive data onto the stack
first.  (But it still doesn't erase the sensitive data _in_ the
registers, so the warning in the manual is still appropriate.)

	* include/string.h: Change declaration of __glibc_read_memory to
        declaration of an internal alias.
        * string/string.h: Declare __glibc_read_memory here.
	* string/explicit_bzero.c: Use the internal alias
        for __glibc_read_memory.
        * string/bits/string2.h: Optimize explicit_bzero.
	* string/bits/string3.h: Fortify explicit_bzero.
        * debug/tst-chk1.c: Test fortification of explicit_bzero.

        * string/Versions: Expose __glibc_read_memory.
        * sysdeps/arm/nacl/libc.abilist
        * sysdeps/unix/sysv/linux/aarch64/libc.abilist
        * sysdeps/unix/sysv/linux/alpha/libc.abilist
        * sysdeps/unix/sysv/linux/arm/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/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/powerpc/powerpc32/fpu/libc.abilist
        * sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
        * sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
        * sysdeps/unix/sysv/linux/powerpc/powerpc64/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/libc.abilist
        * sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
        * sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
        * sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
        * sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
        * sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
        * sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
        * sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist:
        Add __glibc_read_memory.
---
 debug/tst-chk1.c                                   | 28 ++++++++++++++++++++++
 include/string.h                                   |  5 ++--
 string/Versions                                    |  3 +++
 string/bits/string2.h                              | 13 +++++++++-
 string/bits/string3.h                              |  7 ++++++
 string/explicit_bzero.c                            |  2 +-
 string/read_memory.c                               |  5 ++--
 string/string.h                                    |  5 ++++
 sysdeps/arm/nacl/libc.abilist                      |  1 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist       |  1 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist         |  1 +
 sysdeps/unix/sysv/linux/arm/libc.abilist           |  1 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist          |  1 +
 sysdeps/unix/sysv/linux/i386/libc.abilist          |  1 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist          |  1 +
 sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist |  1 +
 sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist   |  1 +
 sysdeps/unix/sysv/linux/microblaze/libc.abilist    |  1 +
 .../unix/sysv/linux/mips/mips32/fpu/libc.abilist   |  1 +
 .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist |  1 +
 .../unix/sysv/linux/mips/mips64/n32/libc.abilist   |  1 +
 .../unix/sysv/linux/mips/mips64/n64/libc.abilist   |  1 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist         |  1 +
 .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist  |  1 +
 .../linux/powerpc/powerpc32/nofpu/libc.abilist     |  1 +
 .../sysv/linux/powerpc/powerpc64/libc-le.abilist   |  1 +
 .../unix/sysv/linux/powerpc/powerpc64/libc.abilist |  1 +
 sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist  |  1 +
 sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist  |  1 +
 sysdeps/unix/sysv/linux/sh/libc.abilist            |  1 +
 sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist |  1 +
 sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist |  1 +
 .../sysv/linux/tile/tilegx/tilegx32/libc.abilist   |  1 +
 .../sysv/linux/tile/tilegx/tilegx64/libc.abilist   |  1 +
 sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist  |  1 +
 sysdeps/unix/sysv/linux/x86_64/64/libc.abilist     |  1 +
 sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist    |  1 +
 37 files changed, 90 insertions(+), 7 deletions(-)

diff --git a/debug/tst-chk1.c b/debug/tst-chk1.c
index 478c2fb..e87a279 100644
--- a/debug/tst-chk1.c
+++ b/debug/tst-chk1.c
@@ -160,6 +160,10 @@ do_test (void)
   if (memcmp (buf, "aabcdabc\0\0", 10))
     FAIL ();
 
+  explicit_bzero (buf + 6, 4);
+  if (memcmp (buf, "aabcda\0\0\0\0", 10))
+    FAIL ();
+
   strcpy (buf + 4, "EDCBA");
   if (memcmp (buf, "aabcEDCBA", 10))
     FAIL ();
@@ -201,6 +205,10 @@ do_test (void)
   if (memcmp (buf, "aabcdabc\0\0", 10))
     FAIL ();
 
+  explicit_bzero (buf + 6, l0 + 4);
+  if (memcmp (buf, "aabcda\0\0\0\0", 10))
+    FAIL ();
+
   strcpy (buf + 4, str1 + 5);
   if (memcmp (buf, "aabcEDCBA", 10))
     FAIL ();
@@ -256,6 +264,10 @@ do_test (void)
   if (memcmp (a.buf1, "aabcdabc\0\0", 10))
     FAIL ();
 
+  explicit_bzero (a.buf1 + 6, l0 + 4);
+  if (memcmp (a.buf1, "aabcda\0\0\0\0", 10))
+    FAIL ();
+
 #if __USE_FORTIFY_LEVEL < 2
   /* The following tests are supposed to crash with -D_FORTIFY_SOURCE=2
      and sufficient GCC support, as the string operations overflow
@@ -345,6 +357,14 @@ do_test (void)
   bzero (buf + 9, l0 + 2);
   CHK_FAIL_END
 
+  CHK_FAIL_START
+  explicit_bzero (buf + 9, 2);
+  CHK_FAIL_END
+
+  CHK_FAIL_START
+  explicit_bzero (buf + 9, l0 + 2);
+  CHK_FAIL_END
+
   CHK_FAIL_START
   strcpy (buf + 5, str1 + 5);
   CHK_FAIL_END
@@ -454,6 +474,14 @@ do_test (void)
   bzero (a.buf1 + 9, l0 + 2);
   CHK_FAIL_END
 
+  CHK_FAIL_START
+  explicit_bzero (a.buf1 + 9, 2);
+  CHK_FAIL_END
+
+  CHK_FAIL_START
+  explicit_bzero (a.buf1 + 9, l0 + 2);
+  CHK_FAIL_END
+
 # if __USE_FORTIFY_LEVEL >= 2
 #  define O 0
 # else
diff --git a/include/string.h b/include/string.h
index dc0edf3..277c07d 100644
--- a/include/string.h
+++ b/include/string.h
@@ -99,9 +99,8 @@ libc_hidden_proto (memmem)
 extern __typeof (memmem) __memmem;
 libc_hidden_proto (__memmem)
 libc_hidden_proto (__ffs)
-extern void __glibc_read_memory (const void *s, size_t len)
-  __THROW __nonnull ((1)) __attribute_noinline__;
-libc_hidden_proto (__glibc_read_memory)
+extern __typeof (__glibc_read_memory) __internal_glibc_read_memory;
+libc_hidden_proto (__internal_glibc_read_memory)
 
 libc_hidden_builtin_proto (memchr)
 libc_hidden_builtin_proto (memcpy)
diff --git a/string/Versions b/string/Versions
index a2c6e6e..3d116f3 100644
--- a/string/Versions
+++ b/string/Versions
@@ -83,6 +83,9 @@ libc {
   GLIBC_2.24 {
   }
   GLIBC_2.25 {
+    # used by inlines in bits/string2.h and bits/string3.h
+    __glibc_read_memory;
+
     # e*
     explicit_bzero;
   }
diff --git a/string/bits/string2.h b/string/bits/string2.h
index 8098760..6066d49 100644
--- a/string/bits/string2.h
+++ b/string/bits/string2.h
@@ -52,11 +52,22 @@
 #define __string2_1bptr_p(__x) \
   ((size_t)(const void *)((__x) + 1) - (size_t)(const void *)(__x) == 1)
 
-/* Set N bytes of S to C.  */
+/* Set N bytes of S to 0.  */
 #if !defined _HAVE_STRING_ARCH_memset
 # define __bzero(s, n) __builtin_memset (s, '\0', n)
 #endif
 
+#if defined __USE_MISC && !defined __fortify_function
+/* As bzero, but the compiler will not delete a call to this function,
+   even if S is dead after the call.  This is a macro instead of an
+   inline function _solely_ so that it will not get turned into an
+   external definition in string-inlines.o; it has its own .c file in
+   libc already.  */
+#define explicit_bzero(s, n)				\
+  (__extension__ ({ void *__s = (s); size_t __n = (n);	\
+		    memset (__s, '\0', __n);		\
+		    __glibc_read_memory (__s, __n); }))
+#endif
 
 #ifndef _HAVE_STRING_ARCH_strchr
 extern void *__rawmemchr (const void *__s, int __c);
diff --git a/string/bits/string3.h b/string/bits/string3.h
index dd8db68..d340bef 100644
--- a/string/bits/string3.h
+++ b/string/bits/string3.h
@@ -102,6 +102,13 @@ __NTH (bzero (void *__dest, size_t __len))
 {
   (void) __builtin___memset_chk (__dest, '\0', __len, __bos0 (__dest));
 }
+
+__fortify_function void
+__NTH (explicit_bzero (void *__dest, size_t __len))
+{
+  (void) __builtin___memset_chk (__dest, '\0', __len, __bos0 (__dest));
+  __glibc_read_memory (__dest, __len);
+}
 #endif
 
 __fortify_function char *
diff --git a/string/explicit_bzero.c b/string/explicit_bzero.c
index a2b75be..a02be4f 100644
--- a/string/explicit_bzero.c
+++ b/string/explicit_bzero.c
@@ -26,5 +26,5 @@ void
 explicit_bzero (void *s, size_t len)
 {
   memset (s, '\0', len);
-  __glibc_read_memory (s, len);
+  __internal_glibc_read_memory (s, len);
 }
diff --git a/string/read_memory.c b/string/read_memory.c
index 5347ee2..c4a5990 100644
--- a/string/read_memory.c
+++ b/string/read_memory.c
@@ -33,8 +33,9 @@
 
 void
 internal_function
-__glibc_read_memory(const void *s, size_t len)
+__internal_glibc_read_memory(const void *s, size_t len)
 {
   asm volatile ("");
 }
-libc_hidden_def (__glibc_read_memory)
+libc_hidden_def (__internal_glibc_read_memory)
+strong_alias (__internal_glibc_read_memory, __glibc_read_memory)
diff --git a/string/string.h b/string/string.h
index 89f5ab2..682661a 100644
--- a/string/string.h
+++ b/string/string.h
@@ -459,6 +459,11 @@ extern void bzero (void *__s, size_t __n) __THROW __nonnull ((1));
    function, even if S is dead after the call.  */
 extern void explicit_bzero (void *__s, size_t __n) __THROW __nonnull ((1));
 
+/* Optimization fence, used by bits/string2.h and bits/string3.h
+   inline versions of explicit_bzero.  */
+extern void __glibc_read_memory (const void *__s, size_t __n)
+     __THROW __nonnull ((1)) __attribute_noinline__;
+
 /* Compare N bytes of S1 and S2 (same as memcmp).  */
 extern int bcmp (const void *__s1, const void *__s2, size_t __n)
      __THROW __attribute_pure__ __nonnull ((1, 2));
diff --git a/sysdeps/arm/nacl/libc.abilist b/sysdeps/arm/nacl/libc.abilist
index 345246c..02d4bc6 100644
--- a/sysdeps/arm/nacl/libc.abilist
+++ b/sysdeps/arm/nacl/libc.abilist
@@ -1843,6 +1843,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 gnu_dev_major F
 GLIBC_2.25 gnu_dev_makedev F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index a6f076a..44dc0d1 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2090,4 +2090,5 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 6d67017..02a490d 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2001,6 +2001,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
index 3f70b6c..d2b2800 100644
--- a/sysdeps/unix/sysv/linux/arm/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
@@ -91,6 +91,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
 GLIBC_2.4 GLIBC_2.4 A
 GLIBC_2.4 _Exit F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 8dd44b3..59b2591 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -1855,6 +1855,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 147d6c4..e64f9c6 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2013,6 +2013,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 77d6743..78acf45 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -1877,6 +1877,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 52e1d01..ceb1909 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -92,6 +92,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
 GLIBC_2.4 GLIBC_2.4 A
 GLIBC_2.4 _Exit F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 6dfe8a1..e8d7256 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -1969,6 +1969,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
index 8fff289..c2e2ecc 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
@@ -2090,4 +2090,5 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 7b9a1d6..705f00b 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -1944,6 +1944,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_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 b1ca58e..41d3e5c 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -1942,6 +1942,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_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 73542d1..4de5839 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -1940,6 +1940,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_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 66d53a1..e1d5bec 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -1935,6 +1935,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 9be8569..34e83a6 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2131,4 +2131,5 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 590b6f0..91a30c8 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -1973,6 +1973,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_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 f191e62..a4ecbc2 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -1978,6 +1978,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_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 39fbee9..277ec26 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
@@ -2178,4 +2178,5 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
index 8921048..e3dafa5 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
@@ -92,6 +92,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 _Exit F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 10109a8..3ab826d 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -1973,6 +1973,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_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 10ad998..c4c0a8e 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -1874,6 +1874,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
index f7fd80d..7a11b8a 100644
--- a/sysdeps/unix/sysv/linux/sh/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
@@ -1859,6 +1859,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 6a77cc9..13efb9f 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -1965,6 +1965,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index da1bc47..da6819b 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -1903,6 +1903,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
index 3cb4463..0d58dc0 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
@@ -2097,4 +2097,5 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
index db16fa5..fc55930 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
@@ -2097,4 +2097,5 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
index 3cb4463..0d58dc0 100644
--- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
@@ -2097,4 +2097,5 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 34bf69c..858a26c 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -1854,6 +1854,7 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_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 c31daa8..9a45eed 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2097,4 +2097,5 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __glibc_read_memory F
 GLIBC_2.25 explicit_bzero F
-- 
2.9.3

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/3] New string function explicit_bzero (from OpenBSD).
  2016-09-15 13:05 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Zack Weinberg
  2016-09-15 13:05   ` [PATCH 2/3] Add fortification and inline optimization of explicit_bzero Zack Weinberg
@ 2016-09-15 15:38   ` Paul Eggert
  2016-09-15 15:59   ` Paul Eggert
  2016-10-06 10:03   ` Florian Weimer
  3 siblings, 0 replies; 15+ messages in thread
From: Paul Eggert @ 2016-09-15 15:38 UTC (permalink / raw)
  To: Zack Weinberg, libc-alpha; +Cc: fweimer

On 09/15/2016 06:05 AM, Zack Weinberg wrote:
> +void
> +internal_function
> +__glibc_read_memory(const void *s, size_t len)
> +{
> +  asm volatile ("");
> +}

This leaks the address S to possibly-buggy code, bypassing address 
randomization. For example, if a function body ends in 'explicit_bzero 
(&x, sizeof x)', then &x is likely to be in a machine register or on the 
stack when explicit_bzero returns, more so than if explicit_bzero were 
never called. If a key is stored next to other somewhat-sensitive data 
this will make the somewhat-sensitive data more vulnerable than it 
otherwise would be.

To help avoid this problem, __glibc_read_member could clear all 
caller-save registers (including the return register of course). This 
would not entirely prevent the problem, but that's OK as explicit_bzero 
does not pretend to entirely prevent information leakage.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/3] New string function explicit_bzero (from OpenBSD).
  2016-09-15 13:05 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Zack Weinberg
  2016-09-15 13:05   ` [PATCH 2/3] Add fortification and inline optimization of explicit_bzero Zack Weinberg
  2016-09-15 15:38   ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Paul Eggert
@ 2016-09-15 15:59   ` Paul Eggert
  2016-10-06 10:03   ` Florian Weimer
  3 siblings, 0 replies; 15+ messages in thread
From: Paul Eggert @ 2016-09-15 15:59 UTC (permalink / raw)
  To: Zack Weinberg, libc-alpha; +Cc: fweimer

On 09/15/2016 06:05 AM, Zack Weinberg wrote:
> +The compiler will not delete a call to this function, even
> +if the object beginning at @var{block} is never referred to again.

That's too strong, no? It'd be OK if the compiler inlined the call, or 
if it deleted the call if LEN is zero. Also, "referred to" is too vague, 
as we don't care whether the block is written to later, only whether it 
is read from. And "beginning at @var{block}" is redundant given the 
previous sentence. I suggest rewording this to "The zeros are written 
even if the object is never read again."

> +Without the call to @code{explicit_bzero}, @var{k} might not need to
> +be stored in memory: depending on the ABI, its value could be returned
Although this info is helpful, it would be even more helpful if the 
example explained how to fix the problem. (Can one declare K to be 
volatile, for example? If not, explain why this does not suffice. Does 
it help to pass &K to explicit_bzero before initializing K? If not, 
explain that too.) If there is no portable way to address the problem, 
the discussion should flat-out say so.

I hate to say it, but multithreading issues might need a brief mention 
too. If some other thread is compromised, a call to explicit_bzero can 
make the current thread more vulnerable, not less.

I must say that after thinking about the above, my opinion of 
explicit_bzero has gone down a bit....

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/3] New string function explicit_bzero (from OpenBSD).
  2016-09-15 13:05 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Zack Weinberg
                     ` (2 preceding siblings ...)
  2016-09-15 15:59   ` Paul Eggert
@ 2016-10-06 10:03   ` Florian Weimer
  2016-10-06 15:49     ` Joseph Myers
  3 siblings, 1 reply; 15+ messages in thread
From: Florian Weimer @ 2016-10-06 10:03 UTC (permalink / raw)
  To: Zack Weinberg, libc-alpha

On 09/15/2016 03:05 PM, Zack Weinberg wrote:
> +/* As bzero, but the compiler will not delete a call to this
> +   function, even if S is dead after the call.  */
> +extern void explicit_bzero (void *__s, size_t __n) __THROW __nonnull ((1));

I would like to redirect callers to __explicit_bzero, so that shared 
objects do not accidentally pick up an implementation of explicit_bzero 
which may or may not do the right thing.

I did this in my getrandom implementation:

   <https://sourceware.org/ml/libc-alpha/2016-09/msg00203.html>

You can use __REDIRECT_NTH (meanining no exceptions) instead of __REDIRECT.

This requires exporting both __explicit_bzero and explicit_bzero.  We 
need a symbol in the implementation namespace anyway because crypt is in 
POSIX, but explicit_bzero is not.

 From the test, I would suggest to remove the fflush (stdout) calls. 
There are some whitespace GNU-style violations as well (missing space 
before paren in function call):

+struct key get_key(void);
+void use_key(struct key);
+with_clear(void)
+  k = get_key();
+  use_key(k);
+  explicit_bzero(&k, sizeof(k));
+__glibc_read_memory(const void *s, size_t len)
+      printf ("ERROR: block(SIGUSR1): %s\n", strerror (errno));
+      printf ("ERROR: sigaction(SIGUSR1): %s\n", strerror (errno));
+          printf ("ERROR: raise(SIGUSR1): %s\n", strerror (errno));
+          printf ("ERROR: unblock(SIGUSR1): %s\n", strerror (errno));
+          printf ("ERROR: unblock(SIGUSR1): %s\n", strerror(errno));

Thanks,
Florian

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/3] New string function explicit_bzero (from OpenBSD).
  2016-10-06 10:03   ` Florian Weimer
@ 2016-10-06 15:49     ` Joseph Myers
  2016-10-18  9:27       ` Florian Weimer
  0 siblings, 1 reply; 15+ messages in thread
From: Joseph Myers @ 2016-10-06 15:49 UTC (permalink / raw)
  To: Florian Weimer; +Cc: Zack Weinberg, libc-alpha

On Thu, 6 Oct 2016, Florian Weimer wrote:

> On 09/15/2016 03:05 PM, Zack Weinberg wrote:
> > +/* As bzero, but the compiler will not delete a call to this
> > +   function, even if S is dead after the call.  */
> > +extern void explicit_bzero (void *__s, size_t __n) __THROW __nonnull ((1));
> 
> I would like to redirect callers to __explicit_bzero, so that shared objects
> do not accidentally pick up an implementation of explicit_bzero which may or
> may not do the right thing.

Do you have a proposed rule for when to do such redirection?  I don't 
think it should be normal to do it; any library function could potentially 
be affected by applications defining their own function with that name.

(Exporting reserved function names at public versions makes sense when 
there is a use for those functions in contexts with namespace issues, such 
as libgcc or libstdc++.)

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/3] New string function explicit_bzero (from OpenBSD).
  2016-10-06 15:49     ` Joseph Myers
@ 2016-10-18  9:27       ` Florian Weimer
  0 siblings, 0 replies; 15+ messages in thread
From: Florian Weimer @ 2016-10-18  9:27 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Zack Weinberg, libc-alpha

On 10/06/2016 05:49 PM, Joseph Myers wrote:
> On Thu, 6 Oct 2016, Florian Weimer wrote:
>
>> On 09/15/2016 03:05 PM, Zack Weinberg wrote:
>>> +/* As bzero, but the compiler will not delete a call to this
>>> +   function, even if S is dead after the call.  */
>>> +extern void explicit_bzero (void *__s, size_t __n) __THROW __nonnull ((1));
>>
>> I would like to redirect callers to __explicit_bzero, so that shared objects
>> do not accidentally pick up an implementation of explicit_bzero which may or
>> may not do the right thing.
>
> Do you have a proposed rule for when to do such redirection?  I don't
> think it should be normal to do it; any library function could potentially
> be affected by applications defining their own function with that name.
>
> (Exporting reserved function names at public versions makes sense when
> there is a use for those functions in contexts with namespace issues, such
> as libgcc or libstdc++.)

Thanks for asking.  I started a new thread for this topic:

   <https://sourceware.org/ml/libc-alpha/2016-10/msg00294.html>

Florian

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/3] New string function explicit_bzero (from OpenBSD).
  2016-12-08 18:08     ` Zack Weinberg
@ 2016-12-08 18:17       ` Joseph Myers
  0 siblings, 0 replies; 15+ messages in thread
From: Joseph Myers @ 2016-12-08 18:17 UTC (permalink / raw)
  To: Zack Weinberg; +Cc: GNU C Library

On Thu, 8 Dec 2016, Zack Weinberg wrote:

> You are again doing this annoying thing you do where you send a small
> number of review comments with no indication of whether you have any
> other comments or concerns, whether you want to see these comments
> addressed before you look at the patches any more, or whether you are
> approving (or have the authority to approve) the patch series.

I've not attempted to review the patch substantively (and don't 
particularly expect to do so, though I support the principle of adding 
this interface).

We don't generally do "authority to approve" (anyone can review patches, 
but some views may have more weight in establishing consensus than 
others).

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/3] New string function explicit_bzero (from OpenBSD).
  2016-12-08 17:14   ` Joseph Myers
@ 2016-12-08 18:08     ` Zack Weinberg
  2016-12-08 18:17       ` Joseph Myers
  0 siblings, 1 reply; 15+ messages in thread
From: Zack Weinberg @ 2016-12-08 18:08 UTC (permalink / raw)
  To: Joseph Myers, GNU C Library

On Thu, Dec 8, 2016 at 12:13 PM, Joseph Myers <joseph@codesourcery.com> wrote:
> On Thu, 8 Dec 2016, Zack Weinberg wrote:
>
>> +    # used by libcrypt
>> +    __explicit_bzero;
>
> Use by libcrypt would be sufficient reason for a GLIBC_PRIVATE export;
> it's not clear it's sufficient for a GLIBC_2.25 public symbol version
> export, absent a general position on adding such exports of
> implementation-namespace names.

Fair point, I will change it to GLIBC_PRIVATE.

[...]

You are again doing this annoying thing you do where you send a small
number of review comments with no indication of whether you have any
other comments or concerns, whether you want to see these comments
addressed before you look at the patches any more, or whether you are
approving (or have the authority to approve) the patch series.

Given the short time to the 2.25 deadline and my own limited time
before I go out of town, I do not intend to rework this patch series
any further unless it is approved in principle for 2.25, and not until
I receive a _complete_ list of things that need to be changed before
it can be committed.

zw

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/3] New string function explicit_bzero (from OpenBSD).
  2016-12-08 14:56 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Zack Weinberg
@ 2016-12-08 17:14   ` Joseph Myers
  2016-12-08 18:08     ` Zack Weinberg
  0 siblings, 1 reply; 15+ messages in thread
From: Joseph Myers @ 2016-12-08 17:14 UTC (permalink / raw)
  To: Zack Weinberg; +Cc: libc-alpha

On Thu, 8 Dec 2016, Zack Weinberg wrote:

> +    # used by libcrypt
> +    __explicit_bzero;

Use by libcrypt would be sufficient reason for a GLIBC_PRIVATE export; 
it's not clear it's sufficient for a GLIBC_2.25 public symbol version 
export, absent a general position on adding such exports of 
implementation-namespace names.

> diff --git a/string/explicit_bzero.c b/string/explicit_bzero.c
> new file mode 100644
> index 0000000000..6c3dc9aedb
> --- /dev/null
> +++ b/string/explicit_bzero.c
> @@ -0,0 +1,33 @@
> +/* Copyright (C) 2016 Free Software Foundation, Inc.

Missing descriptive comment as first line of new file.

> diff --git a/string/read_memory.c b/string/read_memory.c
> new file mode 100644
> index 0000000000..c4a5990c49
> --- /dev/null
> +++ b/string/read_memory.c
> @@ -0,0 +1,41 @@
> +/* Copyright (C) 2016 Free Software Foundation, Inc.

Likewise.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 1/3] New string function explicit_bzero (from OpenBSD).
  2016-12-08 14:56 [PATCH 0/3] explicit_bzero v6 Zack Weinberg
@ 2016-12-08 14:56 ` Zack Weinberg
  2016-12-08 17:14   ` Joseph Myers
  0 siblings, 1 reply; 15+ messages in thread
From: Zack Weinberg @ 2016-12-08 14:56 UTC (permalink / raw)
  To: libc-alpha

explicit_bzero(s, n) is the same as memset(s, 0, n), except that the
compiler is not allowed to delete a call to explicit_bzero even if the
memory pointed to by 's' is dead after the call.  We achieve this effect
by defining it to call memset() and then a second function,

    extern void __glibc_read_memory (const void *, size_t)
       __attribute_noinline__;

which does nothing -- but the compiler is prevented from knowing that
it does nothing, and so the pointer "escapes" and the memory is not
treated as dead.  (Concretely, __glibc_read_memory is forced
out-of-line, defined in a file containing nothing else, and comments
in both string/read_memory.c and string/Makefile document that it must
not be subject to link-time optimization.)

There are two new tests: test-explicit_bzero.c verifies the
visible semantics in the same way as the existing test-bzero.c,
and tst-xbzero-opt.c verifies the not-being-optimized-out property.
The latter is conceptually based on a test written by Matthew Dempsky
for the OpenBSD regression suite.

	* string/explicit_bzero.c, string/read_memory.c: New routines.
	* string/test-explicit_bzero.c, string/tst-xbzero-opt.c: New tests.
	* string/Makefile (routines, strop-tests, tests): Add them.
	* string/test-memset.c: Add ifdeffage for testing explicit_bzero.

	* string/string.h [__USE_MISC]: Declare explicit_bzero and
        __glibc_read_memory.
        * include/string.h: Declare __internal_glibc_read_memory,
        __explicit_bzero, and __internal_explicit_bzero.

	* manual/string.texi: Document explicit_bzero.
	* NEWS: Mention addition of explicit_bzero.

	* string/Versions [GLIBC_2.25]: Add explicit_bzero,
        __explicit_bzero, and __glibc_read_memory.
	* sysdeps/arm/nacl/libc.abilist
	* sysdeps/unix/sysv/linux/aarch64/libc.abilist
	* sysdeps/unix/sysv/linux/alpha/libc.abilist
	* sysdeps/unix/sysv/linux/arm/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/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/powerpc/powerpc32/fpu/libc.abilist
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/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/libc.abilist
	* sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
	* sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
	* sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
	* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
	* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist:
	Add entries for explicit_bzero, __explicit_bzero,
        and __glibc_read_memory.
---
 NEWS                                               |   6 +
 include/string.h                                   |  12 +
 manual/string.texi                                 | 101 +++++++
 string/Makefile                                    |  12 +-
 string/Versions                                    |  10 +
 string/explicit_bzero.c                            |  33 +++
 string/read_memory.c                               |  41 +++
 string/string.h                                    |   9 +
 string/test-explicit_bzero.c                       |  20 ++
 string/test-memset.c                               |  10 +-
 string/tst-xbzero-opt.c                            | 289 +++++++++++++++++++++
 sysdeps/arm/nacl/libc.abilist                      |   3 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist       |   3 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist         |   3 +
 sysdeps/unix/sysv/linux/arm/libc.abilist           |   3 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist          |   3 +
 sysdeps/unix/sysv/linux/i386/libc.abilist          |   3 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist          |   3 +
 sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist |   3 +
 sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist   |   3 +
 sysdeps/unix/sysv/linux/microblaze/libc.abilist    |   3 +
 .../unix/sysv/linux/mips/mips32/fpu/libc.abilist   |   3 +
 .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist |   3 +
 .../unix/sysv/linux/mips/mips64/n32/libc.abilist   |   3 +
 .../unix/sysv/linux/mips/mips64/n64/libc.abilist   |   3 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist         |   3 +
 .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist  |   3 +
 .../linux/powerpc/powerpc32/nofpu/libc.abilist     |   3 +
 .../sysv/linux/powerpc/powerpc64/libc-le.abilist   |   3 +
 .../unix/sysv/linux/powerpc/powerpc64/libc.abilist |   3 +
 sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist  |   3 +
 sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist  |   3 +
 sysdeps/unix/sysv/linux/sh/libc.abilist            |   3 +
 sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist |   3 +
 sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist |   3 +
 .../sysv/linux/tile/tilegx/tilegx32/libc.abilist   |   3 +
 .../sysv/linux/tile/tilegx/tilegx64/libc.abilist   |   3 +
 sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist  |   3 +
 sysdeps/unix/sysv/linux/x86_64/64/libc.abilist     |   3 +
 sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist    |   3 +
 40 files changed, 626 insertions(+), 4 deletions(-)
 create mode 100644 string/explicit_bzero.c
 create mode 100644 string/read_memory.c
 create mode 100644 string/test-explicit_bzero.c
 create mode 100644 string/tst-xbzero-opt.c

diff --git a/NEWS b/NEWS
index 922a5004ff..dc5d05b587 100644
--- a/NEWS
+++ b/NEWS
@@ -71,6 +71,12 @@ Version 2.25
 * The functions strfromd, strfromf, and strfroml, from ISO/IEC TS 18661-1:2014,
   are added to libc.  They convert a floating-point number into string.
 
+* The function explicit_bzero, from OpenBSD, has been added to libc.  It is
+  intended to be used instead of memset() to erase sensitive data after use;
+  the compiler will not optimize out calls to explicit_bzero even if they
+  are "unnecessary" (in the sense that no _correct_ program can observe the
+  effects of the memory clear).
+
 * On ColdFire, MicroBlaze, Nios II and SH3, the float_t type is now defined
   to float instead of double.  This does not affect the ABI of any libraries
   that are part of the GNU C Library, but may affect the ABI of other
diff --git a/include/string.h b/include/string.h
index e145bfdb4c..4185521daa 100644
--- a/include/string.h
+++ b/include/string.h
@@ -100,6 +100,18 @@ extern __typeof (memmem) __memmem;
 libc_hidden_proto (__memmem)
 libc_hidden_proto (__ffs)
 
+/* explicit_bzero is used in libcrypt.  */
+extern __typeof (explicit_bzero) __explicit_bzero;
+extern __typeof (explicit_bzero) __internal_explicit_bzero;
+libc_hidden_proto (__internal_explicit_bzero)
+extern __typeof (__glibc_read_memory) __internal_glibc_read_memory;
+libc_hidden_proto (__internal_glibc_read_memory)
+/* Honor string[23].h overrides when present.  */
+#ifdef explicit_bzero
+# define __explicit_bzero(s,n) explicit_bzero (s,n)
+# define __internal_explicit_bzero(s,n) explicit_bzero (s,n)
+#endif
+
 libc_hidden_builtin_proto (memchr)
 libc_hidden_builtin_proto (memcpy)
 libc_hidden_builtin_proto (mempcpy)
diff --git a/manual/string.texi b/manual/string.texi
index 1986357ee8..faa75ba501 100644
--- a/manual/string.texi
+++ b/manual/string.texi
@@ -34,6 +34,8 @@ too.
 * Search Functions::            Searching for a specific element or substring.
 * Finding Tokens in a String::  Splitting a string into tokens by looking
 				 for delimiters.
+* Erasing Sensitive Data::      Clearing memory which contains sensitive
+                                 data, after it's no longer needed.
 * strfry::                      Function for flash-cooking a string.
 * Trivial Encryption::          Obscuring data.
 * Encode Binary Data::          Encoding and Decoding of Binary Data.
@@ -2404,6 +2406,105 @@ contains no '/' bytes, then "." is returned.  The prototype for this
 function can be found in @file{libgen.h}.
 @end deftypefun
 
+@node Erasing Sensitive Data
+@section Erasing Sensitive Data
+
+Sensitive data, such as cryptographic keys, should be erased from
+memory after use, to reduce the risk that a bug will expose it to the
+outside world.  However, compiler optimizations may determine that an
+erasure operation is ``unnecessary,'' and remove it from the generated
+code, because no @emph{correct} program could access the variable or
+heap object containing the sensitive data after it's deallocated.
+Since erasure is a precaution against bugs, this optimization is
+inappropriate.
+
+The function @code{explicit_bzero} erases a block of memory, and
+guarantees that the compiler will not remove the erasure as
+``unnecessary.''
+
+@smallexample
+@group
+#include <string.h>
+
+extern void encrypt (const char *key, const char *in,
+                     char *out, size_t n);
+extern void genkey (const char *phrase, char *key);
+
+void encrypt_with_phrase (const char *phrase, const char *in,
+                          char *out, size_t n)
+@{
+  char key[16];
+  genkey (phrase, key);
+  encrypt (key, in, out, n);
+  explicit_bzero (key, 16);
+@}
+@end group
+@end smallexample
+
+@noindent
+In this example, if @code{memset}, @code{bzero}, or a hand-written
+loop had been used, the compiler might remove them as ``unnecessary.''
+
+@strong{Warning:} @code{explicit_bzero} does not guarantee that
+sensitive data is @emph{completely} erased from the computer's memory.
+There may be copies in temporary storage areas, such as registers and
+``scratch'' stack space; since these are invisible to the source code,
+a library function cannot erase them.
+
+Also, @code{explicit_bzero} only operates on RAM.  If a sensitive data
+object never needs to have its address taken other than to call
+@code{explicit_bzero}, it might be stored entirely in CPU registers
+@emph{until} the call to @code{explicit_bzero}.  Then it will be
+copied into RAM, the copy will be erased, and the original will remain
+intact.  Data in RAM is more likely to be exposed by a bug than data
+in registers, so this creates a brief window where the data is at
+greater risk of exposure than it would have been if the program didn't
+try to erase it at all.  @Theglibc{}'s implementation of
+@code{explicit_bzero} contains a hack that can prevent the data from
+being copied to RAM in this situation, but it may not always work.
+
+Declaring sensitive variables as @code{volatile} will make both the
+above problems @emph{worse}; a @code{volatile} variable will be stored
+in memory for its entire lifetime, and the compiler will make
+@emph{more} copies of it than it would otherwise have.  Attempting to
+erase a normal variable ``by hand'' through a
+@code{volatile}-qualified pointer doesn't work at all---because the
+variable itself is not @code{volatile}, some compilers will ignore the
+qualification on the pointer and remove the erasure anyway.
+
+Having said all that, in most situations, using @code{explicit_bzero}
+is better than not using it.  At present, the only way to do a more
+thorough job is to write the entire sensitive operation in assembly
+language.  We anticipate that future compilers will recognize calls to
+@code{explicit_bzero} and take appropriate steps to erase all the
+copies of the affected data, whereever they may be.
+
+@comment string.h
+@comment BSD
+@deftypefun void explicit_bzero (void *@var{block}, size_t @var{len})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+
+@code{explicit_bzero} writes zero into @var{len} bytes of memory
+beginning at @var{block}, just as @code{bzero} would.  The zeroes are
+always written, even if the compiler could determine that this is
+``unnecessary'' because no correct program could read them back.
+
+@strong{Note:} The @emph{only} optimization that @code{explicit_bzero}
+disables is removal of ``unnecessary'' writes to memory.  The compiler
+can perform all the other optimizations that it could for a call to
+@code{memset}.  For instance, it may replace the function call with
+inline memory writes, and it may assume that @var{block} cannot be a
+null pointer.
+
+@strong{Portability Note:} This function first appeared in OpenBSD 5.5
+and has not been standardized.  Other systems may provide the same
+functionality under a different name, such as @code{explicit_memset},
+@code{memset_s}, or @code{SecureZeroMemory}.
+
+@Theglibc{} declares this function in @file{string.h}, but on other
+systems it may be in @file{strings.h} instead.
+@end deftypefun
+
 @node strfry
 @section strfry
 
diff --git a/string/Makefile b/string/Makefile
index 69d3f802fb..0b6486e509 100644
--- a/string/Makefile
+++ b/string/Makefile
@@ -41,20 +41,26 @@ routines	:= strcat strchr strcmp strcoll strcpy strcspn		\
 				     addsep replace)			\
 		   envz basename					\
 		   strcoll_l strxfrm_l string-inlines memrchr		\
-		   xpg-strerror strerror_l
+		   xpg-strerror strerror_l explicit_bzero
+
+# Attention future hackers trying to enable link-time optimization for
+# glibc: this file *must not* be subject to LTO.  It is added separately
+# to 'routines' to document this.  See comments in this file for details.
+routines	+= read_memory
 
 strop-tests	:= memchr memcmp memcpy memmove mempcpy memset memccpy	\
 		   stpcpy stpncpy strcat strchr strcmp strcpy strcspn	\
 		   strlen strncmp strncpy strpbrk strrchr strspn memmem	\
 		   strstr strcasestr strnlen strcasecmp strncasecmp	\
-		   strncat rawmemchr strchrnul bcopy bzero memrchr
+		   strncat rawmemchr strchrnul bcopy bzero memrchr	\
+		   explicit_bzero
 tests		:= tester inl-tester noinl-tester testcopy test-ffs	\
 		   tst-strlen stratcliff tst-svc tst-inlcall		\
 		   bug-strncat1 bug-strspn1 bug-strpbrk1 tst-bswap	\
 		   tst-strtok tst-strxfrm bug-strcoll1 tst-strfry	\
 		   bug-strtok1 $(addprefix test-,$(strop-tests))	\
 		   bug-envz1 tst-strxfrm2 tst-endian tst-svc2		\
-		   tst-strtok_r bug-strcoll2 tst-cmp
+		   tst-strtok_r bug-strcoll2 tst-cmp tst-xbzero-opt
 
 xtests = tst-strcoll-overflow
 
diff --git a/string/Versions b/string/Versions
index 475c1fdb64..4f434f371e 100644
--- a/string/Versions
+++ b/string/Versions
@@ -82,4 +82,14 @@ libc {
   }
   GLIBC_2.24 {
   }
+  GLIBC_2.25 {
+    # used by inlines in bits/string2.h and bits/string3.h
+    __glibc_read_memory;
+
+    # used by libcrypt
+    __explicit_bzero;
+
+    # e*
+    explicit_bzero;
+  }
 }
diff --git a/string/explicit_bzero.c b/string/explicit_bzero.c
new file mode 100644
index 0000000000..6c3dc9aedb
--- /dev/null
+++ b/string/explicit_bzero.c
@@ -0,0 +1,33 @@
+/* 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 <features.h>
+#undef __USE_STRING_INLINES
+#define __NO_STRING_INLINES
+#include <string.h>
+
+/* Set LEN bytes of S to 0.  The compiler will not delete a call to
+   this function, even if S is dead after the call.  */
+void
+__internal_explicit_bzero (void *s, size_t len)
+{
+  memset (s, '\0', len);
+  __internal_glibc_read_memory (s, len);
+}
+libc_hidden_def (__internal_explicit_bzero)
+strong_alias (__internal_explicit_bzero, __explicit_bzero)
+weak_alias (__internal_explicit_bzero, explicit_bzero)
diff --git a/string/read_memory.c b/string/read_memory.c
new file mode 100644
index 0000000000..c4a5990c49
--- /dev/null
+++ b/string/read_memory.c
@@ -0,0 +1,41 @@
+/* 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 <string.h>
+
+/* This function is an optimization fence.  It doesn't do anything
+   itself, but calls to it prevent calls to explicit_bzero from being
+   optimized away.  In order to achieve this effect, this function
+   must never, under any circumstances, be inlined or subjected to
+   inter-procedural optimization.  string.h declares this function
+   with attributes that, in conjunction with the no-op asm insert, are
+   sufficient to prevent problems in the current (2016) generation of
+   compilers, but *only if* this file is *not* compiled with -flto.
+   At present, this is not an issue since glibc is never compiled with
+   -flto, but should that ever change, this file must be excepted.
+
+   The 'volatile' below is technically not necessary but is included
+   for explicitness.  */
+
+void
+internal_function
+__internal_glibc_read_memory(const void *s, size_t len)
+{
+  asm volatile ("");
+}
+libc_hidden_def (__internal_glibc_read_memory)
+strong_alias (__internal_glibc_read_memory, __glibc_read_memory)
diff --git a/string/string.h b/string/string.h
index b103e64912..3036679cdd 100644
--- a/string/string.h
+++ b/string/string.h
@@ -453,6 +453,15 @@ extern void bcopy (const void *__src, void *__dest, size_t __n)
 /* Set N bytes of S to 0.  */
 extern void bzero (void *__s, size_t __n) __THROW __nonnull ((1));
 
+/* As bzero, but the compiler will not delete a call to this
+   function, even if S is dead after the call.  */
+extern void explicit_bzero (void *__s, size_t __n) __THROW __nonnull ((1));
+
+/* Optimization fence, used by bits/string2.h and bits/string3.h
+   inline versions of explicit_bzero.  */
+extern void __glibc_read_memory (const void *__s, size_t __n)
+     __THROW __nonnull ((1)) __attribute_noinline__;
+
 /* Compare N bytes of S1 and S2 (same as memcmp).  */
 extern int bcmp (const void *__s1, const void *__s2, size_t __n)
      __THROW __attribute_pure__ __nonnull ((1, 2));
diff --git a/string/test-explicit_bzero.c b/string/test-explicit_bzero.c
new file mode 100644
index 0000000000..5a4543b41a
--- /dev/null
+++ b/string/test-explicit_bzero.c
@@ -0,0 +1,20 @@
+/* Test and measure explicit_bzero.
+   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/>.  */
+#define TEST_EXPLICIT_BZERO
+#define TEST_BZERO
+#include "test-memset.c"
diff --git a/string/test-memset.c b/string/test-memset.c
index fee3bdf37f..7ca4f2076c 100644
--- a/string/test-memset.c
+++ b/string/test-memset.c
@@ -19,7 +19,11 @@
 
 #define TEST_MAIN
 #ifdef TEST_BZERO
-# define TEST_NAME "bzero"
+# ifdef TEST_EXPLICIT_BZERO
+#  define TEST_NAME "explicit_bzero"
+# else
+#  define TEST_NAME "bzero"
+# endif
 #else
 # ifndef WIDE
 #  define TEST_NAME "memset"
@@ -56,7 +60,11 @@ void builtin_bzero (char *, size_t);
 
 IMPL (simple_bzero, 0)
 IMPL (builtin_bzero, 0)
+#ifdef TEST_EXPLICIT_BZERO
+IMPL (explicit_bzero, 1)
+#else
 IMPL (bzero, 1)
+#endif
 
 void
 simple_bzero (char *s, size_t n)
diff --git a/string/tst-xbzero-opt.c b/string/tst-xbzero-opt.c
new file mode 100644
index 0000000000..7d697f4c35
--- /dev/null
+++ b/string/tst-xbzero-opt.c
@@ -0,0 +1,289 @@
+/* Test that explicit_bzero block clears are not optimized out.
+   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/>.  */
+
+/* This test is conceptually based on a test designed by Matthew
+   Dempsky for the OpenBSD regression suite:
+   <openbsd>/src/regress/lib/libc/explicit_bzero/explicit_bzero.c.
+   The basic idea is, we have a function that contains a
+   block-clearing operation (not necessarily explicit_bzero), after
+   which the block is dead, in the compiler-jargon sense.  Execute
+   that function while running on a user-allocated alternative
+   stack. Then we have another pointer to the memory region affected
+   by the block clear -- namely, the original allocation for the
+   alternative stack -- and can find out whether it actually happened.
+
+   The OpenBSD test uses sigaltstack and SIGUSR1 to get onto an
+   alternative stack.  This causes a number of awkward problems; some
+   operating systems (e.g. Solaris and OSX) wipe the signal stack upon
+   returning to the normal stack, there's no way to be sure that other
+   processes running on the same system will not interfere, and the
+   signal stack is very small so it's not safe to call printf there.
+   This implementation instead uses the <ucontext.h> coroutine
+   interface.  The coroutine stack is still too small to safely use
+   printf, but we know the OS won't erase it, so we can do all the
+   checks and printing from the normal stack.  */
+
+#define _GNU_SOURCE 1
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ucontext.h>
+#include <unistd.h>
+
+/* A byte pattern that is unlikely to occur by chance: the first 16
+   prime numbers (OEIS A000040).  */
+static const unsigned char test_pattern[16] =
+{
+  2, 3, 5, 7,  11, 13, 17, 19,  23, 29, 31, 37,  41, 43, 47, 53
+};
+
+/* Immediately after each subtest returns, we call swapcontext to get
+   back onto the main stack.  That call might itself overwrite the
+   test pattern, so we fill a modest-sized buffer with copies of it
+   and check whether any of them survived.  */
+
+#define PATTERN_SIZE (sizeof test_pattern)
+#define PATTERN_REPS 32
+#define TEST_BUFFER_SIZE (PATTERN_SIZE * PATTERN_REPS)
+
+/* There are three subtests, two of which are sanity checks.
+   Each test follows this sequence:
+
+     main                      coroutine
+     ----                      --------
+     advance cur_subtest
+     swap
+                               call setup function
+                                 prepare test buffer
+                                 swap
+     verify that buffer
+     was filled in
+     swap
+                                 possibly clear buffer
+                                 return
+                               swap
+     check buffer again,
+     according to test
+     expectation
+
+   In the "no_clear" case, we don't do anything to the test buffer
+   between preparing it and letting it go out of scope, and we expect
+   to find it.  This confirms that the test buffer does get filled in
+   and we can find it from the stack buffer.  In the "ordinary_clear"
+   case, we clear it using memset, and we expect to find it.  This
+   confirms that the compiler can optimize out block clears in this
+   context; if it can't, the real test might be succeeding for the
+   wrong reason.  Finally, the "explicit_clear" case uses
+   explicit_bzero and expects _not_ to find the test buffer, which is
+   the real test.  */
+
+static ucontext_t uc_main, uc_co;
+
+/* Always check the test buffer immediately after filling it; this
+   makes externally visible side effects depend on the buffer existing
+   and having been filled in.  */
+static void
+prepare_test_buffer (unsigned char *buf)
+{
+  for (unsigned int i = 0; i < PATTERN_REPS; i++)
+    memcpy (buf + i*PATTERN_SIZE, test_pattern, PATTERN_SIZE);
+
+  if (swapcontext (&uc_co, &uc_main))
+    abort ();
+}
+
+static void
+setup_no_clear (void)
+{
+  unsigned char buf[TEST_BUFFER_SIZE];
+  prepare_test_buffer (buf);
+}
+
+static void
+setup_ordinary_clear (void)
+{
+  unsigned char buf[TEST_BUFFER_SIZE];
+  prepare_test_buffer (buf);
+  memset (buf, 0, TEST_BUFFER_SIZE);
+}
+
+static void
+setup_explicit_clear (void)
+{
+  unsigned char buf[TEST_BUFFER_SIZE];
+  prepare_test_buffer (buf);
+  explicit_bzero (buf, TEST_BUFFER_SIZE);
+}
+
+enum test_expectation { EXPECT_NONE, EXPECT_SOME, EXPECT_ALL };
+struct subtest
+{
+  void (*setup_subtest) (void);
+  const char *label;
+  enum test_expectation expected;
+};
+static const struct subtest *cur_subtest;
+
+static const struct subtest subtests[] =
+{
+  { setup_no_clear,       "no clear",       EXPECT_SOME },
+  { setup_ordinary_clear, "ordinary clear", EXPECT_SOME },
+  { setup_explicit_clear, "explicit clear", EXPECT_NONE },
+  { 0,                    0,                -1          }
+};
+
+static void
+test_coroutine (void)
+{
+  while (cur_subtest->setup_subtest)
+    {
+      cur_subtest->setup_subtest ();
+      if (swapcontext (&uc_co, &uc_main))
+	abort ();
+    }
+}
+
+/* All the code above this point runs on the coroutine stack.
+   All the code below this point runs on the main stack.  */
+
+static int test_status;
+static unsigned char *co_stack_buffer;
+static size_t co_stack_size;
+
+static unsigned int
+count_test_patterns (unsigned char *buf, size_t bufsiz)
+{
+  unsigned char *first = memmem (buf, bufsiz, test_pattern, PATTERN_SIZE);
+  if (!first)
+    return 0;
+  unsigned int cnt = 0;
+  for (unsigned int i = 0; i < PATTERN_REPS; i++)
+    {
+      unsigned char *p = first + i*PATTERN_SIZE;
+      if (p + PATTERN_SIZE - buf > bufsiz)
+	break;
+      if (memcmp (p, test_pattern, PATTERN_SIZE) == 0)
+	cnt++;
+    }
+  return cnt;
+}
+
+static void
+check_test_buffer (enum test_expectation expected,
+		   const char *label, const char *stage)
+{
+  unsigned int cnt = count_test_patterns (co_stack_buffer, co_stack_size);
+  switch (expected)
+    {
+    case EXPECT_NONE:
+      if (cnt == 0)
+	printf ("PASS: %s/%s: expected 0 got %d\n", label, stage, cnt);
+      else
+	{
+	  printf ("FAIL: %s/%s: expected 0 got %d\n", label, stage, cnt);
+	  test_status = 1;
+	}
+      break;
+
+    case EXPECT_SOME:
+      if (cnt > 0)
+	printf ("PASS: %s/%s: expected some got %d\n", label, stage, cnt);
+      else
+	{
+	  printf ("FAIL: %s/%s: expected some got 0\n", label, stage);
+	  test_status = 1;
+	}
+      break;
+
+     case EXPECT_ALL:
+      if (cnt == PATTERN_REPS)
+	printf ("PASS: %s/%s: expected %d got %d\n", label, stage,
+		PATTERN_REPS, cnt);
+      else
+	{
+	  printf ("FAIL: %s/%s: expected %d got %d\n", label, stage,
+		  PATTERN_REPS, cnt);
+	  test_status = 1;
+	}
+      break;
+
+    default:
+      printf ("ERROR: %s/%s: invalid value for 'expected' = %d\n",
+	      label, stage, (int)expected);
+      test_status = 1;
+    }
+}
+
+static void
+test_loop (void)
+{
+  cur_subtest = subtests;
+  while (cur_subtest->setup_subtest)
+    {
+      if (swapcontext (&uc_main, &uc_co))
+	abort ();
+      check_test_buffer (EXPECT_ALL, cur_subtest->label, "prepare");
+      if (swapcontext (&uc_main, &uc_co))
+	abort ();
+      check_test_buffer (cur_subtest->expected, cur_subtest->label, "test");
+      cur_subtest++;
+    }
+  /* Terminate the coroutine.  */
+  if (swapcontext (&uc_main, &uc_co))
+    abort ();
+}
+
+static int
+do_test (void)
+{
+  size_t page_alignment = sysconf (_SC_PAGESIZE);
+  if (page_alignment < sizeof (void *))
+    page_alignment = sizeof (void *);
+
+  co_stack_size = SIGSTKSZ + TEST_BUFFER_SIZE;
+  if (co_stack_size < page_alignment * 4)
+    co_stack_size = page_alignment * 4;
+
+  void *p;
+  int err = posix_memalign (&p, page_alignment, co_stack_size);
+  if (err || !p)
+    {
+      printf ("ERROR: allocating alt stack: %s\n", strerror (err));
+      return 2;
+    }
+  co_stack_buffer = p;
+
+  if (getcontext (&uc_co))
+    {
+      printf ("ERROR: allocating coroutine context: %s\n", strerror (err));
+      return 2;
+    }
+  uc_co.uc_stack.ss_sp   = co_stack_buffer;
+  uc_co.uc_stack.ss_size = co_stack_size;
+  uc_co.uc_link          = &uc_main;
+  makecontext (&uc_co, test_coroutine, 0);
+
+  test_loop ();
+  return test_status;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/sysdeps/arm/nacl/libc.abilist b/sysdeps/arm/nacl/libc.abilist
index 807e43d935..b07437496e 100644
--- a/sysdeps/arm/nacl/libc.abilist
+++ b/sysdeps/arm/nacl/libc.abilist
@@ -1843,6 +1843,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 gnu_dev_major F
 GLIBC_2.25 gnu_dev_makedev F
 GLIBC_2.25 gnu_dev_minor F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 77accdf5c1..e26532519f 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2090,6 +2090,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 659b7fcf37..393dd4ca1c 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2001,6 +2001,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
index 8bc979ad7f..b92eccbd5c 100644
--- a/sysdeps/unix/sysv/linux/arm/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
@@ -91,6 +91,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 299b705156..3b1661dc8f 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -1855,6 +1855,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index f00345f673..452e013002 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2013,6 +2013,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index e5fcf88b18..01962345c2 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -1877,6 +1877,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 8f382f680b..d6e0e161b5 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -92,6 +92,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 320b7fef5f..c3a5f245bb 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -1969,6 +1969,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
index 21b14262c6..fa72a0dbf9 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
@@ -2090,6 +2090,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 5c4b596c54..03d3c0c8b6 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -1944,6 +1944,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 001fa6c129..a1c9cd2ee6 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -1942,6 +1942,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 2d870013f7..a8671ba736 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -1940,6 +1940,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index aa1ee66ab7..e71283f99f 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -1935,6 +1935,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 2471d68e87..f92545c8c0 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2131,6 +2131,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 4ba3146902..1748455056 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -1973,6 +1973,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 0557c16130..fa2619950e 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -1978,6 +1978,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
index 821384ebd6..73488a4e8c 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
@@ -2178,6 +2178,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
index c40a3f1cba..ac9cc69777 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
@@ -92,6 +92,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 5b39a60638..933a00a53a 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -1973,6 +1973,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index a9db32f6c2..eb741698bd 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -1874,6 +1874,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
index 294af0a501..37aded2217 100644
--- a/sysdeps/unix/sysv/linux/sh/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
@@ -1859,6 +1859,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 32747bd22d..5b7c54e107 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -1965,6 +1965,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index b0ac4d4472..4854351aea 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -1903,6 +1903,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
index 4d92d81b85..18f61bae76 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
@@ -2097,6 +2097,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
index a68aef7bb7..53a0db1c4e 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
@@ -2097,6 +2097,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
index 4d92d81b85..18f61bae76 100644
--- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
@@ -2097,6 +2097,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index b8623fc59f..d4add67825 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -1854,6 +1854,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index a61d874dfe..18717fa40b 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2097,6 +2097,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
-- 
2.11.0

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/3] New string function explicit_bzero (from OpenBSD).
  2016-11-15 15:55 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Zack Weinberg
@ 2016-11-16 18:38   ` Michael Kerrisk (man-pages)
  0 siblings, 0 replies; 15+ messages in thread
From: Michael Kerrisk (man-pages) @ 2016-11-16 18:38 UTC (permalink / raw)
  To: Zack Weinberg, libc-alpha; +Cc: mtk.manpages, carlos, fweimer

On 11/15/2016 04:55 PM, Zack Weinberg wrote:
> explicit_bzero(s, n) is the same as memset(s, 0, n), except that the
> compiler is not allowed to delete a call to explicit_bzero even if the
> memory pointed to by 's' is dead after the call.  We achieve this effect
> by defining it to call memset() and then a second function,
> 
>     extern void __glibc_read_memory (const void *, size_t)
>        __attribute_noinline__;
> 
> which does nothing -- but the compiler is prevented from knowing that
> it does nothing, and so the pointer "escapes" and the memory is not
> treated as dead.  (Concretely, __glibc_read_memory is forced
> out-of-line, defined in a file containing nothing else, and comments
> in both string/read_memory.c and string/Makefile document that it must
> not be subject to link-time optimization.)
> 
> There are two new tests: test-explicit_bzero.c verifies the
> visible semantics in the same way as the existing test-bzero.c,
> and tst-xbzero-opt.c verifies the not-being-optimized-out property.
> The latter is conceptually based on a test written by Matthew Dempsky
> for the OpenBSD regression suite.

[...]

> diff --git a/manual/string.texi b/manual/string.texi
> index 1986357..3e1bf8d 100644
> --- a/manual/string.texi
> +++ b/manual/string.texi
> @@ -34,6 +34,8 @@ too.
>  * Search Functions::            Searching for a specific element or substring.
>  * Finding Tokens in a String::  Splitting a string into tokens by looking
>  				 for delimiters.
> +* Erasing Sensitive Data::      Clearing memory which contains sensitive
> +                                 data, after it's no longer needed.
>  * strfry::                      Function for flash-cooking a string.
>  * Trivial Encryption::          Obscuring data.
>  * Encode Binary Data::          Encoding and Decoding of Binary Data.
> @@ -2404,6 +2406,128 @@ contains no '/' bytes, then "." is returned.  The prototype for this
>  function can be found in @file{libgen.h}.
>  @end deftypefun
>  
> +@node Erasing Sensitive Data
> +@section Erasing Sensitive Data
> +
> +It is sometimes necessary to make sure that data in memory is erased
> +after use, even if no correct C program could access it again.  For
> +instance, a cryptographic key should not be left in memory after the
> +program is finished using it, because there might be a bug that causes
> +junk data, including the key, to be revealed to the outside world.
> +
> +However, the C compiler knows that no correct program can access data
> +after it's deallocated, so it may delete ``unnecessary'' stores that
> +erase data just before deallocating it.  @code{memset}, @code{bzero},
> +and a manually-written loop are all equally unreliable, and
> +@code{volatile} will not help.
> +
> +For this situation, @theglibc{} provides @code{explicit_bzero}.  It is
> +functionally identical to @code{bzero}, but the C compiler will not
> +treat any use of it as unnecessary.
> +
> +@comment string.h
> +@comment BSD
> +@deftypefun void explicit_bzero (void *@var{block}, size_t @var{len})
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> +
> +@code{explicit_bzero} writes zero into each of the first @var{len}
> +bytes of the object beginning at @var{block}, 

I find that wording ("first len bytes") a little confusing. How about

[[
@code{explicit_bzero} writes zero into each of the @var{len}
bytes starting the location pointed to by @var{block}, 
]]

> just as @code{bzero}
> +would.  The zeroes are always written, even if the object is about to
> +be deallocated.  (Variables on the stack are deallocated when they go
> +out of scope; heap blocks created by @code{malloc} are deallocated
> +when passed to @code{free}.)
> +
> +@smallexample
> +@group
> +#include <string.h>
> +
> +extern void encrypt (const char *key, const char *in,
> +                     char *out, size_t n);
> +extern void genkey (const char *phrase, char *key);
> +
> +void encrypt_with_phrase (const char *phrase, const char *in,
> +                          char *out, size_t n)
> +@{
> +  char key[16];
> +  genkey (phrase, key);
> +  encrypt (key, in, out, n);
> +  explicit_bzero (key, 16);
> +@}
> +@end group
> +@end smallexample
> +
> +@noindent
> +If @code{bzero} or @code{memset} had been used in this function, the C
> +compiler might remove it as unnecessary, but it will not do this with
> +@code{explicit_bzero}.
> +
> +@strong{Warning:} The @emph{only} optimization disabled by

s/@strong{Warning:}/Note:/ ?
(I mean, why does this need to be a _warning_?

> +@code{explicit_bzero} is removal of ``unnecessary'' writes to memory.

Also, I would rewrite that first sentence as:

[[
Note: The @emph{only} optimization that @code{explicit_bzero} disables
is removal of ``unnecessary'' writes to memory.
]]

I find that phrasing a little easier to parse.

> +In all other respects, the compiler is allowed to optimize as it would
> +for @code{memset}.  For instance, it may replace the function call
> +with inline memory writes, and it may deduce that @var{block} cannot
> +be a null pointer.
> +
> +@strong{Warning:} The compiler may make copies of any object, or parts

Maybe make that "Warning" a "Note". Making it a warning tends to scare
the reader about explicit_bzero(), when really this is an issue
that is caused by the compiler.

> +of it, in temporary storage areas, such as registers and ``scratch''
> +stack space.  @code{explicit_bzero} does not erase copies of sensitive
> +data.  At present, there is no way to prevent temporary copies from
> +being made, nor to arrange for them to be erased.  Declaring sensitive
> +variables as @code{volatile} will make the problem @emph{worse}; the
> +compiler needs to make @emph{more} copies of @code{volatile} data in
> +order to operate on it correctly.
> +
> +@strong{Warning:} In some situations, using @code{explicit_bzero} will

So, I think this one really does deserve to be a Warning...


By the way, the name explicit_bzero() does seem odd. "Explicit" 
isn't the right word... But I guess we are stuck with what OpenBSD
gave us.

Cheers,

Michael



> +@emph{cause} creation of an additional copy of sensitive data, and
> +only that copy will be cleared:
> +
> +@smallexample
> +@group
> +#include <string.h>
> +
> +struct key
> +@{
> +  unsigned long long low;
> +  unsigned long long high;
> +@};
> +
> +struct key get_key (void);
> +void use_key (struct key);
> +
> +void
> +with_clear (void)
> +@{
> +  struct key k;
> +  k = get_key ();
> +  use_key (k);
> +  explicit_bzero (&k, sizeof (k));
> +@}
> +@end group
> +@end smallexample
> +
> +@noindent
> +Without the call to @code{explicit_bzero}, @var{k} might not need to
> +be stored in memory: perhaps its value could be returned from
> +@code{get_key} and passed to @code{use_key} using only CPU registers.
> +@code{explicit_bzero} operates on memory, so the compiler has to make
> +a copy of @var{k} in memory for it, and the original in the CPU
> +registers remains intact.  This can occur for any variable whose
> +address is only taken in a call to @code{explicit_bzero}, even if it
> +might seem ``too large'' to be stored in registers.
> +
> +There is currently no way to avoid this problem.  @Theglibc{}'s
> +implementation of @code{explicit_bzero} contains a hack that can
> +sometimes prevent the sensitive data from being copied into memory,
> +but it is not guaranteed to work, and the original in the CPU
> +registers is unaffected.  Again, declaring sensitive variables as
> +@code{volatile} will make the problem worse.
> +
> +@strong{Portability Note:} This function first appeared in OpenBSD 5.5
> +and has not been standardized.  @Theglibc{} declares this function in
> +@file{string.h}, but on other systems it may be in @file{strings.h}
> +instead.
> +@end deftypefun
> +
>  @node strfry
>  @section strfry
>  
> diff --git a/string/Makefile b/string/Makefile
> index 69d3f80..0b6486e 100644
> --- a/string/Makefile
> +++ b/string/Makefile
> @@ -41,20 +41,26 @@ routines	:= strcat strchr strcmp strcoll strcpy strcspn		\
>  				     addsep replace)			\
>  		   envz basename					\
>  		   strcoll_l strxfrm_l string-inlines memrchr		\
> -		   xpg-strerror strerror_l
> +		   xpg-strerror strerror_l explicit_bzero
> +
> +# Attention future hackers trying to enable link-time optimization for
> +# glibc: this file *must not* be subject to LTO.  It is added separately
> +# to 'routines' to document this.  See comments in this file for details.
> +routines	+= read_memory
>  
>  strop-tests	:= memchr memcmp memcpy memmove mempcpy memset memccpy	\
>  		   stpcpy stpncpy strcat strchr strcmp strcpy strcspn	\
>  		   strlen strncmp strncpy strpbrk strrchr strspn memmem	\
>  		   strstr strcasestr strnlen strcasecmp strncasecmp	\
> -		   strncat rawmemchr strchrnul bcopy bzero memrchr
> +		   strncat rawmemchr strchrnul bcopy bzero memrchr	\
> +		   explicit_bzero
>  tests		:= tester inl-tester noinl-tester testcopy test-ffs	\
>  		   tst-strlen stratcliff tst-svc tst-inlcall		\
>  		   bug-strncat1 bug-strspn1 bug-strpbrk1 tst-bswap	\
>  		   tst-strtok tst-strxfrm bug-strcoll1 tst-strfry	\
>  		   bug-strtok1 $(addprefix test-,$(strop-tests))	\
>  		   bug-envz1 tst-strxfrm2 tst-endian tst-svc2		\
> -		   tst-strtok_r bug-strcoll2 tst-cmp
> +		   tst-strtok_r bug-strcoll2 tst-cmp tst-xbzero-opt
>  
>  xtests = tst-strcoll-overflow
>  
> diff --git a/string/Versions b/string/Versions
> index 475c1fd..4f434f3 100644
> --- a/string/Versions
> +++ b/string/Versions
> @@ -82,4 +82,14 @@ libc {
>    }
>    GLIBC_2.24 {
>    }
> +  GLIBC_2.25 {
> +    # used by inlines in bits/string2.h and bits/string3.h
> +    __glibc_read_memory;
> +
> +    # used by libcrypt
> +    __explicit_bzero;
> +
> +    # e*
> +    explicit_bzero;
> +  }
>  }
> diff --git a/string/explicit_bzero.c b/string/explicit_bzero.c
> new file mode 100644
> index 0000000..6c3dc9a
> --- /dev/null
> +++ b/string/explicit_bzero.c
> @@ -0,0 +1,33 @@
> +/* 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 <features.h>
> +#undef __USE_STRING_INLINES
> +#define __NO_STRING_INLINES
> +#include <string.h>
> +
> +/* Set LEN bytes of S to 0.  The compiler will not delete a call to
> +   this function, even if S is dead after the call.  */
> +void
> +__internal_explicit_bzero (void *s, size_t len)
> +{
> +  memset (s, '\0', len);
> +  __internal_glibc_read_memory (s, len);
> +}
> +libc_hidden_def (__internal_explicit_bzero)
> +strong_alias (__internal_explicit_bzero, __explicit_bzero)
> +weak_alias (__internal_explicit_bzero, explicit_bzero)
> diff --git a/string/read_memory.c b/string/read_memory.c
> new file mode 100644
> index 0000000..c4a5990
> --- /dev/null
> +++ b/string/read_memory.c
> @@ -0,0 +1,41 @@
> +/* 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 <string.h>
> +
> +/* This function is an optimization fence.  It doesn't do anything
> +   itself, but calls to it prevent calls to explicit_bzero from being
> +   optimized away.  In order to achieve this effect, this function
> +   must never, under any circumstances, be inlined or subjected to
> +   inter-procedural optimization.  string.h declares this function
> +   with attributes that, in conjunction with the no-op asm insert, are
> +   sufficient to prevent problems in the current (2016) generation of
> +   compilers, but *only if* this file is *not* compiled with -flto.
> +   At present, this is not an issue since glibc is never compiled with
> +   -flto, but should that ever change, this file must be excepted.
> +
> +   The 'volatile' below is technically not necessary but is included
> +   for explicitness.  */
> +
> +void
> +internal_function
> +__internal_glibc_read_memory(const void *s, size_t len)
> +{
> +  asm volatile ("");
> +}
> +libc_hidden_def (__internal_glibc_read_memory)
> +strong_alias (__internal_glibc_read_memory, __glibc_read_memory)
> diff --git a/string/string.h b/string/string.h
> index 57deaa4..682661a 100644
> --- a/string/string.h
> +++ b/string/string.h
> @@ -455,6 +455,15 @@ extern void bcopy (const void *__src, void *__dest, size_t __n)
>  /* Set N bytes of S to 0.  */
>  extern void bzero (void *__s, size_t __n) __THROW __nonnull ((1));
>  
> +/* As bzero, but the compiler will not delete a call to this
> +   function, even if S is dead after the call.  */
> +extern void explicit_bzero (void *__s, size_t __n) __THROW __nonnull ((1));
> +
> +/* Optimization fence, used by bits/string2.h and bits/string3.h
> +   inline versions of explicit_bzero.  */
> +extern void __glibc_read_memory (const void *__s, size_t __n)
> +     __THROW __nonnull ((1)) __attribute_noinline__;
> +
>  /* Compare N bytes of S1 and S2 (same as memcmp).  */
>  extern int bcmp (const void *__s1, const void *__s2, size_t __n)
>       __THROW __attribute_pure__ __nonnull ((1, 2));
> diff --git a/string/test-explicit_bzero.c b/string/test-explicit_bzero.c
> new file mode 100644
> index 0000000..5a4543b
> --- /dev/null
> +++ b/string/test-explicit_bzero.c
> @@ -0,0 +1,20 @@
> +/* Test and measure explicit_bzero.
> +   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/>.  */
> +#define TEST_EXPLICIT_BZERO
> +#define TEST_BZERO
> +#include "test-memset.c"
> diff --git a/string/test-memset.c b/string/test-memset.c
> index fee3bdf..7ca4f20 100644
> --- a/string/test-memset.c
> +++ b/string/test-memset.c
> @@ -19,7 +19,11 @@
>  
>  #define TEST_MAIN
>  #ifdef TEST_BZERO
> -# define TEST_NAME "bzero"
> +# ifdef TEST_EXPLICIT_BZERO
> +#  define TEST_NAME "explicit_bzero"
> +# else
> +#  define TEST_NAME "bzero"
> +# endif
>  #else
>  # ifndef WIDE
>  #  define TEST_NAME "memset"
> @@ -56,7 +60,11 @@ void builtin_bzero (char *, size_t);
>  
>  IMPL (simple_bzero, 0)
>  IMPL (builtin_bzero, 0)
> +#ifdef TEST_EXPLICIT_BZERO
> +IMPL (explicit_bzero, 1)
> +#else
>  IMPL (bzero, 1)
> +#endif
>  
>  void
>  simple_bzero (char *s, size_t n)
> diff --git a/string/tst-xbzero-opt.c b/string/tst-xbzero-opt.c
> new file mode 100644
> index 0000000..da35669
> --- /dev/null
> +++ b/string/tst-xbzero-opt.c
> @@ -0,0 +1,348 @@
> +/* Test that explicit_bzero block clears are not optimized out.
> +   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/>.  */
> +
> +/* This test is conceptually based on a test designed by Matthew
> +   Dempsky for the OpenBSD regression suite:
> +   <openbsd>/src/regress/lib/libc/explicit_bzero/explicit_bzero.c.
> +   The basic idea is, we have a function that contains a
> +   block-clearing operation (not necessarily explicit_bzero), after
> +   which the block is dead, in the compiler-jargon sense.  Execute
> +   that function from a signal handler running on an alternative
> +   signal stack.  Then we have another pointer to the memory region
> +   affected by the block clear -- namely, the sigaltstack buffer --
> +   and can find out whether it actually happened.
> +
> +   The OpenBSD test cautions that some operating systems (e.g. Solaris
> +   and OSX) wipe the signal stack upon returning to the normal stack,
> +   so the test has to happen while still executing on the signal
> +   stack.  This, of course, means that the buffer might be clobbered
> +   by normal stack operations after the function with the block clear
> +   returns (it has to return, so that the block is truly dead).  The
> +   most straightforward way to deal with this is to have a large block
> +   containing several copies of a byte pattern that is unlikely to
> +   occur by chance, and check whether _any_ of them survives.  */
> +
> +#define _GNU_SOURCE 1
> +
> +#include <errno.h>
> +#include <signal.h>
> +#include <stdarg.h>
> +#include <stdbool.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +
> +/* test-skeleton.c unconditionally sets stdout to be unbuffered.
> +   vfprintf allocates a great deal of memory on the stack if called
> +   with an unbuffered FILE*, overflowing the alt-stack.  do_test
> +   therefore resets stdout to fully buffered, and we use this wrapper
> +   exclusively for output.  */
> +static void
> +xprintf (const char *msg, ...)
> +{
> +  va_list ap;
> +  va_start (ap, msg);
> +  vfprintf (stdout, msg, ap);
> +  va_end (ap);
> +  fflush (stdout);
> +}
> +#define printf dont_use_printf_in_this_file
> +
> +/* The "byte pattern that is unlikely to occur by chance": the first
> +   16 prime numbers (OEIS A000040).  */
> +static const unsigned char test_pattern[16] =
> +{
> +  2, 3, 5, 7,  11, 13, 17, 19,  23, 29, 31, 37,  41, 43, 47, 53
> +};
> +
> +#define PATTERN_SIZE (sizeof test_pattern)
> +#define PATTERN_REPS 32
> +#define TEST_BUFFER_SIZE (PATTERN_SIZE * PATTERN_REPS)
> +
> +static void
> +fill_with_test_pattern (unsigned char *buf)
> +{
> +  for (unsigned int i = 0; i < PATTERN_REPS; i++)
> +    memcpy (buf + i*PATTERN_SIZE, test_pattern, PATTERN_SIZE);
> +}
> +
> +static unsigned int
> +count_test_patterns (unsigned char *buf, size_t bufsiz)
> +{
> +  unsigned char *first = memmem (buf, bufsiz, test_pattern, PATTERN_SIZE);
> +  if (!first)
> +    return 0;
> +  unsigned int cnt = 0;
> +  for (unsigned int i = 0; i < PATTERN_REPS; i++)
> +    {
> +      unsigned char *p = first + i*PATTERN_SIZE;
> +      if (p + PATTERN_SIZE - buf > bufsiz)
> +        break;
> +      if (memcmp (p, test_pattern, PATTERN_SIZE) == 0)
> +        cnt++;
> +    }
> +  return cnt;
> +}
> +
> +/* Global test state.  */
> +static int failed_subtests;
> +static bool this_subtest_failed;
> +
> +/* The signal stack is allocated with memalign.  */
> +static unsigned char *signal_stack_buffer;
> +#define SIGNAL_STACK_SIZE (SIGSTKSZ + TEST_BUFFER_SIZE)
> +
> +enum test_expectation { EXPECT_NONE, EXPECT_SOME, EXPECT_ALL };
> +
> +static void
> +check_test_buffer (enum test_expectation expected,
> +                   const char *label, const char *stage)
> +{
> +  unsigned int cnt = count_test_patterns (signal_stack_buffer,
> +                                          SIGNAL_STACK_SIZE);
> +  switch (expected)
> +    {
> +    case EXPECT_NONE:
> +      if (cnt == 0)
> +        xprintf ("PASS: %s/%s: expected 0 got %d\n", label, stage, cnt);
> +      else
> +        {
> +          xprintf ("FAIL: %s/%s: expected 0 got %d\n", label, stage, cnt);
> +          this_subtest_failed = true;
> +          failed_subtests++;
> +        }
> +      break;
> +
> +    case EXPECT_SOME:
> +      if (cnt > 0)
> +        xprintf ("PASS: %s/%s: expected some got %d\n", label, stage, cnt);
> +      else
> +        {
> +          xprintf ("FAIL: %s/%s: expected some got 0\n", label, stage);
> +          this_subtest_failed = true;
> +          failed_subtests++;
> +        }
> +      break;
> +
> +     case EXPECT_ALL:
> +      if (cnt == PATTERN_REPS)
> +        xprintf ("PASS: %s/%s: expected %d got %d\n", label, stage,
> +                 PATTERN_REPS, cnt);
> +      else
> +        {
> +          xprintf ("FAIL: %s/%s: expected %d got %d\n", label, stage,
> +                   PATTERN_REPS, cnt);
> +          this_subtest_failed = true;
> +          failed_subtests++;
> +        }
> +      break;
> +
> +    default:
> +      xprintf ("ERROR: %s/%s: invalid value for 'expected' = %d\n",
> +               label, stage, (int)expected);
> +      this_subtest_failed = true;
> +      failed_subtests++;
> +    }
> +}
> +
> +/* Always check the test buffer immediately after filling it; this
> +   makes externally visible side effects depend on the buffer existing
> +   and having been filled in.  */
> +static void
> +prepare_test_buffer (unsigned char *buf, const char *label)
> +{
> +  fill_with_test_pattern (buf);
> +  check_test_buffer (EXPECT_ALL, label, "prepare");
> +
> +  unsigned char *loc = memmem (signal_stack_buffer, SIGNAL_STACK_SIZE,
> +                               test_pattern, PATTERN_SIZE);
> +  if (loc == buf)
> +      xprintf ("PASS: %s/prepare: expected buffer location %p got %p\n",
> +               label, buf, loc);
> +  else
> +    {
> +      xprintf ("FAIL: %s/prepare: expected buffer location %p got %p\n",
> +               label, buf, loc);
> +      this_subtest_failed = true;
> +      failed_subtests++;
> +    }
> +}
> +
> +/* There are three subtests, two of which are sanity checks.
> +
> +   In the "no_clear" case, we don't do anything to the test buffer
> +   between preparing it and letting it go out of scope, and we expect
> +   to find it.  This confirms that the test buffer does get filled in
> +   and we can find it from the stack buffer.  In the "ordinary_clear"
> +   case, we clear it using memset, and we expect to find it.  This
> +   confirms that the compiler can optimize out block clears in this
> +   context; if it can't, the real test might be succeeding for the
> +   wrong reason.  Finally, the "explicit_clear" case uses
> +   explicit_bzero and expects _not_ to find the test buffer, which is
> +   the real test.  */
> +
> +static void
> +setup_no_clear (void)
> +{
> +  unsigned char buf[TEST_BUFFER_SIZE];
> +  prepare_test_buffer (buf, "no clear");
> +}
> +
> +static void
> +setup_ordinary_clear (void)
> +{
> +  unsigned char buf[TEST_BUFFER_SIZE];
> +  prepare_test_buffer (buf, "ordinary clear");
> +  if (this_subtest_failed)
> +    return;
> +  memset (buf, 0, TEST_BUFFER_SIZE);
> +}
> +
> +static void
> +setup_explicit_clear (void)
> +{
> +  unsigned char buf[TEST_BUFFER_SIZE];
> +  prepare_test_buffer (buf, "explicit clear");
> +  if (this_subtest_failed)
> +    return;
> +  explicit_bzero (buf, TEST_BUFFER_SIZE);
> +}
> +
> +struct subtest
> +{
> +  void (*setup_subtest) (void);
> +  const char *label;
> +  enum test_expectation expected;
> +};
> +
> +static const struct subtest subtests[] =
> +{
> +  { setup_no_clear,       "no clear",       EXPECT_SOME },
> +  { setup_ordinary_clear, "ordinary clear", EXPECT_SOME },
> +  { setup_explicit_clear, "explicit clear", EXPECT_NONE },
> +  { 0,                    0,                -1          }
> +};
> +static const struct subtest *this_subtest;
> +
> +/* This function is called as a signal handler.  The signal is
> +   triggered by a call to sigsuspend, therefore it is safe to do
> +   non-async-signal-safe things within this function.  */
> +static void
> +do_subtest (int signo __attribute__ ((unused)))
> +{
> +  this_subtest->setup_subtest ();
> +  if (!this_subtest_failed)
> +    check_test_buffer (this_subtest->expected, this_subtest->label, "test");
> +}
> +
> +static int
> +do_test (void)
> +{
> +  /* test-skeleton.c unconditionally sets stdout to be unbuffered.
> +     vfprintf allocates a great deal of memory on the stack if called
> +     with an unbuffered FILE*, overflowing the alt-stack.  Reset stdout
> +     to fully buffered to prevent this.  */
> +  if (setvbuf (stdout, 0, _IOFBF, 0))
> +    {
> +      xprintf ("ERROR: restoring stdout buffering: %s\n", strerror (errno));
> +      return 2;
> +    }
> +
> +  size_t page_alignment = sysconf (_SC_PAGESIZE);
> +  if (page_alignment < sizeof (void *))
> +    page_alignment = sizeof (void *);
> +
> +  void *p;
> +  int err = posix_memalign (&p, page_alignment, SIGNAL_STACK_SIZE);
> +  if (err || !p)
> +    {
> +      xprintf ("ERROR: allocating alt stack: %s\n", strerror (err));
> +      return 2;
> +    }
> +  signal_stack_buffer = p;
> +
> +  /* This program will malfunction if it receives SIGUSR1 signals at any
> +     time other than when it's just sent one to itself.  Therefore, keep
> +     it blocked most of the time.  */
> +  sigset_t normal_mask;
> +  sigset_t sigsusp_mask;
> +  sigemptyset (&normal_mask);
> +  sigaddset (&normal_mask, SIGUSR1);
> +  if (sigprocmask (SIG_BLOCK, &normal_mask, &sigsusp_mask))
> +    {
> +      xprintf ("ERROR: block(SIGUSR1): %s\n", strerror (errno));
> +      return 2;
> +    }
> +  /* But ensure that SIGUSR1 is _not_ blocked during calls to
> +     sigsuspend, even if the invoking process blocked it.  */
> +  sigdelset (&sigsusp_mask, SIGUSR1);
> +
> +  stack_t ss;
> +  ss.ss_sp    = signal_stack_buffer;
> +  ss.ss_flags = 0;
> +  ss.ss_size  = SIGNAL_STACK_SIZE;
> +  if (sigaltstack (&ss, 0))
> +    {
> +      xprintf ("ERROR: sigaltstack: %s\n", strerror (errno));
> +      return 2;
> +    }
> +
> +  struct sigaction sa;
> +  sa.sa_mask = normal_mask;
> +  sa.sa_handler = do_subtest;
> +  sa.sa_flags = SA_RESTART | SA_ONSTACK;
> +  if (sigaction (SIGUSR1, &sa, 0))
> +    {
> +      xprintf ("ERROR: sigaction(SIGUSR1): %s\n", strerror (errno));
> +      return 2;
> +    }
> +
> +  /* We use kill instead of raise, because raise may internally modify
> +     the signal mask.  */
> +  pid_t self = getpid ();
> +
> +  this_subtest = subtests;
> +  while (this_subtest->label)
> +    {
> +      this_subtest_failed = false;
> +
> +      /* Completely clear the signal stack between tests, so that junk
> +         from previous tests cannot interfere with the current one.  */
> +      memset (signal_stack_buffer, 0, SIGNAL_STACK_SIZE);
> +
> +      /* Raise SIGUSR1, then call sigsuspend with a mask that unblocks
> +         SIGUSR1.  This will trigger do_subtest to run _once_ on the
> +         alternative stack, at the point of the sigsuspend.  */
> +      if (kill (self, SIGUSR1))
> +        {
> +          xprintf ("ERROR: raise(SIGUSR1): %s\n", strerror (errno));
> +          return 2;
> +        }
> +      /* The return value of sigsuspend is not meaningful.  */
> +      sigsuspend (&sigsusp_mask);
> +
> +      this_subtest++;
> +    }
> +
> +  return failed_subtests ? 1 : 0;
> +}
> +
> +#undef printf
> +#define TEST_FUNCTION do_test ()
> +#include "../test-skeleton.c"
> diff --git a/sysdeps/arm/nacl/libc.abilist b/sysdeps/arm/nacl/libc.abilist
> index 807e43d..b074374 100644
> --- a/sysdeps/arm/nacl/libc.abilist
> +++ b/sysdeps/arm/nacl/libc.abilist
> @@ -1843,6 +1843,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 gnu_dev_major F
>  GLIBC_2.25 gnu_dev_makedev F
>  GLIBC_2.25 gnu_dev_minor F
> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> index 77accdf..e265325 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> @@ -2090,6 +2090,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> index 659b7fc..393dd4c 100644
> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> @@ -2001,6 +2001,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
> index 8bc979a..b92eccb 100644
> --- a/sysdeps/unix/sysv/linux/arm/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
> @@ -91,6 +91,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> index 299b705..3b1661d 100644
> --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> @@ -1855,6 +1855,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
> index f00345f..452e013 100644
> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
> @@ -2013,6 +2013,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> index e5fcf88..0196234 100644
> --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> @@ -1877,6 +1877,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> index 8f382f6..d6e0e16 100644
> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> @@ -92,6 +92,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> index 320b7fe..c3a5f24 100644
> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> @@ -1969,6 +1969,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> index 21b1426..fa72a0d 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> @@ -2090,6 +2090,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> index 5c4b596..03d3c0c 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> @@ -1944,6 +1944,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> index 001fa6c..a1c9cd2 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> @@ -1942,6 +1942,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> index 2d87001..a8671ba 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> @@ -1940,6 +1940,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> index aa1ee66..e71283f 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> @@ -1935,6 +1935,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> index 2471d68..f92545c 100644
> --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> @@ -2131,6 +2131,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> index 4b0cde8..d8427ca 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> @@ -1973,6 +1973,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> index 0557c16..fa26199 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> @@ -1978,6 +1978,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
> index 821384e..73488a4 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
> @@ -2178,6 +2178,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
> index c40a3f1..ac9cc69 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
> @@ -92,6 +92,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> index 5b39a60..933a00a 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> @@ -1973,6 +1973,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> index a9db32f..eb74169 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> @@ -1874,6 +1874,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
> index 294af0a..37aded2 100644
> --- a/sysdeps/unix/sysv/linux/sh/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
> @@ -1859,6 +1859,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> index 32747bd..5b7c54e 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> @@ -1965,6 +1965,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> index b0ac4d4..4854351 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> @@ -1903,6 +1903,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
> index 4d92d81..18f61ba 100644
> --- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
> @@ -2097,6 +2097,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
> index a68aef7..53a0db1 100644
> --- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
> @@ -2097,6 +2097,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
> index 4d92d81..18f61ba 100644
> --- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
> @@ -2097,6 +2097,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> index b8623fc..d4add67 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> @@ -1854,6 +1854,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> index a61d874..18717fa 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> @@ -2097,6 +2097,9 @@ GLIBC_2.23 fts64_set F
>  GLIBC_2.24 GLIBC_2.24 A
>  GLIBC_2.24 quick_exit F
>  GLIBC_2.25 GLIBC_2.25 A
> +GLIBC_2.25 __explicit_bzero F
> +GLIBC_2.25 __glibc_read_memory F
> +GLIBC_2.25 explicit_bzero F
>  GLIBC_2.25 strfromd F
>  GLIBC_2.25 strfromf F
>  GLIBC_2.25 strfroml F
> 

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 1/3] New string function explicit_bzero (from OpenBSD).
  2016-11-15 15:55 [PATCH 0/3] explicit_bzero v5 Zack Weinberg
@ 2016-11-15 15:55 ` Zack Weinberg
  2016-11-16 18:38   ` Michael Kerrisk (man-pages)
  0 siblings, 1 reply; 15+ messages in thread
From: Zack Weinberg @ 2016-11-15 15:55 UTC (permalink / raw)
  To: libc-alpha; +Cc: carlos, fweimer

explicit_bzero(s, n) is the same as memset(s, 0, n), except that the
compiler is not allowed to delete a call to explicit_bzero even if the
memory pointed to by 's' is dead after the call.  We achieve this effect
by defining it to call memset() and then a second function,

    extern void __glibc_read_memory (const void *, size_t)
       __attribute_noinline__;

which does nothing -- but the compiler is prevented from knowing that
it does nothing, and so the pointer "escapes" and the memory is not
treated as dead.  (Concretely, __glibc_read_memory is forced
out-of-line, defined in a file containing nothing else, and comments
in both string/read_memory.c and string/Makefile document that it must
not be subject to link-time optimization.)

There are two new tests: test-explicit_bzero.c verifies the
visible semantics in the same way as the existing test-bzero.c,
and tst-xbzero-opt.c verifies the not-being-optimized-out property.
The latter is conceptually based on a test written by Matthew Dempsky
for the OpenBSD regression suite.

	* string/explicit_bzero.c, string/read_memory.c: New routines.
	* string/test-explicit_bzero.c, string/tst-xbzero-opt.c: New tests.
	* string/Makefile (routines, strop-tests, tests): Add them.
	* string/test-memset.c: Add ifdeffage for testing explicit_bzero.

	* string/string.h [__USE_MISC]: Declare explicit_bzero and
        __glibc_read_memory.
        * include/string.h: Declare __internal_glibc_read_memory,
        __explicit_bzero, and __internal_explicit_bzero.

	* manual/string.texi: Document explicit_bzero.

	* string/Versions [GLIBC_2.25]: Add explicit_bzero,
        __explicit_bzero, and __glibc_read_memory.
	* sysdeps/arm/nacl/libc.abilist
	* sysdeps/unix/sysv/linux/aarch64/libc.abilist
	* sysdeps/unix/sysv/linux/alpha/libc.abilist
	* sysdeps/unix/sysv/linux/arm/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/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/powerpc/powerpc32/fpu/libc.abilist
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/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/libc.abilist
	* sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
	* sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
	* sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
	* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
	* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist:
	Add entries for explicit_bzero, __explicit_bzero,
        and __glibc_read_memory.
---
 include/string.h                                   |  12 +
 manual/string.texi                                 | 124 ++++++++
 string/Makefile                                    |  12 +-
 string/Versions                                    |  10 +
 string/explicit_bzero.c                            |  33 ++
 string/read_memory.c                               |  41 +++
 string/string.h                                    |   9 +
 string/test-explicit_bzero.c                       |  20 ++
 string/test-memset.c                               |  10 +-
 string/tst-xbzero-opt.c                            | 348 +++++++++++++++++++++
 sysdeps/arm/nacl/libc.abilist                      |   3 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist       |   3 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist         |   3 +
 sysdeps/unix/sysv/linux/arm/libc.abilist           |   3 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist          |   3 +
 sysdeps/unix/sysv/linux/i386/libc.abilist          |   3 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist          |   3 +
 sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist |   3 +
 sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist   |   3 +
 sysdeps/unix/sysv/linux/microblaze/libc.abilist    |   3 +
 .../unix/sysv/linux/mips/mips32/fpu/libc.abilist   |   3 +
 .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist |   3 +
 .../unix/sysv/linux/mips/mips64/n32/libc.abilist   |   3 +
 .../unix/sysv/linux/mips/mips64/n64/libc.abilist   |   3 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist         |   3 +
 .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist  |   3 +
 .../linux/powerpc/powerpc32/nofpu/libc.abilist     |   3 +
 .../sysv/linux/powerpc/powerpc64/libc-le.abilist   |   3 +
 .../unix/sysv/linux/powerpc/powerpc64/libc.abilist |   3 +
 sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist  |   3 +
 sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist  |   3 +
 sysdeps/unix/sysv/linux/sh/libc.abilist            |   3 +
 sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist |   3 +
 sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist |   3 +
 .../sysv/linux/tile/tilegx/tilegx32/libc.abilist   |   3 +
 .../sysv/linux/tile/tilegx/tilegx64/libc.abilist   |   3 +
 sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist  |   3 +
 sysdeps/unix/sysv/linux/x86_64/64/libc.abilist     |   3 +
 sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist    |   3 +
 39 files changed, 702 insertions(+), 4 deletions(-)
 create mode 100644 string/explicit_bzero.c
 create mode 100644 string/read_memory.c
 create mode 100644 string/test-explicit_bzero.c
 create mode 100644 string/tst-xbzero-opt.c

diff --git a/include/string.h b/include/string.h
index e145bfd..4185521 100644
--- a/include/string.h
+++ b/include/string.h
@@ -100,6 +100,18 @@ extern __typeof (memmem) __memmem;
 libc_hidden_proto (__memmem)
 libc_hidden_proto (__ffs)
 
+/* explicit_bzero is used in libcrypt.  */
+extern __typeof (explicit_bzero) __explicit_bzero;
+extern __typeof (explicit_bzero) __internal_explicit_bzero;
+libc_hidden_proto (__internal_explicit_bzero)
+extern __typeof (__glibc_read_memory) __internal_glibc_read_memory;
+libc_hidden_proto (__internal_glibc_read_memory)
+/* Honor string[23].h overrides when present.  */
+#ifdef explicit_bzero
+# define __explicit_bzero(s,n) explicit_bzero (s,n)
+# define __internal_explicit_bzero(s,n) explicit_bzero (s,n)
+#endif
+
 libc_hidden_builtin_proto (memchr)
 libc_hidden_builtin_proto (memcpy)
 libc_hidden_builtin_proto (mempcpy)
diff --git a/manual/string.texi b/manual/string.texi
index 1986357..3e1bf8d 100644
--- a/manual/string.texi
+++ b/manual/string.texi
@@ -34,6 +34,8 @@ too.
 * Search Functions::            Searching for a specific element or substring.
 * Finding Tokens in a String::  Splitting a string into tokens by looking
 				 for delimiters.
+* Erasing Sensitive Data::      Clearing memory which contains sensitive
+                                 data, after it's no longer needed.
 * strfry::                      Function for flash-cooking a string.
 * Trivial Encryption::          Obscuring data.
 * Encode Binary Data::          Encoding and Decoding of Binary Data.
@@ -2404,6 +2406,128 @@ contains no '/' bytes, then "." is returned.  The prototype for this
 function can be found in @file{libgen.h}.
 @end deftypefun
 
+@node Erasing Sensitive Data
+@section Erasing Sensitive Data
+
+It is sometimes necessary to make sure that data in memory is erased
+after use, even if no correct C program could access it again.  For
+instance, a cryptographic key should not be left in memory after the
+program is finished using it, because there might be a bug that causes
+junk data, including the key, to be revealed to the outside world.
+
+However, the C compiler knows that no correct program can access data
+after it's deallocated, so it may delete ``unnecessary'' stores that
+erase data just before deallocating it.  @code{memset}, @code{bzero},
+and a manually-written loop are all equally unreliable, and
+@code{volatile} will not help.
+
+For this situation, @theglibc{} provides @code{explicit_bzero}.  It is
+functionally identical to @code{bzero}, but the C compiler will not
+treat any use of it as unnecessary.
+
+@comment string.h
+@comment BSD
+@deftypefun void explicit_bzero (void *@var{block}, size_t @var{len})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+
+@code{explicit_bzero} writes zero into each of the first @var{len}
+bytes of the object beginning at @var{block}, just as @code{bzero}
+would.  The zeroes are always written, even if the object is about to
+be deallocated.  (Variables on the stack are deallocated when they go
+out of scope; heap blocks created by @code{malloc} are deallocated
+when passed to @code{free}.)
+
+@smallexample
+@group
+#include <string.h>
+
+extern void encrypt (const char *key, const char *in,
+                     char *out, size_t n);
+extern void genkey (const char *phrase, char *key);
+
+void encrypt_with_phrase (const char *phrase, const char *in,
+                          char *out, size_t n)
+@{
+  char key[16];
+  genkey (phrase, key);
+  encrypt (key, in, out, n);
+  explicit_bzero (key, 16);
+@}
+@end group
+@end smallexample
+
+@noindent
+If @code{bzero} or @code{memset} had been used in this function, the C
+compiler might remove it as unnecessary, but it will not do this with
+@code{explicit_bzero}.
+
+@strong{Warning:} The @emph{only} optimization disabled by
+@code{explicit_bzero} is removal of ``unnecessary'' writes to memory.
+In all other respects, the compiler is allowed to optimize as it would
+for @code{memset}.  For instance, it may replace the function call
+with inline memory writes, and it may deduce that @var{block} cannot
+be a null pointer.
+
+@strong{Warning:} The compiler may make copies of any object, or parts
+of it, in temporary storage areas, such as registers and ``scratch''
+stack space.  @code{explicit_bzero} does not erase copies of sensitive
+data.  At present, there is no way to prevent temporary copies from
+being made, nor to arrange for them to be erased.  Declaring sensitive
+variables as @code{volatile} will make the problem @emph{worse}; the
+compiler needs to make @emph{more} copies of @code{volatile} data in
+order to operate on it correctly.
+
+@strong{Warning:} In some situations, using @code{explicit_bzero} will
+@emph{cause} creation of an additional copy of sensitive data, and
+only that copy will be cleared:
+
+@smallexample
+@group
+#include <string.h>
+
+struct key
+@{
+  unsigned long long low;
+  unsigned long long high;
+@};
+
+struct key get_key (void);
+void use_key (struct key);
+
+void
+with_clear (void)
+@{
+  struct key k;
+  k = get_key ();
+  use_key (k);
+  explicit_bzero (&k, sizeof (k));
+@}
+@end group
+@end smallexample
+
+@noindent
+Without the call to @code{explicit_bzero}, @var{k} might not need to
+be stored in memory: perhaps its value could be returned from
+@code{get_key} and passed to @code{use_key} using only CPU registers.
+@code{explicit_bzero} operates on memory, so the compiler has to make
+a copy of @var{k} in memory for it, and the original in the CPU
+registers remains intact.  This can occur for any variable whose
+address is only taken in a call to @code{explicit_bzero}, even if it
+might seem ``too large'' to be stored in registers.
+
+There is currently no way to avoid this problem.  @Theglibc{}'s
+implementation of @code{explicit_bzero} contains a hack that can
+sometimes prevent the sensitive data from being copied into memory,
+but it is not guaranteed to work, and the original in the CPU
+registers is unaffected.  Again, declaring sensitive variables as
+@code{volatile} will make the problem worse.
+
+@strong{Portability Note:} This function first appeared in OpenBSD 5.5
+and has not been standardized.  @Theglibc{} declares this function in
+@file{string.h}, but on other systems it may be in @file{strings.h}
+instead.
+@end deftypefun
+
 @node strfry
 @section strfry
 
diff --git a/string/Makefile b/string/Makefile
index 69d3f80..0b6486e 100644
--- a/string/Makefile
+++ b/string/Makefile
@@ -41,20 +41,26 @@ routines	:= strcat strchr strcmp strcoll strcpy strcspn		\
 				     addsep replace)			\
 		   envz basename					\
 		   strcoll_l strxfrm_l string-inlines memrchr		\
-		   xpg-strerror strerror_l
+		   xpg-strerror strerror_l explicit_bzero
+
+# Attention future hackers trying to enable link-time optimization for
+# glibc: this file *must not* be subject to LTO.  It is added separately
+# to 'routines' to document this.  See comments in this file for details.
+routines	+= read_memory
 
 strop-tests	:= memchr memcmp memcpy memmove mempcpy memset memccpy	\
 		   stpcpy stpncpy strcat strchr strcmp strcpy strcspn	\
 		   strlen strncmp strncpy strpbrk strrchr strspn memmem	\
 		   strstr strcasestr strnlen strcasecmp strncasecmp	\
-		   strncat rawmemchr strchrnul bcopy bzero memrchr
+		   strncat rawmemchr strchrnul bcopy bzero memrchr	\
+		   explicit_bzero
 tests		:= tester inl-tester noinl-tester testcopy test-ffs	\
 		   tst-strlen stratcliff tst-svc tst-inlcall		\
 		   bug-strncat1 bug-strspn1 bug-strpbrk1 tst-bswap	\
 		   tst-strtok tst-strxfrm bug-strcoll1 tst-strfry	\
 		   bug-strtok1 $(addprefix test-,$(strop-tests))	\
 		   bug-envz1 tst-strxfrm2 tst-endian tst-svc2		\
-		   tst-strtok_r bug-strcoll2 tst-cmp
+		   tst-strtok_r bug-strcoll2 tst-cmp tst-xbzero-opt
 
 xtests = tst-strcoll-overflow
 
diff --git a/string/Versions b/string/Versions
index 475c1fd..4f434f3 100644
--- a/string/Versions
+++ b/string/Versions
@@ -82,4 +82,14 @@ libc {
   }
   GLIBC_2.24 {
   }
+  GLIBC_2.25 {
+    # used by inlines in bits/string2.h and bits/string3.h
+    __glibc_read_memory;
+
+    # used by libcrypt
+    __explicit_bzero;
+
+    # e*
+    explicit_bzero;
+  }
 }
diff --git a/string/explicit_bzero.c b/string/explicit_bzero.c
new file mode 100644
index 0000000..6c3dc9a
--- /dev/null
+++ b/string/explicit_bzero.c
@@ -0,0 +1,33 @@
+/* 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 <features.h>
+#undef __USE_STRING_INLINES
+#define __NO_STRING_INLINES
+#include <string.h>
+
+/* Set LEN bytes of S to 0.  The compiler will not delete a call to
+   this function, even if S is dead after the call.  */
+void
+__internal_explicit_bzero (void *s, size_t len)
+{
+  memset (s, '\0', len);
+  __internal_glibc_read_memory (s, len);
+}
+libc_hidden_def (__internal_explicit_bzero)
+strong_alias (__internal_explicit_bzero, __explicit_bzero)
+weak_alias (__internal_explicit_bzero, explicit_bzero)
diff --git a/string/read_memory.c b/string/read_memory.c
new file mode 100644
index 0000000..c4a5990
--- /dev/null
+++ b/string/read_memory.c
@@ -0,0 +1,41 @@
+/* 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 <string.h>
+
+/* This function is an optimization fence.  It doesn't do anything
+   itself, but calls to it prevent calls to explicit_bzero from being
+   optimized away.  In order to achieve this effect, this function
+   must never, under any circumstances, be inlined or subjected to
+   inter-procedural optimization.  string.h declares this function
+   with attributes that, in conjunction with the no-op asm insert, are
+   sufficient to prevent problems in the current (2016) generation of
+   compilers, but *only if* this file is *not* compiled with -flto.
+   At present, this is not an issue since glibc is never compiled with
+   -flto, but should that ever change, this file must be excepted.
+
+   The 'volatile' below is technically not necessary but is included
+   for explicitness.  */
+
+void
+internal_function
+__internal_glibc_read_memory(const void *s, size_t len)
+{
+  asm volatile ("");
+}
+libc_hidden_def (__internal_glibc_read_memory)
+strong_alias (__internal_glibc_read_memory, __glibc_read_memory)
diff --git a/string/string.h b/string/string.h
index 57deaa4..682661a 100644
--- a/string/string.h
+++ b/string/string.h
@@ -455,6 +455,15 @@ extern void bcopy (const void *__src, void *__dest, size_t __n)
 /* Set N bytes of S to 0.  */
 extern void bzero (void *__s, size_t __n) __THROW __nonnull ((1));
 
+/* As bzero, but the compiler will not delete a call to this
+   function, even if S is dead after the call.  */
+extern void explicit_bzero (void *__s, size_t __n) __THROW __nonnull ((1));
+
+/* Optimization fence, used by bits/string2.h and bits/string3.h
+   inline versions of explicit_bzero.  */
+extern void __glibc_read_memory (const void *__s, size_t __n)
+     __THROW __nonnull ((1)) __attribute_noinline__;
+
 /* Compare N bytes of S1 and S2 (same as memcmp).  */
 extern int bcmp (const void *__s1, const void *__s2, size_t __n)
      __THROW __attribute_pure__ __nonnull ((1, 2));
diff --git a/string/test-explicit_bzero.c b/string/test-explicit_bzero.c
new file mode 100644
index 0000000..5a4543b
--- /dev/null
+++ b/string/test-explicit_bzero.c
@@ -0,0 +1,20 @@
+/* Test and measure explicit_bzero.
+   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/>.  */
+#define TEST_EXPLICIT_BZERO
+#define TEST_BZERO
+#include "test-memset.c"
diff --git a/string/test-memset.c b/string/test-memset.c
index fee3bdf..7ca4f20 100644
--- a/string/test-memset.c
+++ b/string/test-memset.c
@@ -19,7 +19,11 @@
 
 #define TEST_MAIN
 #ifdef TEST_BZERO
-# define TEST_NAME "bzero"
+# ifdef TEST_EXPLICIT_BZERO
+#  define TEST_NAME "explicit_bzero"
+# else
+#  define TEST_NAME "bzero"
+# endif
 #else
 # ifndef WIDE
 #  define TEST_NAME "memset"
@@ -56,7 +60,11 @@ void builtin_bzero (char *, size_t);
 
 IMPL (simple_bzero, 0)
 IMPL (builtin_bzero, 0)
+#ifdef TEST_EXPLICIT_BZERO
+IMPL (explicit_bzero, 1)
+#else
 IMPL (bzero, 1)
+#endif
 
 void
 simple_bzero (char *s, size_t n)
diff --git a/string/tst-xbzero-opt.c b/string/tst-xbzero-opt.c
new file mode 100644
index 0000000..da35669
--- /dev/null
+++ b/string/tst-xbzero-opt.c
@@ -0,0 +1,348 @@
+/* Test that explicit_bzero block clears are not optimized out.
+   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/>.  */
+
+/* This test is conceptually based on a test designed by Matthew
+   Dempsky for the OpenBSD regression suite:
+   <openbsd>/src/regress/lib/libc/explicit_bzero/explicit_bzero.c.
+   The basic idea is, we have a function that contains a
+   block-clearing operation (not necessarily explicit_bzero), after
+   which the block is dead, in the compiler-jargon sense.  Execute
+   that function from a signal handler running on an alternative
+   signal stack.  Then we have another pointer to the memory region
+   affected by the block clear -- namely, the sigaltstack buffer --
+   and can find out whether it actually happened.
+
+   The OpenBSD test cautions that some operating systems (e.g. Solaris
+   and OSX) wipe the signal stack upon returning to the normal stack,
+   so the test has to happen while still executing on the signal
+   stack.  This, of course, means that the buffer might be clobbered
+   by normal stack operations after the function with the block clear
+   returns (it has to return, so that the block is truly dead).  The
+   most straightforward way to deal with this is to have a large block
+   containing several copies of a byte pattern that is unlikely to
+   occur by chance, and check whether _any_ of them survives.  */
+
+#define _GNU_SOURCE 1
+
+#include <errno.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* test-skeleton.c unconditionally sets stdout to be unbuffered.
+   vfprintf allocates a great deal of memory on the stack if called
+   with an unbuffered FILE*, overflowing the alt-stack.  do_test
+   therefore resets stdout to fully buffered, and we use this wrapper
+   exclusively for output.  */
+static void
+xprintf (const char *msg, ...)
+{
+  va_list ap;
+  va_start (ap, msg);
+  vfprintf (stdout, msg, ap);
+  va_end (ap);
+  fflush (stdout);
+}
+#define printf dont_use_printf_in_this_file
+
+/* The "byte pattern that is unlikely to occur by chance": the first
+   16 prime numbers (OEIS A000040).  */
+static const unsigned char test_pattern[16] =
+{
+  2, 3, 5, 7,  11, 13, 17, 19,  23, 29, 31, 37,  41, 43, 47, 53
+};
+
+#define PATTERN_SIZE (sizeof test_pattern)
+#define PATTERN_REPS 32
+#define TEST_BUFFER_SIZE (PATTERN_SIZE * PATTERN_REPS)
+
+static void
+fill_with_test_pattern (unsigned char *buf)
+{
+  for (unsigned int i = 0; i < PATTERN_REPS; i++)
+    memcpy (buf + i*PATTERN_SIZE, test_pattern, PATTERN_SIZE);
+}
+
+static unsigned int
+count_test_patterns (unsigned char *buf, size_t bufsiz)
+{
+  unsigned char *first = memmem (buf, bufsiz, test_pattern, PATTERN_SIZE);
+  if (!first)
+    return 0;
+  unsigned int cnt = 0;
+  for (unsigned int i = 0; i < PATTERN_REPS; i++)
+    {
+      unsigned char *p = first + i*PATTERN_SIZE;
+      if (p + PATTERN_SIZE - buf > bufsiz)
+        break;
+      if (memcmp (p, test_pattern, PATTERN_SIZE) == 0)
+        cnt++;
+    }
+  return cnt;
+}
+
+/* Global test state.  */
+static int failed_subtests;
+static bool this_subtest_failed;
+
+/* The signal stack is allocated with memalign.  */
+static unsigned char *signal_stack_buffer;
+#define SIGNAL_STACK_SIZE (SIGSTKSZ + TEST_BUFFER_SIZE)
+
+enum test_expectation { EXPECT_NONE, EXPECT_SOME, EXPECT_ALL };
+
+static void
+check_test_buffer (enum test_expectation expected,
+                   const char *label, const char *stage)
+{
+  unsigned int cnt = count_test_patterns (signal_stack_buffer,
+                                          SIGNAL_STACK_SIZE);
+  switch (expected)
+    {
+    case EXPECT_NONE:
+      if (cnt == 0)
+        xprintf ("PASS: %s/%s: expected 0 got %d\n", label, stage, cnt);
+      else
+        {
+          xprintf ("FAIL: %s/%s: expected 0 got %d\n", label, stage, cnt);
+          this_subtest_failed = true;
+          failed_subtests++;
+        }
+      break;
+
+    case EXPECT_SOME:
+      if (cnt > 0)
+        xprintf ("PASS: %s/%s: expected some got %d\n", label, stage, cnt);
+      else
+        {
+          xprintf ("FAIL: %s/%s: expected some got 0\n", label, stage);
+          this_subtest_failed = true;
+          failed_subtests++;
+        }
+      break;
+
+     case EXPECT_ALL:
+      if (cnt == PATTERN_REPS)
+        xprintf ("PASS: %s/%s: expected %d got %d\n", label, stage,
+                 PATTERN_REPS, cnt);
+      else
+        {
+          xprintf ("FAIL: %s/%s: expected %d got %d\n", label, stage,
+                   PATTERN_REPS, cnt);
+          this_subtest_failed = true;
+          failed_subtests++;
+        }
+      break;
+
+    default:
+      xprintf ("ERROR: %s/%s: invalid value for 'expected' = %d\n",
+               label, stage, (int)expected);
+      this_subtest_failed = true;
+      failed_subtests++;
+    }
+}
+
+/* Always check the test buffer immediately after filling it; this
+   makes externally visible side effects depend on the buffer existing
+   and having been filled in.  */
+static void
+prepare_test_buffer (unsigned char *buf, const char *label)
+{
+  fill_with_test_pattern (buf);
+  check_test_buffer (EXPECT_ALL, label, "prepare");
+
+  unsigned char *loc = memmem (signal_stack_buffer, SIGNAL_STACK_SIZE,
+                               test_pattern, PATTERN_SIZE);
+  if (loc == buf)
+      xprintf ("PASS: %s/prepare: expected buffer location %p got %p\n",
+               label, buf, loc);
+  else
+    {
+      xprintf ("FAIL: %s/prepare: expected buffer location %p got %p\n",
+               label, buf, loc);
+      this_subtest_failed = true;
+      failed_subtests++;
+    }
+}
+
+/* There are three subtests, two of which are sanity checks.
+
+   In the "no_clear" case, we don't do anything to the test buffer
+   between preparing it and letting it go out of scope, and we expect
+   to find it.  This confirms that the test buffer does get filled in
+   and we can find it from the stack buffer.  In the "ordinary_clear"
+   case, we clear it using memset, and we expect to find it.  This
+   confirms that the compiler can optimize out block clears in this
+   context; if it can't, the real test might be succeeding for the
+   wrong reason.  Finally, the "explicit_clear" case uses
+   explicit_bzero and expects _not_ to find the test buffer, which is
+   the real test.  */
+
+static void
+setup_no_clear (void)
+{
+  unsigned char buf[TEST_BUFFER_SIZE];
+  prepare_test_buffer (buf, "no clear");
+}
+
+static void
+setup_ordinary_clear (void)
+{
+  unsigned char buf[TEST_BUFFER_SIZE];
+  prepare_test_buffer (buf, "ordinary clear");
+  if (this_subtest_failed)
+    return;
+  memset (buf, 0, TEST_BUFFER_SIZE);
+}
+
+static void
+setup_explicit_clear (void)
+{
+  unsigned char buf[TEST_BUFFER_SIZE];
+  prepare_test_buffer (buf, "explicit clear");
+  if (this_subtest_failed)
+    return;
+  explicit_bzero (buf, TEST_BUFFER_SIZE);
+}
+
+struct subtest
+{
+  void (*setup_subtest) (void);
+  const char *label;
+  enum test_expectation expected;
+};
+
+static const struct subtest subtests[] =
+{
+  { setup_no_clear,       "no clear",       EXPECT_SOME },
+  { setup_ordinary_clear, "ordinary clear", EXPECT_SOME },
+  { setup_explicit_clear, "explicit clear", EXPECT_NONE },
+  { 0,                    0,                -1          }
+};
+static const struct subtest *this_subtest;
+
+/* This function is called as a signal handler.  The signal is
+   triggered by a call to sigsuspend, therefore it is safe to do
+   non-async-signal-safe things within this function.  */
+static void
+do_subtest (int signo __attribute__ ((unused)))
+{
+  this_subtest->setup_subtest ();
+  if (!this_subtest_failed)
+    check_test_buffer (this_subtest->expected, this_subtest->label, "test");
+}
+
+static int
+do_test (void)
+{
+  /* test-skeleton.c unconditionally sets stdout to be unbuffered.
+     vfprintf allocates a great deal of memory on the stack if called
+     with an unbuffered FILE*, overflowing the alt-stack.  Reset stdout
+     to fully buffered to prevent this.  */
+  if (setvbuf (stdout, 0, _IOFBF, 0))
+    {
+      xprintf ("ERROR: restoring stdout buffering: %s\n", strerror (errno));
+      return 2;
+    }
+
+  size_t page_alignment = sysconf (_SC_PAGESIZE);
+  if (page_alignment < sizeof (void *))
+    page_alignment = sizeof (void *);
+
+  void *p;
+  int err = posix_memalign (&p, page_alignment, SIGNAL_STACK_SIZE);
+  if (err || !p)
+    {
+      xprintf ("ERROR: allocating alt stack: %s\n", strerror (err));
+      return 2;
+    }
+  signal_stack_buffer = p;
+
+  /* This program will malfunction if it receives SIGUSR1 signals at any
+     time other than when it's just sent one to itself.  Therefore, keep
+     it blocked most of the time.  */
+  sigset_t normal_mask;
+  sigset_t sigsusp_mask;
+  sigemptyset (&normal_mask);
+  sigaddset (&normal_mask, SIGUSR1);
+  if (sigprocmask (SIG_BLOCK, &normal_mask, &sigsusp_mask))
+    {
+      xprintf ("ERROR: block(SIGUSR1): %s\n", strerror (errno));
+      return 2;
+    }
+  /* But ensure that SIGUSR1 is _not_ blocked during calls to
+     sigsuspend, even if the invoking process blocked it.  */
+  sigdelset (&sigsusp_mask, SIGUSR1);
+
+  stack_t ss;
+  ss.ss_sp    = signal_stack_buffer;
+  ss.ss_flags = 0;
+  ss.ss_size  = SIGNAL_STACK_SIZE;
+  if (sigaltstack (&ss, 0))
+    {
+      xprintf ("ERROR: sigaltstack: %s\n", strerror (errno));
+      return 2;
+    }
+
+  struct sigaction sa;
+  sa.sa_mask = normal_mask;
+  sa.sa_handler = do_subtest;
+  sa.sa_flags = SA_RESTART | SA_ONSTACK;
+  if (sigaction (SIGUSR1, &sa, 0))
+    {
+      xprintf ("ERROR: sigaction(SIGUSR1): %s\n", strerror (errno));
+      return 2;
+    }
+
+  /* We use kill instead of raise, because raise may internally modify
+     the signal mask.  */
+  pid_t self = getpid ();
+
+  this_subtest = subtests;
+  while (this_subtest->label)
+    {
+      this_subtest_failed = false;
+
+      /* Completely clear the signal stack between tests, so that junk
+         from previous tests cannot interfere with the current one.  */
+      memset (signal_stack_buffer, 0, SIGNAL_STACK_SIZE);
+
+      /* Raise SIGUSR1, then call sigsuspend with a mask that unblocks
+         SIGUSR1.  This will trigger do_subtest to run _once_ on the
+         alternative stack, at the point of the sigsuspend.  */
+      if (kill (self, SIGUSR1))
+        {
+          xprintf ("ERROR: raise(SIGUSR1): %s\n", strerror (errno));
+          return 2;
+        }
+      /* The return value of sigsuspend is not meaningful.  */
+      sigsuspend (&sigsusp_mask);
+
+      this_subtest++;
+    }
+
+  return failed_subtests ? 1 : 0;
+}
+
+#undef printf
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/sysdeps/arm/nacl/libc.abilist b/sysdeps/arm/nacl/libc.abilist
index 807e43d..b074374 100644
--- a/sysdeps/arm/nacl/libc.abilist
+++ b/sysdeps/arm/nacl/libc.abilist
@@ -1843,6 +1843,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 gnu_dev_major F
 GLIBC_2.25 gnu_dev_makedev F
 GLIBC_2.25 gnu_dev_minor F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 77accdf..e265325 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2090,6 +2090,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 659b7fc..393dd4c 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2001,6 +2001,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
index 8bc979a..b92eccb 100644
--- a/sysdeps/unix/sysv/linux/arm/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
@@ -91,6 +91,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 299b705..3b1661d 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -1855,6 +1855,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index f00345f..452e013 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2013,6 +2013,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index e5fcf88..0196234 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -1877,6 +1877,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 8f382f6..d6e0e16 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -92,6 +92,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 320b7fe..c3a5f24 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -1969,6 +1969,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
index 21b1426..fa72a0d 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
@@ -2090,6 +2090,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 5c4b596..03d3c0c 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -1944,6 +1944,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 001fa6c..a1c9cd2 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -1942,6 +1942,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 2d87001..a8671ba 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -1940,6 +1940,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index aa1ee66..e71283f 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -1935,6 +1935,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 2471d68..f92545c 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2131,6 +2131,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 4b0cde8..d8427ca 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -1973,6 +1973,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 0557c16..fa26199 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -1978,6 +1978,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
index 821384e..73488a4 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
@@ -2178,6 +2178,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
index c40a3f1..ac9cc69 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
@@ -92,6 +92,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 5b39a60..933a00a 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -1973,6 +1973,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index a9db32f..eb74169 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -1874,6 +1874,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
index 294af0a..37aded2 100644
--- a/sysdeps/unix/sysv/linux/sh/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
@@ -1859,6 +1859,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 32747bd..5b7c54e 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -1965,6 +1965,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index b0ac4d4..4854351 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -1903,6 +1903,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
index 4d92d81..18f61ba 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
@@ -2097,6 +2097,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
index a68aef7..53a0db1 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
@@ -2097,6 +2097,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
index 4d92d81..18f61ba 100644
--- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
@@ -2097,6 +2097,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index b8623fc..d4add67 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -1854,6 +1854,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index a61d874..18717fa 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2097,6 +2097,9 @@ GLIBC_2.23 fts64_set F
 GLIBC_2.24 GLIBC_2.24 A
 GLIBC_2.24 quick_exit F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __explicit_bzero F
+GLIBC_2.25 __glibc_read_memory F
+GLIBC_2.25 explicit_bzero F
 GLIBC_2.25 strfromd F
 GLIBC_2.25 strfromf F
 GLIBC_2.25 strfroml F
-- 
2.10.2

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2016-12-08 18:17 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-15 13:05 [PATCH 0/3] explicit_bzero again Zack Weinberg
2016-09-15 13:05 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Zack Weinberg
2016-09-15 13:05   ` [PATCH 2/3] Add fortification and inline optimization of explicit_bzero Zack Weinberg
2016-09-15 13:05     ` [PATCH 3/3] Use explicit_bzero where appropriate Zack Weinberg
2016-09-15 15:38   ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Paul Eggert
2016-09-15 15:59   ` Paul Eggert
2016-10-06 10:03   ` Florian Weimer
2016-10-06 15:49     ` Joseph Myers
2016-10-18  9:27       ` Florian Weimer
2016-11-15 15:55 [PATCH 0/3] explicit_bzero v5 Zack Weinberg
2016-11-15 15:55 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Zack Weinberg
2016-11-16 18:38   ` Michael Kerrisk (man-pages)
2016-12-08 14:56 [PATCH 0/3] explicit_bzero v6 Zack Weinberg
2016-12-08 14:56 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Zack Weinberg
2016-12-08 17:14   ` Joseph Myers
2016-12-08 18:08     ` Zack Weinberg
2016-12-08 18:17       ` Joseph Myers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).