[RFC] explicit_bzero, again

Message ID 55C7E246.3000006@panix.com
State Superseded
Headers

Commit Message

Zack Weinberg Aug. 9, 2015, 11:29 p.m. UTC
  I'd like to resume the discussion of adding explicit_bzero or similar
to glibc.  This was originally proposed by Nick Mathewson last
December (https://sourceware.org/ml/libc-alpha/2014-12/msg00506.html)
and I have prepared an updated patchset, which is attached to this
message.  One patch adds the function, and the second adds several
intra-libc uses; I suspect I haven't found all of the places where
it should be used.

To reiterate from last time, the problem explicit_bzero solves is: in
a function of the form

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

      memset(key, 0, 16);
    }

the compiler may well remove the final call to memset, because `key`
goes out of scope immediately afterward, so no conforming C program
can access the memory to see that it has been cleared.  However, a
crash dump, a debugger, or a plain old bug in the program might expose
that region of the stack to prying eyes.  This is listed at
https://cwe.mitre.org/data/definitions/14.html as a "common weakness".
explicit_bzero is just bzero with an additional, documented guarantee
that the compiler will not optimize it out even if the memory region is
dead afterward.

In earlier discussion, Rich Felker pointed out that this is inadequate
to solve the problem, because the compiler might make temporary copies
of the data in `key` in memory or registers; a complete fix requires
additional compiler features.
(https://sourceware.org/ml/libc-alpha/2014-12/msg00513.html) This is
true, but I do not think it should be an obstacle to adding the
function to gcc, for three reasons:

1) explicit_bzero in glibc is strictly better than the status quo.
In its absence, application developers either cross their fingers and
call `memset` (there are cases of this in glibc itself!) or they
invent their own version, with varying degrees of correctness and
efficiency.  By providing it in glibc we can ensure that applications
using it get as close to the effect they want as is possible without
compiler support.  (In my patch, I have carefully documented what
explicit_bzero can and cannot be expected to do.)

2) If compiler support for erasure of sensitive data becomes available
in the future, explicit_bzero can become a backward-compatible
indicator of which data needs to be reliably erased.  Hypothetically,
in GCC terms, the obvious programmer-visible interface would be
__attribute__ ((sensitive)) applied to a variable or structure field.
GCC could then implicitly apply this attribute to any object passed to
explicit_bzero.

3) It is possible to implement explicit_bzero *in the C library* more
efficiently than it is to implement it anywhere else.  This is
because, in the C library, it doesn't need to be anything more than a
weak alias for bzero!  Exposing bzero under a second name that is
meaningless to the compiler is all you have to do to inhibit the
undesired dead-store removal.  (In my patch I have gone somewhat
beyond this, see below.)

3a) It is impractical for anyone but glibc to equip explicit_bzero
with -D_FORTIFY_SOURCE support.

There was also a question of what to name the function, there being
several competing options.  In my updated patch I have selected
explicit_bzero, largely because it is more broadly adopted by both C
libraries (OpenBSD _and_ FreeBSD, which is more than any other
competitor can say) and in applications (see
e.g. https://codesearch.debian.net/results/explicit_bzero/page_0) than
any of its competitors.

memset_s was also suggested; it has the advantage of being part of an
official standard (C99 Annex K), but the disadvantage of a
significantly more complicated specification and API, which would
require it to be its own function rather than another name for an
existing one.  Moreover, despite Annex K being Microsoft's invention,
MSVC's runtime does _not_ provide it; the only C library I've found
that has it is MacOS X's.  And
https://codesearch.debian.net/results/memset_s/page_0/ indicates that
some programs (notably util-linux) supply their own definition of
memset_s which is _incompatible_ with Annex K.  All these mean that
IMNSHO standardization does not outweigh community adoption in this
case.

Finally, some notes on my implementation.  As I said above, all you
_really_ need to do this reliably (as far as it can be without
compiler support) is to expose a function that does what bzero does,
but under a name that is meaningless to the compiler.  Then it can't
be optimized out, and obviously the implementation will continue to do
what it does.

However, if you have a construct that expresses a read access to the
written memory region, but generates no instructions, you can use that
to force the compiler to preserve the write.  Then it becomes safe to
replace explicit_bzero with memset, which is desirable because e.g. it
re-enables conversion to inline store instructions.  I was able to
find a construct with this effect, but not a universal one.  It only
works in GCC, only when compiling C, and the manual implies that it
might not be sound when the size of the memory region isn't known at
compile time.

    __STRING_INLINE void
    __explicit_bzero_constn(void *__s, size_t __n)
    {
      typedef struct {char __x[__n];} __memblk;
      memset(__s, 0, __n);
      __asm__ ("" : :
        "m" (*(__memblk __attribute__ ((may_alias)) *)__s));
    }

When compiling C++, 'struct {char x[n]}' is a hard error, even if I
convert the whole thing to a macro and guard it with
__builtin_constant_p.  The same is true for clang in both C and C++.

Because we don't have a universal read-use construct, the fortify
wrapper for explicit_bzero is more complicated than it could have
been: in particular, __explicit_bzero_chk has to be a real,
out-of-line function (unlike __bzero_chk, which doesn't exist) and
that caused me a certain amount of headache -- see the other thread
about __memset_chk.  But it works.  All this can also easily be
improved if compiler support improves.

I did add tests, but they are cursory.  For an automated test that
explicit_bzero can't be optimized out, without doing anything
undefined in the test program, we would need something like GCC's
scan-assembler tests, which I don't believe there is any way to do in
the existing glibc testsuite.  I've manually vetted assembly output
for several code fragments, like the one at the top of the message.

(Appropriate additions to debug/tst-chk1.c are stacked up in my repo on
top of the fix for bug 18975.  I was going to hold off posting this
until that got committed, but then someone else started a thread to
which it is Highly Relevant. ;-)

zw
  

Comments

Joseph Myers Aug. 10, 2015, 2:40 p.m. UTC | #1
On Sun, 9 Aug 2015, Zack Weinberg wrote:

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

sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist also needs 
updating.

> +libc_hidden_def(__memset_chk)

Missing space before '('.

> +/* used by __explicit_bzero_chk */
> +libc_hidden_proto(__memset_chk)

Likewise.  Uppercase at start of comment, ".  " at end.

> +__explicit_bzero_constn(void *__s, size_t __n)

Missing space before '('.

> +{
> +  typedef struct {char __x[__n];} __memblk;
> +  memset(__s, 0, __n);

Likewise.

> +  __asm__ ("" : : "m" (*(__memblk __attribute__ ((may_alias)) *)__s));

I think you should use __may_alias__ here (there's no reason to take the 
symbol may_alias from the user's namespace, notwithstanding that this is 
__USE_MISC).

> +                  ? __explicit_bzero_constn(s, n)       \
> +                  : explicit_bzero(s, n)))

More missing spaces.

> @@ -90,6 +91,7 @@ __NTH (memset (void *__dest, int __ch, size_t __len))
>    return __builtin___memset_chk (__dest, __ch, __len, __bos0 (__dest));
>  }
>  
> +
>  #ifdef __USE_MISC
>  __fortify_function void
>  __NTH (bcopy (const void *__src, void *__dest, size_t __len))

