public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] explicit_bzero final
@ 2016-12-12 23:06 Zack Weinberg
  2016-12-13  1:58 ` Paul Eggert
  2016-12-13  7:02 ` Florian Weimer
  0 siblings, 2 replies; 21+ messages in thread
From: Zack Weinberg @ 2016-12-12 23:06 UTC (permalink / raw)
  To: libc-alpha, joseph, adhemerval.zanella, Wilco.Dijkstra, fweimer

I've addressed Joseph's comments, moved the bits/string2.h inline to
string.h proper to get it out of the way of Wilco's work removing
bits/string2.h (this also means that it can be a proper inline rather
than a macro, although the necessary #if conditional is pretty ugly),
and squashed all three changesets together.

This is the last call for feedback.  I intend to check this in on
Wednesday the 14th (forty-eight hours from now) if there are no
hard objections.

zw

---
New string function explicit_bzero (from OpenBSD).

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.)

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-style inline 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.)

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.

The crypt() implementation has an immediate use for this new feature.
As this is in libcrypt, there is a GLIBC_PRIVATE, impl-namespace alias
for explicit_bzero (even though it doesn't get used, thanks to the
aforementioned optimization).  I did not find any other places that needed
explicit_bzero, but all the glue is in place should we want to use it in
libc proper in the future.  The legacy DES implementation wasn't bothering
to clear its buffers, so I added that, mostly for consistency's sake.

	* 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.  Define explicit_zero as an inline
	when possible.
        * string/bits/string3.h: Fortify explicit_bzero.
        * include/string.h: Declare __internal_glibc_read_memory,
        __explicit_bzero, and __internal_explicit_bzero.
        * debug/tst-chk1.c: Test fortification of explicit_bzero.

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

	* 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.

	* string/Versions [GLIBC_2.25]:
	Add explicit_bzero and __glibc_read_memory.
	[GLIBC_PRIVATE]: Add __explicit_bzero.
	* 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 and __glibc_read_memory.
---
 NEWS                                               |   6 +
 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                                   |  16 ++
 manual/string.texi                                 | 101 +++++++
 string/Makefile                                    |  12 +-
 string/Versions                                    |  11 +
 string/bits/string3.h                              |   7 +
 string/explicit_bzero.c                            |  34 +++
 string/read_memory.c                               |  47 ++++
 string/string.h                                    |  22 ++
 string/test-explicit_bzero.c                       |  20 ++
 string/test-memset.c                               |  10 +-
 string/tst-xbzero-opt.c                            | 291 +++++++++++++++++++++
 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, 688 insertions(+), 22 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 64ed6593cb..43a5c4e538 100644
--- a/NEWS
+++ b/NEWS
@@ -84,6 +84,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/crypt/crypt-entry.c b/crypt/crypt-entry.c
index a7dfccaa36..2d72691ceb 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 2243bc7aed..617ccd3ac1 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 d768234879..53f00c041e 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 f404c88b20..86b63542ca 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);
diff --git a/debug/tst-chk1.c b/debug/tst-chk1.c
index 478c2fbb81..e87a279fb2 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 e145bfdb4c..56d02deb83 100644
--- a/include/string.h
+++ b/include/string.h
@@ -100,6 +100,22 @@ 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.h inlines when present.  */
+#if __GNUC_PREREQ (3,4)							\
+  && ((defined __extern_always_inline					\
+       && defined __OPTIMIZE__ && !defined __OPTIMIZE_SIZE__		\
+       && !defined __NO_INLINE__ && !defined __NO_STRING_INLINES)	\
+      || (__USE_FORTIFY_LEVEL > 0 && defined __fortify_function))
+# 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..73bb1cbf72 100644
--- a/string/Versions
+++ b/string/Versions
@@ -82,4 +82,15 @@ libc {
   }
   GLIBC_2.24 {
   }
+  GLIBC_2.25 {
+    # used by inlines in string.h and bits/string3.h
+    __glibc_read_memory;
+
+    # e*
+    explicit_bzero;
+  }
+  GLIBC_PRIVATE {
+    # used by libcrypt
+    __explicit_bzero;
+  }
 }
