public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 3/3] Use explicit_bzero where appropriate
  2016-11-15 15:55   ` [PATCH 2/3] Add fortification and inline optimization of explicit_bzero Zack Weinberg
@ 2016-11-15 15:55     ` Zack Weinberg
  0 siblings, 0 replies; 36+ messages in thread
From: Zack Weinberg @ 2016-11-15 15:55 UTC (permalink / raw)
  To: libc-alpha; +Cc: carlos, 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..2d72691 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..617ccd3 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..2971454 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..421d6da 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.10.2

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

* [PATCH 2/3] Add fortification and inline optimization of explicit_bzero.
  2016-11-15 15:55 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Zack Weinberg
@ 2016-11-15 15:55   ` Zack Weinberg
  2016-11-15 15:55     ` [PATCH 3/3] Use explicit_bzero where appropriate Zack Weinberg
  2016-11-16 18:38   ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Michael Kerrisk (man-pages)
  1 sibling, 1 reply; 36+ messages in thread
From: Zack Weinberg @ 2016-11-15 15:55 UTC (permalink / raw)
  To: libc-alpha; +Cc: carlos, 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.)

        * string/bits/string2.h: Optimize explicit_bzero.
        * string/bits/string3.h: Fortify explicit_bzero.
        * debug/tst-chk1.c: Test fortification of explicit_bzero.
---
 debug/tst-chk1.c      | 28 ++++++++++++++++++++++++++++
 string/bits/string2.h | 11 +++++++++++
 string/bits/string3.h |  8 ++++++++
 3 files changed, 47 insertions(+)

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/string/bits/string2.h b/string/bits/string2.h
index ca1eda9..d509533 100644
--- a/string/bits/string2.h
+++ b/string/bits/string2.h
@@ -57,6 +57,17 @@
 # define __bzero(s, n) __builtin_memset (s, '\0', n)
 #endif
 