Stray patch hunk adding a blank line.

> +      __asm__ ("" : : "m" (*(__memblk __attribute__ ((may_alias)) *)__dest));

__may_alias__ again.

> +    __explicit_bzero_chk(__dest, __len, __bos (__dest));
> +  else
> +    __explicit_bzero_alias(__dest, __len);

More missing spaces.
  
Zack Weinberg Aug. 10, 2015, 10:55 p.m. UTC | #2
On Mon, Aug 10, 2015 at 10:40 AM, Joseph Myers <joseph@codesourcery.com> wrote:
> On Sun, 9 Aug 2015, Zack Weinberg wrote:
>
>>       * 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.abilist
>
> sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist also needs
> updating.

Did that just get added, like, yesterday?  I am not sure why `find`
didn't find it.

>> +libc_hidden_def(__memset_chk)
>
> Missing space before '('.
[etc]

Thanks, I'm a bit out of practice coding in GNU style.

> I think you should use __may_alias__ here (there's no reason to take the
> symbol may_alias from the user's namespace, notwithstanding that this is
> __USE_MISC).

I thought attribute names didn't conflict with any other namespace?
But sure, I can make that change.

> Stray patch hunk adding a blank line.

That was actually intentional -- this file seems to separate groups of
functions with double blank lines.  But I can take it back out again.

Does anyone have more substantive concerns with this patch, or are we
good to go once I fix up the style?

zw
  
Joseph Myers Aug. 11, 2015, 12:23 a.m. UTC | #3
On Mon, 10 Aug 2015, Zack Weinberg wrote:

> > sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist also needs
> > updating.
> 
> Did that just get added, like, yesterday?  I am not sure why `find`
> didn't find it.

Because it's called libc-le.abilist not libc.abilist (to avoid the need 
for extra sysdeps directories solely for ABI baselines).

> > I think you should use __may_alias__ here (there's no reason to take the
> > symbol may_alias from the user's namespace, notwithstanding that this is
> > __USE_MISC).
> 
> I thought attribute names didn't conflict with any other namespace?

They conflict with macros.
  

Patch

New library function, explicit_bzero

The new function explicit_bzero is functionally identical to bzero,
but the compiler will not delete a call to it, even if the memory
region it's applied to is dead after the call.  You should use this
function, for instance, to erase cryptographic keys or similar when
you are done with them.  Taken from OpenBSD.

YYYY-MM-DD  Nick Mathewson <nickm@freehaven.net>
            Zack Weinberg <zackw@panix.com>

	* manual/string.texi: Document new function explicit_bzero.

	* string/Versions [GLIBC_2.23]: Add explicit_bzero.
	* string/string.h [__USE_MISC]: Declare explicit_bzero.
	* string/bits/string2.h: Optimize explicit_bzero when possible.
	* string/bits/string3.h: Fortify explicit_bzero.
	* string/test-explicit_bzero.c: New file, basic test for explicit_bzero.
	* string/Makefile, string/test-memset.c: Support the new test.

	* string/bzero.c
	* sysdeps/aarch64/bzero.S
	* sysdeps/alpha/bzero.S
	* sysdeps/i386/bzero.c
	* sysdeps/i386/i586/bzero.S
	* sysdeps/i386/i686/bzero.S
	* sysdeps/powerpc/powerpc32/bzero.S
	* sysdeps/powerpc/powerpc32/power4/multiarch/bzero.c
	* sysdeps/powerpc/powerpc64/memset.S
	* sysdeps/powerpc/powerpc64/multiarch/bzero.c
	* sysdeps/powerpc/powerpc64/power4/memset.S
	* sysdeps/powerpc/powerpc64/power6/memset.S
	* sysdeps/powerpc/powerpc64/power7/memset.S
	* sysdeps/powerpc/powerpc64/power8/memset.S
	* sysdeps/s390/s390-32/bzero.S
	* sysdeps/s390/s390-64/bzero.S
	* sysdeps/sparc/sparc32/memset.S
	* sysdeps/sparc/sparc64/memset.S
	* sysdeps/sparc/sparc64/multiarch/memset.S
	* sysdeps/tile/bzero.S
	* sysdeps/x86_64/memset.S:
	Declare explicit_bzero as weak alias of __bzero.

	* debug/explicit_bzero_chk.c: New file.
	* debug/Makefile: Compile it.
	* debug/Versions [GLIBC_2.23]: Add __explicit_bzero_chk.

	* include/string.h: Add libc_hidden_proto for __memset_chk.
	* debug/memset_chk.c: Add libc_hidden_def for __memset_chk.
	En passant, convert to prototyped function definition and
	remove unnecessary #include.
	* sysdeps/i386/i586/memset.S
	* sysdeps/i386/i686/memset.S
	* sysdeps/i386/i686/multiarch/memset.S
	* sysdeps/x86_64/memset.S
	* sysdeps/x86_64/multiarch/memset.S:
	Add libc_hidden_builtin_def for __memset_chk.

	* 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.abilist
	* sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
	* sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
	* sysdeps/unix/sysv/linux/sh/libc.abilist
	* sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
	* sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
	* sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
	* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
	* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist:
	Add GLIBC_2.23 stanza containing explicit_bzero and
	__explicit_bzero_chk.
