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