+#if defined __USE_MISC
+/* 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 8f13b65..c9e2e62 100644
--- a/string/bits/string3.h
+++ b/string/bits/string3.h
@@ -42,6 +42,7 @@ __warndecl (__warn_memset_zero_len,
 # ifdef __USE_MISC
 #  undef bcopy
 #  undef bzero
+#  undef explicit_bzero
 # endif
 #endif
 
@@ -102,6 +103,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 *
-- 
2.10.2

^ permalink raw reply	[flat|nested] 36+ 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-15 15:55   ` [PATCH 2/3] Add fortification and inline optimization of explicit_bzero Zack Weinberg
  2016-11-16 18:38   ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Michael Kerrisk (man-pages)
  2016-11-15 16:20 ` [PATCH 0/3] explicit_bzero v5 Paul Eggert
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 36+ 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] 36+ messages in thread

* [PATCH 0/3] explicit_bzero v5
@ 2016-11-15 15:55 Zack Weinberg
  2016-11-15 15:55 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Zack Weinberg
                   ` (3 more replies)
  0 siblings, 4 replies; 36+ messages in thread
From: Zack Weinberg @ 2016-11-15 15:55 UTC (permalink / raw)
  To: libc-alpha; +Cc: carlos, fweimer

I would really like to get this into 2.25, and I believe that I have
addressed all substantive objections.  Please review.

The core implementation strategy is the same as for the previous
iteration.  Changes since then are:

 * All of the ABI-affecting changes appear in patch 1/3 to minimize
   clutter.  (The plan is still to squash all three commits into one
   for landing.)

 * libc.so now exports __explicit_bzero as well as explicit_bzero; the
   implementation-namespace symbol is used by libcrypt.so, and the
   user-namespace symbol is weak.  (Requested by Joseph, iirc.)
   The impl-namespace symbol is versioned GLIBC_2.25 instead of
   GLIBC_PRIVATE, because that seems to be what was done for other
   impl-namespace aliases for string functions.  I wasn't able to find
   anything definitive about when GLIBC_PRIVATE should be used.

 * tst-xbzero-opt.c has been tightened up a bit.
 * The interaction between bits/string2.h and bits/string3.h should
   now be more robust.
 * The documentation has been revised per Paul Eggert's comments.

Paul Eggert also observed that a call to explicit_bzero might expose
the _address_ of a buffer containing sensitive data, and perhaps
another thread could exfiltrate the data before it was erased.
I thought about it and I have concluded that this, like the other
remaining problems with this API, needs to be addressed in the
compiler; there's nothing glibc can reasonably do about it.
Clobbering all caller-save registers and incoming argument space is
the best thing we _could_ do about it, but that would have to happen
_after_ the memset, so it doesn't actually help.

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                                   |  12 +
 manual/string.texi                                 | 124 ++++++++
 string/Makefile                                    |  12 +-
 string/Versions                                    |  10 +
 string/bits/string2.h                              |  11 +
 string/bits/string3.h                              |   8 +
 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 +
 46 files changed, 778 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

-- 
2.10.2

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

* Re: [PATCH 0/3] explicit_bzero v5
  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-15 16:20 ` Paul Eggert
  2016-11-15 17:46   ` Zack Weinberg
  2016-11-15 21:12 ` Richard Henderson
  2016-11-16  2:03 ` Joseph Myers
  3 siblings, 1 reply; 36+ messages in thread
From: Paul Eggert @ 2016-11-15 16:20 UTC (permalink / raw)
  To: Zack Weinberg, libc-alpha; +Cc: carlos, fweimer

On 11/15/2016 07:55 AM, Zack Weinberg wrote:
> Paul Eggert also observed that a call to explicit_bzero might expose
> the_address_  of a buffer containing sensitive data, and perhaps
> another thread could exfiltrate the data before it was erased.
> I thought about it and I have concluded that this, like the other
> remaining problems with this API, needs to be addressed in the
> compiler

That sounds reasonable. Could you please document this, though? Perhaps 
something like the following, after the paragraph about copying objects?


@strong{Warning:} Calling @code{explicit_bzero} may expose
the object's address to other parts of the program, defeating
address space layout randomization.

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

* Re: [PATCH 0/3] explicit_bzero v5
  2016-11-15 16:20 ` [PATCH 0/3] explicit_bzero v5 Paul Eggert
@ 2016-11-15 17:46   ` Zack Weinberg
  2016-11-15 18:02     ` Paul Eggert
  0 siblings, 1 reply; 36+ messages in thread
From: Zack Weinberg @ 2016-11-15 17:46 UTC (permalink / raw)
  To: Paul Eggert; +Cc: GNU C Library, Carlos O'Donell, Florian Weimer

On Tue, Nov 15, 2016 at 11:20 AM, Paul Eggert <eggert@cs.ucla.edu> wrote:
> On 11/15/2016 07:55 AM, Zack Weinberg wrote:
>>
>> Paul Eggert also observed that a call to explicit_bzero might expose
>> the_address_  of a buffer containing sensitive data, and perhaps
>> another thread could exfiltrate the data before it was erased.
>> I thought about it and I have concluded that this, like the other
>> remaining problems with this API, needs to be addressed in the
>> compiler
>
>
> That sounds reasonable. Could you please document this, though? Perhaps
> something like the following, after the paragraph about copying objects?
>
>
> @strong{Warning:} Calling @code{explicit_bzero} may expose
> the object's address to other parts of the program, defeating
> address space layout randomization.

Without a concrete, short example, like we have for the
copying-objects scenario, I think this will confuse people more than
it helps.  And I am currently failing to think of such an example - in
fact, thinking about it is only leading me to suspect that, in any
scenario where the arguments to explicit_bzero are visible to
malicious code, the adversary has already won.  Those arguments, after
all, are either in registers or on the stack.  If the adversary can
read either of those, they can already learn return addresses.

Do you have any suggestions?

zw

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

* Re: [PATCH 0/3] explicit_bzero v5
  2016-11-15 17:46   ` Zack Weinberg
@ 2016-11-15 18:02     ` Paul Eggert
  2016-11-15 18:42       ` Florian Weimer
  0 siblings, 1 reply; 36+ messages in thread
From: Paul Eggert @ 2016-11-15 18:02 UTC (permalink / raw)
  To: Zack Weinberg; +Cc: GNU C Library, Carlos O'Donell, Florian Weimer

On 11/15/2016 09:46 AM, Zack Weinberg wrote:

> in any scenario where the arguments to explicit_bzero are visible to
> malicious code, the adversary has already won.  Those arguments, after
> all, are either in registers or on the stack.  If the adversary can
> read either of those, they can already learn return addresses.


It's possible that the adversary can read the stack but not registers, 
that the object address is already in a register but not in the stack, 
and that the call to explicit_bzero copies the address to the stack, 
making the address visible to the attacker. Perhaps something like the 
following instead?


@strong{Warning:} Calling @code{explicit_bzero} may copy the
the object's address from a register to the stack, thereby exposing
the address to other parts of the program (e.g., another thread),
which may defeat address space layout randomization.

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

* Re: [PATCH 0/3] explicit_bzero v5
  2016-11-15 18:02     ` Paul Eggert
@ 2016-11-15 18:42       ` Florian Weimer
  2016-11-15 18:54         ` Zack Weinberg
  2016-11-15 19:35         ` Paul Eggert
  0 siblings, 2 replies; 36+ messages in thread
From: Florian Weimer @ 2016-11-15 18:42 UTC (permalink / raw)
  To: Paul Eggert, Zack Weinberg; +Cc: GNU C Library, Carlos O'Donell

On 11/15/2016 07:02 PM, Paul Eggert wrote:
> On 11/15/2016 09:46 AM, Zack Weinberg wrote:
>
>> in any scenario where the arguments to explicit_bzero are visible to
>> malicious code, the adversary has already won.  Those arguments, after
>> all, are either in registers or on the stack.  If the adversary can
>> read either of those, they can already learn return addresses.
>
>
> It's possible that the adversary can read the stack but not registers,
> that the object address is already in a register but not in the stack,
> and that the call to explicit_bzero copies the address to the stack,
> making the address visible to the attacker. Perhaps something like the
> following instead?
>
> @strong{Warning:} Calling @code{explicit_bzero} may copy the
> the object's address from a register to the stack, thereby exposing
> the address to other parts of the program (e.g., another thread),
> which may defeat address space layout randomization.

I'm concerned that developers will read all these warnings and use 
memset instead (or a hand-written loop) because this appears to avoid 
all these issues.

Florian

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

* Re: [PATCH 0/3] explicit_bzero v5
  2016-11-15 18:42       ` Florian Weimer
@ 2016-11-15 18:54         ` Zack Weinberg
  2016-11-15 19:35           ` Paul Eggert
  2016-11-16 18:34           ` Michael Kerrisk (man-pages)
  2016-11-15 19:35         ` Paul Eggert
  1 sibling, 2 replies; 36+ messages in thread
From: Zack Weinberg @ 2016-11-15 18:54 UTC (permalink / raw)
  To: Florian Weimer
  Cc: Paul Eggert, GNU C Library, Carlos O'Donell,
	Michael Kerrisk (man-pages)

On Tue, Nov 15, 2016 at 1:42 PM, Florian Weimer <fweimer@redhat.com> wrote:
> On 11/15/2016 07:02 PM, Paul Eggert wrote:
>> On 11/15/2016 09:46 AM, Zack Weinberg wrote:
>>
>>> in any scenario where the arguments to explicit_bzero are visible to
>>> malicious code, the adversary has already won.  Those arguments, after
>>> all, are either in registers or on the stack.  If the adversary can
>>> read either of those, they can already learn return addresses.
>>
>> It's possible that the adversary can read the stack but not registers

If the adversary can read the stack at all, I suspect they've already
won, no matter what we do.

> I'm concerned that developers will read all these warnings and use memset
> instead (or a hand-written loop) because this appears to avoid all these
> issues.

Yeah, I'm actually worried that the warnings I already wrote are
already too over-the-top.

cc:ing Michael Kerrisk - you write manpages all day, does the
documentation added in
<https://sourceware.org/ml/libc-alpha/2016-11/msg00499.html> look like
it would scare people off using the function at all?

zw

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

* Re: [PATCH 0/3] explicit_bzero v5
  2016-11-15 18:54         ` Zack Weinberg
@ 2016-11-15 19:35           ` Paul Eggert
  2016-11-16 14:56             ` Zack Weinberg
  2016-11-16 18:34           ` Michael Kerrisk (man-pages)
  1 sibling, 1 reply; 36+ messages in thread
From: Paul Eggert @ 2016-11-15 19:35 UTC (permalink / raw)
  To: Zack Weinberg, Florian Weimer
  Cc: GNU C Library, Carlos O'Donell, Michael Kerrisk (man-pages)

On 11/15/2016 10:54 AM, Zack Weinberg wrote:
> If the adversary can read the stack at all, I suspect they've already
> won, no matter what we do.

That will likely be true in many applications, but not in all. It's 
worth documenting the issue for applications that put sensitive objects 
in the heap, as they might not expose these object addresses to the 
stack now, but could do so if modified to invoke explicit_bzero.

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

* Re: [PATCH 0/3] explicit_bzero v5
  2016-11-15 18:42       ` Florian Weimer
  2016-11-15 18:54         ` Zack Weinberg
@ 2016-11-15 19:35         ` Paul Eggert
  2016-11-16 14:58           ` Zack Weinberg
  1 sibling, 1 reply; 36+ messages in thread
From: Paul Eggert @ 2016-11-15 19:35 UTC (permalink / raw)
  To: Florian Weimer, Zack Weinberg; +Cc: GNU C Library, Carlos O'Donell

On 11/15/2016 10:42 AM, Florian Weimer wrote:
> I'm concerned that developers will read all these warnings and use 
> memset instead (or a hand-written loop) because this appears to avoid 
> all these issues.

Conversely if we omit the warnings, developers could easily be misled 
into thinking that explicit_bzero keeps secrets reliably, and we 
wouldn't want to mislead them. Perhaps we could add something like this, 
after all the Warnings: paragraphs:

The above warnings do not imply that using @code{memset} or a 
hand-written loop are ``safer'' than using @code{explicit_bzero}, as 
these other techniques can run afoul of even more problems than 
@code{explicit_bzero} does.

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

* Re: [PATCH 0/3] explicit_bzero v5
  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-15 16:20 ` [PATCH 0/3] explicit_bzero v5 Paul Eggert
@ 2016-11-15 21:12 ` Richard Henderson
  2016-11-16 14:45   ` Zack Weinberg
  2016-11-16  2:03 ` Joseph Myers
  3 siblings, 1 reply; 36+ messages in thread
From: Richard Henderson @ 2016-11-15 21:12 UTC (permalink / raw)
  To: Zack Weinberg, libc-alpha; +Cc: carlos, fweimer

On 11/15/2016 04:55 PM, Zack Weinberg wrote:
> I wasn't able to find anything definitive about when GLIBC_PRIVATE should be used.

Between .so libraries of glibc's implementation, as such symbols are (wait for 
it) private and are allowed to change at will between releases.


r~

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

* Re: [PATCH 0/3] explicit_bzero v5
  2016-11-15 15:55 [PATCH 0/3] explicit_bzero v5 Zack Weinberg
                   ` (2 preceding siblings ...)
  2016-11-15 21:12 ` Richard Henderson
@ 2016-11-16  2:03 ` Joseph Myers
  2016-11-16 15:06   ` Zack Weinberg
  3 siblings, 1 reply; 36+ messages in thread
From: Joseph Myers @ 2016-11-16  2:03 UTC (permalink / raw)
  To: Zack Weinberg; +Cc: libc-alpha, carlos, fweimer

On Tue, 15 Nov 2016, Zack Weinberg wrote:

>  * libc.so now exports __explicit_bzero as well as explicit_bzero; the
>    implementation-namespace symbol is used by libcrypt.so, and the
>    user-namespace symbol is weak.  (Requested by Joseph, iirc.)

Requested by Florian (together with header pieces to cause normal calls to 
explicit_bzero to end up calling the implementation-namespace version) 
because of concerns about interposition.

>    The impl-namespace symbol is versioned GLIBC_2.25 instead of
>    GLIBC_PRIVATE, because that seems to be what was done for other
>    impl-namespace aliases for string functions.  I wasn't able to find
>    anything definitive about when GLIBC_PRIVATE should be used.

We need an implementation-namespace export for libcrypt use for namespace 
reasons [*].

If it's only for libcrypt use, GLIBC_PRIVATE would suffice.  If we want to 
support it for other libraries limiting the namespace they use, with or 
without header pieces to protect against accidental interposition, a 
GLIBC_2.25 export is needed.


[*] I had thought libcrypt was irrelevant for linknamespace issues, but 
actually I just missed that it should be included in the linknamespace 
tests because I took the list of libraries to consider there from the 
POSIX rules for which functions require which libraries for linking with 
the POSIX c99 utility.  glibc has separate libdl and libcrypt libraries 
for some POSIX functions, although POSIX does not mention such libraries, 
so a correct implementation of that utility with glibc would need to 
handle linking with those libraries automatically.  The only existing 
namespace bug I see on x86_64 or x86 when adding libcrypt / libdl to the 
libraries checked in the linknamespace tests is use of snprintf in crypt 
functions when not reserved by XPG3/XPG4; I'll deal with that before 
committing the linknamespace support.  crypt.h is indeed non-POSIX, but 
XSI POSIX has the functions in unistd.h.

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

I'd expect a NEWS entry to be included somewhere in the patch series.

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* Re: [PATCH 0/3] explicit_bzero v5
  2016-11-15 21:12 ` Richard Henderson
@ 2016-11-16 14:45   ` Zack Weinberg
  2016-11-16 14:58     ` Andreas Schwab
  2016-11-16 20:06     ` Richard Henderson
  0 siblings, 2 replies; 36+ messages in thread
From: Zack Weinberg @ 2016-11-16 14:45 UTC (permalink / raw)
  To: Richard Henderson, libc-alpha; +Cc: fweimer

On 11/15/2016 04:11 PM, Richard Henderson wrote:
> On 11/15/2016 04:55 PM, Zack Weinberg wrote:
>> I wasn't able to find anything definitive about when GLIBC_PRIVATE
>> should be used.
> 
> Between .so libraries of glibc's implementation, as such symbols are
> (wait for it) private and are allowed to change at will between releases.

This doesn't fully resolve the question in my head, though.  The case
we're discussing is an impl-namespace symbol __explicit_bzero, which is
functionally identical to a public symbol explicit_bzero, and not
expected ever to change its behavior.  It exists, as far as I
understand, _solely_ so that uses of this symbol in libcrypt.so will
resolve to the definition in libc.so even if other objects in the link
interpose on the public symbol.  Other symbols that exist for the same
reason have been given both GLIBC_2.xx versions (e.g. __bzero,
__strtok_r, __clone, __connect, __send) and GLIBC_PRIVATE versions
(__getrlimit, __madvise, __recv, __socket) so I don't know what is
considered to be the Right Thing.

(If I were to make the public declaration in string.h redirect to
__explicit_bzero, then clearly it ought to be a GLIBC_2.xx export rather
than a GLIBC_PRIVATE export.  But, as I'll go into more elsewhere, I'm
not convinced that's actually a good idea.)

zw

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

* Re: [PATCH 0/3] explicit_bzero v5
  2016-11-15 19:35           ` Paul Eggert
@ 2016-11-16 14:56             ` Zack Weinberg
  2016-11-16 21:38               ` Paul Eggert
  0 siblings, 1 reply; 36+ messages in thread
From: Zack Weinberg @ 2016-11-16 14:56 UTC (permalink / raw)
  To: Paul Eggert, Florian Weimer
  Cc: GNU C Library, Carlos O'Donell, Michael Kerrisk (man-pages)

On 11/15/2016 02:35 PM, Paul Eggert wrote:
> On 11/15/2016 10:54 AM, Zack Weinberg wrote:
>> If the adversary can read the stack at all, I suspect they've
>> already won, no matter what we do.
> 
> That will likely be true in many applications, but not in all.

I doubt that very much.  An adversary who can read the stack has access
to at least one pointer into the executable image (i.e. a return
address) and that is sufficient to walk the entire address space,
including all static data and the complete contents of the heap.

> It's worth documenting the issue for applications that put sensitive
> objects in the heap, as they might not expose these object addresses
> to the stack now

How on earth are they to operate on sensitive objects on the heap
without holding their addresses in function-local variables, which one
must assume do from time to time get spilled onto the stack?

zw

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

* Re: [PATCH 0/3] explicit_bzero v5
  2016-11-16 14:45   ` Zack Weinberg
@ 2016-11-16 14:58     ` Andreas Schwab
  2016-11-16 15:00       ` Zack Weinberg
  2016-11-16 20:06     ` Richard Henderson
  1 sibling, 1 reply; 36+ messages in thread
From: Andreas Schwab @ 2016-11-16 14:58 UTC (permalink / raw)
  To: Zack Weinberg; +Cc: Richard Henderson, libc-alpha, fweimer

On Nov 16 2016, Zack Weinberg <zackw@panix.com> wrote:

> This doesn't fully resolve the question in my head, though.  The case
> we're discussing is an impl-namespace symbol __explicit_bzero, which is
> functionally identical to a public symbol explicit_bzero, and not
> expected ever to change its behavior.  It exists, as far as I
> understand, _solely_ so that uses of this symbol in libcrypt.so will
> resolve to the definition in libc.so even if other objects in the link
> interpose on the public symbol.

It's a public symbol, so it gets a public version.  It does not matter
whether the reference is created explicitly or implicitly.

Andreas.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."

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

* Re: [PATCH 0/3] explicit_bzero v5
  2016-11-15 19:35         ` Paul Eggert
@ 2016-11-16 14:58           ` Zack Weinberg
  0 siblings, 0 replies; 36+ messages in thread
From: Zack Weinberg @ 2016-11-16 14:58 UTC (permalink / raw)
  To: Paul Eggert, Florian Weimer; +Cc: GNU C Library, Carlos O'Donell

On 11/15/2016 02:35 PM, Paul Eggert wrote:
> On 11/15/2016 10:42 AM, Florian Weimer wrote:
>> I'm concerned that developers will read all these warnings and use
>> memset instead (or a hand-written loop) because this appears to avoid
>> all these issues.
> 
> Conversely if we omit the warnings, developers could easily be misled
> into thinking that explicit_bzero keeps secrets reliably, and we
> wouldn't want to mislead them. Perhaps we could add something like this,
> after all the Warnings: paragraphs:
> 
> The above warnings do not imply that using @code{memset} or a
> hand-written loop are ``safer'' than using @code{explicit_bzero}, as
> these other techniques can run afoul of even more problems than
> @code{explicit_bzero} does.

That's not a terrible idea.  I'm still concerned that the warnings
constitute a wall of scary text that will put people off reading,
though. I will think about this some more and send revised text later
today or tomorrow morning.

zw

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

* Re: [PATCH 0/3] explicit_bzero v5
  2016-11-16 14:58     ` Andreas Schwab
@ 2016-11-16 15:00       ` Zack Weinberg
  2016-11-16 15:09         ` Andreas Schwab
  0 siblings, 1 reply; 36+ messages in thread
From: Zack Weinberg @ 2016-11-16 15:00 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: libc-alpha

On 11/16/2016 09:58 AM, Andreas Schwab wrote:
> On Nov 16 2016, Zack Weinberg <zackw@panix.com> wrote:
> 
>> This doesn't fully resolve the question in my head, though.  The case
>> we're discussing is an impl-namespace symbol __explicit_bzero, which is
>> functionally identical to a public symbol explicit_bzero, and not
>> expected ever to change its behavior.  It exists, as far as I
>> understand, _solely_ so that uses of this symbol in libcrypt.so will
>> resolve to the definition in libc.so even if other objects in the link
>> interpose on the public symbol.
> 
> It's a public symbol, so it gets a public version.  It does not matter
> whether the reference is created explicitly or implicitly.

It is not obvious to me that it is a public symbol.  Please explain
exactly what your criteria are for declaring it a public symbol.

zw

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

* Re: [PATCH 0/3] explicit_bzero v5
  2016-11-16  2:03 ` Joseph Myers
@ 2016-11-16 15:06   ` Zack Weinberg
  0 siblings, 0 replies; 36+ messages in thread
From: Zack Weinberg @ 2016-11-16 15:06 UTC (permalink / raw)
  To: Joseph Myers; +Cc: libc-alpha, carlos, fweimer

On 11/15/2016 09:03 PM, Joseph Myers wrote:
> On Tue, 15 Nov 2016, Zack Weinberg wrote:
> 
>>  * libc.so now exports __explicit_bzero as well as explicit_bzero; the
>>    implementation-namespace symbol is used by libcrypt.so, and the
>>    user-namespace symbol is weak.  (Requested by Joseph, iirc.)
> 
> Requested by Florian (together with header pieces to cause normal calls to 
> explicit_bzero to end up calling the implementation-namespace version) 
> because of concerns about interposition.

Oh, right, that.  I think I should reply directly to Florian's proposal
for impl-namespace names for all new symbols; I'm not convinced it's a
good idea.  I'd feel better about it if __REDIRECT could be implemented
using only ISO C facilities, but I'd still be somewhat dubious.

>>    The impl-namespace symbol is versioned GLIBC_2.25 instead of
>>    GLIBC_PRIVATE, because that seems to be what was done for other
>>    impl-namespace aliases for string functions.  I wasn't able to find
>>    anything definitive about when GLIBC_PRIVATE should be used.
> 
> We need an implementation-namespace export for libcrypt use for namespace 
> reasons [*].

That's what I thought.

> If it's only for libcrypt use, GLIBC_PRIVATE would suffice.  If we want to 
> support it for other libraries limiting the namespace they use, with or 
> without header pieces to protect against accidental interposition, a 
> GLIBC_2.25 export is needed.

It does seem to me that e.g. libssl might want to take defensive
measures against a broken explicit_bzero in the main executable.

> I'd expect a NEWS entry to be included somewhere in the patch series.

I have been holding off on writing one until it was clear that the
_feature_ was going to be accepted.  Have we reached that point?

zw

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

* Re: [PATCH 0/3] explicit_bzero v5
  2016-11-16 15:00       ` Zack Weinberg
@ 2016-11-16 15:09         ` Andreas Schwab
  2016-11-16 15:14           ` Zack Weinberg
  0 siblings, 1 reply; 36+ messages in thread
From: Andreas Schwab @ 2016-11-16 15:09 UTC (permalink / raw)
  To: Zack Weinberg; +Cc: libc-alpha

On Nov 16 2016, Zack Weinberg <zackw@panix.com> wrote:

> On 11/16/2016 09:58 AM, Andreas Schwab wrote:
>> On Nov 16 2016, Zack Weinberg <zackw@panix.com> wrote:
>> 
>>> This doesn't fully resolve the question in my head, though.  The case
>>> we're discussing is an impl-namespace symbol __explicit_bzero, which is
>>> functionally identical to a public symbol explicit_bzero, and not
>>> expected ever to change its behavior.  It exists, as far as I
>>> understand, _solely_ so that uses of this symbol in libcrypt.so will
>>> resolve to the definition in libc.so even if other objects in the link
>>> interpose on the public symbol.
>> 
>> It's a public symbol, so it gets a public version.  It does not matter
>> whether the reference is created explicitly or implicitly.
>
> It is not obvious to me that it is a public symbol.

It is used outside of glibc.

Andreas.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."

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

* Re: [PATCH 0/3] explicit_bzero v5
  2016-11-16 15:09         ` Andreas Schwab
@ 2016-11-16 15:14           ` Zack Weinberg
  2016-11-16 15:22             ` Andreas Schwab
  0 siblings, 1 reply; 36+ messages in thread
From: Zack Weinberg @ 2016-11-16 15:14 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: libc-alpha

On 11/16/2016 10:09 AM, Andreas Schwab wrote:
> On Nov 16 2016, Zack Weinberg <zackw@panix.com> wrote:
> 
>> On 11/16/2016 09:58 AM, Andreas Schwab wrote:
>>> On Nov 16 2016, Zack Weinberg <zackw@panix.com> wrote:
>>>
>>>> This doesn't fully resolve the question in my head, though.  The case
>>>> we're discussing is an impl-namespace symbol __explicit_bzero, which is
>>>> functionally identical to a public symbol explicit_bzero, and not
>>>> expected ever to change its behavior.  It exists, as far as I
>>>> understand, _solely_ so that uses of this symbol in libcrypt.so will
>>>> resolve to the definition in libc.so even if other objects in the link
>>>> interpose on the public symbol.
>>>
>>> It's a public symbol, so it gets a public version.  It does not matter
>>> whether the reference is created explicitly or implicitly.
>>
>> It is not obvious to me that it is a public symbol.
> 
> It is used outside of glibc.

Every symbol exported as GLIBC_PRIVATE is used outside of libc.so.6.  In
the current revision of the patchset, callers that don't see
include/string.h will call explicit_bzero, not __explicit_bzero.

If that's not what you meant, please elaborate.

zw

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

* Re: [PATCH 0/3] explicit_bzero v5
  2016-11-16 15:14           ` Zack Weinberg
@ 2016-11-16 15:22             ` Andreas Schwab
  0 siblings, 0 replies; 36+ messages in thread
From: Andreas Schwab @ 2016-11-16 15:22 UTC (permalink / raw)
  To: Zack Weinberg; +Cc: libc-alpha

On Nov 16 2016, Zack Weinberg <zackw@panix.com> wrote:

> On 11/16/2016 10:09 AM, Andreas Schwab wrote:
>> On Nov 16 2016, Zack Weinberg <zackw@panix.com> wrote:
>> 
>>> On 11/16/2016 09:58 AM, Andreas Schwab wrote:
>>>> On Nov 16 2016, Zack Weinberg <zackw@panix.com> wrote:
>>>>
>>>>> This doesn't fully resolve the question in my head, though.  The case
>>>>> we're discussing is an impl-namespace symbol __explicit_bzero, which is
>>>>> functionally identical to a public symbol explicit_bzero, and not
>>>>> expected ever to change its behavior.  It exists, as far as I
>>>>> understand, _solely_ so that uses of this symbol in libcrypt.so will
>>>>> resolve to the definition in libc.so even if other objects in the link
>>>>> interpose on the public symbol.
>>>>
>>>> It's a public symbol, so it gets a public version.  It does not matter
>>>> whether the reference is created explicitly or implicitly.
>>>
>>> It is not obvious to me that it is a public symbol.
>> 
>> It is used outside of glibc.
>
> Every symbol exported as GLIBC_PRIVATE is used outside of libc.so.6.

I wrote glibc, not libc.so.

Andreas.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."

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

* Re: [PATCH 0/3] explicit_bzero v5
  2016-11-15 18:54         ` Zack Weinberg
  2016-11-15 19:35           ` Paul Eggert
@ 2016-11-16 18:34           ` Michael Kerrisk (man-pages)
  1 sibling, 0 replies; 36+ messages in thread
From: Michael Kerrisk (man-pages) @ 2016-11-16 18:34 UTC (permalink / raw)
  To: Zack Weinberg, Florian Weimer
  Cc: mtk.manpages, Paul Eggert, GNU C Library, Carlos O'Donell

On 11/15/2016 07:54 PM, Zack Weinberg wrote:
> On Tue, Nov 15, 2016 at 1:42 PM, Florian Weimer <fweimer@redhat.com> wrote:
>> On 11/15/2016 07:02 PM, Paul Eggert wrote:
>>> On 11/15/2016 09:46 AM, Zack Weinberg wrote:
>>>
>>>> in any scenario where the arguments to explicit_bzero are visible to
>>>> malicious code, the adversary has already won.  Those arguments, after
>>>> all, are either in registers or on the stack.  If the adversary can
>>>> read either of those, they can already learn return addresses.
>>>
>>> It's possible that the adversary can read the stack but not registers
> 
> If the adversary can read the stack at all, I suspect they've already
> won, no matter what we do.
> 
>> I'm concerned that developers will read all these warnings and use memset
>> instead (or a hand-written loop) because this appears to avoid all these
>> issues.
> 
> Yeah, I'm actually worried that the warnings I already wrote are
> already too over-the-top.
> 
> cc:ing Michael Kerrisk - you write manpages all day, 

(Wouldn't it be great if someone did have that job :-). I don't.
But, I do write a lot of man pages...)

> does the
> documentation added in
> <https://sourceware.org/ml/libc-alpha/2016-11/msg00499.html> look like
> it would scare people off using the function at all?

So, I saw this message from you, Zack, went away and read the text
you point at, and then went back and started looking at other
people's messages in this thread. And I was struck by Florian's
comment, because I had exactly the same the same response. In fact,
worse: I was almost left worrying that explicit_bzero() creates
as many problems for me as it solves. I'll go back now and comment
on the actual document text.

Cheers,

Michael

^ permalink raw reply	[flat|nested] 36+ 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-15 15:55   ` [PATCH 2/3] Add fortification and inline optimization of explicit_bzero Zack Weinberg
@ 2016-11-16 18:38   ` Michael Kerrisk (man-pages)
  1 sibling, 0 replies; 36+ 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] 36+ messages in thread

* Re: [PATCH 0/3] explicit_bzero v5
  2016-11-16 14:45   ` Zack Weinberg
  2016-11-16 14:58     ` Andreas Schwab
@ 2016-11-16 20:06     ` Richard Henderson
  1 sibling, 0 replies; 36+ messages in thread
From: Richard Henderson @ 2016-11-16 20:06 UTC (permalink / raw)
  To: Zack Weinberg, libc-alpha; +Cc: fweimer

On 11/16/2016 03:45 PM, Zack Weinberg wrote:
> (If I were to make the public declaration in string.h redirect to
> __explicit_bzero, then clearly it ought to be a GLIBC_2.xx export rather
> than a GLIBC_PRIVATE export.  But, as I'll go into more elsewhere, I'm
> not convinced that's actually a good idea.)

Ah, that's exactly what I thought we were doing.

So, yes, without a string.h redirect this would seem to be a case for 
GLIBC_PRIVATE.


r~

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

* Re: [PATCH 0/3] explicit_bzero v5
  2016-11-16 14:56             ` Zack Weinberg
@ 2016-11-16 21:38               ` Paul Eggert
  0 siblings, 0 replies; 36+ messages in thread
From: Paul Eggert @ 2016-11-16 21:38 UTC (permalink / raw)
  To: Zack Weinberg, Florian Weimer
  Cc: GNU C Library, Carlos O'Donell, Michael Kerrisk (man-pages)

On 11/16/2016 06:56 AM, Zack Weinberg wrote:
> On 11/15/2016 02:35 PM, Paul Eggert wrote:
>> On 11/15/2016 10:54 AM, Zack Weinberg wrote:
>>> If the adversary can read the stack at all, I suspect they've
>>> already won, no matter what we do.
>> That will likely be true in many applications, but not in all.
> An adversary who can read the stack has access
> to at least one pointer into the executable image (i.e. a return
> address) and that is sufficient to walk the entire address space,
> including all static data and the complete contents of the heap.

Sorry, I'm not following. Typically searching a stack is much cheaper 
than searching all of address space. ASLR is about increasing the 
adversary's cost; it is not about creating a perfect defense. If ASLR 
can force an adversary to search all of address space instead of 
searching just the stack, then that is a win.

Another way to put it: Even if an adversary can obtain the address of 
one object, that doesn't mean that ASLR is useless thereafter. ASLR can 
still make it hard for the adversary to obtain the addresses of other 
objects, and this can still make the program harder to attack overall. 
So, even if the adversary can read the stack, ASLR can still be useful 
if the password buffer is on the heap and if no addresses in the stack 
point to the password buffer.

>
>> It's worth documenting the issue for applications that put sensitive
>> objects in the heap, as they might not expose these object addresses
>> to the stack now
> How on earth are they to operate on sensitive objects on the heap
> without holding their addresses in function-local variables, which one
> must assume do from time to time get spilled onto the stack?

Yes, one must assume that if one is considering a worst-case compiler. 
But there are other possibilities. Perhaps the addresses are not spilled 
in code that calls memset or uses inline code, whereas the addresses do 
get spilled in the code that calls explicit_bzero. So, in practice, 
changing C code to call explicit_bzero can create spills that didn't 
exist before, which means that in practice the machine code can be less 
secure than before.

^ permalink raw reply	[flat|nested] 36+ 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; 36+ 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] 36+ 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; 36+ 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] 36+ 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; 36+ 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] 36+ 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; 36+ 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] 36+ 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; 36+ 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] 36+ 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; 36+ 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] 36+ 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 15:38   ` Paul Eggert
  2016-09-15 15:59   ` Paul Eggert
@ 2016-10-06 10:03   ` Florian Weimer
  2016-10-06 15:49     ` Joseph Myers
  2 siblings, 1 reply; 36+ 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] 36+ 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 15:38   ` Paul Eggert
@ 2016-09-15 15:59   ` Paul Eggert
  2016-10-06 10:03   ` Florian Weimer
  2 siblings, 0 replies; 36+ 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] 36+ 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 15:38   ` Paul Eggert
  2016-09-15 15:59   ` Paul Eggert
  2016-10-06 10:03   ` Florian Weimer
  2 siblings, 0 replies; 36+ 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] 36+ messages in thread

* [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 15:38   ` Paul Eggert
                     ` (2 more replies)
  0 siblings, 3 replies; 36+ 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] 36+ messages in thread

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

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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-15 15:55   ` [PATCH 2/3] Add fortification and inline optimization of explicit_bzero Zack Weinberg
2016-11-15 15:55     ` [PATCH 3/3] Use explicit_bzero where appropriate Zack Weinberg
2016-11-16 18:38   ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Michael Kerrisk (man-pages)
2016-11-15 16:20 ` [PATCH 0/3] explicit_bzero v5 Paul Eggert
2016-11-15 17:46   ` Zack Weinberg
2016-11-15 18:02     ` Paul Eggert
2016-11-15 18:42       ` Florian Weimer
2016-11-15 18:54         ` Zack Weinberg
2016-11-15 19:35           ` Paul Eggert
2016-11-16 14:56             ` Zack Weinberg
2016-11-16 21:38               ` Paul Eggert
2016-11-16 18:34           ` Michael Kerrisk (man-pages)
2016-11-15 19:35         ` Paul Eggert
2016-11-16 14:58           ` Zack Weinberg
2016-11-15 21:12 ` Richard Henderson
2016-11-16 14:45   ` Zack Weinberg
2016-11-16 14:58     ` Andreas Schwab
2016-11-16 15:00       ` Zack Weinberg
2016-11-16 15:09         ` Andreas Schwab
2016-11-16 15:14           ` Zack Weinberg
2016-11-16 15:22             ` Andreas Schwab
2016-11-16 20:06     ` Richard Henderson
2016-11-16  2:03 ` Joseph Myers
2016-11-16 15:06   ` Zack Weinberg
  -- strict thread matches above, loose matches on Subject: below --
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
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 15:38   ` 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

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