---
 debug/Makefile                                     |  1 +
 debug/Versions                                     |  3 +
 debug/explicit_bzero_chk.c                         | 28 ++++++++++
 debug/memset_chk.c                                 |  8 +--
 include/string.h                                   |  4 ++
 manual/string.texi                                 | 64 ++++++++++++++++++++++
 string/Makefile                                    |  3 +-
 string/Versions                                    |  3 +
 string/bits/string2.h                              | 28 ++++++++++
 string/bits/string3.h                              | 39 +++++++++++++
 string/bzero.c                                     |  1 +
 string/string.h                                    |  4 ++
 string/test-explicit_bzero.c                       | 21 +++++++
 string/test-memset.c                               | 10 +++-
 sysdeps/aarch64/bzero.S                            |  1 +
 sysdeps/alpha/bzero.S                              |  1 +
 sysdeps/arm/nacl/libc.abilist                      |  4 ++
 sysdeps/i386/bzero.c                               |  1 +
 sysdeps/i386/i586/bzero.S                          |  1 +
 sysdeps/i386/i586/memset.S                         |  1 +
 sysdeps/i386/i686/bzero.S                          |  1 +
 sysdeps/i386/i686/memset.S                         |  1 +
 sysdeps/i386/i686/multiarch/memset.S               |  8 ++-
 sysdeps/powerpc/powerpc32/bzero.S                  |  1 +
 sysdeps/powerpc/powerpc32/power4/multiarch/bzero.c |  1 +
 sysdeps/powerpc/powerpc64/memset.S                 |  1 +
 sysdeps/powerpc/powerpc64/multiarch/bzero.c        |  1 +
 sysdeps/powerpc/powerpc64/power4/memset.S          |  1 +
 sysdeps/powerpc/powerpc64/power6/memset.S          |  1 +
 sysdeps/powerpc/powerpc64/power7/memset.S          |  1 +
 sysdeps/powerpc/powerpc64/power8/memset.S          |  1 +
 sysdeps/s390/s390-32/bzero.S                       |  1 +
 sysdeps/s390/s390-64/bzero.S                       |  1 +
 sysdeps/sparc/sparc32/memset.S                     |  1 +
 sysdeps/sparc/sparc64/memset.S                     |  1 +
 sysdeps/sparc/sparc64/multiarch/memset.S           |  1 +
 sysdeps/tile/bzero.S                               |  1 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist       |  4 ++
 sysdeps/unix/sysv/linux/alpha/libc.abilist         |  4 ++
 sysdeps/unix/sysv/linux/arm/libc.abilist           |  4 ++
 sysdeps/unix/sysv/linux/hppa/libc.abilist          |  4 ++
 sysdeps/unix/sysv/linux/i386/libc.abilist          |  4 ++
 sysdeps/unix/sysv/linux/ia64/libc.abilist          |  4 ++
 sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist |  4 ++
 sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist   |  4 ++
 sysdeps/unix/sysv/linux/microblaze/libc.abilist    |  4 ++
 .../unix/sysv/linux/mips/mips32/fpu/libc.abilist   |  4 ++
 .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist |  4 ++
 .../unix/sysv/linux/mips/mips64/n32/libc.abilist   |  4 ++
 .../unix/sysv/linux/mips/mips64/n64/libc.abilist   |  4 ++
 sysdeps/unix/sysv/linux/nios2/libc.abilist         |  4 ++
 .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist  |  4 ++
 .../linux/powerpc/powerpc32/nofpu/libc.abilist     |  4 ++
 .../unix/sysv/linux/powerpc/powerpc64/libc.abilist |  4 ++
 sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist  |  4 ++
 sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist  |  4 ++
 sysdeps/unix/sysv/linux/sh/libc.abilist            |  4 ++
 sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist |  4 ++
 sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist |  4 ++
 .../sysv/linux/tile/tilegx/tilegx32/libc.abilist   |  4 ++
 .../sysv/linux/tile/tilegx/tilegx64/libc.abilist   |  4 ++
 sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist  |  4 ++
 sysdeps/unix/sysv/linux/x86_64/64/libc.abilist     |  4 ++
 sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist    |  4 ++
 sysdeps/x86_64/memset.S                            |  2 +
 sysdeps/x86_64/multiarch/memset.S                  |  2 +-
 66 files changed, 350 insertions(+), 12 deletions(-)
 create mode 100644 debug/explicit_bzero_chk.c
 create mode 100644 string/test-explicit_bzero.c

