This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH 1/3] New string function explicit_bzero (from OpenBSD).


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
> 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]