diff --git a/string/bits/string3.h b/string/bits/string3.h
index 8f13b65fa6..c1fcbd9e10 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
new file mode 100644
index 0000000000..571595d1b5
--- /dev/null
+++ b/string/explicit_bzero.c
@@ -0,0 +1,34 @@
+/* Erasure of sensitive data.
+   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..8e08a46dcd
--- /dev/null
+++ b/string/read_memory.c
@@ -0,0 +1,47 @@
+/* "Read" a range of memory, from the caller's perspective.
+   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,
+   but the compiler doesn't know that, and must assume that it reads
+   the block of memory pointed to by S and extending for LEN bytes.
+   This prevents any earlier write to that memory from being optimized
+   away.  For instance, explicit_bzero uses this function to ensure
+   that its erasure of a piece of sensitive data is preserved.
+
+   In order to achieve the desired 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..1ef33101f8 100644
--- a/string/string.h
+++ b/string/string.h
@@ -453,6 +453,28 @@ 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 the inline versions of explicit_bzero
+   below and in bits/string3.h.  */
+extern void __glibc_read_memory (const void *__s, size_t __n)
+     __THROW __nonnull ((1)) __attribute_noinline__;
+
+# if __GNUC_PREREQ (3,4) && defined __extern_always_inline	\
+  && defined __OPTIMIZE__ && !defined __OPTIMIZE_SIZE__		\
+  && !defined __NO_INLINE__ && !defined __NO_STRING_INLINES	\
+  && (__USE_FORTIFY_LEVEL == 0 || !defined __fortify_function)
+
+__extern_always_inline void
+__NTH (explicit_bzero (void *__s, size_t __n))
+{
+  memset (__s, '\0', __n);
+  __glibc_read_memory (__s, __n);
+}
+# endif
+
 /* 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..a777432e1c
--- /dev/null
+++ b/string/tst-xbzero-opt.c
@@ -0,0 +1,291 @@
+/* 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.
+
+   If this test begins to fail with a new compiler, investigate
+   whether __glibc_read_memory is still doing its job.  */
+
+#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 ();
+}
+
+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;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/arm/nacl/libc.abilist b/sysdeps/arm/nacl/libc.abilist
index 0a39f4d13e..8583317ad3 100644
--- a/sysdeps/arm/nacl/libc.abilist
+++ b/sysdeps/arm/nacl/libc.abilist
@@ -1843,6 +1843,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 gnu_dev_major F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 8d3435f210..e5bdd2138c 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2090,6 +2090,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 2381616b71..693a97217f 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2001,6 +2001,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
index e2dbf6fee7..51b21726d6 100644
--- a/sysdeps/unix/sysv/linux/arm/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
@@ -91,6 +91,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 231f039e69..da8d858217 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -1855,6 +1855,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 5d0159348b..ea34f48b0a 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2013,6 +2013,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 00ef4d77ab..df0e999d9a 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -1877,6 +1877,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 7de0b0e9bd..f5fda4820d 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -92,6 +92,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 93e1124592..1e5ce204ae 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -1969,6 +1969,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
index da70083bdd..4a2b238a60 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
@@ -2090,6 +2090,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 570bbf6791..a48d869967 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -1944,6 +1944,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 5022e5a186..de591fc28d 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -1942,6 +1942,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index ca9f91924f..673393b340 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -1940,6 +1940,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 2a090db5c6..cfc03d9018 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -1935,6 +1935,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index d10bb32513..58d148dffa 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2131,6 +2131,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index a7e688bed9..4d6efdd6b6 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -1973,6 +1973,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 8c32c33076..a0f8608119 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -1978,6 +1978,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
index 2a13e49a9e..a097b1c317 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
@@ -2178,6 +2178,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
index 4f29a6db6e..0e7fac196f 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
@@ -92,6 +92,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 1e9d4f4d91..ad93e221e0 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -1973,6 +1973,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 6b3d9320e1..7b53df33fb 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -1874,6 +1874,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
index 93b79d3758..425ae6cc28 100644
--- a/sysdeps/unix/sysv/linux/sh/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
@@ -1859,6 +1859,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index a29b0c149b..cad6a4706d 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -1965,6 +1965,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 8ac06e9b01..55c0ea6f7d 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -1903,6 +1903,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
index 208e7425ff..b95c3d4023 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
@@ -2097,6 +2097,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
index 3d7836d546..6fde0c43b0 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
@@ -2097,6 +2097,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
index 208e7425ff..b95c3d4023 100644
--- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
@@ -2097,6 +2097,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 32cd1e07b4..1f77aadc9a 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -1854,6 +1854,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 4ff7acf300..f528b85665 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2097,6 +2097,8 @@ 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 getentropy F
 GLIBC_2.25 getrandom F
 GLIBC_2.25 strfromd F
-- 
2.11.0

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

end of thread, other threads:[~2016-12-16 21:35 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-12-12 23:06 [PATCH] explicit_bzero final Zack Weinberg
2016-12-13  1:58 ` Paul Eggert
2016-12-13  7:02 ` Florian Weimer
2016-12-13 15:53   ` Zack Weinberg
2016-12-13 22:47     ` Jeff Law
2016-12-14  1:04       ` Zack Weinberg
2016-12-14  1:05         ` Zack Weinberg
2016-12-14 13:15         ` Florian Weimer
2016-12-14 17:06           ` Florian Weimer
2016-12-14 22:28             ` Zack Weinberg
2016-12-14 22:37               ` Joseph Myers
2016-12-15  9:08               ` Florian Weimer
2016-12-15 10:20                 ` Florian Weimer
2016-12-15 23:31                 ` Zack Weinberg
2016-12-16  7:50                   ` Florian Weimer
2016-12-14 16:58         ` Jeff Law
2016-12-14 23:11           ` Zack Weinberg
2016-12-15  5:25             ` Jeff Law
2016-12-15 23:21               ` Zack Weinberg
2016-12-16 18:26                 ` Jeff Law
2016-12-16 21:35                   ` Zack Weinberg

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).