diff --git a/debug/Makefile b/debug/Makefile
index 9ff357b..93e044f 100644
--- a/debug/Makefile
+++ b/debug/Makefile
@@ -29,6 +29,7 @@  headers	:= execinfo.h
 # build, its _FORTIFY_SOURCE support will be too.
 routines  = backtrace backtracesyms backtracesymsfd noophooks \
 	    memcpy_chk memmove_chk mempcpy_chk memset_chk stpcpy_chk \
+	    explicit_bzero_chk \
 	    strcat_chk strcpy_chk strncat_chk strncpy_chk stpncpy_chk \
 	    sprintf_chk vsprintf_chk snprintf_chk vsnprintf_chk \
 	    printf_chk fprintf_chk vprintf_chk vfprintf_chk \
diff --git a/debug/Versions b/debug/Versions
index 0482c85..3c7feb1 100644
--- a/debug/Versions
+++ b/debug/Versions
@@ -55,6 +55,9 @@  libc {
   GLIBC_2.16 {
     __poll_chk; __ppoll_chk;
   }
+  GLIBC_2.23 {
+    __explicit_bzero_chk;
+  }
   GLIBC_PRIVATE {
     __fortify_fail;
   }
diff --git a/debug/explicit_bzero_chk.c b/debug/explicit_bzero_chk.c
new file mode 100644
index 0000000..15330c6
--- /dev/null
+++ b/debug/explicit_bzero_chk.c
@@ -0,0 +1,28 @@ 
+/* Copyright (C) 1991-2015 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 has to be an exported symbol, unlike for plain bzero, because
+   bits/string3.h cannot always optimize explicit_bzero to memset.
+   See comments there, and "Erasing Sensitive Data" in the manual.  */
+
+void
+__explicit_bzero_chk (void *dstpp, size_t len, size_t dstlen)
+{
+  (void) __memset_chk (dstpp, 0, len, dstlen);
+}
diff --git a/debug/memset_chk.c b/debug/memset_chk.c
index 293172f..de697ca 100644
--- a/debug/memset_chk.c
+++ b/debug/memset_chk.c
@@ -16,17 +16,13 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 #include <string.h>
-#include <memcopy.h>
 
 void *
-__memset_chk (dstpp, c, len, dstlen)
-     void *dstpp;
-     int c;
-     size_t len;
-     size_t dstlen;
+__memset_chk (void *dstpp, int c, size_t len, size_t dstlen)
 {
   if (__glibc_unlikely (dstlen < len))
     __chk_fail ();
 
   return memset (dstpp, c, len);
 }
+libc_hidden_def(__memset_chk)
diff --git a/include/string.h b/include/string.h
index c57671e..3ddc218 100644
--- a/include/string.h
+++ b/include/string.h
@@ -160,6 +160,10 @@  extern char *__strcat_chk (char *__restrict __dest,
 extern char *__strncat_chk (char *__restrict __dest,
 			    const char *__restrict __src,
 			    size_t __len, size_t __destlen) __THROW;
+
+/* used by __explicit_bzero_chk */
+libc_hidden_proto(__memset_chk)
+
 #endif
 
 #endif
diff --git a/manual/string.texi b/manual/string.texi
index 5f8a17e..cbf3f70 100644
--- a/manual/string.texi
+++ b/manual/string.texi
@@ -33,6 +33,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.
@@ -2303,6 +2305,68 @@  contains no '/' characters, 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.  For example:
+
+@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
+
+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}.
+
+@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 used again.
+
+This function first appeared in OpenBSD 5.5 and has not been
+standardized.
+
+@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.
+
+@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.
+@end deftypefun
+
 @node strfry
 @section strfry
 
diff --git a/string/Makefile b/string/Makefile
index 8424a61..8246c10 100644
--- a/string/Makefile
+++ b/string/Makefile
@@ -47,7 +47,8 @@  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	\
diff --git a/string/Versions b/string/Versions
index 59bf35a..0a02884 100644
--- a/string/Versions
+++ b/string/Versions
@@ -80,4 +80,7 @@  libc {
   GLIBC_2.6 {
     strerror_l;
   }
+  GLIBC_2.23 {
+    explicit_bzero;
+  }
 }
diff --git a/string/bits/string2.h b/string/bits/string2.h
index 7645176..7c40f70 100644
--- a/string/bits/string2.h
+++ b/string/bits/string2.h
@@ -194,6 +194,34 @@  __STRING2_COPY_TYPE (8);
 #  define __bzero(s, n) __builtin_memset (s, '\0', n)
 # endif
 
+#endif /* !_HAVE_STRING_ARCH_memset */
+
+/* explicit_bzero can be optimized to memset plus a vacuous (but
+   non-deletable) use of the memory region, thus enabling all the
+   usual memset optimizations.
+
+   The __asm__ construct used below is known to work with GCC 4 and
+   later, when the size of the memory region is constant.  It's not
+   documented to work otherwise.  Moreover, even when guarded by
+   __builtin_constant_p, 'struct {char __x[n];}', where 'n' isn't
+   _syntactically_ an integer constant expression, is a hard error for
+   GCC when compiling C++, and a hard error for clang in both C and C++.  */
+
+#ifdef __USE_MISC
+# if __GNUC_PREREQ (4, 0) && !defined __clang__ && !defined __cplusplus
+__STRING_INLINE void
+__explicit_bzero_constn(void *__s, size_t __n)
+{
+  typedef struct {char __x[__n];} __memblk;
+  memset(__s, 0, __n);
+  __asm__ ("" : : "m" (*(__memblk __attribute__ ((may_alias)) *)__s));
+}
+
+#  define explicit_bzero(s, n)                          \
+  (__extension__ (__builtin_constant_p (n) && (n) > 0   \
+                  ? __explicit_bzero_constn(s, n)       \
+                  : explicit_bzero(s, n)))
+# endif
 #endif
 
 
diff --git a/string/bits/string3.h b/string/bits/string3.h
index f482935..ce096cc 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
 
@@ -90,6 +91,7 @@  __NTH (memset (void *__dest, int __ch, size_t __len))
   return __builtin___memset_chk (__dest, __ch, __len, __bos0 (__dest));
 }
 
