* [PATCH 0/3] explicit_bzero again @ 2016-09-15 13:05 Zack Weinberg 2016-09-15 13:05 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Zack Weinberg 0 siblings, 1 reply; 15+ messages in thread From: Zack Weinberg @ 2016-09-15 13:05 UTC (permalink / raw) To: libc-alpha; +Cc: fweimer The implementation strategy is the same as in the previous iteration. I have reorganized it again to make clearer what is and is not essential. The first patch adds only an out-of-line definition of explicit_bzero, plus tests. The second patch exposes __glibc_read_memory to external callers and uses that to define a fortify wrapper and a string2.h optimization. The third patch makes use of explicit_bzero in libcrypt, which I believe to be the only current place where it's needed inside glibc itself. zw Zack Weinberg (3): New string function explicit_bzero (from OpenBSD). Add fortification and inline optimization of explicit_bzero. Use explicit_bzero where appropriate crypt/crypt-entry.c | 11 + crypt/md5-crypt.c | 8 +- crypt/sha256-crypt.c | 14 +- crypt/sha512-crypt.c | 14 +- debug/tst-chk1.c | 28 ++ include/string.h | 2 + manual/string.texi | 101 ++++++ string/Makefile | 12 +- string/Versions | 7 + string/bits/string2.h | 13 +- string/bits/string3.h | 7 + string/explicit_bzero.c | 30 ++ string/read_memory.c | 41 +++ string/string.h | 9 + string/test-explicit_bzero.c | 20 ++ string/test-memset.c | 10 +- string/tst-xbzero-opt.c | 383 +++++++++++++++++++++ sysdeps/arm/nacl/libc.abilist | 2 + sysdeps/unix/sysv/linux/aarch64/libc.abilist | 2 + sysdeps/unix/sysv/linux/alpha/libc.abilist | 2 + sysdeps/unix/sysv/linux/arm/libc.abilist | 2 + sysdeps/unix/sysv/linux/hppa/libc.abilist | 2 + sysdeps/unix/sysv/linux/i386/libc.abilist | 2 + sysdeps/unix/sysv/linux/ia64/libc.abilist | 2 + sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist | 2 + sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist | 2 + sysdeps/unix/sysv/linux/microblaze/libc.abilist | 2 + .../unix/sysv/linux/mips/mips32/fpu/libc.abilist | 2 + .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist | 2 + .../unix/sysv/linux/mips/mips64/n32/libc.abilist | 2 + .../unix/sysv/linux/mips/mips64/n64/libc.abilist | 2 + sysdeps/unix/sysv/linux/nios2/libc.abilist | 2 + .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist | 2 + .../linux/powerpc/powerpc32/nofpu/libc.abilist | 2 + .../sysv/linux/powerpc/powerpc64/libc-le.abilist | 2 + .../unix/sysv/linux/powerpc/powerpc64/libc.abilist | 2 + sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist | 2 + sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist | 2 + sysdeps/unix/sysv/linux/sh/libc.abilist | 2 + sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist | 2 + sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist | 2 + .../sysv/linux/tile/tilegx/tilegx32/libc.abilist | 2 + .../sysv/linux/tile/tilegx/tilegx64/libc.abilist | 2 + sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist | 2 + sysdeps/unix/sysv/linux/x86_64/64/libc.abilist | 2 + sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist | 2 + 46 files changed, 745 insertions(+), 23 deletions(-) create mode 100644 string/explicit_bzero.c create mode 100644 string/read_memory.c create mode 100644 string/test-explicit_bzero.c create mode 100644 string/tst-xbzero-opt.c -- 2.9.3 ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 1/3] New string function explicit_bzero (from OpenBSD). 2016-09-15 13:05 [PATCH 0/3] explicit_bzero again Zack Weinberg @ 2016-09-15 13:05 ` Zack Weinberg 2016-09-15 13:05 ` [PATCH 2/3] Add fortification and inline optimization of explicit_bzero Zack Weinberg ` (3 more replies) 0 siblings, 4 replies; 15+ messages in thread From: Zack Weinberg @ 2016-09-15 13:05 UTC (permalink / raw) To: libc-alpha; +Cc: fweimer explicit_bzero(s, n) is the same as memset(s, 0, n), except that the compiler is not allowed to delete a call to explicit_bzero even if the memory pointed to by 's' is dead after the call. We achieve this effect by defining it to call memset() and then a second function, extern void __glibc_read_memory (const void *, size_t) __attribute_noinline__; which does nothing -- but the compiler is prevented from knowing that it does nothing, and so the pointer "escapes" and the memory is not treated as dead. (Concretely, __glibc_read_memory is forced out-of-line, defined in a file containing nothing else, and comments in both string/read_memory.c and string/Makefile document that it must not be subject to link-time optimization.) There are two new tests: test-explicit_bzero.c verifies the visible semantics in the same way as the existing test-bzero.c, and tst-xbzero-opt.c verifies the not-being-optimized-out property. The latter is conceptually based on a test written by Matthew Dempsky for the OpenBSD regression suite. * string/explicit_bzero.c, string/read_memory.c: New routines. * string/test-explicit_bzero.c, string/tst-xbzero-opt.c: New tests. * string/Makefile (routines, strop-tests, tests): Add them. * string/test-memset.c: Add ifdeffage for testing explicit_bzero. * string/string.h [__USE_MISC]: Declare explicit_bzero. * manual/string.texi: Document explicit_bzero. * string/Versions [GLIBC_2.25]: Add explicit_bzero. * include/string.h: Hidden prototype for __glibc_read_memory. * sysdeps/arm/nacl/libc.abilist * sysdeps/unix/sysv/linux/aarch64/libc.abilist * sysdeps/unix/sysv/linux/alpha/libc.abilist * sysdeps/unix/sysv/linux/arm/libc.abilist * sysdeps/unix/sysv/linux/hppa/libc.abilist * sysdeps/unix/sysv/linux/i386/libc.abilist * sysdeps/unix/sysv/linux/ia64/libc.abilist * sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist * sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist * sysdeps/unix/sysv/linux/microblaze/libc.abilist * sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist * sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist * sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist * sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist * sysdeps/unix/sysv/linux/nios2/libc.abilist * sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist * sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist * sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist * sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist * sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist * sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist * sysdeps/unix/sysv/linux/sh/libc.abilist * sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist * sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist * sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist * sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist * sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist * sysdeps/unix/sysv/linux/x86_64/64/libc.abilist * sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist: Add entry for explicit_bzero. --- include/string.h | 3 + manual/string.texi | 101 ++++++ string/Makefile | 12 +- string/Versions | 4 + string/explicit_bzero.c | 30 ++ string/read_memory.c | 40 +++ string/string.h | 4 + string/test-explicit_bzero.c | 20 ++ string/test-memset.c | 10 +- string/tst-xbzero-opt.c | 383 +++++++++++++++++++++ sysdeps/arm/nacl/libc.abilist | 1 + sysdeps/unix/sysv/linux/aarch64/libc.abilist | 1 + sysdeps/unix/sysv/linux/alpha/libc.abilist | 1 + sysdeps/unix/sysv/linux/arm/libc.abilist | 1 + sysdeps/unix/sysv/linux/hppa/libc.abilist | 1 + sysdeps/unix/sysv/linux/i386/libc.abilist | 1 + sysdeps/unix/sysv/linux/ia64/libc.abilist | 1 + sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist | 1 + sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist | 1 + sysdeps/unix/sysv/linux/microblaze/libc.abilist | 1 + .../unix/sysv/linux/mips/mips32/fpu/libc.abilist | 1 + .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist | 1 + .../unix/sysv/linux/mips/mips64/n32/libc.abilist | 1 + .../unix/sysv/linux/mips/mips64/n64/libc.abilist | 1 + sysdeps/unix/sysv/linux/nios2/libc.abilist | 1 + .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist | 1 + .../linux/powerpc/powerpc32/nofpu/libc.abilist | 1 + .../sysv/linux/powerpc/powerpc64/libc-le.abilist | 1 + .../unix/sysv/linux/powerpc/powerpc64/libc.abilist | 1 + sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist | 1 + sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist | 1 + sysdeps/unix/sysv/linux/sh/libc.abilist | 1 + sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist | 1 + sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist | 1 + .../sysv/linux/tile/tilegx/tilegx32/libc.abilist | 1 + .../sysv/linux/tile/tilegx/tilegx64/libc.abilist | 1 + sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist | 1 + sysdeps/unix/sysv/linux/x86_64/64/libc.abilist | 1 + sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist | 1 + 39 files changed, 632 insertions(+), 4 deletions(-) create mode 100644 string/explicit_bzero.c create mode 100644 string/read_memory.c create mode 100644 string/test-explicit_bzero.c create mode 100644 string/tst-xbzero-opt.c diff --git a/include/string.h b/include/string.h index e145bfd..dc0edf3 100644 --- a/include/string.h +++ b/include/string.h @@ -99,6 +99,9 @@ libc_hidden_proto (memmem) extern __typeof (memmem) __memmem; libc_hidden_proto (__memmem) libc_hidden_proto (__ffs) +extern void __glibc_read_memory (const void *s, size_t len) + __THROW __nonnull ((1)) __attribute_noinline__; +libc_hidden_proto (__glibc_read_memory) libc_hidden_builtin_proto (memchr) libc_hidden_builtin_proto (memcpy) diff --git a/manual/string.texi b/manual/string.texi index bce81a7..fe4ca48 100644 --- a/manual/string.texi +++ b/manual/string.texi @@ -34,6 +34,8 @@ too. * Search Functions:: Searching for a specific element or substring. * Finding Tokens in a String:: Splitting a string into tokens by looking for delimiters. +* Erasing Sensitive Data:: Clearing memory which contains sensitive + data, after it's no longer needed. * strfry:: Function for flash-cooking a string. * Trivial Encryption:: Obscuring data. * Encode Binary Data:: Encoding and Decoding of Binary Data. @@ -2375,6 +2377,105 @@ contains no '/' bytes, then "." is returned. The prototype for this function can be found in @file{libgen.h}. @end deftypefun +@node Erasing Sensitive Data +@section Erasing Sensitive Data + +It is sometimes necessary to make sure that a block of data in memory +is erased after use, even if no correct C program could access it +again. For instance, a cryptographic key should not be allowed to +survive on the stack after the program is finished using it, because +there might be a bug that causes junk stack data, including the key, +to be revealed to the outside world. @code{memset} and @code{bzero} +are not safe to use for this, because the C compiler knows what they +do, and can delete ``unnecessary'' calls to them. For this situation, +@theglibc{} provides @code{explicit_bzero}, which is functionally +identical to @code{bzero}, except that the C compiler will @emph{not} +delete apparently-unnecessary calls. + +@comment string.h +@comment BSD +@deftypefun void explicit_bzero (void *@var{block}, size_t @var{len}) +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + +@code{explicit_bzero} writes zero into each of the first @var{len} +bytes of the object beginning at @var{block}, just as @code{bzero} +would. The compiler will not delete a call to this function, even +if the object beginning at @var{block} is never referred to again. + +@smallexample +#include <string.h> + +extern void encrypt (const char *key, const char *in, + char *out, size_t n); +extern void genkey (const char *phrase, char *key); + +void encrypt_with_phrase (const char *phrase, const char *in, + char *out, size_t n) +@{ + char key[16]; + genkey (phrase, key); + encrypt (key, in, out, n); + explicit_bzero (key, 16); +@} +@end smallexample + +@noindent +If @code{bzero} or @code{memset} had been used in this function, the C +compiler might remove it as unnecessary, but it will not do this with +@code{explicit_bzero}. + +@strong{Warning:} The @emph{only} optimization disabled by +@code{explicit_bzero} is removal of ``unnecessary'' calls. In all +other respects, the compiler is allowed to optimize as it would for +@code{memset}. For instance, it may deduce that @var{block} cannot be +a null pointer, and propagate this information both forward and +backward in control flow. + +@strong{Warning:} The compiler is free to make additional copies of +any object, or parts of it, in temporary storage areas (such as +registers and ``scratch'' stack space). @code{explicit_bzero} does +not guarantee that temporary copies of sensitive data are destroyed. +In fact, in some situations, using @code{explicit_bzero} will +@emph{cause} creation of an additional copy, and only that copy will +be cleared: + +@smallexample +#include <string.h> + +struct key @{ + unsigned long long low; + unsigned long long high; +@}; + +struct key get_key(void); +void use_key(struct key); + +void +with_clear(void) +@{ + struct key k; + k = get_key(); + use_key(k); + explicit_bzero(&k, sizeof(k)); +@} +@end smallexample + +@noindent +Without the call to @code{explicit_bzero}, @var{k} might not need to +be stored in memory: depending on the ABI, its value could be returned +from @code{get_key} and passed to @code{use_key} using only CPU +registers. @code{explicit_bzero} operates on memory, so the compiler +has to make a copy of @var{k} in memory for it, and the copy in the +CPU registers remains intact. This can occur for any variable whose +address is only taken in a call to @code{explicit_bzero}, even if it +might seem ``too large'' to be stored in registers. + +@strong{Portability Note:} This function first appeared in OpenBSD 5.5 +and has not been standardized. @Theglibc{} declares this function in +@file{string.h}, but on other systems it may be in @file{strings.h} +instead. +@end deftypefun + @node strfry @section strfry diff --git a/string/Makefile b/string/Makefile index 69d3f80..0b6486e 100644 --- a/string/Makefile +++ b/string/Makefile @@ -41,20 +41,26 @@ routines := strcat strchr strcmp strcoll strcpy strcspn \ addsep replace) \ envz basename \ strcoll_l strxfrm_l string-inlines memrchr \ - xpg-strerror strerror_l + xpg-strerror strerror_l explicit_bzero + +# Attention future hackers trying to enable link-time optimization for +# glibc: this file *must not* be subject to LTO. It is added separately +# to 'routines' to document this. See comments in this file for details. +routines += read_memory strop-tests := memchr memcmp memcpy memmove mempcpy memset memccpy \ stpcpy stpncpy strcat strchr strcmp strcpy strcspn \ strlen strncmp strncpy strpbrk strrchr strspn memmem \ strstr strcasestr strnlen strcasecmp strncasecmp \ - strncat rawmemchr strchrnul bcopy bzero memrchr + strncat rawmemchr strchrnul bcopy bzero memrchr \ + explicit_bzero tests := tester inl-tester noinl-tester testcopy test-ffs \ tst-strlen stratcliff tst-svc tst-inlcall \ bug-strncat1 bug-strspn1 bug-strpbrk1 tst-bswap \ tst-strtok tst-strxfrm bug-strcoll1 tst-strfry \ bug-strtok1 $(addprefix test-,$(strop-tests)) \ bug-envz1 tst-strxfrm2 tst-endian tst-svc2 \ - tst-strtok_r bug-strcoll2 tst-cmp + tst-strtok_r bug-strcoll2 tst-cmp tst-xbzero-opt xtests = tst-strcoll-overflow diff --git a/string/Versions b/string/Versions index 475c1fd..a2c6e6e 100644 --- a/string/Versions +++ b/string/Versions @@ -82,4 +82,8 @@ libc { } GLIBC_2.24 { } + GLIBC_2.25 { + # e* + explicit_bzero; + } } diff --git a/string/explicit_bzero.c b/string/explicit_bzero.c new file mode 100644 index 0000000..a2b75be --- /dev/null +++ b/string/explicit_bzero.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <features.h> +#undef __USE_STRING_INLINES +#define __NO_STRING_INLINES +#include <string.h> + +/* Set LEN bytes of S to 0. The compiler will not delete a call to + this function, even if S is dead after the call. */ +void +explicit_bzero (void *s, size_t len) +{ + memset (s, '\0', len); + __glibc_read_memory (s, len); +} diff --git a/string/read_memory.c b/string/read_memory.c new file mode 100644 index 0000000..5347ee2 --- /dev/null +++ b/string/read_memory.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> + +/* This function is an optimization fence. It doesn't do anything + itself, but calls to it prevent calls to explicit_bzero from being + optimized away. In order to achieve this effect, this function + must never, under any circumstances, be inlined or subjected to + inter-procedural optimization. string.h declares this function + with attributes that, in conjunction with the no-op asm insert, are + sufficient to prevent problems in the current (2016) generation of + compilers, but *only if* this file is *not* compiled with -flto. + At present, this is not an issue since glibc is never compiled with + -flto, but should that ever change, this file must be excepted. + + The 'volatile' below is technically not necessary but is included + for explicitness. */ + +void +internal_function +__glibc_read_memory(const void *s, size_t len) +{ + asm volatile (""); +} +libc_hidden_def (__glibc_read_memory) diff --git a/string/string.h b/string/string.h index 57deaa4..89f5ab2 100644 --- a/string/string.h +++ b/string/string.h @@ -455,6 +455,10 @@ extern void bcopy (const void *__src, void *__dest, size_t __n) /* Set N bytes of S to 0. */ extern void bzero (void *__s, size_t __n) __THROW __nonnull ((1)); +/* As bzero, but the compiler will not delete a call to this + function, even if S is dead after the call. */ +extern void explicit_bzero (void *__s, size_t __n) __THROW __nonnull ((1)); + /* Compare N bytes of S1 and S2 (same as memcmp). */ extern int bcmp (const void *__s1, const void *__s2, size_t __n) __THROW __attribute_pure__ __nonnull ((1, 2)); diff --git a/string/test-explicit_bzero.c b/string/test-explicit_bzero.c new file mode 100644 index 0000000..5a4543b --- /dev/null +++ b/string/test-explicit_bzero.c @@ -0,0 +1,20 @@ +/* Test and measure explicit_bzero. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ +#define TEST_EXPLICIT_BZERO +#define TEST_BZERO +#include "test-memset.c" diff --git a/string/test-memset.c b/string/test-memset.c index fee3bdf..7ca4f20 100644 --- a/string/test-memset.c +++ b/string/test-memset.c @@ -19,7 +19,11 @@ #define TEST_MAIN #ifdef TEST_BZERO -# define TEST_NAME "bzero" +# ifdef TEST_EXPLICIT_BZERO +# define TEST_NAME "explicit_bzero" +# else +# define TEST_NAME "bzero" +# endif #else # ifndef WIDE # define TEST_NAME "memset" @@ -56,7 +60,11 @@ void builtin_bzero (char *, size_t); IMPL (simple_bzero, 0) IMPL (builtin_bzero, 0) +#ifdef TEST_EXPLICIT_BZERO +IMPL (explicit_bzero, 1) +#else IMPL (bzero, 1) +#endif void simple_bzero (char *s, size_t n) diff --git a/string/tst-xbzero-opt.c b/string/tst-xbzero-opt.c new file mode 100644 index 0000000..81eb5c1 --- /dev/null +++ b/string/tst-xbzero-opt.c @@ -0,0 +1,383 @@ +/* Test that explicit_bzero block clears are not optimized out. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +/* This test is conceptually based on a test designed by Matthew + Dempsky for the OpenBSD regression suite: + <openbsd>/src/regress/lib/libc/explicit_bzero/explicit_bzero.c. + The basic idea is, we have a function that contains a + block-clearing operation (not necessarily explicit_bzero), after + which the block is dead, in the compiler-jargon sense. Execute + that function from a signal handler running on an alternative + signal stack. Then we have another pointer to the memory region + affected by the block clear -- namely, the sigaltstack buffer -- + and can find out whether it actually happened. + + The OpenBSD test cautions that some operating systems (e.g. Solaris + and OSX) wipe the signal stack upon returning to the normal stack, + so the test has to happen while still executing on the signal + stack. This, of course, means that the buffer might be clobbered + by normal stack operations after the function with the block clear + returns (it has to return, so that the block is truly dead). The + most straightforward way to deal with this is to have a large block + containing several copies of a byte pattern that is unlikely to + occur by chance, and check whether _any_ of them survives. */ + +#define _GNU_SOURCE 1 + +#include <stdbool.h> +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +/* The "byte pattern that is unlikely to occur by chance": the first + 16 prime numbers (OEIS A000040). */ +static const unsigned char test_pattern[16] = +{ + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53 +}; + +#define PATTERN_SIZE (sizeof test_pattern) +#define PATTERN_REPS 32 +#define TEST_BUFFER_SIZE (PATTERN_SIZE * PATTERN_REPS) + +static void +fill_with_test_pattern (unsigned char *buf) +{ + for (unsigned int i = 0; i < PATTERN_REPS; i++) + memcpy (buf + i*PATTERN_SIZE, test_pattern, PATTERN_SIZE); +} + +static unsigned int +count_test_patterns (unsigned char *buf, size_t bufsiz) +{ + unsigned char *first = memmem (buf, bufsiz, test_pattern, PATTERN_SIZE); + if (!first) + return 0; + unsigned int cnt = 0; + for (unsigned int i = 0; i < PATTERN_REPS; i++) + { + unsigned char *p = first + i*PATTERN_SIZE; + if (p + PATTERN_SIZE - buf > bufsiz) + break; + if (memcmp (p, test_pattern, PATTERN_SIZE) == 0) + cnt++; + } + return cnt; +} + +/* Global test state. */ +static int failed_subtests; +static bool this_subtest_failed; + +/* The signal stack is allocated with memalign. */ +static unsigned char *signal_stack_buffer; +#define SIGNAL_STACK_SIZE (SIGSTKSZ + TEST_BUFFER_SIZE) + +enum test_expectation { EXPECT_NONE, EXPECT_SOME, EXPECT_ALL }; + +static void +check_test_buffer (enum test_expectation expected, + const char *label, const char *stage) +{ + unsigned int cnt = count_test_patterns (signal_stack_buffer, + SIGNAL_STACK_SIZE); + switch (expected) + { + case EXPECT_NONE: + if (cnt == 0) + { + printf ("PASS: %s/%s: expected 0 got %d\n", label, stage, cnt); + fflush (stdout); + } + else + { + printf ("FAIL: %s/%s: expected 0 got %d\n", label, stage, cnt); + fflush (stdout); + this_subtest_failed = true; + failed_subtests++; + } + break; + + case EXPECT_SOME: + if (cnt > 0) + { + printf ("PASS: %s/%s: expected some got %d\n", label, stage, cnt); + fflush (stdout); + } + else + { + printf ("FAIL: %s/%s: expected some got 0\n", label, stage); + fflush (stdout); + this_subtest_failed = true; + failed_subtests++; + } + break; + + case EXPECT_ALL: + if (cnt == PATTERN_REPS) + { + printf ("PASS: %s/%s: expected %d got %d\n", label, stage, + PATTERN_REPS, cnt); + fflush (stdout); + } + else + { + printf ("FAIL: %s/%s: expected %d got %d\n", label, stage, + PATTERN_REPS, cnt); + fflush (stdout); + this_subtest_failed = true; + failed_subtests++; + } + break; + + default: + printf ("ERROR: %s/%s: invalid value for 'expected' = %d\n", + label, stage, (int)expected); + fflush (stdout); + this_subtest_failed = true; + failed_subtests++; + } +} + +/* Always check the test buffer immediately after filling it; this + makes externally visible side effects depend on the buffer existing + and having been filled in. */ +static void +prepare_test_buffer (unsigned char *buf, const char *label) +{ + fill_with_test_pattern (buf); + check_test_buffer (EXPECT_ALL, label, "prepare"); + + unsigned char *loc = memmem (signal_stack_buffer, SIGNAL_STACK_SIZE, + test_pattern, PATTERN_SIZE); + if (loc == buf) + { + printf ("PASS: %s/prepare: expected buffer location %p got %p\n", + label, buf, loc); + fflush (stdout); + } + else + { + printf ("FAIL: %s/prepare: expected buffer location %p got %p\n", + label, buf, loc); + fflush (stdout); + this_subtest_failed = true; + failed_subtests++; + } +} + +/* There are three subtests, two of which are sanity checks. + + In the "no_clear" case, we don't do anything to the test buffer + between preparing it and letting it go out of scope, and we expect + to find it. This confirms that the test buffer does get filled in + and we can find it from the stack buffer. In the "ordinary_clear" + case, we clear it using memset, and we expect to find it. This + confirms that the compiler can optimize out block clears in this + context; if it can't, the real test might be succeeding for the + wrong reason. Finally, the "explicit_clear" case uses + explicit_bzero and expects _not_ to find the test buffer, which is + the real test. */ + +static void +setup_no_clear (void) +{ + unsigned char buf[TEST_BUFFER_SIZE]; + prepare_test_buffer (buf, "no clear"); +} + +static void +setup_ordinary_clear (void) +{ + unsigned char buf[TEST_BUFFER_SIZE]; + prepare_test_buffer (buf, "ordinary clear"); + if (this_subtest_failed) + return; + memset (buf, 0, TEST_BUFFER_SIZE); +} + +static void +setup_explicit_clear (void) +{ + unsigned char buf[TEST_BUFFER_SIZE]; + prepare_test_buffer (buf, "explicit clear"); + if (this_subtest_failed) + return; + explicit_bzero (buf, TEST_BUFFER_SIZE); +} + +struct subtest +{ + void (*setup_subtest) (void); + const char *label; + enum test_expectation expected; +}; + +static const struct subtest subtests[] = +{ + { setup_no_clear, "no clear", EXPECT_SOME }, + { setup_ordinary_clear, "ordinary clear", EXPECT_SOME }, + { setup_explicit_clear, "explicit clear", EXPECT_NONE }, + { 0, 0, -1 } +}; +static const struct subtest *this_subtest; +static bool this_subtest_complete; + +/* This function is called as a signal handler. The signal is + triggered by a call to raise, therefore it is safe to do + non-async-signal-safe things within this function. + + The this_subtest_complete flag addresses a race. The outer loop + keeps SIGUSR1 blocked all the time, unblocking it only immediately + after setting up the appropriate conditions for a test and then + raising SIGUSR1 itself. SIGUSR1 is not a real-time signal, so if + another process sends this process SIGUSR1 _before_ it's unblocked + by the outer loop, this function will only be called once. + However, if another process sends this process SIGUSR1 _while this + handler is already running_, that signal will be pending upon + return from this function, and will fire before the outer loop has + a chance to re-block SIGUSR1. This is unavoidable; the workaround + is to arrange for this function not to do anything if it's called + several times in a row. */ +static void +do_subtest (int signo __attribute__ ((unused))) +{ + if (!this_subtest_complete) + { + this_subtest->setup_subtest (); + if (!this_subtest_failed) + check_test_buffer (this_subtest->expected, + this_subtest->label, + "test"); + this_subtest_complete = true; + } +} + +static int +do_test (void) +{ + /* test-skeleton.c unconditionally sets stdout to be unbuffered. + vfprintf allocates a great deal of memory on the stack if called + with an unbuffered FILE*, overflowing the alt-stack. This is + also why there is a call to fflush after every call to printf in + this file. */ + if (setvbuf (stdout, 0, _IOFBF, 0)) + { + printf ("ERROR: restoring stdout buffering: %s\n", strerror (errno)); + fflush (stdout); + return 2; + } + + size_t page_alignment = sysconf (_SC_PAGESIZE); + if (page_alignment < sizeof (void *)) + page_alignment = sizeof (void *); + + void *p; + int err = posix_memalign (&p, page_alignment, SIGNAL_STACK_SIZE); + if (err || !p) + { + printf ("ERROR: allocating alt stack: %s\n", strerror (err)); + fflush (stdout); + return 2; + } + signal_stack_buffer = p; + + /* This program will malfunction if it receives SIGUSR1 signals at any + time other than when it's just sent one to itself. Therefore, keep + it blocked most of the time. */ + sigset_t sigusr1_mask; + sigemptyset (&sigusr1_mask); + sigaddset (&sigusr1_mask, SIGUSR1); + if (sigprocmask (SIG_BLOCK, &sigusr1_mask, 0)) + { + printf ("ERROR: block(SIGUSR1): %s\n", strerror (errno)); + fflush (stdout); + return 2; + } + + stack_t ss; + ss.ss_sp = signal_stack_buffer; + ss.ss_flags = 0; + ss.ss_size = SIGNAL_STACK_SIZE; + if (sigaltstack (&ss, 0)) + { + printf ("ERROR: sigaltstack: %s\n", strerror (errno)); + fflush (stdout); + return 2; + } + + struct sigaction sa; + sigemptyset (&sa.sa_mask); + sigaddset (&sa.sa_mask, SIGUSR1); + sa.sa_handler = do_subtest; + sa.sa_flags = SA_RESTART | SA_ONSTACK; + if (sigaction (SIGUSR1, &sa, 0)) + { + printf ("ERROR: sigaction(SIGUSR1): %s\n", strerror (errno)); + fflush (stdout); + return 2; + } + + /* We use kill instead of raise, because raise screws with the + signal mask, which we don't want. */ + pid_t self = getpid (); + + this_subtest = subtests; + while (this_subtest->label) + { + this_subtest_complete = false; + this_subtest_failed = false; + + /* Completely clear the signal stack between tests, so that junk + from previous tests cannot interfere with the current one. */ + memset (signal_stack_buffer, 0, SIGNAL_STACK_SIZE); + + /* Raise SIGUSR1, then unblock it, then immediately block it + again. This will trigger do_subtest to run _once_ on the + alternative stack, at the point of calling sigprocmask to + unblock the signal. */ + if (kill (self, SIGUSR1)) + { + printf ("ERROR: raise(SIGUSR1): %s\n", strerror (errno)); + fflush (stdout); + return 2; + } + if (sigprocmask (SIG_UNBLOCK, &sigusr1_mask, 0)) + { + printf ("ERROR: unblock(SIGUSR1): %s\n", strerror (errno)); + fflush (stdout); + return 2; + } + if (sigprocmask (SIG_BLOCK, &sigusr1_mask, 0)) + { + printf ("ERROR: unblock(SIGUSR1): %s\n", strerror(errno)); + fflush (stdout); + return 2; + } + + this_subtest++; + } + + return failed_subtests ? 1 : 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/arm/nacl/libc.abilist b/sysdeps/arm/nacl/libc.abilist index 4d3b0b9..345246c 100644 --- a/sysdeps/arm/nacl/libc.abilist +++ b/sysdeps/arm/nacl/libc.abilist @@ -1843,6 +1843,7 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F GLIBC_2.25 gnu_dev_major F GLIBC_2.25 gnu_dev_makedev F GLIBC_2.25 gnu_dev_minor F diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist index 2c2f49e..a6f076a 100644 --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist @@ -2090,3 +2090,4 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist index 8afba47..6d67017 100644 --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist @@ -2001,6 +2001,7 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __ctype_b_loc F GLIBC_2.3 __ctype_tolower_loc F diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist index de3bdf4..3f70b6c 100644 --- a/sysdeps/unix/sysv/linux/arm/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/libc.abilist @@ -91,6 +91,7 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F GLIBC_2.4 GLIBC_2.4 A GLIBC_2.4 _Exit F GLIBC_2.4 _IO_2_1_stderr_ D 0xa0 diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist index 3261b93..8dd44b3 100644 --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist @@ -1855,6 +1855,7 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __ctype_b_loc F GLIBC_2.3 __ctype_tolower_loc F diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist index 6465a55..147d6c4 100644 --- a/sysdeps/unix/sysv/linux/i386/libc.abilist +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist @@ -2013,6 +2013,7 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __ctype_b_loc F GLIBC_2.3 __ctype_tolower_loc F diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist index 4536271..77d6743 100644 --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist @@ -1877,6 +1877,7 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __ctype_b_loc F GLIBC_2.3 __ctype_tolower_loc F diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist index 287d7a5..52e1d01 100644 --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist @@ -92,6 +92,7 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F GLIBC_2.4 GLIBC_2.4 A GLIBC_2.4 _Exit F GLIBC_2.4 _IO_2_1_stderr_ D 0x98 diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist index c9229fa..6dfe8a1 100644 --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist @@ -1969,6 +1969,7 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __ctype_b_loc F GLIBC_2.3 __ctype_tolower_loc F diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist index 0409791..8fff289 100644 --- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist @@ -2090,3 +2090,4 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist index f31653e..7b9a1d6 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist @@ -1944,6 +1944,7 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __ctype_b_loc F GLIBC_2.3 __ctype_tolower_loc F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist index a56bd99..b1ca58e 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist @@ -1942,6 +1942,7 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __ctype_b_loc F GLIBC_2.3 __ctype_tolower_loc F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist index 44552df..73542d1 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist @@ -1940,6 +1940,7 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __ctype_b_loc F GLIBC_2.3 __ctype_tolower_loc F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist index 8d2a09d..66d53a1 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist @@ -1935,6 +1935,7 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __ctype_b_loc F GLIBC_2.3 __ctype_tolower_loc F diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist index 0443b92..9be8569 100644 --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist @@ -2131,3 +2131,4 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist index ba9a29a..590b6f0 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist @@ -1973,6 +1973,7 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __ctype_b_loc F GLIBC_2.3 __ctype_tolower_loc F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist index f19534c..f191e62 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist @@ -1978,6 +1978,7 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __ctype_b_loc F GLIBC_2.3 __ctype_tolower_loc F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist index f8de1ab..39fbee9 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist @@ -2178,3 +2178,4 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist index 6819133..8921048 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist @@ -92,6 +92,7 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 _Exit F GLIBC_2.3 _IO_2_1_stderr_ D 0xe0 diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist index 4cd5d85..10109a8 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist @@ -1973,6 +1973,7 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __ctype_b_loc F GLIBC_2.3 __ctype_tolower_loc F diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist index 8cdb9df..10ad998 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist @@ -1874,6 +1874,7 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __ctype_b_loc F GLIBC_2.3 __ctype_tolower_loc F diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist index 69791b4..f7fd80d 100644 --- a/sysdeps/unix/sysv/linux/sh/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/libc.abilist @@ -1859,6 +1859,7 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __ctype_b_loc F GLIBC_2.3 __ctype_tolower_loc F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist index fce58a8..6a77cc9 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist @@ -1965,6 +1965,7 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __ctype_b_loc F GLIBC_2.3 __ctype_tolower_loc F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist index 16ce739..da1bc47 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist @@ -1903,6 +1903,7 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __ctype_b_loc F GLIBC_2.3 __ctype_tolower_loc F diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist index f99c298..3cb4463 100644 --- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist +++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist @@ -2097,3 +2097,4 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist index c601ab0..db16fa5 100644 --- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist +++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist @@ -2097,3 +2097,4 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist index f99c298..3cb4463 100644 --- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist +++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist @@ -2097,3 +2097,4 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist index 8e6fa57..34bf69c 100644 --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist @@ -1854,6 +1854,7 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __ctype_b_loc F GLIBC_2.3 __ctype_tolower_loc F diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist index 1e12f48..c31daa8 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist @@ -2097,3 +2097,4 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 explicit_bzero F -- 2.9.3 ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 2/3] Add fortification and inline optimization of explicit_bzero. 2016-09-15 13:05 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Zack Weinberg @ 2016-09-15 13:05 ` Zack Weinberg 2016-09-15 13:05 ` [PATCH 3/3] Use explicit_bzero where appropriate Zack Weinberg 2016-09-15 15:38 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Paul Eggert ` (2 subsequent siblings) 3 siblings, 1 reply; 15+ messages in thread From: Zack Weinberg @ 2016-09-15 13:05 UTC (permalink / raw) To: libc-alpha; +Cc: fweimer By exposing __glibc_read_memory to external callers, we can write a fortify wrapper for explicit_bzero in terms of __memset_chk and __glibc_read_memory. There is no out-of-line __bzero_chk defined in libc.so, so I see no need to add an out-of-line __explicit_bzero_chk either. We can also add a bits/string2.h macro that optimizes explicit_bzero to memset + __glibc_read_memory, thus allowing the compiler to use intrinsic code generation for memset. I think this is worth doing because it partially addresses the problem pointed out in the manual, where explicit_bzero might _cause_ sensitive data to be copied out of registers onto the stack. With memset visible to the compiler, it will just clear a scratch area on the stack and then call __glibc_read_memory; it won't copy the sensitive data onto the stack first. (But it still doesn't erase the sensitive data _in_ the registers, so the warning in the manual is still appropriate.) * include/string.h: Change declaration of __glibc_read_memory to declaration of an internal alias. * string/string.h: Declare __glibc_read_memory here. * string/explicit_bzero.c: Use the internal alias for __glibc_read_memory. * string/bits/string2.h: Optimize explicit_bzero. * string/bits/string3.h: Fortify explicit_bzero. * debug/tst-chk1.c: Test fortification of explicit_bzero. * string/Versions: Expose __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 __glibc_read_memory. --- debug/tst-chk1.c | 28 ++++++++++++++++++++++ include/string.h | 5 ++-- string/Versions | 3 +++ string/bits/string2.h | 13 +++++++++- string/bits/string3.h | 7 ++++++ string/explicit_bzero.c | 2 +- string/read_memory.c | 5 ++-- string/string.h | 5 ++++ 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 + 37 files changed, 90 insertions(+), 7 deletions(-) diff --git a/debug/tst-chk1.c b/debug/tst-chk1.c index 478c2fb..e87a279 100644 --- a/debug/tst-chk1.c +++ b/debug/tst-chk1.c @@ -160,6 +160,10 @@ do_test (void) if (memcmp (buf, "aabcdabc\0\0", 10)) FAIL (); + explicit_bzero (buf + 6, 4); + if (memcmp (buf, "aabcda\0\0\0\0", 10)) + FAIL (); + strcpy (buf + 4, "EDCBA"); if (memcmp (buf, "aabcEDCBA", 10)) FAIL (); @@ -201,6 +205,10 @@ do_test (void) if (memcmp (buf, "aabcdabc\0\0", 10)) FAIL (); + explicit_bzero (buf + 6, l0 + 4); + if (memcmp (buf, "aabcda\0\0\0\0", 10)) + FAIL (); + strcpy (buf + 4, str1 + 5); if (memcmp (buf, "aabcEDCBA", 10)) FAIL (); @@ -256,6 +264,10 @@ do_test (void) if (memcmp (a.buf1, "aabcdabc\0\0", 10)) FAIL (); + explicit_bzero (a.buf1 + 6, l0 + 4); + if (memcmp (a.buf1, "aabcda\0\0\0\0", 10)) + FAIL (); + #if __USE_FORTIFY_LEVEL < 2 /* The following tests are supposed to crash with -D_FORTIFY_SOURCE=2 and sufficient GCC support, as the string operations overflow @@ -345,6 +357,14 @@ do_test (void) bzero (buf + 9, l0 + 2); CHK_FAIL_END + CHK_FAIL_START + explicit_bzero (buf + 9, 2); + CHK_FAIL_END + + CHK_FAIL_START + explicit_bzero (buf + 9, l0 + 2); + CHK_FAIL_END + CHK_FAIL_START strcpy (buf + 5, str1 + 5); CHK_FAIL_END @@ -454,6 +474,14 @@ do_test (void) bzero (a.buf1 + 9, l0 + 2); CHK_FAIL_END + CHK_FAIL_START + explicit_bzero (a.buf1 + 9, 2); + CHK_FAIL_END + + CHK_FAIL_START + explicit_bzero (a.buf1 + 9, l0 + 2); + CHK_FAIL_END + # if __USE_FORTIFY_LEVEL >= 2 # define O 0 # else diff --git a/include/string.h b/include/string.h index dc0edf3..277c07d 100644 --- a/include/string.h +++ b/include/string.h @@ -99,9 +99,8 @@ 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) +extern __typeof (__glibc_read_memory) __internal_glibc_read_memory; +libc_hidden_proto (__internal_glibc_read_memory) libc_hidden_builtin_proto (memchr) libc_hidden_builtin_proto (memcpy) diff --git a/string/Versions b/string/Versions index a2c6e6e..3d116f3 100644 --- a/string/Versions +++ b/string/Versions @@ -83,6 +83,9 @@ libc { GLIBC_2.24 { } GLIBC_2.25 { + # used by inlines in bits/string2.h and bits/string3.h + __glibc_read_memory; + # e* explicit_bzero; } diff --git a/string/bits/string2.h b/string/bits/string2.h index 8098760..6066d49 100644 --- a/string/bits/string2.h +++ b/string/bits/string2.h @@ -52,11 +52,22 @@ #define __string2_1bptr_p(__x) \ ((size_t)(const void *)((__x) + 1) - (size_t)(const void *)(__x) == 1) -/* Set N bytes of S to C. */ +/* Set N bytes of S to 0. */ #if !defined _HAVE_STRING_ARCH_memset # define __bzero(s, n) __builtin_memset (s, '\0', n) #endif +#if defined __USE_MISC && !defined __fortify_function +/* As bzero, but the compiler will not delete a call to this function, + even if S is dead after the call. This is a macro instead of an + inline function _solely_ so that it will not get turned into an + external definition in string-inlines.o; it has its own .c file in + libc already. */ +#define explicit_bzero(s, n) \ + (__extension__ ({ void *__s = (s); size_t __n = (n); \ + memset (__s, '\0', __n); \ + __glibc_read_memory (__s, __n); })) +#endif #ifndef _HAVE_STRING_ARCH_strchr extern void *__rawmemchr (const void *__s, int __c); diff --git a/string/bits/string3.h b/string/bits/string3.h index dd8db68..d340bef 100644 --- a/string/bits/string3.h +++ b/string/bits/string3.h @@ -102,6 +102,13 @@ __NTH (bzero (void *__dest, size_t __len)) { (void) __builtin___memset_chk (__dest, '\0', __len, __bos0 (__dest)); } + +__fortify_function void +__NTH (explicit_bzero (void *__dest, size_t __len)) +{ + (void) __builtin___memset_chk (__dest, '\0', __len, __bos0 (__dest)); + __glibc_read_memory (__dest, __len); +} #endif __fortify_function char * diff --git a/string/explicit_bzero.c b/string/explicit_bzero.c index a2b75be..a02be4f 100644 --- a/string/explicit_bzero.c +++ b/string/explicit_bzero.c @@ -26,5 +26,5 @@ void explicit_bzero (void *s, size_t len) { memset (s, '\0', len); - __glibc_read_memory (s, len); + __internal_glibc_read_memory (s, len); } diff --git a/string/read_memory.c b/string/read_memory.c index 5347ee2..c4a5990 100644 --- a/string/read_memory.c +++ b/string/read_memory.c @@ -33,8 +33,9 @@ void internal_function -__glibc_read_memory(const void *s, size_t len) +__internal_glibc_read_memory(const void *s, size_t len) { asm volatile (""); } -libc_hidden_def (__glibc_read_memory) +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 89f5ab2..682661a 100644 --- a/string/string.h +++ b/string/string.h @@ -459,6 +459,11 @@ extern void bzero (void *__s, size_t __n) __THROW __nonnull ((1)); 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/sysdeps/arm/nacl/libc.abilist b/sysdeps/arm/nacl/libc.abilist index 345246c..02d4bc6 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 __glibc_read_memory F GLIBC_2.25 explicit_bzero F GLIBC_2.25 gnu_dev_major F GLIBC_2.25 gnu_dev_makedev F diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist index a6f076a..44dc0d1 100644 --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist @@ -2090,4 +2090,5 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __glibc_read_memory F GLIBC_2.25 explicit_bzero F diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist index 6d67017..02a490d 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 __glibc_read_memory F GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __ctype_b_loc F diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist index 3f70b6c..d2b2800 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 __glibc_read_memory F GLIBC_2.25 explicit_bzero F GLIBC_2.4 GLIBC_2.4 A GLIBC_2.4 _Exit F diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist index 8dd44b3..59b2591 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 __glibc_read_memory F GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __ctype_b_loc F diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist index 147d6c4..e64f9c6 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 __glibc_read_memory F GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __ctype_b_loc F diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist index 77d6743..78acf45 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 __glibc_read_memory F GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __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 52e1d01..ceb1909 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 __glibc_read_memory F GLIBC_2.25 explicit_bzero F GLIBC_2.4 GLIBC_2.4 A GLIBC_2.4 _Exit F diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist index 6dfe8a1..e8d7256 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 __glibc_read_memory F GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __ctype_b_loc F diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist index 8fff289..c2e2ecc 100644 --- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist @@ -2090,4 +2090,5 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __glibc_read_memory F GLIBC_2.25 explicit_bzero F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist index 7b9a1d6..705f00b 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 __glibc_read_memory F GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __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 b1ca58e..41d3e5c 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 __glibc_read_memory F GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __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 73542d1..4de5839 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 __glibc_read_memory F GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __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 66d53a1..e1d5bec 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 __glibc_read_memory F GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __ctype_b_loc F diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist index 9be8569..34e83a6 100644 --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist @@ -2131,4 +2131,5 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __glibc_read_memory F GLIBC_2.25 explicit_bzero F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist index 590b6f0..91a30c8 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 __glibc_read_memory F GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __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 f191e62..a4ecbc2 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 __glibc_read_memory F GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __ctype_b_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 39fbee9..277ec26 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist @@ -2178,4 +2178,5 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __glibc_read_memory F GLIBC_2.25 explicit_bzero F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist index 8921048..e3dafa5 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 __glibc_read_memory F GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 _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 10109a8..3ab826d 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 __glibc_read_memory F GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __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 10ad998..c4c0a8e 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 __glibc_read_memory F GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __ctype_b_loc F diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist index f7fd80d..7a11b8a 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 __glibc_read_memory F GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __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 6a77cc9..13efb9f 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 __glibc_read_memory F GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __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 da1bc47..da6819b 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 __glibc_read_memory F GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __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 3cb4463..0d58dc0 100644 --- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist +++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist @@ -2097,4 +2097,5 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __glibc_read_memory F GLIBC_2.25 explicit_bzero F diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist index db16fa5..fc55930 100644 --- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist +++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist @@ -2097,4 +2097,5 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __glibc_read_memory F GLIBC_2.25 explicit_bzero F diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist index 3cb4463..0d58dc0 100644 --- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist +++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist @@ -2097,4 +2097,5 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __glibc_read_memory F GLIBC_2.25 explicit_bzero F diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist index 34bf69c..858a26c 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 __glibc_read_memory F GLIBC_2.25 explicit_bzero F GLIBC_2.3 GLIBC_2.3 A GLIBC_2.3 __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 c31daa8..9a45eed 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist @@ -2097,4 +2097,5 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __glibc_read_memory F GLIBC_2.25 explicit_bzero F -- 2.9.3 ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 3/3] Use explicit_bzero where appropriate 2016-09-15 13:05 ` [PATCH 2/3] Add fortification and inline optimization of explicit_bzero Zack Weinberg @ 2016-09-15 13:05 ` Zack Weinberg 0 siblings, 0 replies; 15+ messages in thread From: Zack Weinberg @ 2016-09-15 13:05 UTC (permalink / raw) To: libc-alpha; +Cc: fweimer I *believe* these are the only places where memset was being used to clear buffers containing sensitive data. The compiler probably couldn't optimize *all* of them out but it seems best to change them all. The legacy DES implementation wasn't bothering to clear its buffers, so I added that, mostly for consistency's sake. * crypt/crypt-entry.c (__crypt_r): Clear key-dependent intermediate data before returning, using explicit_bzero. * crypt/md5-crypt.c (__md5_crypt_r): Likewise. * crypt/sha256-crypt.c (__sha256_crypt_r): Likewise. * crypt/sha512-crypt.c (__sha512_crypt_r): Likewise. --- crypt/crypt-entry.c | 11 +++++++++++ crypt/md5-crypt.c | 8 ++++---- crypt/sha256-crypt.c | 14 +++++++------- crypt/sha512-crypt.c | 14 +++++++------- 4 files changed, 29 insertions(+), 18 deletions(-) diff --git a/crypt/crypt-entry.c b/crypt/crypt-entry.c index a7dfcca..09a5664 100644 --- a/crypt/crypt-entry.c +++ b/crypt/crypt-entry.c @@ -141,6 +141,17 @@ __crypt_r (const char *key, const char *salt, * And convert back to 6 bit ASCII */ _ufc_output_conversion_r (res[0], res[1], salt, data); + +#ifdef _LIBC + /* + * Erase key-dependent intermediate data. Data dependent only on + * the salt is not considered sensitive. + */ + explicit_bzero (ktab, sizeof (ktab)); + explicit_bzero (data->keysched, sizeof (data->keysched)); + explicit_bzero (res, sizeof (res)); +#endif + return data->crypt_3_buf; } weak_alias (__crypt_r, crypt_r) diff --git a/crypt/md5-crypt.c b/crypt/md5-crypt.c index 2243bc7..6125c7f 100644 --- a/crypt/md5-crypt.c +++ b/crypt/md5-crypt.c @@ -288,13 +288,13 @@ __md5_crypt_r (const char *key, const char *salt, char *buffer, int buflen) #ifndef USE_NSS __md5_init_ctx (&ctx); __md5_finish_ctx (&ctx, alt_result); - memset (&ctx, '\0', sizeof (ctx)); - memset (&alt_ctx, '\0', sizeof (alt_ctx)); + explicit_bzero (&ctx, sizeof (ctx)); + explicit_bzero (&alt_ctx, sizeof (alt_ctx)); #endif if (copied_key != NULL) - memset (copied_key, '\0', key_len); + explicit_bzero (copied_key, key_len); if (copied_salt != NULL) - memset (copied_salt, '\0', salt_len); + explicit_bzero (copied_salt, salt_len); free (free_key); return buffer; diff --git a/crypt/sha256-crypt.c b/crypt/sha256-crypt.c index ca703de..6717e22 100644 --- a/crypt/sha256-crypt.c +++ b/crypt/sha256-crypt.c @@ -371,16 +371,16 @@ __sha256_crypt_r (const char *key, const char *salt, char *buffer, int buflen) #ifndef USE_NSS __sha256_init_ctx (&ctx); __sha256_finish_ctx (&ctx, alt_result); - memset (&ctx, '\0', sizeof (ctx)); - memset (&alt_ctx, '\0', sizeof (alt_ctx)); + explicit_bzero (&ctx, sizeof (ctx)); + explicit_bzero (&alt_ctx, sizeof (alt_ctx)); #endif - memset (temp_result, '\0', sizeof (temp_result)); - memset (p_bytes, '\0', key_len); - memset (s_bytes, '\0', salt_len); + explicit_bzero (temp_result, sizeof (temp_result)); + explicit_bzero (p_bytes, key_len); + explicit_bzero (s_bytes, salt_len); if (copied_key != NULL) - memset (copied_key, '\0', key_len); + explicit_bzero (copied_key, key_len); if (copied_salt != NULL) - memset (copied_salt, '\0', salt_len); + explicit_bzero (copied_salt, salt_len); free (free_key); free (free_pbytes); diff --git a/crypt/sha512-crypt.c b/crypt/sha512-crypt.c index c42e5b7..1965191 100644 --- a/crypt/sha512-crypt.c +++ b/crypt/sha512-crypt.c @@ -393,16 +393,16 @@ __sha512_crypt_r (const char *key, const char *salt, char *buffer, int buflen) #ifndef USE_NSS __sha512_init_ctx (&ctx); __sha512_finish_ctx (&ctx, alt_result); - memset (&ctx, '\0', sizeof (ctx)); - memset (&alt_ctx, '\0', sizeof (alt_ctx)); + explicit_bzero (&ctx, sizeof (ctx)); + explicit_bzero (&alt_ctx, sizeof (alt_ctx)); #endif - memset (temp_result, '\0', sizeof (temp_result)); - memset (p_bytes, '\0', key_len); - memset (s_bytes, '\0', salt_len); + explicit_bzero (temp_result, sizeof (temp_result)); + explicit_bzero (p_bytes, key_len); + explicit_bzero (s_bytes, salt_len); if (copied_key != NULL) - memset (copied_key, '\0', key_len); + explicit_bzero (copied_key, key_len); if (copied_salt != NULL) - memset (copied_salt, '\0', salt_len); + explicit_bzero (copied_salt, salt_len); free (free_key); free (free_pbytes); -- 2.9.3 ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] New string function explicit_bzero (from OpenBSD). 2016-09-15 13:05 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Zack Weinberg 2016-09-15 13:05 ` [PATCH 2/3] Add fortification and inline optimization of explicit_bzero Zack Weinberg @ 2016-09-15 15:38 ` Paul Eggert 2016-09-15 15:59 ` Paul Eggert 2016-10-06 10:03 ` Florian Weimer 3 siblings, 0 replies; 15+ messages in thread From: Paul Eggert @ 2016-09-15 15:38 UTC (permalink / raw) To: Zack Weinberg, libc-alpha; +Cc: fweimer On 09/15/2016 06:05 AM, Zack Weinberg wrote: > +void > +internal_function > +__glibc_read_memory(const void *s, size_t len) > +{ > + asm volatile (""); > +} This leaks the address S to possibly-buggy code, bypassing address randomization. For example, if a function body ends in 'explicit_bzero (&x, sizeof x)', then &x is likely to be in a machine register or on the stack when explicit_bzero returns, more so than if explicit_bzero were never called. If a key is stored next to other somewhat-sensitive data this will make the somewhat-sensitive data more vulnerable than it otherwise would be. To help avoid this problem, __glibc_read_member could clear all caller-save registers (including the return register of course). This would not entirely prevent the problem, but that's OK as explicit_bzero does not pretend to entirely prevent information leakage. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] New string function explicit_bzero (from OpenBSD). 2016-09-15 13:05 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Zack Weinberg 2016-09-15 13:05 ` [PATCH 2/3] Add fortification and inline optimization of explicit_bzero Zack Weinberg 2016-09-15 15:38 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Paul Eggert @ 2016-09-15 15:59 ` Paul Eggert 2016-10-06 10:03 ` Florian Weimer 3 siblings, 0 replies; 15+ messages in thread From: Paul Eggert @ 2016-09-15 15:59 UTC (permalink / raw) To: Zack Weinberg, libc-alpha; +Cc: fweimer On 09/15/2016 06:05 AM, Zack Weinberg wrote: > +The compiler will not delete a call to this function, even > +if the object beginning at @var{block} is never referred to again. That's too strong, no? It'd be OK if the compiler inlined the call, or if it deleted the call if LEN is zero. Also, "referred to" is too vague, as we don't care whether the block is written to later, only whether it is read from. And "beginning at @var{block}" is redundant given the previous sentence. I suggest rewording this to "The zeros are written even if the object is never read again." > +Without the call to @code{explicit_bzero}, @var{k} might not need to > +be stored in memory: depending on the ABI, its value could be returned Although this info is helpful, it would be even more helpful if the example explained how to fix the problem. (Can one declare K to be volatile, for example? If not, explain why this does not suffice. Does it help to pass &K to explicit_bzero before initializing K? If not, explain that too.) If there is no portable way to address the problem, the discussion should flat-out say so. I hate to say it, but multithreading issues might need a brief mention too. If some other thread is compromised, a call to explicit_bzero can make the current thread more vulnerable, not less. I must say that after thinking about the above, my opinion of explicit_bzero has gone down a bit.... ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] New string function explicit_bzero (from OpenBSD). 2016-09-15 13:05 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Zack Weinberg ` (2 preceding siblings ...) 2016-09-15 15:59 ` Paul Eggert @ 2016-10-06 10:03 ` Florian Weimer 2016-10-06 15:49 ` Joseph Myers 3 siblings, 1 reply; 15+ messages in thread From: Florian Weimer @ 2016-10-06 10:03 UTC (permalink / raw) To: Zack Weinberg, libc-alpha On 09/15/2016 03:05 PM, Zack Weinberg wrote: > +/* As bzero, but the compiler will not delete a call to this > + function, even if S is dead after the call. */ > +extern void explicit_bzero (void *__s, size_t __n) __THROW __nonnull ((1)); I would like to redirect callers to __explicit_bzero, so that shared objects do not accidentally pick up an implementation of explicit_bzero which may or may not do the right thing. I did this in my getrandom implementation: <https://sourceware.org/ml/libc-alpha/2016-09/msg00203.html> You can use __REDIRECT_NTH (meanining no exceptions) instead of __REDIRECT. This requires exporting both __explicit_bzero and explicit_bzero. We need a symbol in the implementation namespace anyway because crypt is in POSIX, but explicit_bzero is not. From the test, I would suggest to remove the fflush (stdout) calls. There are some whitespace GNU-style violations as well (missing space before paren in function call): +struct key get_key(void); +void use_key(struct key); +with_clear(void) + k = get_key(); + use_key(k); + explicit_bzero(&k, sizeof(k)); +__glibc_read_memory(const void *s, size_t len) + printf ("ERROR: block(SIGUSR1): %s\n", strerror (errno)); + printf ("ERROR: sigaction(SIGUSR1): %s\n", strerror (errno)); + printf ("ERROR: raise(SIGUSR1): %s\n", strerror (errno)); + printf ("ERROR: unblock(SIGUSR1): %s\n", strerror (errno)); + printf ("ERROR: unblock(SIGUSR1): %s\n", strerror(errno)); Thanks, Florian ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] New string function explicit_bzero (from OpenBSD). 2016-10-06 10:03 ` Florian Weimer @ 2016-10-06 15:49 ` Joseph Myers 2016-10-18 9:27 ` Florian Weimer 0 siblings, 1 reply; 15+ messages in thread From: Joseph Myers @ 2016-10-06 15:49 UTC (permalink / raw) To: Florian Weimer; +Cc: Zack Weinberg, libc-alpha On Thu, 6 Oct 2016, Florian Weimer wrote: > On 09/15/2016 03:05 PM, Zack Weinberg wrote: > > +/* As bzero, but the compiler will not delete a call to this > > + function, even if S is dead after the call. */ > > +extern void explicit_bzero (void *__s, size_t __n) __THROW __nonnull ((1)); > > I would like to redirect callers to __explicit_bzero, so that shared objects > do not accidentally pick up an implementation of explicit_bzero which may or > may not do the right thing. Do you have a proposed rule for when to do such redirection? I don't think it should be normal to do it; any library function could potentially be affected by applications defining their own function with that name. (Exporting reserved function names at public versions makes sense when there is a use for those functions in contexts with namespace issues, such as libgcc or libstdc++.) -- Joseph S. Myers joseph@codesourcery.com ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] New string function explicit_bzero (from OpenBSD). 2016-10-06 15:49 ` Joseph Myers @ 2016-10-18 9:27 ` Florian Weimer 0 siblings, 0 replies; 15+ messages in thread From: Florian Weimer @ 2016-10-18 9:27 UTC (permalink / raw) To: Joseph Myers; +Cc: Zack Weinberg, libc-alpha On 10/06/2016 05:49 PM, Joseph Myers wrote: > On Thu, 6 Oct 2016, Florian Weimer wrote: > >> On 09/15/2016 03:05 PM, Zack Weinberg wrote: >>> +/* As bzero, but the compiler will not delete a call to this >>> + function, even if S is dead after the call. */ >>> +extern void explicit_bzero (void *__s, size_t __n) __THROW __nonnull ((1)); >> >> I would like to redirect callers to __explicit_bzero, so that shared objects >> do not accidentally pick up an implementation of explicit_bzero which may or >> may not do the right thing. > > Do you have a proposed rule for when to do such redirection? I don't > think it should be normal to do it; any library function could potentially > be affected by applications defining their own function with that name. > > (Exporting reserved function names at public versions makes sense when > there is a use for those functions in contexts with namespace issues, such > as libgcc or libstdc++.) Thanks for asking. I started a new thread for this topic: <https://sourceware.org/ml/libc-alpha/2016-10/msg00294.html> Florian ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 0/3] explicit_bzero v5 @ 2016-11-15 15:55 Zack Weinberg 2016-11-15 15:55 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Zack Weinberg 0 siblings, 1 reply; 15+ messages in thread From: Zack Weinberg @ 2016-11-15 15:55 UTC (permalink / raw) To: libc-alpha; +Cc: carlos, fweimer I would really like to get this into 2.25, and I believe that I have addressed all substantive objections. Please review. The core implementation strategy is the same as for the previous iteration. Changes since then are: * All of the ABI-affecting changes appear in patch 1/3 to minimize clutter. (The plan is still to squash all three commits into one for landing.) * libc.so now exports __explicit_bzero as well as explicit_bzero; the implementation-namespace symbol is used by libcrypt.so, and the user-namespace symbol is weak. (Requested by Joseph, iirc.) The impl-namespace symbol is versioned GLIBC_2.25 instead of GLIBC_PRIVATE, because that seems to be what was done for other impl-namespace aliases for string functions. I wasn't able to find anything definitive about when GLIBC_PRIVATE should be used. * tst-xbzero-opt.c has been tightened up a bit. * The interaction between bits/string2.h and bits/string3.h should now be more robust. * The documentation has been revised per Paul Eggert's comments. Paul Eggert also observed that a call to explicit_bzero might expose the _address_ of a buffer containing sensitive data, and perhaps another thread could exfiltrate the data before it was erased. I thought about it and I have concluded that this, like the other remaining problems with this API, needs to be addressed in the compiler; there's nothing glibc can reasonably do about it. Clobbering all caller-save registers and incoming argument space is the best thing we _could_ do about it, but that would have to happen _after_ the memset, so it doesn't actually help. zw Zack Weinberg (3): New string function explicit_bzero (from OpenBSD). Add fortification and inline optimization of explicit_bzero. Use explicit_bzero where appropriate crypt/crypt-entry.c | 11 + crypt/md5-crypt.c | 8 +- crypt/sha256-crypt.c | 14 +- crypt/sha512-crypt.c | 14 +- debug/tst-chk1.c | 28 ++ include/string.h | 12 + manual/string.texi | 124 ++++++++ string/Makefile | 12 +- string/Versions | 10 + string/bits/string2.h | 11 + string/bits/string3.h | 8 + string/explicit_bzero.c | 33 ++ string/read_memory.c | 41 +++ string/string.h | 9 + string/test-explicit_bzero.c | 20 ++ string/test-memset.c | 10 +- string/tst-xbzero-opt.c | 348 +++++++++++++++++++++ sysdeps/arm/nacl/libc.abilist | 3 + sysdeps/unix/sysv/linux/aarch64/libc.abilist | 3 + sysdeps/unix/sysv/linux/alpha/libc.abilist | 3 + sysdeps/unix/sysv/linux/arm/libc.abilist | 3 + sysdeps/unix/sysv/linux/hppa/libc.abilist | 3 + sysdeps/unix/sysv/linux/i386/libc.abilist | 3 + sysdeps/unix/sysv/linux/ia64/libc.abilist | 3 + sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist | 3 + sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist | 3 + sysdeps/unix/sysv/linux/microblaze/libc.abilist | 3 + .../unix/sysv/linux/mips/mips32/fpu/libc.abilist | 3 + .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist | 3 + .../unix/sysv/linux/mips/mips64/n32/libc.abilist | 3 + .../unix/sysv/linux/mips/mips64/n64/libc.abilist | 3 + sysdeps/unix/sysv/linux/nios2/libc.abilist | 3 + .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist | 3 + .../linux/powerpc/powerpc32/nofpu/libc.abilist | 3 + .../sysv/linux/powerpc/powerpc64/libc-le.abilist | 3 + .../unix/sysv/linux/powerpc/powerpc64/libc.abilist | 3 + sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist | 3 + sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist | 3 + sysdeps/unix/sysv/linux/sh/libc.abilist | 3 + sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist | 3 + sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist | 3 + .../sysv/linux/tile/tilegx/tilegx32/libc.abilist | 3 + .../sysv/linux/tile/tilegx/tilegx64/libc.abilist | 3 + sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist | 3 + sysdeps/unix/sysv/linux/x86_64/64/libc.abilist | 3 + sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist | 3 + 46 files changed, 778 insertions(+), 22 deletions(-) create mode 100644 string/explicit_bzero.c create mode 100644 string/read_memory.c create mode 100644 string/test-explicit_bzero.c create mode 100644 string/tst-xbzero-opt.c -- 2.10.2 ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 1/3] New string function explicit_bzero (from OpenBSD). 2016-11-15 15:55 [PATCH 0/3] explicit_bzero v5 Zack Weinberg @ 2016-11-15 15:55 ` Zack Weinberg 2016-11-16 18:38 ` Michael Kerrisk (man-pages) 0 siblings, 1 reply; 15+ messages in thread From: Zack Weinberg @ 2016-11-15 15:55 UTC (permalink / raw) To: libc-alpha; +Cc: carlos, fweimer explicit_bzero(s, n) is the same as memset(s, 0, n), except that the compiler is not allowed to delete a call to explicit_bzero even if the memory pointed to by 's' is dead after the call. We achieve this effect by defining it to call memset() and then a second function, extern void __glibc_read_memory (const void *, size_t) __attribute_noinline__; which does nothing -- but the compiler is prevented from knowing that it does nothing, and so the pointer "escapes" and the memory is not treated as dead. (Concretely, __glibc_read_memory is forced out-of-line, defined in a file containing nothing else, and comments in both string/read_memory.c and string/Makefile document that it must not be subject to link-time optimization.) There are two new tests: test-explicit_bzero.c verifies the visible semantics in the same way as the existing test-bzero.c, and tst-xbzero-opt.c verifies the not-being-optimized-out property. The latter is conceptually based on a test written by Matthew Dempsky for the OpenBSD regression suite. * string/explicit_bzero.c, string/read_memory.c: New routines. * string/test-explicit_bzero.c, string/tst-xbzero-opt.c: New tests. * string/Makefile (routines, strop-tests, tests): Add them. * string/test-memset.c: Add ifdeffage for testing explicit_bzero. * string/string.h [__USE_MISC]: Declare explicit_bzero and __glibc_read_memory. * include/string.h: Declare __internal_glibc_read_memory, __explicit_bzero, and __internal_explicit_bzero. * manual/string.texi: Document explicit_bzero. * string/Versions [GLIBC_2.25]: Add explicit_bzero, __explicit_bzero, and __glibc_read_memory. * sysdeps/arm/nacl/libc.abilist * sysdeps/unix/sysv/linux/aarch64/libc.abilist * sysdeps/unix/sysv/linux/alpha/libc.abilist * sysdeps/unix/sysv/linux/arm/libc.abilist * sysdeps/unix/sysv/linux/hppa/libc.abilist * sysdeps/unix/sysv/linux/i386/libc.abilist * sysdeps/unix/sysv/linux/ia64/libc.abilist * sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist * sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist * sysdeps/unix/sysv/linux/microblaze/libc.abilist * sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist * sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist * sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist * sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist * sysdeps/unix/sysv/linux/nios2/libc.abilist * sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist * sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist * sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist * sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist * sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist * sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist * sysdeps/unix/sysv/linux/sh/libc.abilist * sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist * sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist * sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist * sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist * sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist * sysdeps/unix/sysv/linux/x86_64/64/libc.abilist * sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist: Add entries for explicit_bzero, __explicit_bzero, and __glibc_read_memory. --- include/string.h | 12 + manual/string.texi | 124 ++++++++ string/Makefile | 12 +- string/Versions | 10 + string/explicit_bzero.c | 33 ++ string/read_memory.c | 41 +++ string/string.h | 9 + string/test-explicit_bzero.c | 20 ++ string/test-memset.c | 10 +- string/tst-xbzero-opt.c | 348 +++++++++++++++++++++ sysdeps/arm/nacl/libc.abilist | 3 + sysdeps/unix/sysv/linux/aarch64/libc.abilist | 3 + sysdeps/unix/sysv/linux/alpha/libc.abilist | 3 + sysdeps/unix/sysv/linux/arm/libc.abilist | 3 + sysdeps/unix/sysv/linux/hppa/libc.abilist | 3 + sysdeps/unix/sysv/linux/i386/libc.abilist | 3 + sysdeps/unix/sysv/linux/ia64/libc.abilist | 3 + sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist | 3 + sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist | 3 + sysdeps/unix/sysv/linux/microblaze/libc.abilist | 3 + .../unix/sysv/linux/mips/mips32/fpu/libc.abilist | 3 + .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist | 3 + .../unix/sysv/linux/mips/mips64/n32/libc.abilist | 3 + .../unix/sysv/linux/mips/mips64/n64/libc.abilist | 3 + sysdeps/unix/sysv/linux/nios2/libc.abilist | 3 + .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist | 3 + .../linux/powerpc/powerpc32/nofpu/libc.abilist | 3 + .../sysv/linux/powerpc/powerpc64/libc-le.abilist | 3 + .../unix/sysv/linux/powerpc/powerpc64/libc.abilist | 3 + sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist | 3 + sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist | 3 + sysdeps/unix/sysv/linux/sh/libc.abilist | 3 + sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist | 3 + sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist | 3 + .../sysv/linux/tile/tilegx/tilegx32/libc.abilist | 3 + .../sysv/linux/tile/tilegx/tilegx64/libc.abilist | 3 + sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist | 3 + sysdeps/unix/sysv/linux/x86_64/64/libc.abilist | 3 + sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist | 3 + 39 files changed, 702 insertions(+), 4 deletions(-) create mode 100644 string/explicit_bzero.c create mode 100644 string/read_memory.c create mode 100644 string/test-explicit_bzero.c create mode 100644 string/tst-xbzero-opt.c diff --git a/include/string.h b/include/string.h index e145bfd..4185521 100644 --- a/include/string.h +++ b/include/string.h @@ -100,6 +100,18 @@ extern __typeof (memmem) __memmem; libc_hidden_proto (__memmem) libc_hidden_proto (__ffs) +/* explicit_bzero is used in libcrypt. */ +extern __typeof (explicit_bzero) __explicit_bzero; +extern __typeof (explicit_bzero) __internal_explicit_bzero; +libc_hidden_proto (__internal_explicit_bzero) +extern __typeof (__glibc_read_memory) __internal_glibc_read_memory; +libc_hidden_proto (__internal_glibc_read_memory) +/* Honor string[23].h overrides when present. */ +#ifdef explicit_bzero +# define __explicit_bzero(s,n) explicit_bzero (s,n) +# define __internal_explicit_bzero(s,n) explicit_bzero (s,n) +#endif + libc_hidden_builtin_proto (memchr) libc_hidden_builtin_proto (memcpy) libc_hidden_builtin_proto (mempcpy) diff --git a/manual/string.texi b/manual/string.texi index 1986357..3e1bf8d 100644 --- a/manual/string.texi +++ b/manual/string.texi @@ -34,6 +34,8 @@ too. * Search Functions:: Searching for a specific element or substring. * Finding Tokens in a String:: Splitting a string into tokens by looking for delimiters. +* Erasing Sensitive Data:: Clearing memory which contains sensitive + data, after it's no longer needed. * strfry:: Function for flash-cooking a string. * Trivial Encryption:: Obscuring data. * Encode Binary Data:: Encoding and Decoding of Binary Data. @@ -2404,6 +2406,128 @@ contains no '/' bytes, then "." is returned. The prototype for this function can be found in @file{libgen.h}. @end deftypefun +@node Erasing Sensitive Data +@section Erasing Sensitive Data + +It is sometimes necessary to make sure that data in memory is erased +after use, even if no correct C program could access it again. For +instance, a cryptographic key should not be left in memory after the +program is finished using it, because there might be a bug that causes +junk data, including the key, to be revealed to the outside world. + +However, the C compiler knows that no correct program can access data +after it's deallocated, so it may delete ``unnecessary'' stores that +erase data just before deallocating it. @code{memset}, @code{bzero}, +and a manually-written loop are all equally unreliable, and +@code{volatile} will not help. + +For this situation, @theglibc{} provides @code{explicit_bzero}. It is +functionally identical to @code{bzero}, but the C compiler will not +treat any use of it as unnecessary. + +@comment string.h +@comment BSD +@deftypefun void explicit_bzero (void *@var{block}, size_t @var{len}) +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + +@code{explicit_bzero} writes zero into each of the first @var{len} +bytes of the object beginning at @var{block}, just as @code{bzero} +would. The zeroes are always written, even if the object is about to +be deallocated. (Variables on the stack are deallocated when they go +out of scope; heap blocks created by @code{malloc} are deallocated +when passed to @code{free}.) + +@smallexample +@group +#include <string.h> + +extern void encrypt (const char *key, const char *in, + char *out, size_t n); +extern void genkey (const char *phrase, char *key); + +void encrypt_with_phrase (const char *phrase, const char *in, + char *out, size_t n) +@{ + char key[16]; + genkey (phrase, key); + encrypt (key, in, out, n); + explicit_bzero (key, 16); +@} +@end group +@end smallexample + +@noindent +If @code{bzero} or @code{memset} had been used in this function, the C +compiler might remove it as unnecessary, but it will not do this with +@code{explicit_bzero}. + +@strong{Warning:} The @emph{only} optimization disabled by +@code{explicit_bzero} is removal of ``unnecessary'' writes to memory. +In all other respects, the compiler is allowed to optimize as it would +for @code{memset}. For instance, it may replace the function call +with inline memory writes, and it may deduce that @var{block} cannot +be a null pointer. + +@strong{Warning:} The compiler may make copies of any object, or parts +of it, in temporary storage areas, such as registers and ``scratch'' +stack space. @code{explicit_bzero} does not erase copies of sensitive +data. At present, there is no way to prevent temporary copies from +being made, nor to arrange for them to be erased. Declaring sensitive +variables as @code{volatile} will make the problem @emph{worse}; the +compiler needs to make @emph{more} copies of @code{volatile} data in +order to operate on it correctly. + +@strong{Warning:} In some situations, using @code{explicit_bzero} will +@emph{cause} creation of an additional copy of sensitive data, and +only that copy will be cleared: + +@smallexample +@group +#include <string.h> + +struct key +@{ + unsigned long long low; + unsigned long long high; +@}; + +struct key get_key (void); +void use_key (struct key); + +void +with_clear (void) +@{ + struct key k; + k = get_key (); + use_key (k); + explicit_bzero (&k, sizeof (k)); +@} +@end group +@end smallexample + +@noindent +Without the call to @code{explicit_bzero}, @var{k} might not need to +be stored in memory: perhaps its value could be returned from +@code{get_key} and passed to @code{use_key} using only CPU registers. +@code{explicit_bzero} operates on memory, so the compiler has to make +a copy of @var{k} in memory for it, and the original in the CPU +registers remains intact. This can occur for any variable whose +address is only taken in a call to @code{explicit_bzero}, even if it +might seem ``too large'' to be stored in registers. + +There is currently no way to avoid this problem. @Theglibc{}'s +implementation of @code{explicit_bzero} contains a hack that can +sometimes prevent the sensitive data from being copied into memory, +but it is not guaranteed to work, and the original in the CPU +registers is unaffected. Again, declaring sensitive variables as +@code{volatile} will make the problem worse. + +@strong{Portability Note:} This function first appeared in OpenBSD 5.5 +and has not been standardized. @Theglibc{} declares this function in +@file{string.h}, but on other systems it may be in @file{strings.h} +instead. +@end deftypefun + @node strfry @section strfry diff --git a/string/Makefile b/string/Makefile index 69d3f80..0b6486e 100644 --- a/string/Makefile +++ b/string/Makefile @@ -41,20 +41,26 @@ routines := strcat strchr strcmp strcoll strcpy strcspn \ addsep replace) \ envz basename \ strcoll_l strxfrm_l string-inlines memrchr \ - xpg-strerror strerror_l + xpg-strerror strerror_l explicit_bzero + +# Attention future hackers trying to enable link-time optimization for +# glibc: this file *must not* be subject to LTO. It is added separately +# to 'routines' to document this. See comments in this file for details. +routines += read_memory strop-tests := memchr memcmp memcpy memmove mempcpy memset memccpy \ stpcpy stpncpy strcat strchr strcmp strcpy strcspn \ strlen strncmp strncpy strpbrk strrchr strspn memmem \ strstr strcasestr strnlen strcasecmp strncasecmp \ - strncat rawmemchr strchrnul bcopy bzero memrchr + strncat rawmemchr strchrnul bcopy bzero memrchr \ + explicit_bzero tests := tester inl-tester noinl-tester testcopy test-ffs \ tst-strlen stratcliff tst-svc tst-inlcall \ bug-strncat1 bug-strspn1 bug-strpbrk1 tst-bswap \ tst-strtok tst-strxfrm bug-strcoll1 tst-strfry \ bug-strtok1 $(addprefix test-,$(strop-tests)) \ bug-envz1 tst-strxfrm2 tst-endian tst-svc2 \ - tst-strtok_r bug-strcoll2 tst-cmp + tst-strtok_r bug-strcoll2 tst-cmp tst-xbzero-opt xtests = tst-strcoll-overflow diff --git a/string/Versions b/string/Versions index 475c1fd..4f434f3 100644 --- a/string/Versions +++ b/string/Versions @@ -82,4 +82,14 @@ libc { } GLIBC_2.24 { } + GLIBC_2.25 { + # used by inlines in bits/string2.h and bits/string3.h + __glibc_read_memory; + + # used by libcrypt + __explicit_bzero; + + # e* + explicit_bzero; + } } diff --git a/string/explicit_bzero.c b/string/explicit_bzero.c new file mode 100644 index 0000000..6c3dc9a --- /dev/null +++ b/string/explicit_bzero.c @@ -0,0 +1,33 @@ +/* Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <features.h> +#undef __USE_STRING_INLINES +#define __NO_STRING_INLINES +#include <string.h> + +/* Set LEN bytes of S to 0. The compiler will not delete a call to + this function, even if S is dead after the call. */ +void +__internal_explicit_bzero (void *s, size_t len) +{ + memset (s, '\0', len); + __internal_glibc_read_memory (s, len); +} +libc_hidden_def (__internal_explicit_bzero) +strong_alias (__internal_explicit_bzero, __explicit_bzero) +weak_alias (__internal_explicit_bzero, explicit_bzero) diff --git a/string/read_memory.c b/string/read_memory.c new file mode 100644 index 0000000..c4a5990 --- /dev/null +++ b/string/read_memory.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> + +/* This function is an optimization fence. It doesn't do anything + itself, but calls to it prevent calls to explicit_bzero from being + optimized away. In order to achieve this effect, this function + must never, under any circumstances, be inlined or subjected to + inter-procedural optimization. string.h declares this function + with attributes that, in conjunction with the no-op asm insert, are + sufficient to prevent problems in the current (2016) generation of + compilers, but *only if* this file is *not* compiled with -flto. + At present, this is not an issue since glibc is never compiled with + -flto, but should that ever change, this file must be excepted. + + The 'volatile' below is technically not necessary but is included + for explicitness. */ + +void +internal_function +__internal_glibc_read_memory(const void *s, size_t len) +{ + asm volatile (""); +} +libc_hidden_def (__internal_glibc_read_memory) +strong_alias (__internal_glibc_read_memory, __glibc_read_memory) diff --git a/string/string.h b/string/string.h index 57deaa4..682661a 100644 --- a/string/string.h +++ b/string/string.h @@ -455,6 +455,15 @@ extern void bcopy (const void *__src, void *__dest, size_t __n) /* Set N bytes of S to 0. */ extern void bzero (void *__s, size_t __n) __THROW __nonnull ((1)); +/* As bzero, but the compiler will not delete a call to this + function, even if S is dead after the call. */ +extern void explicit_bzero (void *__s, size_t __n) __THROW __nonnull ((1)); + +/* Optimization fence, used by bits/string2.h and bits/string3.h + inline versions of explicit_bzero. */ +extern void __glibc_read_memory (const void *__s, size_t __n) + __THROW __nonnull ((1)) __attribute_noinline__; + /* Compare N bytes of S1 and S2 (same as memcmp). */ extern int bcmp (const void *__s1, const void *__s2, size_t __n) __THROW __attribute_pure__ __nonnull ((1, 2)); diff --git a/string/test-explicit_bzero.c b/string/test-explicit_bzero.c new file mode 100644 index 0000000..5a4543b --- /dev/null +++ b/string/test-explicit_bzero.c @@ -0,0 +1,20 @@ +/* Test and measure explicit_bzero. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ +#define TEST_EXPLICIT_BZERO +#define TEST_BZERO +#include "test-memset.c" diff --git a/string/test-memset.c b/string/test-memset.c index fee3bdf..7ca4f20 100644 --- a/string/test-memset.c +++ b/string/test-memset.c @@ -19,7 +19,11 @@ #define TEST_MAIN #ifdef TEST_BZERO -# define TEST_NAME "bzero" +# ifdef TEST_EXPLICIT_BZERO +# define TEST_NAME "explicit_bzero" +# else +# define TEST_NAME "bzero" +# endif #else # ifndef WIDE # define TEST_NAME "memset" @@ -56,7 +60,11 @@ void builtin_bzero (char *, size_t); IMPL (simple_bzero, 0) IMPL (builtin_bzero, 0) +#ifdef TEST_EXPLICIT_BZERO +IMPL (explicit_bzero, 1) +#else IMPL (bzero, 1) +#endif void simple_bzero (char *s, size_t n) diff --git a/string/tst-xbzero-opt.c b/string/tst-xbzero-opt.c new file mode 100644 index 0000000..da35669 --- /dev/null +++ b/string/tst-xbzero-opt.c @@ -0,0 +1,348 @@ +/* Test that explicit_bzero block clears are not optimized out. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +/* This test is conceptually based on a test designed by Matthew + Dempsky for the OpenBSD regression suite: + <openbsd>/src/regress/lib/libc/explicit_bzero/explicit_bzero.c. + The basic idea is, we have a function that contains a + block-clearing operation (not necessarily explicit_bzero), after + which the block is dead, in the compiler-jargon sense. Execute + that function from a signal handler running on an alternative + signal stack. Then we have another pointer to the memory region + affected by the block clear -- namely, the sigaltstack buffer -- + and can find out whether it actually happened. + + The OpenBSD test cautions that some operating systems (e.g. Solaris + and OSX) wipe the signal stack upon returning to the normal stack, + so the test has to happen while still executing on the signal + stack. This, of course, means that the buffer might be clobbered + by normal stack operations after the function with the block clear + returns (it has to return, so that the block is truly dead). The + most straightforward way to deal with this is to have a large block + containing several copies of a byte pattern that is unlikely to + occur by chance, and check whether _any_ of them survives. */ + +#define _GNU_SOURCE 1 + +#include <errno.h> +#include <signal.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +/* test-skeleton.c unconditionally sets stdout to be unbuffered. + vfprintf allocates a great deal of memory on the stack if called + with an unbuffered FILE*, overflowing the alt-stack. do_test + therefore resets stdout to fully buffered, and we use this wrapper + exclusively for output. */ +static void +xprintf (const char *msg, ...) +{ + va_list ap; + va_start (ap, msg); + vfprintf (stdout, msg, ap); + va_end (ap); + fflush (stdout); +} +#define printf dont_use_printf_in_this_file + +/* The "byte pattern that is unlikely to occur by chance": the first + 16 prime numbers (OEIS A000040). */ +static const unsigned char test_pattern[16] = +{ + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53 +}; + +#define PATTERN_SIZE (sizeof test_pattern) +#define PATTERN_REPS 32 +#define TEST_BUFFER_SIZE (PATTERN_SIZE * PATTERN_REPS) + +static void +fill_with_test_pattern (unsigned char *buf) +{ + for (unsigned int i = 0; i < PATTERN_REPS; i++) + memcpy (buf + i*PATTERN_SIZE, test_pattern, PATTERN_SIZE); +} + +static unsigned int +count_test_patterns (unsigned char *buf, size_t bufsiz) +{ + unsigned char *first = memmem (buf, bufsiz, test_pattern, PATTERN_SIZE); + if (!first) + return 0; + unsigned int cnt = 0; + for (unsigned int i = 0; i < PATTERN_REPS; i++) + { + unsigned char *p = first + i*PATTERN_SIZE; + if (p + PATTERN_SIZE - buf > bufsiz) + break; + if (memcmp (p, test_pattern, PATTERN_SIZE) == 0) + cnt++; + } + return cnt; +} + +/* Global test state. */ +static int failed_subtests; +static bool this_subtest_failed; + +/* The signal stack is allocated with memalign. */ +static unsigned char *signal_stack_buffer; +#define SIGNAL_STACK_SIZE (SIGSTKSZ + TEST_BUFFER_SIZE) + +enum test_expectation { EXPECT_NONE, EXPECT_SOME, EXPECT_ALL }; + +static void +check_test_buffer (enum test_expectation expected, + const char *label, const char *stage) +{ + unsigned int cnt = count_test_patterns (signal_stack_buffer, + SIGNAL_STACK_SIZE); + switch (expected) + { + case EXPECT_NONE: + if (cnt == 0) + xprintf ("PASS: %s/%s: expected 0 got %d\n", label, stage, cnt); + else + { + xprintf ("FAIL: %s/%s: expected 0 got %d\n", label, stage, cnt); + this_subtest_failed = true; + failed_subtests++; + } + break; + + case EXPECT_SOME: + if (cnt > 0) + xprintf ("PASS: %s/%s: expected some got %d\n", label, stage, cnt); + else + { + xprintf ("FAIL: %s/%s: expected some got 0\n", label, stage); + this_subtest_failed = true; + failed_subtests++; + } + break; + + case EXPECT_ALL: + if (cnt == PATTERN_REPS) + xprintf ("PASS: %s/%s: expected %d got %d\n", label, stage, + PATTERN_REPS, cnt); + else + { + xprintf ("FAIL: %s/%s: expected %d got %d\n", label, stage, + PATTERN_REPS, cnt); + this_subtest_failed = true; + failed_subtests++; + } + break; + + default: + xprintf ("ERROR: %s/%s: invalid value for 'expected' = %d\n", + label, stage, (int)expected); + this_subtest_failed = true; + failed_subtests++; + } +} + +/* Always check the test buffer immediately after filling it; this + makes externally visible side effects depend on the buffer existing + and having been filled in. */ +static void +prepare_test_buffer (unsigned char *buf, const char *label) +{ + fill_with_test_pattern (buf); + check_test_buffer (EXPECT_ALL, label, "prepare"); + + unsigned char *loc = memmem (signal_stack_buffer, SIGNAL_STACK_SIZE, + test_pattern, PATTERN_SIZE); + if (loc == buf) + xprintf ("PASS: %s/prepare: expected buffer location %p got %p\n", + label, buf, loc); + else + { + xprintf ("FAIL: %s/prepare: expected buffer location %p got %p\n", + label, buf, loc); + this_subtest_failed = true; + failed_subtests++; + } +} + +/* There are three subtests, two of which are sanity checks. + + In the "no_clear" case, we don't do anything to the test buffer + between preparing it and letting it go out of scope, and we expect + to find it. This confirms that the test buffer does get filled in + and we can find it from the stack buffer. In the "ordinary_clear" + case, we clear it using memset, and we expect to find it. This + confirms that the compiler can optimize out block clears in this + context; if it can't, the real test might be succeeding for the + wrong reason. Finally, the "explicit_clear" case uses + explicit_bzero and expects _not_ to find the test buffer, which is + the real test. */ + +static void +setup_no_clear (void) +{ + unsigned char buf[TEST_BUFFER_SIZE]; + prepare_test_buffer (buf, "no clear"); +} + +static void +setup_ordinary_clear (void) +{ + unsigned char buf[TEST_BUFFER_SIZE]; + prepare_test_buffer (buf, "ordinary clear"); + if (this_subtest_failed) + return; + memset (buf, 0, TEST_BUFFER_SIZE); +} + +static void +setup_explicit_clear (void) +{ + unsigned char buf[TEST_BUFFER_SIZE]; + prepare_test_buffer (buf, "explicit clear"); + if (this_subtest_failed) + return; + explicit_bzero (buf, TEST_BUFFER_SIZE); +} + +struct subtest +{ + void (*setup_subtest) (void); + const char *label; + enum test_expectation expected; +}; + +static const struct subtest subtests[] = +{ + { setup_no_clear, "no clear", EXPECT_SOME }, + { setup_ordinary_clear, "ordinary clear", EXPECT_SOME }, + { setup_explicit_clear, "explicit clear", EXPECT_NONE }, + { 0, 0, -1 } +}; +static const struct subtest *this_subtest; + +/* This function is called as a signal handler. The signal is + triggered by a call to sigsuspend, therefore it is safe to do + non-async-signal-safe things within this function. */ +static void +do_subtest (int signo __attribute__ ((unused))) +{ + this_subtest->setup_subtest (); + if (!this_subtest_failed) + check_test_buffer (this_subtest->expected, this_subtest->label, "test"); +} + +static int +do_test (void) +{ + /* test-skeleton.c unconditionally sets stdout to be unbuffered. + vfprintf allocates a great deal of memory on the stack if called + with an unbuffered FILE*, overflowing the alt-stack. Reset stdout + to fully buffered to prevent this. */ + if (setvbuf (stdout, 0, _IOFBF, 0)) + { + xprintf ("ERROR: restoring stdout buffering: %s\n", strerror (errno)); + return 2; + } + + size_t page_alignment = sysconf (_SC_PAGESIZE); + if (page_alignment < sizeof (void *)) + page_alignment = sizeof (void *); + + void *p; + int err = posix_memalign (&p, page_alignment, SIGNAL_STACK_SIZE); + if (err || !p) + { + xprintf ("ERROR: allocating alt stack: %s\n", strerror (err)); + return 2; + } + signal_stack_buffer = p; + + /* This program will malfunction if it receives SIGUSR1 signals at any + time other than when it's just sent one to itself. Therefore, keep + it blocked most of the time. */ + sigset_t normal_mask; + sigset_t sigsusp_mask; + sigemptyset (&normal_mask); + sigaddset (&normal_mask, SIGUSR1); + if (sigprocmask (SIG_BLOCK, &normal_mask, &sigsusp_mask)) + { + xprintf ("ERROR: block(SIGUSR1): %s\n", strerror (errno)); + return 2; + } + /* But ensure that SIGUSR1 is _not_ blocked during calls to + sigsuspend, even if the invoking process blocked it. */ + sigdelset (&sigsusp_mask, SIGUSR1); + + stack_t ss; + ss.ss_sp = signal_stack_buffer; + ss.ss_flags = 0; + ss.ss_size = SIGNAL_STACK_SIZE; + if (sigaltstack (&ss, 0)) + { + xprintf ("ERROR: sigaltstack: %s\n", strerror (errno)); + return 2; + } + + struct sigaction sa; + sa.sa_mask = normal_mask; + sa.sa_handler = do_subtest; + sa.sa_flags = SA_RESTART | SA_ONSTACK; + if (sigaction (SIGUSR1, &sa, 0)) + { + xprintf ("ERROR: sigaction(SIGUSR1): %s\n", strerror (errno)); + return 2; + } + + /* We use kill instead of raise, because raise may internally modify + the signal mask. */ + pid_t self = getpid (); + + this_subtest = subtests; + while (this_subtest->label) + { + this_subtest_failed = false; + + /* Completely clear the signal stack between tests, so that junk + from previous tests cannot interfere with the current one. */ + memset (signal_stack_buffer, 0, SIGNAL_STACK_SIZE); + + /* Raise SIGUSR1, then call sigsuspend with a mask that unblocks + SIGUSR1. This will trigger do_subtest to run _once_ on the + alternative stack, at the point of the sigsuspend. */ + if (kill (self, SIGUSR1)) + { + xprintf ("ERROR: raise(SIGUSR1): %s\n", strerror (errno)); + return 2; + } + /* The return value of sigsuspend is not meaningful. */ + sigsuspend (&sigsusp_mask); + + this_subtest++; + } + + return failed_subtests ? 1 : 0; +} + +#undef printf +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/arm/nacl/libc.abilist b/sysdeps/arm/nacl/libc.abilist index 807e43d..b074374 100644 --- a/sysdeps/arm/nacl/libc.abilist +++ b/sysdeps/arm/nacl/libc.abilist @@ -1843,6 +1843,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 gnu_dev_major F GLIBC_2.25 gnu_dev_makedev F GLIBC_2.25 gnu_dev_minor F diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist index 77accdf..e265325 100644 --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist @@ -2090,6 +2090,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist index 659b7fc..393dd4c 100644 --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist @@ -2001,6 +2001,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist index 8bc979a..b92eccb 100644 --- a/sysdeps/unix/sysv/linux/arm/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/libc.abilist @@ -91,6 +91,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist index 299b705..3b1661d 100644 --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist @@ -1855,6 +1855,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist index f00345f..452e013 100644 --- a/sysdeps/unix/sysv/linux/i386/libc.abilist +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist @@ -2013,6 +2013,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist index e5fcf88..0196234 100644 --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist @@ -1877,6 +1877,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist index 8f382f6..d6e0e16 100644 --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist @@ -92,6 +92,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist index 320b7fe..c3a5f24 100644 --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist @@ -1969,6 +1969,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist index 21b1426..fa72a0d 100644 --- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist @@ -2090,6 +2090,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist index 5c4b596..03d3c0c 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist @@ -1944,6 +1944,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist index 001fa6c..a1c9cd2 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist @@ -1942,6 +1942,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist index 2d87001..a8671ba 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist @@ -1940,6 +1940,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist index aa1ee66..e71283f 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist @@ -1935,6 +1935,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist index 2471d68..f92545c 100644 --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist @@ -2131,6 +2131,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist index 4b0cde8..d8427ca 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist @@ -1973,6 +1973,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist index 0557c16..fa26199 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist @@ -1978,6 +1978,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist index 821384e..73488a4 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist @@ -2178,6 +2178,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist index c40a3f1..ac9cc69 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist @@ -92,6 +92,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist index 5b39a60..933a00a 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist @@ -1973,6 +1973,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist index a9db32f..eb74169 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist @@ -1874,6 +1874,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist index 294af0a..37aded2 100644 --- a/sysdeps/unix/sysv/linux/sh/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/libc.abilist @@ -1859,6 +1859,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist index 32747bd..5b7c54e 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist @@ -1965,6 +1965,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist index b0ac4d4..4854351 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist @@ -1903,6 +1903,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist index 4d92d81..18f61ba 100644 --- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist +++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist @@ -2097,6 +2097,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist index a68aef7..53a0db1 100644 --- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist +++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist @@ -2097,6 +2097,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist index 4d92d81..18f61ba 100644 --- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist +++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist @@ -2097,6 +2097,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist index b8623fc..d4add67 100644 --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist @@ -1854,6 +1854,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist index a61d874..18717fa 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist @@ -2097,6 +2097,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F -- 2.10.2 ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] New string function explicit_bzero (from OpenBSD). 2016-11-15 15:55 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Zack Weinberg @ 2016-11-16 18:38 ` Michael Kerrisk (man-pages) 0 siblings, 0 replies; 15+ messages in thread From: Michael Kerrisk (man-pages) @ 2016-11-16 18:38 UTC (permalink / raw) To: Zack Weinberg, libc-alpha; +Cc: mtk.manpages, carlos, fweimer On 11/15/2016 04:55 PM, Zack Weinberg wrote: > explicit_bzero(s, n) is the same as memset(s, 0, n), except that the > compiler is not allowed to delete a call to explicit_bzero even if the > memory pointed to by 's' is dead after the call. We achieve this effect > by defining it to call memset() and then a second function, > > extern void __glibc_read_memory (const void *, size_t) > __attribute_noinline__; > > which does nothing -- but the compiler is prevented from knowing that > it does nothing, and so the pointer "escapes" and the memory is not > treated as dead. (Concretely, __glibc_read_memory is forced > out-of-line, defined in a file containing nothing else, and comments > in both string/read_memory.c and string/Makefile document that it must > not be subject to link-time optimization.) > > There are two new tests: test-explicit_bzero.c verifies the > visible semantics in the same way as the existing test-bzero.c, > and tst-xbzero-opt.c verifies the not-being-optimized-out property. > The latter is conceptually based on a test written by Matthew Dempsky > for the OpenBSD regression suite. [...] > diff --git a/manual/string.texi b/manual/string.texi > index 1986357..3e1bf8d 100644 > --- a/manual/string.texi > +++ b/manual/string.texi > @@ -34,6 +34,8 @@ too. > * Search Functions:: Searching for a specific element or substring. > * Finding Tokens in a String:: Splitting a string into tokens by looking > for delimiters. > +* Erasing Sensitive Data:: Clearing memory which contains sensitive > + data, after it's no longer needed. > * strfry:: Function for flash-cooking a string. > * Trivial Encryption:: Obscuring data. > * Encode Binary Data:: Encoding and Decoding of Binary Data. > @@ -2404,6 +2406,128 @@ contains no '/' bytes, then "." is returned. The prototype for this > function can be found in @file{libgen.h}. > @end deftypefun > > +@node Erasing Sensitive Data > +@section Erasing Sensitive Data > + > +It is sometimes necessary to make sure that data in memory is erased > +after use, even if no correct C program could access it again. For > +instance, a cryptographic key should not be left in memory after the > +program is finished using it, because there might be a bug that causes > +junk data, including the key, to be revealed to the outside world. > + > +However, the C compiler knows that no correct program can access data > +after it's deallocated, so it may delete ``unnecessary'' stores that > +erase data just before deallocating it. @code{memset}, @code{bzero}, > +and a manually-written loop are all equally unreliable, and > +@code{volatile} will not help. > + > +For this situation, @theglibc{} provides @code{explicit_bzero}. It is > +functionally identical to @code{bzero}, but the C compiler will not > +treat any use of it as unnecessary. > + > +@comment string.h > +@comment BSD > +@deftypefun void explicit_bzero (void *@var{block}, size_t @var{len}) > +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} > + > +@code{explicit_bzero} writes zero into each of the first @var{len} > +bytes of the object beginning at @var{block}, I find that wording ("first len bytes") a little confusing. How about [[ @code{explicit_bzero} writes zero into each of the @var{len} bytes starting the location pointed to by @var{block}, ]] > just as @code{bzero} > +would. The zeroes are always written, even if the object is about to > +be deallocated. (Variables on the stack are deallocated when they go > +out of scope; heap blocks created by @code{malloc} are deallocated > +when passed to @code{free}.) > + > +@smallexample > +@group > +#include <string.h> > + > +extern void encrypt (const char *key, const char *in, > + char *out, size_t n); > +extern void genkey (const char *phrase, char *key); > + > +void encrypt_with_phrase (const char *phrase, const char *in, > + char *out, size_t n) > +@{ > + char key[16]; > + genkey (phrase, key); > + encrypt (key, in, out, n); > + explicit_bzero (key, 16); > +@} > +@end group > +@end smallexample > + > +@noindent > +If @code{bzero} or @code{memset} had been used in this function, the C > +compiler might remove it as unnecessary, but it will not do this with > +@code{explicit_bzero}. > + > +@strong{Warning:} The @emph{only} optimization disabled by s/@strong{Warning:}/Note:/ ? (I mean, why does this need to be a _warning_? > +@code{explicit_bzero} is removal of ``unnecessary'' writes to memory. Also, I would rewrite that first sentence as: [[ Note: The @emph{only} optimization that @code{explicit_bzero} disables is removal of ``unnecessary'' writes to memory. ]] I find that phrasing a little easier to parse. > +In all other respects, the compiler is allowed to optimize as it would > +for @code{memset}. For instance, it may replace the function call > +with inline memory writes, and it may deduce that @var{block} cannot > +be a null pointer. > + > +@strong{Warning:} The compiler may make copies of any object, or parts Maybe make that "Warning" a "Note". Making it a warning tends to scare the reader about explicit_bzero(), when really this is an issue that is caused by the compiler. > +of it, in temporary storage areas, such as registers and ``scratch'' > +stack space. @code{explicit_bzero} does not erase copies of sensitive > +data. At present, there is no way to prevent temporary copies from > +being made, nor to arrange for them to be erased. Declaring sensitive > +variables as @code{volatile} will make the problem @emph{worse}; the > +compiler needs to make @emph{more} copies of @code{volatile} data in > +order to operate on it correctly. > + > +@strong{Warning:} In some situations, using @code{explicit_bzero} will So, I think this one really does deserve to be a Warning... By the way, the name explicit_bzero() does seem odd. "Explicit" isn't the right word... But I guess we are stuck with what OpenBSD gave us. Cheers, Michael > +@emph{cause} creation of an additional copy of sensitive data, and > +only that copy will be cleared: > + > +@smallexample > +@group > +#include <string.h> > + > +struct key > +@{ > + unsigned long long low; > + unsigned long long high; > +@}; > + > +struct key get_key (void); > +void use_key (struct key); > + > +void > +with_clear (void) > +@{ > + struct key k; > + k = get_key (); > + use_key (k); > + explicit_bzero (&k, sizeof (k)); > +@} > +@end group > +@end smallexample > + > +@noindent > +Without the call to @code{explicit_bzero}, @var{k} might not need to > +be stored in memory: perhaps its value could be returned from > +@code{get_key} and passed to @code{use_key} using only CPU registers. > +@code{explicit_bzero} operates on memory, so the compiler has to make > +a copy of @var{k} in memory for it, and the original in the CPU > +registers remains intact. This can occur for any variable whose > +address is only taken in a call to @code{explicit_bzero}, even if it > +might seem ``too large'' to be stored in registers. > + > +There is currently no way to avoid this problem. @Theglibc{}'s > +implementation of @code{explicit_bzero} contains a hack that can > +sometimes prevent the sensitive data from being copied into memory, > +but it is not guaranteed to work, and the original in the CPU > +registers is unaffected. Again, declaring sensitive variables as > +@code{volatile} will make the problem worse. > + > +@strong{Portability Note:} This function first appeared in OpenBSD 5.5 > +and has not been standardized. @Theglibc{} declares this function in > +@file{string.h}, but on other systems it may be in @file{strings.h} > +instead. > +@end deftypefun > + > @node strfry > @section strfry > > diff --git a/string/Makefile b/string/Makefile > index 69d3f80..0b6486e 100644 > --- a/string/Makefile > +++ b/string/Makefile > @@ -41,20 +41,26 @@ routines := strcat strchr strcmp strcoll strcpy strcspn \ > addsep replace) \ > envz basename \ > strcoll_l strxfrm_l string-inlines memrchr \ > - xpg-strerror strerror_l > + xpg-strerror strerror_l explicit_bzero > + > +# Attention future hackers trying to enable link-time optimization for > +# glibc: this file *must not* be subject to LTO. It is added separately > +# to 'routines' to document this. See comments in this file for details. > +routines += read_memory > > strop-tests := memchr memcmp memcpy memmove mempcpy memset memccpy \ > stpcpy stpncpy strcat strchr strcmp strcpy strcspn \ > strlen strncmp strncpy strpbrk strrchr strspn memmem \ > strstr strcasestr strnlen strcasecmp strncasecmp \ > - strncat rawmemchr strchrnul bcopy bzero memrchr > + strncat rawmemchr strchrnul bcopy bzero memrchr \ > + explicit_bzero > tests := tester inl-tester noinl-tester testcopy test-ffs \ > tst-strlen stratcliff tst-svc tst-inlcall \ > bug-strncat1 bug-strspn1 bug-strpbrk1 tst-bswap \ > tst-strtok tst-strxfrm bug-strcoll1 tst-strfry \ > bug-strtok1 $(addprefix test-,$(strop-tests)) \ > bug-envz1 tst-strxfrm2 tst-endian tst-svc2 \ > - tst-strtok_r bug-strcoll2 tst-cmp > + tst-strtok_r bug-strcoll2 tst-cmp tst-xbzero-opt > > xtests = tst-strcoll-overflow > > diff --git a/string/Versions b/string/Versions > index 475c1fd..4f434f3 100644 > --- a/string/Versions > +++ b/string/Versions > @@ -82,4 +82,14 @@ libc { > } > GLIBC_2.24 { > } > + GLIBC_2.25 { > + # used by inlines in bits/string2.h and bits/string3.h > + __glibc_read_memory; > + > + # used by libcrypt > + __explicit_bzero; > + > + # e* > + explicit_bzero; > + } > } > diff --git a/string/explicit_bzero.c b/string/explicit_bzero.c > new file mode 100644 > index 0000000..6c3dc9a > --- /dev/null > +++ b/string/explicit_bzero.c > @@ -0,0 +1,33 @@ > +/* Copyright (C) 2016 Free Software Foundation, Inc. > + This file is part of the GNU C Library. > + > + The GNU C Library is free software; you can redistribute it and/or > + modify it under the terms of the GNU Lesser General Public > + License as published by the Free Software Foundation; either > + version 2.1 of the License, or (at your option) any later version. > + > + The GNU C Library is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + Lesser General Public License for more details. > + > + You should have received a copy of the GNU Lesser General Public > + License along with the GNU C Library; if not, see > + <http://www.gnu.org/licenses/>. */ > + > +#include <features.h> > +#undef __USE_STRING_INLINES > +#define __NO_STRING_INLINES > +#include <string.h> > + > +/* Set LEN bytes of S to 0. The compiler will not delete a call to > + this function, even if S is dead after the call. */ > +void > +__internal_explicit_bzero (void *s, size_t len) > +{ > + memset (s, '\0', len); > + __internal_glibc_read_memory (s, len); > +} > +libc_hidden_def (__internal_explicit_bzero) > +strong_alias (__internal_explicit_bzero, __explicit_bzero) > +weak_alias (__internal_explicit_bzero, explicit_bzero) > diff --git a/string/read_memory.c b/string/read_memory.c > new file mode 100644 > index 0000000..c4a5990 > --- /dev/null > +++ b/string/read_memory.c > @@ -0,0 +1,41 @@ > +/* Copyright (C) 2016 Free Software Foundation, Inc. > + This file is part of the GNU C Library. > + > + The GNU C Library is free software; you can redistribute it and/or > + modify it under the terms of the GNU Lesser General Public > + License as published by the Free Software Foundation; either > + version 2.1 of the License, or (at your option) any later version. > + > + The GNU C Library is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + Lesser General Public License for more details. > + > + You should have received a copy of the GNU Lesser General Public > + License along with the GNU C Library; if not, see > + <http://www.gnu.org/licenses/>. */ > + > +#include <string.h> > + > +/* This function is an optimization fence. It doesn't do anything > + itself, but calls to it prevent calls to explicit_bzero from being > + optimized away. In order to achieve this effect, this function > + must never, under any circumstances, be inlined or subjected to > + inter-procedural optimization. string.h declares this function > + with attributes that, in conjunction with the no-op asm insert, are > + sufficient to prevent problems in the current (2016) generation of > + compilers, but *only if* this file is *not* compiled with -flto. > + At present, this is not an issue since glibc is never compiled with > + -flto, but should that ever change, this file must be excepted. > + > + The 'volatile' below is technically not necessary but is included > + for explicitness. */ > + > +void > +internal_function > +__internal_glibc_read_memory(const void *s, size_t len) > +{ > + asm volatile (""); > +} > +libc_hidden_def (__internal_glibc_read_memory) > +strong_alias (__internal_glibc_read_memory, __glibc_read_memory) > diff --git a/string/string.h b/string/string.h > index 57deaa4..682661a 100644 > --- a/string/string.h > +++ b/string/string.h > @@ -455,6 +455,15 @@ extern void bcopy (const void *__src, void *__dest, size_t __n) > /* Set N bytes of S to 0. */ > extern void bzero (void *__s, size_t __n) __THROW __nonnull ((1)); > > +/* As bzero, but the compiler will not delete a call to this > + function, even if S is dead after the call. */ > +extern void explicit_bzero (void *__s, size_t __n) __THROW __nonnull ((1)); > + > +/* Optimization fence, used by bits/string2.h and bits/string3.h > + inline versions of explicit_bzero. */ > +extern void __glibc_read_memory (const void *__s, size_t __n) > + __THROW __nonnull ((1)) __attribute_noinline__; > + > /* Compare N bytes of S1 and S2 (same as memcmp). */ > extern int bcmp (const void *__s1, const void *__s2, size_t __n) > __THROW __attribute_pure__ __nonnull ((1, 2)); > diff --git a/string/test-explicit_bzero.c b/string/test-explicit_bzero.c > new file mode 100644 > index 0000000..5a4543b > --- /dev/null > +++ b/string/test-explicit_bzero.c > @@ -0,0 +1,20 @@ > +/* Test and measure explicit_bzero. > + Copyright (C) 2016 Free Software Foundation, Inc. > + This file is part of the GNU C Library. > + > + The GNU C Library is free software; you can redistribute it and/or > + modify it under the terms of the GNU Lesser General Public > + License as published by the Free Software Foundation; either > + version 2.1 of the License, or (at your option) any later version. > + > + The GNU C Library is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + Lesser General Public License for more details. > + > + You should have received a copy of the GNU Lesser General Public > + License along with the GNU C Library; if not, see > + <http://www.gnu.org/licenses/>. */ > +#define TEST_EXPLICIT_BZERO > +#define TEST_BZERO > +#include "test-memset.c" > diff --git a/string/test-memset.c b/string/test-memset.c > index fee3bdf..7ca4f20 100644 > --- a/string/test-memset.c > +++ b/string/test-memset.c > @@ -19,7 +19,11 @@ > > #define TEST_MAIN > #ifdef TEST_BZERO > -# define TEST_NAME "bzero" > +# ifdef TEST_EXPLICIT_BZERO > +# define TEST_NAME "explicit_bzero" > +# else > +# define TEST_NAME "bzero" > +# endif > #else > # ifndef WIDE > # define TEST_NAME "memset" > @@ -56,7 +60,11 @@ void builtin_bzero (char *, size_t); > > IMPL (simple_bzero, 0) > IMPL (builtin_bzero, 0) > +#ifdef TEST_EXPLICIT_BZERO > +IMPL (explicit_bzero, 1) > +#else > IMPL (bzero, 1) > +#endif > > void > simple_bzero (char *s, size_t n) > diff --git a/string/tst-xbzero-opt.c b/string/tst-xbzero-opt.c > new file mode 100644 > index 0000000..da35669 > --- /dev/null > +++ b/string/tst-xbzero-opt.c > @@ -0,0 +1,348 @@ > +/* Test that explicit_bzero block clears are not optimized out. > + Copyright (C) 2016 Free Software Foundation, Inc. > + This file is part of the GNU C Library. > + > + The GNU C Library is free software; you can redistribute it and/or > + modify it under the terms of the GNU Lesser General Public > + License as published by the Free Software Foundation; either > + version 2.1 of the License, or (at your option) any later version. > + > + The GNU C Library is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + Lesser General Public License for more details. > + > + You should have received a copy of the GNU Lesser General Public > + License along with the GNU C Library; if not, see > + <http://www.gnu.org/licenses/>. */ > + > +/* This test is conceptually based on a test designed by Matthew > + Dempsky for the OpenBSD regression suite: > + <openbsd>/src/regress/lib/libc/explicit_bzero/explicit_bzero.c. > + The basic idea is, we have a function that contains a > + block-clearing operation (not necessarily explicit_bzero), after > + which the block is dead, in the compiler-jargon sense. Execute > + that function from a signal handler running on an alternative > + signal stack. Then we have another pointer to the memory region > + affected by the block clear -- namely, the sigaltstack buffer -- > + and can find out whether it actually happened. > + > + The OpenBSD test cautions that some operating systems (e.g. Solaris > + and OSX) wipe the signal stack upon returning to the normal stack, > + so the test has to happen while still executing on the signal > + stack. This, of course, means that the buffer might be clobbered > + by normal stack operations after the function with the block clear > + returns (it has to return, so that the block is truly dead). The > + most straightforward way to deal with this is to have a large block > + containing several copies of a byte pattern that is unlikely to > + occur by chance, and check whether _any_ of them survives. */ > + > +#define _GNU_SOURCE 1 > + > +#include <errno.h> > +#include <signal.h> > +#include <stdarg.h> > +#include <stdbool.h> > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > + > +/* test-skeleton.c unconditionally sets stdout to be unbuffered. > + vfprintf allocates a great deal of memory on the stack if called > + with an unbuffered FILE*, overflowing the alt-stack. do_test > + therefore resets stdout to fully buffered, and we use this wrapper > + exclusively for output. */ > +static void > +xprintf (const char *msg, ...) > +{ > + va_list ap; > + va_start (ap, msg); > + vfprintf (stdout, msg, ap); > + va_end (ap); > + fflush (stdout); > +} > +#define printf dont_use_printf_in_this_file > + > +/* The "byte pattern that is unlikely to occur by chance": the first > + 16 prime numbers (OEIS A000040). */ > +static const unsigned char test_pattern[16] = > +{ > + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53 > +}; > + > +#define PATTERN_SIZE (sizeof test_pattern) > +#define PATTERN_REPS 32 > +#define TEST_BUFFER_SIZE (PATTERN_SIZE * PATTERN_REPS) > + > +static void > +fill_with_test_pattern (unsigned char *buf) > +{ > + for (unsigned int i = 0; i < PATTERN_REPS; i++) > + memcpy (buf + i*PATTERN_SIZE, test_pattern, PATTERN_SIZE); > +} > + > +static unsigned int > +count_test_patterns (unsigned char *buf, size_t bufsiz) > +{ > + unsigned char *first = memmem (buf, bufsiz, test_pattern, PATTERN_SIZE); > + if (!first) > + return 0; > + unsigned int cnt = 0; > + for (unsigned int i = 0; i < PATTERN_REPS; i++) > + { > + unsigned char *p = first + i*PATTERN_SIZE; > + if (p + PATTERN_SIZE - buf > bufsiz) > + break; > + if (memcmp (p, test_pattern, PATTERN_SIZE) == 0) > + cnt++; > + } > + return cnt; > +} > + > +/* Global test state. */ > +static int failed_subtests; > +static bool this_subtest_failed; > + > +/* The signal stack is allocated with memalign. */ > +static unsigned char *signal_stack_buffer; > +#define SIGNAL_STACK_SIZE (SIGSTKSZ + TEST_BUFFER_SIZE) > + > +enum test_expectation { EXPECT_NONE, EXPECT_SOME, EXPECT_ALL }; > + > +static void > +check_test_buffer (enum test_expectation expected, > + const char *label, const char *stage) > +{ > + unsigned int cnt = count_test_patterns (signal_stack_buffer, > + SIGNAL_STACK_SIZE); > + switch (expected) > + { > + case EXPECT_NONE: > + if (cnt == 0) > + xprintf ("PASS: %s/%s: expected 0 got %d\n", label, stage, cnt); > + else > + { > + xprintf ("FAIL: %s/%s: expected 0 got %d\n", label, stage, cnt); > + this_subtest_failed = true; > + failed_subtests++; > + } > + break; > + > + case EXPECT_SOME: > + if (cnt > 0) > + xprintf ("PASS: %s/%s: expected some got %d\n", label, stage, cnt); > + else > + { > + xprintf ("FAIL: %s/%s: expected some got 0\n", label, stage); > + this_subtest_failed = true; > + failed_subtests++; > + } > + break; > + > + case EXPECT_ALL: > + if (cnt == PATTERN_REPS) > + xprintf ("PASS: %s/%s: expected %d got %d\n", label, stage, > + PATTERN_REPS, cnt); > + else > + { > + xprintf ("FAIL: %s/%s: expected %d got %d\n", label, stage, > + PATTERN_REPS, cnt); > + this_subtest_failed = true; > + failed_subtests++; > + } > + break; > + > + default: > + xprintf ("ERROR: %s/%s: invalid value for 'expected' = %d\n", > + label, stage, (int)expected); > + this_subtest_failed = true; > + failed_subtests++; > + } > +} > + > +/* Always check the test buffer immediately after filling it; this > + makes externally visible side effects depend on the buffer existing > + and having been filled in. */ > +static void > +prepare_test_buffer (unsigned char *buf, const char *label) > +{ > + fill_with_test_pattern (buf); > + check_test_buffer (EXPECT_ALL, label, "prepare"); > + > + unsigned char *loc = memmem (signal_stack_buffer, SIGNAL_STACK_SIZE, > + test_pattern, PATTERN_SIZE); > + if (loc == buf) > + xprintf ("PASS: %s/prepare: expected buffer location %p got %p\n", > + label, buf, loc); > + else > + { > + xprintf ("FAIL: %s/prepare: expected buffer location %p got %p\n", > + label, buf, loc); > + this_subtest_failed = true; > + failed_subtests++; > + } > +} > + > +/* There are three subtests, two of which are sanity checks. > + > + In the "no_clear" case, we don't do anything to the test buffer > + between preparing it and letting it go out of scope, and we expect > + to find it. This confirms that the test buffer does get filled in > + and we can find it from the stack buffer. In the "ordinary_clear" > + case, we clear it using memset, and we expect to find it. This > + confirms that the compiler can optimize out block clears in this > + context; if it can't, the real test might be succeeding for the > + wrong reason. Finally, the "explicit_clear" case uses > + explicit_bzero and expects _not_ to find the test buffer, which is > + the real test. */ > + > +static void > +setup_no_clear (void) > +{ > + unsigned char buf[TEST_BUFFER_SIZE]; > + prepare_test_buffer (buf, "no clear"); > +} > + > +static void > +setup_ordinary_clear (void) > +{ > + unsigned char buf[TEST_BUFFER_SIZE]; > + prepare_test_buffer (buf, "ordinary clear"); > + if (this_subtest_failed) > + return; > + memset (buf, 0, TEST_BUFFER_SIZE); > +} > + > +static void > +setup_explicit_clear (void) > +{ > + unsigned char buf[TEST_BUFFER_SIZE]; > + prepare_test_buffer (buf, "explicit clear"); > + if (this_subtest_failed) > + return; > + explicit_bzero (buf, TEST_BUFFER_SIZE); > +} > + > +struct subtest > +{ > + void (*setup_subtest) (void); > + const char *label; > + enum test_expectation expected; > +}; > + > +static const struct subtest subtests[] = > +{ > + { setup_no_clear, "no clear", EXPECT_SOME }, > + { setup_ordinary_clear, "ordinary clear", EXPECT_SOME }, > + { setup_explicit_clear, "explicit clear", EXPECT_NONE }, > + { 0, 0, -1 } > +}; > +static const struct subtest *this_subtest; > + > +/* This function is called as a signal handler. The signal is > + triggered by a call to sigsuspend, therefore it is safe to do > + non-async-signal-safe things within this function. */ > +static void > +do_subtest (int signo __attribute__ ((unused))) > +{ > + this_subtest->setup_subtest (); > + if (!this_subtest_failed) > + check_test_buffer (this_subtest->expected, this_subtest->label, "test"); > +} > + > +static int > +do_test (void) > +{ > + /* test-skeleton.c unconditionally sets stdout to be unbuffered. > + vfprintf allocates a great deal of memory on the stack if called > + with an unbuffered FILE*, overflowing the alt-stack. Reset stdout > + to fully buffered to prevent this. */ > + if (setvbuf (stdout, 0, _IOFBF, 0)) > + { > + xprintf ("ERROR: restoring stdout buffering: %s\n", strerror (errno)); > + return 2; > + } > + > + size_t page_alignment = sysconf (_SC_PAGESIZE); > + if (page_alignment < sizeof (void *)) > + page_alignment = sizeof (void *); > + > + void *p; > + int err = posix_memalign (&p, page_alignment, SIGNAL_STACK_SIZE); > + if (err || !p) > + { > + xprintf ("ERROR: allocating alt stack: %s\n", strerror (err)); > + return 2; > + } > + signal_stack_buffer = p; > + > + /* This program will malfunction if it receives SIGUSR1 signals at any > + time other than when it's just sent one to itself. Therefore, keep > + it blocked most of the time. */ > + sigset_t normal_mask; > + sigset_t sigsusp_mask; > + sigemptyset (&normal_mask); > + sigaddset (&normal_mask, SIGUSR1); > + if (sigprocmask (SIG_BLOCK, &normal_mask, &sigsusp_mask)) > + { > + xprintf ("ERROR: block(SIGUSR1): %s\n", strerror (errno)); > + return 2; > + } > + /* But ensure that SIGUSR1 is _not_ blocked during calls to > + sigsuspend, even if the invoking process blocked it. */ > + sigdelset (&sigsusp_mask, SIGUSR1); > + > + stack_t ss; > + ss.ss_sp = signal_stack_buffer; > + ss.ss_flags = 0; > + ss.ss_size = SIGNAL_STACK_SIZE; > + if (sigaltstack (&ss, 0)) > + { > + xprintf ("ERROR: sigaltstack: %s\n", strerror (errno)); > + return 2; > + } > + > + struct sigaction sa; > + sa.sa_mask = normal_mask; > + sa.sa_handler = do_subtest; > + sa.sa_flags = SA_RESTART | SA_ONSTACK; > + if (sigaction (SIGUSR1, &sa, 0)) > + { > + xprintf ("ERROR: sigaction(SIGUSR1): %s\n", strerror (errno)); > + return 2; > + } > + > + /* We use kill instead of raise, because raise may internally modify > + the signal mask. */ > + pid_t self = getpid (); > + > + this_subtest = subtests; > + while (this_subtest->label) > + { > + this_subtest_failed = false; > + > + /* Completely clear the signal stack between tests, so that junk > + from previous tests cannot interfere with the current one. */ > + memset (signal_stack_buffer, 0, SIGNAL_STACK_SIZE); > + > + /* Raise SIGUSR1, then call sigsuspend with a mask that unblocks > + SIGUSR1. This will trigger do_subtest to run _once_ on the > + alternative stack, at the point of the sigsuspend. */ > + if (kill (self, SIGUSR1)) > + { > + xprintf ("ERROR: raise(SIGUSR1): %s\n", strerror (errno)); > + return 2; > + } > + /* The return value of sigsuspend is not meaningful. */ > + sigsuspend (&sigsusp_mask); > + > + this_subtest++; > + } > + > + return failed_subtests ? 1 : 0; > +} > + > +#undef printf > +#define TEST_FUNCTION do_test () > +#include "../test-skeleton.c" > diff --git a/sysdeps/arm/nacl/libc.abilist b/sysdeps/arm/nacl/libc.abilist > index 807e43d..b074374 100644 > --- a/sysdeps/arm/nacl/libc.abilist > +++ b/sysdeps/arm/nacl/libc.abilist > @@ -1843,6 +1843,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 gnu_dev_major F > GLIBC_2.25 gnu_dev_makedev F > GLIBC_2.25 gnu_dev_minor F > diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist > index 77accdf..e265325 100644 > --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist > +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist > @@ -2090,6 +2090,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist > index 659b7fc..393dd4c 100644 > --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist > +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist > @@ -2001,6 +2001,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist > index 8bc979a..b92eccb 100644 > --- a/sysdeps/unix/sysv/linux/arm/libc.abilist > +++ b/sysdeps/unix/sysv/linux/arm/libc.abilist > @@ -91,6 +91,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist > index 299b705..3b1661d 100644 > --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist > +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist > @@ -1855,6 +1855,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist > index f00345f..452e013 100644 > --- a/sysdeps/unix/sysv/linux/i386/libc.abilist > +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist > @@ -2013,6 +2013,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist > index e5fcf88..0196234 100644 > --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist > +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist > @@ -1877,6 +1877,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist > index 8f382f6..d6e0e16 100644 > --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist > +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist > @@ -92,6 +92,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist > index 320b7fe..c3a5f24 100644 > --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist > +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist > @@ -1969,6 +1969,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist > index 21b1426..fa72a0d 100644 > --- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist > +++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist > @@ -2090,6 +2090,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist > index 5c4b596..03d3c0c 100644 > --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist > +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist > @@ -1944,6 +1944,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist > index 001fa6c..a1c9cd2 100644 > --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist > +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist > @@ -1942,6 +1942,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist > index 2d87001..a8671ba 100644 > --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist > +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist > @@ -1940,6 +1940,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist > index aa1ee66..e71283f 100644 > --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist > +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist > @@ -1935,6 +1935,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist > index 2471d68..f92545c 100644 > --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist > +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist > @@ -2131,6 +2131,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist > index 4b0cde8..d8427ca 100644 > --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist > +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist > @@ -1973,6 +1973,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist > index 0557c16..fa26199 100644 > --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist > +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist > @@ -1978,6 +1978,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist > index 821384e..73488a4 100644 > --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist > +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist > @@ -2178,6 +2178,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist > index c40a3f1..ac9cc69 100644 > --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist > +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist > @@ -92,6 +92,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist > index 5b39a60..933a00a 100644 > --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist > +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist > @@ -1973,6 +1973,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist > index a9db32f..eb74169 100644 > --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist > +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist > @@ -1874,6 +1874,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist > index 294af0a..37aded2 100644 > --- a/sysdeps/unix/sysv/linux/sh/libc.abilist > +++ b/sysdeps/unix/sysv/linux/sh/libc.abilist > @@ -1859,6 +1859,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist > index 32747bd..5b7c54e 100644 > --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist > +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist > @@ -1965,6 +1965,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist > index b0ac4d4..4854351 100644 > --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist > +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist > @@ -1903,6 +1903,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist > index 4d92d81..18f61ba 100644 > --- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist > +++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist > @@ -2097,6 +2097,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist > index a68aef7..53a0db1 100644 > --- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist > +++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist > @@ -2097,6 +2097,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist > index 4d92d81..18f61ba 100644 > --- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist > +++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist > @@ -2097,6 +2097,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist > index b8623fc..d4add67 100644 > --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist > +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist > @@ -1854,6 +1854,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist > index a61d874..18717fa 100644 > --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist > +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist > @@ -2097,6 +2097,9 @@ GLIBC_2.23 fts64_set F > GLIBC_2.24 GLIBC_2.24 A > GLIBC_2.24 quick_exit F > GLIBC_2.25 GLIBC_2.25 A > +GLIBC_2.25 __explicit_bzero F > +GLIBC_2.25 __glibc_read_memory F > +GLIBC_2.25 explicit_bzero F > GLIBC_2.25 strfromd F > GLIBC_2.25 strfromf F > GLIBC_2.25 strfroml F > ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 0/3] explicit_bzero v6 @ 2016-12-08 14:56 Zack Weinberg 2016-12-08 14:56 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Zack Weinberg 0 siblings, 1 reply; 15+ messages in thread From: Zack Weinberg @ 2016-12-08 14:56 UTC (permalink / raw) To: libc-alpha This contains the revised documentation discussed earlier, and an improved test that doesn't use signal stacks (it uses swapcontext instead, and does no printing on the alternate stack, so we don't need a printf wrapper anymore) (I thought about using pthreads instead of the POSIX-obsolesced swapcontext, but then I'd have had to figure out how to get random tests in string/ linked with libpthread). There is no mangling of the public symbol name. As with getentropy/getrandom, I'm OK with adding mangling if archive rebuilds indicate a problem. I'm going to be out of town for the last two weeks of December, so I would like a go/no-go decision on the inclusion of explicit_bzero for 2.25 as soon as possible. zw Zack Weinberg (3): New string function explicit_bzero (from OpenBSD). Add fortification and inline optimization of explicit_bzero. Use explicit_bzero where appropriate NEWS | 6 + crypt/crypt-entry.c | 11 + crypt/md5-crypt.c | 8 +- crypt/sha256-crypt.c | 14 +- crypt/sha512-crypt.c | 14 +- debug/tst-chk1.c | 28 ++ include/string.h | 12 + manual/string.texi | 101 +++++++ string/Makefile | 12 +- string/Versions | 10 + string/bits/string2.h | 11 + string/bits/string3.h | 8 + string/explicit_bzero.c | 33 +++ string/read_memory.c | 41 +++ string/string.h | 9 + string/test-explicit_bzero.c | 20 ++ string/test-memset.c | 10 +- string/tst-xbzero-opt.c | 289 +++++++++++++++++++++ sysdeps/arm/nacl/libc.abilist | 3 + sysdeps/unix/sysv/linux/aarch64/libc.abilist | 3 + sysdeps/unix/sysv/linux/alpha/libc.abilist | 3 + sysdeps/unix/sysv/linux/arm/libc.abilist | 3 + sysdeps/unix/sysv/linux/hppa/libc.abilist | 3 + sysdeps/unix/sysv/linux/i386/libc.abilist | 3 + sysdeps/unix/sysv/linux/ia64/libc.abilist | 3 + sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist | 3 + sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist | 3 + sysdeps/unix/sysv/linux/microblaze/libc.abilist | 3 + .../unix/sysv/linux/mips/mips32/fpu/libc.abilist | 3 + .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist | 3 + .../unix/sysv/linux/mips/mips64/n32/libc.abilist | 3 + .../unix/sysv/linux/mips/mips64/n64/libc.abilist | 3 + sysdeps/unix/sysv/linux/nios2/libc.abilist | 3 + .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist | 3 + .../linux/powerpc/powerpc32/nofpu/libc.abilist | 3 + .../sysv/linux/powerpc/powerpc64/libc-le.abilist | 3 + .../unix/sysv/linux/powerpc/powerpc64/libc.abilist | 3 + sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist | 3 + sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist | 3 + sysdeps/unix/sysv/linux/sh/libc.abilist | 3 + sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist | 3 + sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist | 3 + .../sysv/linux/tile/tilegx/tilegx32/libc.abilist | 3 + .../sysv/linux/tile/tilegx/tilegx64/libc.abilist | 3 + sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist | 3 + sysdeps/unix/sysv/linux/x86_64/64/libc.abilist | 3 + sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist | 3 + 47 files changed, 702 insertions(+), 22 deletions(-) create mode 100644 string/explicit_bzero.c create mode 100644 string/read_memory.c create mode 100644 string/test-explicit_bzero.c create mode 100644 string/tst-xbzero-opt.c -- 2.11.0 ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 1/3] New string function explicit_bzero (from OpenBSD). 2016-12-08 14:56 [PATCH 0/3] explicit_bzero v6 Zack Weinberg @ 2016-12-08 14:56 ` Zack Weinberg 2016-12-08 17:14 ` Joseph Myers 0 siblings, 1 reply; 15+ messages in thread From: Zack Weinberg @ 2016-12-08 14:56 UTC (permalink / raw) To: libc-alpha explicit_bzero(s, n) is the same as memset(s, 0, n), except that the compiler is not allowed to delete a call to explicit_bzero even if the memory pointed to by 's' is dead after the call. We achieve this effect by defining it to call memset() and then a second function, extern void __glibc_read_memory (const void *, size_t) __attribute_noinline__; which does nothing -- but the compiler is prevented from knowing that it does nothing, and so the pointer "escapes" and the memory is not treated as dead. (Concretely, __glibc_read_memory is forced out-of-line, defined in a file containing nothing else, and comments in both string/read_memory.c and string/Makefile document that it must not be subject to link-time optimization.) There are two new tests: test-explicit_bzero.c verifies the visible semantics in the same way as the existing test-bzero.c, and tst-xbzero-opt.c verifies the not-being-optimized-out property. The latter is conceptually based on a test written by Matthew Dempsky for the OpenBSD regression suite. * string/explicit_bzero.c, string/read_memory.c: New routines. * string/test-explicit_bzero.c, string/tst-xbzero-opt.c: New tests. * string/Makefile (routines, strop-tests, tests): Add them. * string/test-memset.c: Add ifdeffage for testing explicit_bzero. * string/string.h [__USE_MISC]: Declare explicit_bzero and __glibc_read_memory. * include/string.h: Declare __internal_glibc_read_memory, __explicit_bzero, and __internal_explicit_bzero. * manual/string.texi: Document explicit_bzero. * NEWS: Mention addition of explicit_bzero. * string/Versions [GLIBC_2.25]: Add explicit_bzero, __explicit_bzero, and __glibc_read_memory. * sysdeps/arm/nacl/libc.abilist * sysdeps/unix/sysv/linux/aarch64/libc.abilist * sysdeps/unix/sysv/linux/alpha/libc.abilist * sysdeps/unix/sysv/linux/arm/libc.abilist * sysdeps/unix/sysv/linux/hppa/libc.abilist * sysdeps/unix/sysv/linux/i386/libc.abilist * sysdeps/unix/sysv/linux/ia64/libc.abilist * sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist * sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist * sysdeps/unix/sysv/linux/microblaze/libc.abilist * sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist * sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist * sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist * sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist * sysdeps/unix/sysv/linux/nios2/libc.abilist * sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist * sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist * sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist * sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist * sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist * sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist * sysdeps/unix/sysv/linux/sh/libc.abilist * sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist * sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist * sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist * sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist * sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist * sysdeps/unix/sysv/linux/x86_64/64/libc.abilist * sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist: Add entries for explicit_bzero, __explicit_bzero, and __glibc_read_memory. --- NEWS | 6 + include/string.h | 12 + manual/string.texi | 101 +++++++ string/Makefile | 12 +- string/Versions | 10 + string/explicit_bzero.c | 33 +++ string/read_memory.c | 41 +++ string/string.h | 9 + string/test-explicit_bzero.c | 20 ++ string/test-memset.c | 10 +- string/tst-xbzero-opt.c | 289 +++++++++++++++++++++ sysdeps/arm/nacl/libc.abilist | 3 + sysdeps/unix/sysv/linux/aarch64/libc.abilist | 3 + sysdeps/unix/sysv/linux/alpha/libc.abilist | 3 + sysdeps/unix/sysv/linux/arm/libc.abilist | 3 + sysdeps/unix/sysv/linux/hppa/libc.abilist | 3 + sysdeps/unix/sysv/linux/i386/libc.abilist | 3 + sysdeps/unix/sysv/linux/ia64/libc.abilist | 3 + sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist | 3 + sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist | 3 + sysdeps/unix/sysv/linux/microblaze/libc.abilist | 3 + .../unix/sysv/linux/mips/mips32/fpu/libc.abilist | 3 + .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist | 3 + .../unix/sysv/linux/mips/mips64/n32/libc.abilist | 3 + .../unix/sysv/linux/mips/mips64/n64/libc.abilist | 3 + sysdeps/unix/sysv/linux/nios2/libc.abilist | 3 + .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist | 3 + .../linux/powerpc/powerpc32/nofpu/libc.abilist | 3 + .../sysv/linux/powerpc/powerpc64/libc-le.abilist | 3 + .../unix/sysv/linux/powerpc/powerpc64/libc.abilist | 3 + sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist | 3 + sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist | 3 + sysdeps/unix/sysv/linux/sh/libc.abilist | 3 + sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist | 3 + sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist | 3 + .../sysv/linux/tile/tilegx/tilegx32/libc.abilist | 3 + .../sysv/linux/tile/tilegx/tilegx64/libc.abilist | 3 + sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist | 3 + sysdeps/unix/sysv/linux/x86_64/64/libc.abilist | 3 + sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist | 3 + 40 files changed, 626 insertions(+), 4 deletions(-) create mode 100644 string/explicit_bzero.c create mode 100644 string/read_memory.c create mode 100644 string/test-explicit_bzero.c create mode 100644 string/tst-xbzero-opt.c diff --git a/NEWS b/NEWS index 922a5004ff..dc5d05b587 100644 --- a/NEWS +++ b/NEWS @@ -71,6 +71,12 @@ Version 2.25 * The functions strfromd, strfromf, and strfroml, from ISO/IEC TS 18661-1:2014, are added to libc. They convert a floating-point number into string. +* The function explicit_bzero, from OpenBSD, has been added to libc. It is + intended to be used instead of memset() to erase sensitive data after use; + the compiler will not optimize out calls to explicit_bzero even if they + are "unnecessary" (in the sense that no _correct_ program can observe the + effects of the memory clear). + * On ColdFire, MicroBlaze, Nios II and SH3, the float_t type is now defined to float instead of double. This does not affect the ABI of any libraries that are part of the GNU C Library, but may affect the ABI of other diff --git a/include/string.h b/include/string.h index e145bfdb4c..4185521daa 100644 --- a/include/string.h +++ b/include/string.h @@ -100,6 +100,18 @@ extern __typeof (memmem) __memmem; libc_hidden_proto (__memmem) libc_hidden_proto (__ffs) +/* explicit_bzero is used in libcrypt. */ +extern __typeof (explicit_bzero) __explicit_bzero; +extern __typeof (explicit_bzero) __internal_explicit_bzero; +libc_hidden_proto (__internal_explicit_bzero) +extern __typeof (__glibc_read_memory) __internal_glibc_read_memory; +libc_hidden_proto (__internal_glibc_read_memory) +/* Honor string[23].h overrides when present. */ +#ifdef explicit_bzero +# define __explicit_bzero(s,n) explicit_bzero (s,n) +# define __internal_explicit_bzero(s,n) explicit_bzero (s,n) +#endif + libc_hidden_builtin_proto (memchr) libc_hidden_builtin_proto (memcpy) libc_hidden_builtin_proto (mempcpy) diff --git a/manual/string.texi b/manual/string.texi index 1986357ee8..faa75ba501 100644 --- a/manual/string.texi +++ b/manual/string.texi @@ -34,6 +34,8 @@ too. * Search Functions:: Searching for a specific element or substring. * Finding Tokens in a String:: Splitting a string into tokens by looking for delimiters. +* Erasing Sensitive Data:: Clearing memory which contains sensitive + data, after it's no longer needed. * strfry:: Function for flash-cooking a string. * Trivial Encryption:: Obscuring data. * Encode Binary Data:: Encoding and Decoding of Binary Data. @@ -2404,6 +2406,105 @@ contains no '/' bytes, then "." is returned. The prototype for this function can be found in @file{libgen.h}. @end deftypefun +@node Erasing Sensitive Data +@section Erasing Sensitive Data + +Sensitive data, such as cryptographic keys, should be erased from +memory after use, to reduce the risk that a bug will expose it to the +outside world. However, compiler optimizations may determine that an +erasure operation is ``unnecessary,'' and remove it from the generated +code, because no @emph{correct} program could access the variable or +heap object containing the sensitive data after it's deallocated. +Since erasure is a precaution against bugs, this optimization is +inappropriate. + +The function @code{explicit_bzero} erases a block of memory, and +guarantees that the compiler will not remove the erasure as +``unnecessary.'' + +@smallexample +@group +#include <string.h> + +extern void encrypt (const char *key, const char *in, + char *out, size_t n); +extern void genkey (const char *phrase, char *key); + +void encrypt_with_phrase (const char *phrase, const char *in, + char *out, size_t n) +@{ + char key[16]; + genkey (phrase, key); + encrypt (key, in, out, n); + explicit_bzero (key, 16); +@} +@end group +@end smallexample + +@noindent +In this example, if @code{memset}, @code{bzero}, or a hand-written +loop had been used, the compiler might remove them as ``unnecessary.'' + +@strong{Warning:} @code{explicit_bzero} does not guarantee that +sensitive data is @emph{completely} erased from the computer's memory. +There may be copies in temporary storage areas, such as registers and +``scratch'' stack space; since these are invisible to the source code, +a library function cannot erase them. + +Also, @code{explicit_bzero} only operates on RAM. If a sensitive data +object never needs to have its address taken other than to call +@code{explicit_bzero}, it might be stored entirely in CPU registers +@emph{until} the call to @code{explicit_bzero}. Then it will be +copied into RAM, the copy will be erased, and the original will remain +intact. Data in RAM is more likely to be exposed by a bug than data +in registers, so this creates a brief window where the data is at +greater risk of exposure than it would have been if the program didn't +try to erase it at all. @Theglibc{}'s implementation of +@code{explicit_bzero} contains a hack that can prevent the data from +being copied to RAM in this situation, but it may not always work. + +Declaring sensitive variables as @code{volatile} will make both the +above problems @emph{worse}; a @code{volatile} variable will be stored +in memory for its entire lifetime, and the compiler will make +@emph{more} copies of it than it would otherwise have. Attempting to +erase a normal variable ``by hand'' through a +@code{volatile}-qualified pointer doesn't work at all---because the +variable itself is not @code{volatile}, some compilers will ignore the +qualification on the pointer and remove the erasure anyway. + +Having said all that, in most situations, using @code{explicit_bzero} +is better than not using it. At present, the only way to do a more +thorough job is to write the entire sensitive operation in assembly +language. We anticipate that future compilers will recognize calls to +@code{explicit_bzero} and take appropriate steps to erase all the +copies of the affected data, whereever they may be. + +@comment string.h +@comment BSD +@deftypefun void explicit_bzero (void *@var{block}, size_t @var{len}) +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + +@code{explicit_bzero} writes zero into @var{len} bytes of memory +beginning at @var{block}, just as @code{bzero} would. The zeroes are +always written, even if the compiler could determine that this is +``unnecessary'' because no correct program could read them back. + +@strong{Note:} The @emph{only} optimization that @code{explicit_bzero} +disables is removal of ``unnecessary'' writes to memory. The compiler +can perform all the other optimizations that it could for a call to +@code{memset}. For instance, it may replace the function call with +inline memory writes, and it may assume that @var{block} cannot be a +null pointer. + +@strong{Portability Note:} This function first appeared in OpenBSD 5.5 +and has not been standardized. Other systems may provide the same +functionality under a different name, such as @code{explicit_memset}, +@code{memset_s}, or @code{SecureZeroMemory}. + +@Theglibc{} declares this function in @file{string.h}, but on other +systems it may be in @file{strings.h} instead. +@end deftypefun + @node strfry @section strfry diff --git a/string/Makefile b/string/Makefile index 69d3f802fb..0b6486e509 100644 --- a/string/Makefile +++ b/string/Makefile @@ -41,20 +41,26 @@ routines := strcat strchr strcmp strcoll strcpy strcspn \ addsep replace) \ envz basename \ strcoll_l strxfrm_l string-inlines memrchr \ - xpg-strerror strerror_l + xpg-strerror strerror_l explicit_bzero + +# Attention future hackers trying to enable link-time optimization for +# glibc: this file *must not* be subject to LTO. It is added separately +# to 'routines' to document this. See comments in this file for details. +routines += read_memory strop-tests := memchr memcmp memcpy memmove mempcpy memset memccpy \ stpcpy stpncpy strcat strchr strcmp strcpy strcspn \ strlen strncmp strncpy strpbrk strrchr strspn memmem \ strstr strcasestr strnlen strcasecmp strncasecmp \ - strncat rawmemchr strchrnul bcopy bzero memrchr + strncat rawmemchr strchrnul bcopy bzero memrchr \ + explicit_bzero tests := tester inl-tester noinl-tester testcopy test-ffs \ tst-strlen stratcliff tst-svc tst-inlcall \ bug-strncat1 bug-strspn1 bug-strpbrk1 tst-bswap \ tst-strtok tst-strxfrm bug-strcoll1 tst-strfry \ bug-strtok1 $(addprefix test-,$(strop-tests)) \ bug-envz1 tst-strxfrm2 tst-endian tst-svc2 \ - tst-strtok_r bug-strcoll2 tst-cmp + tst-strtok_r bug-strcoll2 tst-cmp tst-xbzero-opt xtests = tst-strcoll-overflow diff --git a/string/Versions b/string/Versions index 475c1fdb64..4f434f371e 100644 --- a/string/Versions +++ b/string/Versions @@ -82,4 +82,14 @@ libc { } GLIBC_2.24 { } + GLIBC_2.25 { + # used by inlines in bits/string2.h and bits/string3.h + __glibc_read_memory; + + # used by libcrypt + __explicit_bzero; + + # e* + explicit_bzero; + } } diff --git a/string/explicit_bzero.c b/string/explicit_bzero.c new file mode 100644 index 0000000000..6c3dc9aedb --- /dev/null +++ b/string/explicit_bzero.c @@ -0,0 +1,33 @@ +/* Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <features.h> +#undef __USE_STRING_INLINES +#define __NO_STRING_INLINES +#include <string.h> + +/* Set LEN bytes of S to 0. The compiler will not delete a call to + this function, even if S is dead after the call. */ +void +__internal_explicit_bzero (void *s, size_t len) +{ + memset (s, '\0', len); + __internal_glibc_read_memory (s, len); +} +libc_hidden_def (__internal_explicit_bzero) +strong_alias (__internal_explicit_bzero, __explicit_bzero) +weak_alias (__internal_explicit_bzero, explicit_bzero) diff --git a/string/read_memory.c b/string/read_memory.c new file mode 100644 index 0000000000..c4a5990c49 --- /dev/null +++ b/string/read_memory.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> + +/* This function is an optimization fence. It doesn't do anything + itself, but calls to it prevent calls to explicit_bzero from being + optimized away. In order to achieve this effect, this function + must never, under any circumstances, be inlined or subjected to + inter-procedural optimization. string.h declares this function + with attributes that, in conjunction with the no-op asm insert, are + sufficient to prevent problems in the current (2016) generation of + compilers, but *only if* this file is *not* compiled with -flto. + At present, this is not an issue since glibc is never compiled with + -flto, but should that ever change, this file must be excepted. + + The 'volatile' below is technically not necessary but is included + for explicitness. */ + +void +internal_function +__internal_glibc_read_memory(const void *s, size_t len) +{ + asm volatile (""); +} +libc_hidden_def (__internal_glibc_read_memory) +strong_alias (__internal_glibc_read_memory, __glibc_read_memory) diff --git a/string/string.h b/string/string.h index b103e64912..3036679cdd 100644 --- a/string/string.h +++ b/string/string.h @@ -453,6 +453,15 @@ extern void bcopy (const void *__src, void *__dest, size_t __n) /* Set N bytes of S to 0. */ extern void bzero (void *__s, size_t __n) __THROW __nonnull ((1)); +/* As bzero, but the compiler will not delete a call to this + function, even if S is dead after the call. */ +extern void explicit_bzero (void *__s, size_t __n) __THROW __nonnull ((1)); + +/* Optimization fence, used by bits/string2.h and bits/string3.h + inline versions of explicit_bzero. */ +extern void __glibc_read_memory (const void *__s, size_t __n) + __THROW __nonnull ((1)) __attribute_noinline__; + /* Compare N bytes of S1 and S2 (same as memcmp). */ extern int bcmp (const void *__s1, const void *__s2, size_t __n) __THROW __attribute_pure__ __nonnull ((1, 2)); diff --git a/string/test-explicit_bzero.c b/string/test-explicit_bzero.c new file mode 100644 index 0000000000..5a4543b41a --- /dev/null +++ b/string/test-explicit_bzero.c @@ -0,0 +1,20 @@ +/* Test and measure explicit_bzero. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ +#define TEST_EXPLICIT_BZERO +#define TEST_BZERO +#include "test-memset.c" diff --git a/string/test-memset.c b/string/test-memset.c index fee3bdf37f..7ca4f2076c 100644 --- a/string/test-memset.c +++ b/string/test-memset.c @@ -19,7 +19,11 @@ #define TEST_MAIN #ifdef TEST_BZERO -# define TEST_NAME "bzero" +# ifdef TEST_EXPLICIT_BZERO +# define TEST_NAME "explicit_bzero" +# else +# define TEST_NAME "bzero" +# endif #else # ifndef WIDE # define TEST_NAME "memset" @@ -56,7 +60,11 @@ void builtin_bzero (char *, size_t); IMPL (simple_bzero, 0) IMPL (builtin_bzero, 0) +#ifdef TEST_EXPLICIT_BZERO +IMPL (explicit_bzero, 1) +#else IMPL (bzero, 1) +#endif void simple_bzero (char *s, size_t n) diff --git a/string/tst-xbzero-opt.c b/string/tst-xbzero-opt.c new file mode 100644 index 0000000000..7d697f4c35 --- /dev/null +++ b/string/tst-xbzero-opt.c @@ -0,0 +1,289 @@ +/* Test that explicit_bzero block clears are not optimized out. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +/* This test is conceptually based on a test designed by Matthew + Dempsky for the OpenBSD regression suite: + <openbsd>/src/regress/lib/libc/explicit_bzero/explicit_bzero.c. + The basic idea is, we have a function that contains a + block-clearing operation (not necessarily explicit_bzero), after + which the block is dead, in the compiler-jargon sense. Execute + that function while running on a user-allocated alternative + stack. Then we have another pointer to the memory region affected + by the block clear -- namely, the original allocation for the + alternative stack -- and can find out whether it actually happened. + + The OpenBSD test uses sigaltstack and SIGUSR1 to get onto an + alternative stack. This causes a number of awkward problems; some + operating systems (e.g. Solaris and OSX) wipe the signal stack upon + returning to the normal stack, there's no way to be sure that other + processes running on the same system will not interfere, and the + signal stack is very small so it's not safe to call printf there. + This implementation instead uses the <ucontext.h> coroutine + interface. The coroutine stack is still too small to safely use + printf, but we know the OS won't erase it, so we can do all the + checks and printing from the normal stack. */ + +#define _GNU_SOURCE 1 + +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ucontext.h> +#include <unistd.h> + +/* A byte pattern that is unlikely to occur by chance: the first 16 + prime numbers (OEIS A000040). */ +static const unsigned char test_pattern[16] = +{ + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53 +}; + +/* Immediately after each subtest returns, we call swapcontext to get + back onto the main stack. That call might itself overwrite the + test pattern, so we fill a modest-sized buffer with copies of it + and check whether any of them survived. */ + +#define PATTERN_SIZE (sizeof test_pattern) +#define PATTERN_REPS 32 +#define TEST_BUFFER_SIZE (PATTERN_SIZE * PATTERN_REPS) + +/* There are three subtests, two of which are sanity checks. + Each test follows this sequence: + + main coroutine + ---- -------- + advance cur_subtest + swap + call setup function + prepare test buffer + swap + verify that buffer + was filled in + swap + possibly clear buffer + return + swap + check buffer again, + according to test + expectation + + In the "no_clear" case, we don't do anything to the test buffer + between preparing it and letting it go out of scope, and we expect + to find it. This confirms that the test buffer does get filled in + and we can find it from the stack buffer. In the "ordinary_clear" + case, we clear it using memset, and we expect to find it. This + confirms that the compiler can optimize out block clears in this + context; if it can't, the real test might be succeeding for the + wrong reason. Finally, the "explicit_clear" case uses + explicit_bzero and expects _not_ to find the test buffer, which is + the real test. */ + +static ucontext_t uc_main, uc_co; + +/* Always check the test buffer immediately after filling it; this + makes externally visible side effects depend on the buffer existing + and having been filled in. */ +static void +prepare_test_buffer (unsigned char *buf) +{ + for (unsigned int i = 0; i < PATTERN_REPS; i++) + memcpy (buf + i*PATTERN_SIZE, test_pattern, PATTERN_SIZE); + + if (swapcontext (&uc_co, &uc_main)) + abort (); +} + +static void +setup_no_clear (void) +{ + unsigned char buf[TEST_BUFFER_SIZE]; + prepare_test_buffer (buf); +} + +static void +setup_ordinary_clear (void) +{ + unsigned char buf[TEST_BUFFER_SIZE]; + prepare_test_buffer (buf); + memset (buf, 0, TEST_BUFFER_SIZE); +} + +static void +setup_explicit_clear (void) +{ + unsigned char buf[TEST_BUFFER_SIZE]; + prepare_test_buffer (buf); + explicit_bzero (buf, TEST_BUFFER_SIZE); +} + +enum test_expectation { EXPECT_NONE, EXPECT_SOME, EXPECT_ALL }; +struct subtest +{ + void (*setup_subtest) (void); + const char *label; + enum test_expectation expected; +}; +static const struct subtest *cur_subtest; + +static const struct subtest subtests[] = +{ + { setup_no_clear, "no clear", EXPECT_SOME }, + { setup_ordinary_clear, "ordinary clear", EXPECT_SOME }, + { setup_explicit_clear, "explicit clear", EXPECT_NONE }, + { 0, 0, -1 } +}; + +static void +test_coroutine (void) +{ + while (cur_subtest->setup_subtest) + { + cur_subtest->setup_subtest (); + if (swapcontext (&uc_co, &uc_main)) + abort (); + } +} + +/* All the code above this point runs on the coroutine stack. + All the code below this point runs on the main stack. */ + +static int test_status; +static unsigned char *co_stack_buffer; +static size_t co_stack_size; + +static unsigned int +count_test_patterns (unsigned char *buf, size_t bufsiz) +{ + unsigned char *first = memmem (buf, bufsiz, test_pattern, PATTERN_SIZE); + if (!first) + return 0; + unsigned int cnt = 0; + for (unsigned int i = 0; i < PATTERN_REPS; i++) + { + unsigned char *p = first + i*PATTERN_SIZE; + if (p + PATTERN_SIZE - buf > bufsiz) + break; + if (memcmp (p, test_pattern, PATTERN_SIZE) == 0) + cnt++; + } + return cnt; +} + +static void +check_test_buffer (enum test_expectation expected, + const char *label, const char *stage) +{ + unsigned int cnt = count_test_patterns (co_stack_buffer, co_stack_size); + switch (expected) + { + case EXPECT_NONE: + if (cnt == 0) + printf ("PASS: %s/%s: expected 0 got %d\n", label, stage, cnt); + else + { + printf ("FAIL: %s/%s: expected 0 got %d\n", label, stage, cnt); + test_status = 1; + } + break; + + case EXPECT_SOME: + if (cnt > 0) + printf ("PASS: %s/%s: expected some got %d\n", label, stage, cnt); + else + { + printf ("FAIL: %s/%s: expected some got 0\n", label, stage); + test_status = 1; + } + break; + + case EXPECT_ALL: + if (cnt == PATTERN_REPS) + printf ("PASS: %s/%s: expected %d got %d\n", label, stage, + PATTERN_REPS, cnt); + else + { + printf ("FAIL: %s/%s: expected %d got %d\n", label, stage, + PATTERN_REPS, cnt); + test_status = 1; + } + break; + + default: + printf ("ERROR: %s/%s: invalid value for 'expected' = %d\n", + label, stage, (int)expected); + test_status = 1; + } +} + +static void +test_loop (void) +{ + cur_subtest = subtests; + while (cur_subtest->setup_subtest) + { + if (swapcontext (&uc_main, &uc_co)) + abort (); + check_test_buffer (EXPECT_ALL, cur_subtest->label, "prepare"); + if (swapcontext (&uc_main, &uc_co)) + abort (); + check_test_buffer (cur_subtest->expected, cur_subtest->label, "test"); + cur_subtest++; + } + /* Terminate the coroutine. */ + if (swapcontext (&uc_main, &uc_co)) + abort (); +} + +static int +do_test (void) +{ + size_t page_alignment = sysconf (_SC_PAGESIZE); + if (page_alignment < sizeof (void *)) + page_alignment = sizeof (void *); + + co_stack_size = SIGSTKSZ + TEST_BUFFER_SIZE; + if (co_stack_size < page_alignment * 4) + co_stack_size = page_alignment * 4; + + void *p; + int err = posix_memalign (&p, page_alignment, co_stack_size); + if (err || !p) + { + printf ("ERROR: allocating alt stack: %s\n", strerror (err)); + return 2; + } + co_stack_buffer = p; + + if (getcontext (&uc_co)) + { + printf ("ERROR: allocating coroutine context: %s\n", strerror (err)); + return 2; + } + uc_co.uc_stack.ss_sp = co_stack_buffer; + uc_co.uc_stack.ss_size = co_stack_size; + uc_co.uc_link = &uc_main; + makecontext (&uc_co, test_coroutine, 0); + + test_loop (); + return test_status; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/arm/nacl/libc.abilist b/sysdeps/arm/nacl/libc.abilist index 807e43d935..b07437496e 100644 --- a/sysdeps/arm/nacl/libc.abilist +++ b/sysdeps/arm/nacl/libc.abilist @@ -1843,6 +1843,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 gnu_dev_major F GLIBC_2.25 gnu_dev_makedev F GLIBC_2.25 gnu_dev_minor F diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist index 77accdf5c1..e26532519f 100644 --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist @@ -2090,6 +2090,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist index 659b7fcf37..393dd4ca1c 100644 --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist @@ -2001,6 +2001,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist index 8bc979ad7f..b92eccbd5c 100644 --- a/sysdeps/unix/sysv/linux/arm/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/libc.abilist @@ -91,6 +91,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist index 299b705156..3b1661dc8f 100644 --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist @@ -1855,6 +1855,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist index f00345f673..452e013002 100644 --- a/sysdeps/unix/sysv/linux/i386/libc.abilist +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist @@ -2013,6 +2013,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist index e5fcf88b18..01962345c2 100644 --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist @@ -1877,6 +1877,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist index 8f382f680b..d6e0e161b5 100644 --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist @@ -92,6 +92,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist index 320b7fef5f..c3a5f245bb 100644 --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist @@ -1969,6 +1969,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist index 21b14262c6..fa72a0dbf9 100644 --- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist @@ -2090,6 +2090,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist index 5c4b596c54..03d3c0c8b6 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist @@ -1944,6 +1944,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist index 001fa6c129..a1c9cd2ee6 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist @@ -1942,6 +1942,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist index 2d870013f7..a8671ba736 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist @@ -1940,6 +1940,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist index aa1ee66ab7..e71283f99f 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist @@ -1935,6 +1935,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist index 2471d68e87..f92545c8c0 100644 --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist @@ -2131,6 +2131,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist index 4ba3146902..1748455056 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist @@ -1973,6 +1973,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist index 0557c16130..fa2619950e 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist @@ -1978,6 +1978,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist index 821384ebd6..73488a4e8c 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist @@ -2178,6 +2178,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist index c40a3f1cba..ac9cc69777 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist @@ -92,6 +92,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist index 5b39a60638..933a00a53a 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist @@ -1973,6 +1973,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist index a9db32f6c2..eb741698bd 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist @@ -1874,6 +1874,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist index 294af0a501..37aded2217 100644 --- a/sysdeps/unix/sysv/linux/sh/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/libc.abilist @@ -1859,6 +1859,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist index 32747bd22d..5b7c54e107 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist @@ -1965,6 +1965,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist index b0ac4d4472..4854351aea 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist @@ -1903,6 +1903,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist index 4d92d81b85..18f61bae76 100644 --- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist +++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist @@ -2097,6 +2097,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist index a68aef7bb7..53a0db1c4e 100644 --- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist +++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist @@ -2097,6 +2097,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist index 4d92d81b85..18f61bae76 100644 --- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist +++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist @@ -2097,6 +2097,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist index b8623fc59f..d4add67825 100644 --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist @@ -1854,6 +1854,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist index a61d874dfe..18717fa40b 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist @@ -2097,6 +2097,9 @@ GLIBC_2.23 fts64_set F GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F GLIBC_2.25 GLIBC_2.25 A +GLIBC_2.25 __explicit_bzero F +GLIBC_2.25 __glibc_read_memory F +GLIBC_2.25 explicit_bzero F GLIBC_2.25 strfromd F GLIBC_2.25 strfromf F GLIBC_2.25 strfroml F -- 2.11.0 ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] New string function explicit_bzero (from OpenBSD). 2016-12-08 14:56 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Zack Weinberg @ 2016-12-08 17:14 ` Joseph Myers 2016-12-08 18:08 ` Zack Weinberg 0 siblings, 1 reply; 15+ messages in thread From: Joseph Myers @ 2016-12-08 17:14 UTC (permalink / raw) To: Zack Weinberg; +Cc: libc-alpha On Thu, 8 Dec 2016, Zack Weinberg wrote: > + # used by libcrypt > + __explicit_bzero; Use by libcrypt would be sufficient reason for a GLIBC_PRIVATE export; it's not clear it's sufficient for a GLIBC_2.25 public symbol version export, absent a general position on adding such exports of implementation-namespace names. > diff --git a/string/explicit_bzero.c b/string/explicit_bzero.c > new file mode 100644 > index 0000000000..6c3dc9aedb > --- /dev/null > +++ b/string/explicit_bzero.c > @@ -0,0 +1,33 @@ > +/* Copyright (C) 2016 Free Software Foundation, Inc. Missing descriptive comment as first line of new file. > diff --git a/string/read_memory.c b/string/read_memory.c > new file mode 100644 > index 0000000000..c4a5990c49 > --- /dev/null > +++ b/string/read_memory.c > @@ -0,0 +1,41 @@ > +/* Copyright (C) 2016 Free Software Foundation, Inc. Likewise. -- Joseph S. Myers joseph@codesourcery.com ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] New string function explicit_bzero (from OpenBSD). 2016-12-08 17:14 ` Joseph Myers @ 2016-12-08 18:08 ` Zack Weinberg 2016-12-08 18:17 ` Joseph Myers 0 siblings, 1 reply; 15+ messages in thread From: Zack Weinberg @ 2016-12-08 18:08 UTC (permalink / raw) To: Joseph Myers, GNU C Library On Thu, Dec 8, 2016 at 12:13 PM, Joseph Myers <joseph@codesourcery.com> wrote: > On Thu, 8 Dec 2016, Zack Weinberg wrote: > >> + # used by libcrypt >> + __explicit_bzero; > > Use by libcrypt would be sufficient reason for a GLIBC_PRIVATE export; > it's not clear it's sufficient for a GLIBC_2.25 public symbol version > export, absent a general position on adding such exports of > implementation-namespace names. Fair point, I will change it to GLIBC_PRIVATE. [...] You are again doing this annoying thing you do where you send a small number of review comments with no indication of whether you have any other comments or concerns, whether you want to see these comments addressed before you look at the patches any more, or whether you are approving (or have the authority to approve) the patch series. Given the short time to the 2.25 deadline and my own limited time before I go out of town, I do not intend to rework this patch series any further unless it is approved in principle for 2.25, and not until I receive a _complete_ list of things that need to be changed before it can be committed. zw ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] New string function explicit_bzero (from OpenBSD). 2016-12-08 18:08 ` Zack Weinberg @ 2016-12-08 18:17 ` Joseph Myers 0 siblings, 0 replies; 15+ messages in thread From: Joseph Myers @ 2016-12-08 18:17 UTC (permalink / raw) To: Zack Weinberg; +Cc: GNU C Library On Thu, 8 Dec 2016, Zack Weinberg wrote: > You are again doing this annoying thing you do where you send a small > number of review comments with no indication of whether you have any > other comments or concerns, whether you want to see these comments > addressed before you look at the patches any more, or whether you are > approving (or have the authority to approve) the patch series. I've not attempted to review the patch substantively (and don't particularly expect to do so, though I support the principle of adding this interface). We don't generally do "authority to approve" (anyone can review patches, but some views may have more weight in establishing consensus than others). -- Joseph S. Myers joseph@codesourcery.com ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2016-12-08 18:17 UTC | newest] Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2016-09-15 13:05 [PATCH 0/3] explicit_bzero again Zack Weinberg 2016-09-15 13:05 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Zack Weinberg 2016-09-15 13:05 ` [PATCH 2/3] Add fortification and inline optimization of explicit_bzero Zack Weinberg 2016-09-15 13:05 ` [PATCH 3/3] Use explicit_bzero where appropriate Zack Weinberg 2016-09-15 15:38 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Paul Eggert 2016-09-15 15:59 ` Paul Eggert 2016-10-06 10:03 ` Florian Weimer 2016-10-06 15:49 ` Joseph Myers 2016-10-18 9:27 ` Florian Weimer 2016-11-15 15:55 [PATCH 0/3] explicit_bzero v5 Zack Weinberg 2016-11-15 15:55 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Zack Weinberg 2016-11-16 18:38 ` Michael Kerrisk (man-pages) 2016-12-08 14:56 [PATCH 0/3] explicit_bzero v6 Zack Weinberg 2016-12-08 14:56 ` [PATCH 1/3] New string function explicit_bzero (from OpenBSD) Zack Weinberg 2016-12-08 17:14 ` Joseph Myers 2016-12-08 18:08 ` Zack Weinberg 2016-12-08 18:17 ` Joseph Myers
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).