+
 #ifdef __USE_MISC
 __fortify_function void
 __NTH (bcopy (const void *__src, void *__dest, size_t __len))
@@ -102,6 +104,43 @@  __NTH (bzero (void *__dest, size_t __len))
 {
   (void) __builtin___memset_chk (__dest, '\0', __len, __bos0 (__dest));
 }
+
+/* XXX We have no corresponding builtin yet.
+
+   __explicit_bzero_chk can be optimized to __builtin___memset_chk
+   plus a vacuous (but non-deletable) use of the memory region, thus
+   enabling all the usual memset optimizations.
+
+   The __asm__ construct used below is known to work with GCC 4 and
+   later, when the size of the memory region is constant.  It's not
+   documented to work otherwise.  Moreover, even when guarded by
+   __builtin_constant_p, 'struct {char __x[n];}', where 'n' isn't
+   _syntactically_ an integer constant expression, is a hard error for
+   GCC when compiling C++, and a hard error for clang in both C and C++.  */
+
+extern void __explicit_bzero_chk (void *__dest, size_t __len, size_t __dstlen);
+extern void __REDIRECT_NTH (__explicit_bzero_alias,
+                            (void *__dest, size_t __len),
+                            explicit_bzero);
+
+__fortify_function void
+__NTH (explicit_bzero (void *__dest, size_t __len))
+{
+# if __GNUC_PREREQ (4, 0) && !defined __clang__ && !defined __cplusplus
+  if (__builtin_constant_p (__len) && __len > 0)
+    {
+      (void) __builtin___memset_chk (__dest, '\0', __len, __bos0 (__dest));
+      typedef struct { char __x[__len]; } __memblk;
+      __asm__ ("" : : "m" (*(__memblk __attribute__ ((may_alias)) *)__dest));
+    }
+  else
+# endif
+  if (__bos (__dest) != (size_t) -1
+      && (!__builtin_constant_p (__len) || __len > __bos (__dest)))
+    __explicit_bzero_chk(__dest, __len, __bos (__dest));
+  else
+    __explicit_bzero_alias(__dest, __len);
+}
 #endif
 
 __fortify_function char *
diff --git a/string/bzero.c b/string/bzero.c
index 43e2b38..d60f494 100644
--- a/string/bzero.c
+++ b/string/bzero.c
@@ -27,3 +27,4 @@  __bzero (void *s, size_t len)
   memset (s, '\0', len);
 }
 weak_alias (__bzero, bzero)
+weak_alias (__bzero, explicit_bzero)
diff --git a/string/string.h b/string/string.h
index 3ab7103..0df7789 100644
--- a/string/string.h
+++ b/string/string.h
@@ -453,6 +453,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..8e354c7
--- /dev/null
+++ b/string/test-explicit_bzero.c
@@ -0,0 +1,21 @@ 
+/* Test and measure explicit_bzero.
+   Copyright (C) 2012-2015 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 9f3af46..ca56857 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
 # define TEST_NAME "memset"
 #endif
@@ -35,7 +39,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/sysdeps/aarch64/bzero.S b/sysdeps/aarch64/bzero.S
index 7343896..375457b 100644
--- a/sysdeps/aarch64/bzero.S
+++ b/sysdeps/aarch64/bzero.S
@@ -25,3 +25,4 @@  ENTRY(__bzero)
 	b	__memset
 END(__bzero)
 weak_alias (__bzero, bzero)
+weak_alias (__bzero, explicit_bzero)
diff --git a/sysdeps/alpha/bzero.S b/sysdeps/alpha/bzero.S
index e3c015a..582b85a 100644
--- a/sysdeps/alpha/bzero.S
+++ b/sysdeps/alpha/bzero.S
@@ -108,3 +108,4 @@  $done:	ret
 
 	cfi_endproc
 weak_alias (__bzero, bzero)
+weak_alias (__bzero, explicit_bzero)
diff --git a/sysdeps/arm/nacl/libc.abilist b/sysdeps/arm/nacl/libc.abilist
index bef1259..f0c6a36 100644
--- a/sysdeps/arm/nacl/libc.abilist
+++ b/sysdeps/arm/nacl/libc.abilist
@@ -1835,3 +1835,7 @@  GLIBC_2.22
  write F
  writev F
  wscanf F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ explicit_bzero F
diff --git a/sysdeps/i386/bzero.c b/sysdeps/i386/bzero.c
index 1a89444..c7575f8 100644
--- a/sysdeps/i386/bzero.c
+++ b/sysdeps/i386/bzero.c
@@ -76,6 +76,7 @@  __bzero (dstpp, len)
 		"memory");
 }
 weak_alias (__bzero, bzero)
+weak_alias (__bzero, explicit_bzero)
 
 #else
 #include <string/bzero.c>
diff --git a/sysdeps/i386/i586/bzero.S b/sysdeps/i386/i586/bzero.S
index 84d2f70..23ee2c9 100644
--- a/sysdeps/i386/i586/bzero.S
+++ b/sysdeps/i386/i586/bzero.S
@@ -1,3 +1,4 @@ 
 #define memset __bzero
 #include <sysdeps/i386/i586/memset.S>
 weak_alias (__bzero, bzero)
+weak_alias (__bzero, explicit_bzero)
diff --git a/sysdeps/i386/i586/memset.S b/sysdeps/i386/i586/memset.S
index bc26501..c15e4a7 100644
--- a/sysdeps/i386/i586/memset.S
+++ b/sysdeps/i386/i586/memset.S
@@ -119,3 +119,4 @@  L(2):	shrl	$2, %ecx	/* convert byte count to longword count */
 #endif
 END (memset)
 libc_hidden_builtin_def (memset)
+libc_hidden_builtin_def (__memset_chk)
diff --git a/sysdeps/i386/i686/bzero.S b/sysdeps/i386/i686/bzero.S
index 34b0faa..25a9811 100644
--- a/sysdeps/i386/i686/bzero.S
+++ b/sysdeps/i386/i686/bzero.S
@@ -1,3 +1,4 @@ 
 #define memset __bzero
 #include <sysdeps/i386/i686/memset.S>
 weak_alias (__bzero, bzero)
+weak_alias (__bzero, explicit_bzero)
diff --git a/sysdeps/i386/i686/memset.S b/sysdeps/i386/i686/memset.S
index b6dbf2a..01b79c0 100644
--- a/sysdeps/i386/i686/memset.S
+++ b/sysdeps/i386/i686/memset.S
@@ -98,6 +98,7 @@  ENTRY (memset)
 #endif
 END (memset)
 libc_hidden_builtin_def (memset)
+libc_hidden_builtin_def (__memset_chk)
 
 #if defined PIC && IS_IN (libc) && !BZERO_P
 strong_alias (__memset_chk, __memset_zero_constant_len_parameter)
diff --git a/sysdeps/i386/i686/multiarch/memset.S b/sysdeps/i386/i686/multiarch/memset.S
index 6d7d919..f9131b4 100644
--- a/sysdeps/i386/i686/multiarch/memset.S
+++ b/sysdeps/i386/i686/multiarch/memset.S
@@ -90,9 +90,11 @@  END(memset)
 #  undef libc_hidden_builtin_def
 /* IFUNC doesn't work with the hidden functions in shared library since
    they will be called without setting up EBX needed for PLT which is
-   used by IFUNC.  */
-#  define libc_hidden_builtin_def(name) \
-	.globl __GI_memset; __GI_memset = __memset_ia32
+   used by IFUNC.  ../memset.S will barf if we #define memset, so we
+   must instead create the necessary __GI_ symbols manually.  */
+#  define libc_hidden_builtin_def(name) /* disable */
+        .globl __GI_memset; __GI_memset = __memset_ia32
+        .globl __GI___memset_chk; __GI__memset_chk = __memset_chk_ia32
 # endif
 
 # undef strong_alias
diff --git a/sysdeps/powerpc/powerpc32/bzero.S b/sysdeps/powerpc/powerpc32/bzero.S
index ae21c53..2f9614e 100644
--- a/sysdeps/powerpc/powerpc32/bzero.S
+++ b/sysdeps/powerpc/powerpc32/bzero.S
@@ -25,3 +25,4 @@  ENTRY (__bzero)
 	b	memset@local
 END (__bzero)
 weak_alias (__bzero, bzero)
+weak_alias (__bzero, explicit_bzero)
diff --git a/sysdeps/powerpc/powerpc32/power4/multiarch/bzero.c b/sysdeps/powerpc/powerpc32/power4/multiarch/bzero.c
index e938643..88aec9c 100644
--- a/sysdeps/powerpc/powerpc32/power4/multiarch/bzero.c
+++ b/sysdeps/powerpc/powerpc32/power4/multiarch/bzero.c
@@ -34,4 +34,5 @@  libc_ifunc (__bzero,
             : __bzero_ppc);
 
 weak_alias (__bzero, bzero)
+weak_alias (__bzero, explicit_bzero)
 #endif
diff --git a/sysdeps/powerpc/powerpc64/memset.S b/sysdeps/powerpc/powerpc64/memset.S
index f8543e5..7acc1aa 100644
--- a/sysdeps/powerpc/powerpc64/memset.S
+++ b/sysdeps/powerpc/powerpc64/memset.S
@@ -258,4 +258,5 @@  ENTRY (__bzero)
 END_GEN_TB (__bzero,TB_TOCLESS)
 
 weak_alias (__bzero, bzero)
+weak_alias (__bzero, explicit_bzero)
 #endif
diff --git a/sysdeps/powerpc/powerpc64/multiarch/bzero.c b/sysdeps/powerpc/powerpc64/multiarch/bzero.c
index 4953284..df10f36 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/bzero.c
+++ b/sysdeps/powerpc/powerpc64/multiarch/bzero.c
@@ -40,4 +40,5 @@  libc_ifunc (__bzero,
             : __bzero_ppc);
 
 weak_alias (__bzero, bzero)
+weak_alias (__bzero, explicit_bzero)
 #endif
diff --git a/sysdeps/powerpc/powerpc64/power4/memset.S b/sysdeps/powerpc/powerpc64/power4/memset.S
index 58877af..709db11 100644
--- a/sysdeps/powerpc/powerpc64/power4/memset.S
+++ b/sysdeps/powerpc/powerpc64/power4/memset.S
@@ -245,4 +245,5 @@  ENTRY (__bzero)
 END (__bzero)
 #ifndef __bzero
 weak_alias (__bzero, bzero)
+weak_alias (__bzero, explicit_bzero)
 #endif
diff --git a/sysdeps/powerpc/powerpc64/power6/memset.S b/sysdeps/powerpc/powerpc64/power6/memset.S
index 02f279d..b49b0a8 100644
--- a/sysdeps/powerpc/powerpc64/power6/memset.S
+++ b/sysdeps/powerpc/powerpc64/power6/memset.S
@@ -389,4 +389,5 @@  ENTRY (__bzero)
 END (__bzero)
 #ifndef __bzero
 weak_alias (__bzero, bzero)
+weak_alias (__bzero, explicit_bzero)
 #endif
diff --git a/sysdeps/powerpc/powerpc64/power7/memset.S b/sysdeps/powerpc/powerpc64/power7/memset.S
index 4c8c06f..adf4bfd 100644
--- a/sysdeps/powerpc/powerpc64/power7/memset.S
+++ b/sysdeps/powerpc/powerpc64/power7/memset.S
@@ -393,4 +393,5 @@  ENTRY (__bzero)
 END (__bzero)
 #ifndef __bzero
 weak_alias (__bzero, bzero)
+weak_alias (__bzero, explicit_bzero)
 #endif
diff --git a/sysdeps/powerpc/powerpc64/power8/memset.S b/sysdeps/powerpc/powerpc64/power8/memset.S
index eaff0e6..6d2ca37 100644
--- a/sysdeps/powerpc/powerpc64/power8/memset.S
+++ b/sysdeps/powerpc/powerpc64/power8/memset.S
@@ -451,4 +451,5 @@  ENTRY (__bzero)
 END (__bzero)
 #ifndef __bzero
 weak_alias (__bzero, bzero)
+weak_alias (__bzero, explicit_bzero)
 #endif
diff --git a/sysdeps/s390/s390-32/bzero.S b/sysdeps/s390/s390-32/bzero.S
index 7c03c3e..8a3c0cc 100644
--- a/sysdeps/s390/s390-32/bzero.S
+++ b/sysdeps/s390/s390-32/bzero.S
@@ -39,4 +39,5 @@  END(__bzero)
 
 #ifndef NO_WEAK_ALIAS
 weak_alias (__bzero, bzero)
+weak_alias (__bzero, explicit_bzero)
 #endif
diff --git a/sysdeps/s390/s390-64/bzero.S b/sysdeps/s390/s390-64/bzero.S
index 355142b..3b72e50 100644
--- a/sysdeps/s390/s390-64/bzero.S
+++ b/sysdeps/s390/s390-64/bzero.S
@@ -38,4 +38,5 @@  END(__bzero)
 
 #ifndef NO_WEAK_ALIAS
 weak_alias (__bzero, bzero)
+weak_alias (__bzero, explicit_bzero)
 #endif
diff --git a/sysdeps/sparc/sparc32/memset.S b/sysdeps/sparc/sparc32/memset.S
index 7021ce4..67a18f1 100644
--- a/sysdeps/sparc/sparc32/memset.S
+++ b/sysdeps/sparc/sparc32/memset.S
@@ -152,3 +152,4 @@  END(memset)
 libc_hidden_builtin_def (memset)
 
 weak_alias (__bzero, bzero)
+weak_alias (__bzero, explicit_bzero)
diff --git a/sysdeps/sparc/sparc64/memset.S b/sysdeps/sparc/sparc64/memset.S
index d3293fc..85a7a1f 100644
--- a/sysdeps/sparc/sparc64/memset.S
+++ b/sysdeps/sparc/sparc64/memset.S
@@ -312,3 +312,4 @@  ENTRY(__bzero)
 END(__bzero)
 
 weak_alias (__bzero, bzero)
+weak_alias (__bzero, explicit_bzero)
diff --git a/sysdeps/sparc/sparc64/multiarch/memset.S b/sysdeps/sparc/sparc64/multiarch/memset.S
index 45de5ab..ca26cb0 100644
--- a/sysdeps/sparc/sparc64/multiarch/memset.S
+++ b/sysdeps/sparc/sparc64/multiarch/memset.S
@@ -107,6 +107,7 @@  ENTRY(__bzero)
 END(__bzero)
 
 weak_alias (__bzero, bzero)
+weak_alias (__bzero, explicit_bzero)
 
 # undef weak_alias
 # define weak_alias(a, b)
diff --git a/sysdeps/tile/bzero.S b/sysdeps/tile/bzero.S
index 412dc97..3472738 100644
--- a/sysdeps/tile/bzero.S
+++ b/sysdeps/tile/bzero.S
@@ -28,3 +28,4 @@  ENTRY(__bzero)
 	j __memset
 END(__bzero)
 weak_alias (__bzero, bzero)
+weak_alias (__bzero, explicit_bzero)
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 3e0f329..c2b077f 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2084,3 +2084,7 @@  GLIBC_2.18
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ explicit_bzero F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 58c8b32..dd75663 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -1825,6 +1825,10 @@  GLIBC_2.18
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ explicit_bzero F
 GLIBC_2.2
  GLIBC_2.2 A
  _IO_adjust_wcolumn F
diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
index f2b20ad..6014129 100644
--- a/sysdeps/unix/sysv/linux/arm/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
@@ -92,6 +92,10 @@  GLIBC_2.18
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ explicit_bzero F
 GLIBC_2.4
  GLIBC_2.4 A
  _Exit F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index cf0ad90..a563c40 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -98,6 +98,10 @@  GLIBC_2.19
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ explicit_bzero F
 GLIBC_2.2
  GLIBC_2.2 A
  _Exit F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index fcf1b72..5c4972f 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2026,6 +2026,10 @@  GLIBC_2.2.6
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ explicit_bzero F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 16c2e3d..16c82e9 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -1884,6 +1884,10 @@  GLIBC_2.2.6
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ explicit_bzero F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 902b0c3..945dc34 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -93,6 +93,10 @@  GLIBC_2.18
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ explicit_bzero F
 GLIBC_2.4
  GLIBC_2.4 A
  _Exit F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 4db00b0..fd50ed5 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -1982,6 +1982,10 @@  GLIBC_2.2.6
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ explicit_bzero F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
index f1f76a1..8c3b4aa 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
@@ -2083,3 +2083,7 @@  GLIBC_2.18
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ 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 2d51989..2cf852c 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -1954,6 +1954,10 @@  GLIBC_2.2.6
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ explicit_bzero F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index b012bdf..86c2f78 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -1952,6 +1952,10 @@  GLIBC_2.2.6
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ explicit_bzero F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 9db0e8b..8f6890d 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -1950,6 +1950,10 @@  GLIBC_2.2.6
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ explicit_bzero F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index eecfcfe..d1975c7 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -1944,6 +1944,10 @@  GLIBC_2.2.6
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ explicit_bzero F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index b10bf62..0bc6c5c 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2124,3 +2124,7 @@  GLIBC_2.21
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ 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 0f15463..e80f798 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -1986,6 +1986,10 @@  GLIBC_2.2.6
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ explicit_bzero F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 7bcaa07..bcc8383 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -1992,6 +1992,10 @@  GLIBC_2.2.6
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ explicit_bzero F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
index e58a00d..2dc2424 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
@@ -93,6 +93,10 @@  GLIBC_2.18
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ explicit_bzero F
 GLIBC_2.3
  GLIBC_2.3 A
  _Exit F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 0ce7824..eaca001 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -1987,6 +1987,10 @@  GLIBC_2.2.6
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ explicit_bzero F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index dc79912..7513fda 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -1883,6 +1883,10 @@  GLIBC_2.2.6
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ explicit_bzero F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
index 9ed1b45..c5625b6 100644
--- a/sysdeps/unix/sysv/linux/sh/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
@@ -1867,6 +1867,10 @@  GLIBC_2.2.6
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ explicit_bzero F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 5a40ff3..ea7aa50 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -1978,6 +1978,10 @@  GLIBC_2.2.6
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ explicit_bzero F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index fa70645..0da655f 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -1911,6 +1911,10 @@  GLIBC_2.2.6
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ explicit_bzero F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
index dd215d7..f968929 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
@@ -2094,3 +2094,7 @@  GLIBC_2.18
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ 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 ef4747a..4305450 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
@@ -2094,3 +2094,7 @@  GLIBC_2.18
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ explicit_bzero F
diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
index dd215d7..f968929 100644
--- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
@@ -2094,3 +2094,7 @@  GLIBC_2.18
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ 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 b377b04..fd7c07e 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -1857,6 +1857,10 @@  GLIBC_2.2.6
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ explicit_bzero F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 5f70329..c632178 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2092,3 +2092,7 @@  GLIBC_2.18
 GLIBC_2.22
  GLIBC_2.22 A
  fmemopen F
+GLIBC_2.23
+ GLIBC_2.23 A
+ __explicit_bzero_chk F
+ explicit_bzero F
diff --git a/sysdeps/x86_64/memset.S b/sysdeps/x86_64/memset.S
index e496254..7f1e136 100644
--- a/sysdeps/x86_64/memset.S
+++ b/sysdeps/x86_64/memset.S
@@ -28,6 +28,7 @@  ENTRY(__bzero)
 	jmp	L(entry_from_bzero)
 END(__bzero)
 weak_alias (__bzero, bzero)
+weak_alias (__bzero, explicit_bzero)
 
 /* Like memset but takes additional parameter with return value.  */
 ENTRY(__memset_tail)
@@ -124,6 +125,7 @@  L(between8_16bytes):
 
 END (memset)
 libc_hidden_builtin_def (memset)
+libc_hidden_builtin_def (__memset_chk)
 
 #if defined PIC && IS_IN (libc) && !defined USE_MULTIARCH
 strong_alias (__memset_chk, __memset_zero_constant_len_parameter)
diff --git a/sysdeps/x86_64/multiarch/memset.S b/sysdeps/x86_64/multiarch/memset.S
index c5f1fb3..a7e6606 100644
--- a/sysdeps/x86_64/multiarch/memset.S
+++ b/sysdeps/x86_64/multiarch/memset.S
@@ -50,7 +50,7 @@  END(memset)
    The speedup we get from using GPR instruction is likely eaten away
    by the indirect call in the PLT.  */
 #  define libc_hidden_builtin_def(name) \
-	.globl __GI_memset; __GI_memset = __memset_sse2
+	.globl __GI_##name; __GI_##name = name
 #  endif
 
 #  undef strong_alias
-- 
2.5.0