[2/4] New string function explicit_bzero (from OpenBSD).
Commit Message
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.)
* string/explicit_bzero.c, string/read_memory.c: New routines.
* string/test-explicit_bzero.c: New test.
* string/Makefile (routines, strop-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.
* string/bits/string2.h [__USE_MISC]: Provide inline version of
explicit_bzero.
* manual/string.texi: Document explicit_bzero.
* string/Versions [GLIBC_2.25]: Add explicit_bzero and
__glibc_read_memory.
* include/string.h: Hidden prototype for __internal_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 and __glibc_read_memory.
---
include/string.h | 2 +
manual/string.texi | 101 +++++++++++++++++++++
string/Makefile | 10 +-
string/Versions | 7 ++
string/bits/string2.h | 14 ++-
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 +-
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 +
39 files changed, 298 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
Comments
On 08/17/2016 07:19 PM, Zack Weinberg wrote:
> +#ifdef __USE_MISC
> +/* As bzero, but the compiler will not delete a call to this
> + function, even if S is dead after the call. Note: this function
> + has its own implementation file and should not be slurped into
> + string-inlines.o. */
> +__extern_inline void
> +explicit_bzero (void *__s, size_t __n)
> +{
> + memset (__s, '\0', __n);
> + __glibc_read_memory (__s, __n);
> +}
> +#endif
__extern_inline can expand to nothing at all, and you would get multiple
definitions of explicit_bzero this way.
I don't think we want explicit_bzero to be inlined, it's useful to have
this name in the executable. Furthermore, we might want to add
additional state clearing later, so an implementation in libc.so.6 seems
desirable anyway.
For an implementation in libc, there is currently no different between
the __glibc_read_memory kludge and a full memory barrier, so I suggest
to go with the latter. (The explicit_bzero call will serve as a rather
broad barrier anyway, but we can annotate it with __THROW.)
Thanks,
Florian
On Thu, 2016-08-18 at 20:31 +0200, Florian Weimer wrote:
> On 08/17/2016 07:19 PM, Zack Weinberg wrote:
> > +#ifdef __USE_MISC
> > +/* As bzero, but the compiler will not delete a call to this
> > + function, even if S is dead after the call. Note: this function
> > + has its own implementation file and should not be slurped into
> > + string-inlines.o. */
> > +__extern_inline void
> > +explicit_bzero (void *__s, size_t __n)
> > +{
> > + memset (__s, '\0', __n);
> > + __glibc_read_memory (__s, __n);
> > +}
> > +#endif
>
> __extern_inline can expand to nothing at all, and you would get multiple
> definitions of explicit_bzero this way.
>
> I don't think we want explicit_bzero to be inlined, it's useful to have
> this name in the executable. Furthermore, we might want to add
> additional state clearing later, so an implementation in libc.so.6 seems
> desirable anyway.
>
> For an implementation in libc, there is currently no different between
> the __glibc_read_memory kludge and a full memory barrier, so I suggest
> to go with the latter. (The explicit_bzero call will serve as a rather
> broad barrier anyway, but we can annotate it with __THROW.)
I suppose we just want a compiler barrier here though, and don't need a
memory barrier in the sense of something that constrains HW reordering.
On 18/08/2016 17:53, Torvald Riegel wrote:
> On Thu, 2016-08-18 at 20:31 +0200, Florian Weimer wrote:
>> On 08/17/2016 07:19 PM, Zack Weinberg wrote:
>>> +#ifdef __USE_MISC
>>> +/* As bzero, but the compiler will not delete a call to this
>>> + function, even if S is dead after the call. Note: this function
>>> + has its own implementation file and should not be slurped into
>>> + string-inlines.o. */
>>> +__extern_inline void
>>> +explicit_bzero (void *__s, size_t __n)
>>> +{
>>> + memset (__s, '\0', __n);
>>> + __glibc_read_memory (__s, __n);
>>> +}
>>> +#endif
>>
>> __extern_inline can expand to nothing at all, and you would get multiple
>> definitions of explicit_bzero this way.
>>
>> I don't think we want explicit_bzero to be inlined, it's useful to have
>> this name in the executable. Furthermore, we might want to add
>> additional state clearing later, so an implementation in libc.so.6 seems
>> desirable anyway.
>>
>> For an implementation in libc, there is currently no different between
>> the __glibc_read_memory kludge and a full memory barrier, so I suggest
>> to go with the latter. (The explicit_bzero call will serve as a rather
>> broad barrier anyway, but we can annotate it with __THROW.)
>
> I suppose we just want a compiler barrier here though, and don't need a
> memory barrier in the sense of something that constrains HW reordering.
I would also suggest to avoid adding this inline optimization, it just add
another exported symbol by glibc with little performance benefit.
On 08/18/2016 10:53 PM, Torvald Riegel wrote:
> On Thu, 2016-08-18 at 20:31 +0200, Florian Weimer wrote:
>> I don't think we want explicit_bzero to be inlined, it's useful to have
>> this name in the executable. Furthermore, we might want to add
>> additional state clearing later, so an implementation in libc.so.6 seems
>> desirable anyway.
>>
>> For an implementation in libc, there is currently no different between
>> the __glibc_read_memory kludge and a full memory barrier, so I suggest
>> to go with the latter. (The explicit_bzero call will serve as a rather
>> broad barrier anyway, but we can annotate it with __THROW.)
>
> I suppose we just want a compiler barrier here though, and don't need a
> memory barrier in the sense of something that constrains HW reordering.
Yes, I meant an asm statement with a "memory" clobber.
Thanks,
Florian
On 08/19/2016 08:43 AM, Adhemerval Zanella wrote:
> On 18/08/2016 17:53, Torvald Riegel wrote:
>> On Thu, 2016-08-18 at 20:31 +0200, Florian Weimer wrote:
>>> On 08/17/2016 07:19 PM, Zack Weinberg wrote:
>>>> +#ifdef __USE_MISC
>>>> +/* As bzero, but the compiler will not delete a call to this
>>>> + function, even if S is dead after the call. Note: this function
>>>> + has its own implementation file and should not be slurped into
>>>> + string-inlines.o. */
>>>> +__extern_inline void
>>>> +explicit_bzero (void *__s, size_t __n)
>>>> +{
>>>> + memset (__s, '\0', __n);
>>>> + __glibc_read_memory (__s, __n);
>>>> +}
>>>> +#endif
>>>
>>> __extern_inline can expand to nothing at all, and you would get multiple
>>> definitions of explicit_bzero this way.
OK, what should I be using instead?
>>> I don't think we want explicit_bzero to be inlined, it's useful to have
>>> this name in the executable. Furthermore, we might want to add
>>> additional state clearing later, so an implementation in libc.so.6 seems
>>> desirable anyway.
Oddly enough, inlining the memset leads to better security properties
for generated code. Remember the "key that lives in the vector
registers until it has to be copied onto the stack to be erased" scenario?
---
#include <emmintrin.h>
#include <string.h>
extern void explicit_bzero (void *ptr, size_t size);
extern __m128 get_key ();
extern void encrypt_with_key (__m128 key, void *data, size_t size);
void encrypt (void *data, size_t size)
{
__m128 key = get_key ();
encrypt_with_key (key, data, size);
explicit_bzero (&key, sizeof key);
}
---
(Assume an ABI where __m128 actually gets passed in registers.)
If you expose the memset to inlining, the key *won't* be copied into
the stack and then immediately erased; the compiler will just dutifully
clear 16 bytes of the stack and then pass them to __glibc_read_memory.
It still won't be erased from the vector registers, but that can only be
fixed with compiler support.
(It also leads to significantly more compact code -- see my experiment
with OpenSSL from last year -- but that's not as important.)
>> I suppose we just want a compiler barrier here though, and don't need a
>> memory barrier in the sense of something that constrains HW reordering.
That is correct; however, the "memory barrier" I was talking about was
asm volatile ("" ::: "memory");
which is also only a compiler barrier.
> I would also suggest to avoid adding this inline optimization, it just add
> another exported symbol by glibc with little performance benefit.
The *other* reason why I want to keep the inline optimization is that it
means I don't need to add __explicit_bzero_chk (which, because of
ifuncs, means futzing with *every sysdeps definition of memset*!). So
either way there's going to be a new exported symbol.
zw
On 19/08/2016 10:00, Zack Weinberg wrote:
> On 08/19/2016 08:43 AM, Adhemerval Zanella wrote:
>> On 18/08/2016 17:53, Torvald Riegel wrote:
>>> On Thu, 2016-08-18 at 20:31 +0200, Florian Weimer wrote:
>>>> On 08/17/2016 07:19 PM, Zack Weinberg wrote:
>>>>> +#ifdef __USE_MISC
>>>>> +/* As bzero, but the compiler will not delete a call to this
>>>>> + function, even if S is dead after the call. Note: this function
>>>>> + has its own implementation file and should not be slurped into
>>>>> + string-inlines.o. */
>>>>> +__extern_inline void
>>>>> +explicit_bzero (void *__s, size_t __n)
>>>>> +{
>>>>> + memset (__s, '\0', __n);
>>>>> + __glibc_read_memory (__s, __n);
>>>>> +}
>>>>> +#endif
>>>>
>>>> __extern_inline can expand to nothing at all, and you would get multiple
>>>> definitions of explicit_bzero this way.
>
> OK, what should I be using instead?
Fortify functions uses '__fortify_function' which defines both
__extern_always_inline and __attribute_artificial__. However fortify is guarded
by _FORTIFY_SOURCE, which requires GCC 4.1 (so __extern_always_inline will be
defined anyway).
Stdio also defines:
#ifndef __extern_inline
# define __STDIO_INLINE inline
#else
# define __STDIO_INLINE __extern_inline
#endif
#ifdef __USE_EXTERN_INLINES
...
#endif
But I think this will also only add unnecessary complexity on the patch.
Also, another issue with gnu_inline is when building for C++ it might get also
multiple definitions [1].
That's why I think simpler solution would be just to remove this inline
optimization.
[1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=41194
>
>>>> I don't think we want explicit_bzero to be inlined, it's useful to have
>>>> this name in the executable. Furthermore, we might want to add
>>>> additional state clearing later, so an implementation in libc.so.6 seems
>>>> desirable anyway.
>
> Oddly enough, inlining the memset leads to better security properties
> for generated code. Remember the "key that lives in the vector
> registers until it has to be copied onto the stack to be erased" scenario?
>
> ---
> #include <emmintrin.h>
> #include <string.h>
>
> extern void explicit_bzero (void *ptr, size_t size);
>
> extern __m128 get_key ();
> extern void encrypt_with_key (__m128 key, void *data, size_t size);
>
> void encrypt (void *data, size_t size)
> {
> __m128 key = get_key ();
> encrypt_with_key (key, data, size);
> explicit_bzero (&key, sizeof key);
> }
> ---
>
> (Assume an ABI where __m128 actually gets passed in registers.)
>
> If you expose the memset to inlining, the key *won't* be copied into
> the stack and then immediately erased; the compiler will just dutifully
> clear 16 bytes of the stack and then pass them to __glibc_read_memory.
> It still won't be erased from the vector registers, but that can only be
> fixed with compiler support.
>
> (It also leads to significantly more compact code -- see my experiment
> with OpenSSL from last year -- but that's not as important.)
I also think compact code should not be a blocker here as well. However I
do not have a better solution for this specific solution without compiler
support.
>
>>> I suppose we just want a compiler barrier here though, and don't need a
>>> memory barrier in the sense of something that constrains HW reordering.
>
> That is correct; however, the "memory barrier" I was talking about was
>
> asm volatile ("" ::: "memory");
>
> which is also only a compiler barrier.
>
>> I would also suggest to avoid adding this inline optimization, it just add
>> another exported symbol by glibc with little performance benefit.
>
> The *other* reason why I want to keep the inline optimization is that it
> means I don't need to add __explicit_bzero_chk (which, because of
> ifuncs, means futzing with *every sysdeps definition of memset*!). So
> either way there's going to be a new exported symbol.
>
> zw
I do not think this is really required, you can still add a default
debug/explicit_bzero_chk.c which will call explicit_bzero/memset. Each
port already defines how internal memset is called (either using
internal ifunc or redirecting to a default symbol) so I see no need
to add arch specific implementations.
This does not prevent though to later we add arch-specific optimized
version (which might be ifunc).
On Fri, Aug 19, 2016 at 10:00 AM, Adhemerval Zanella
<adhemerval.zanella@linaro.org> wrote:
> On 19/08/2016 10:00, Zack Weinberg wrote:
>>
>> OK, what should I be using instead?
>
> [... some options which I will look into ...]
>
> That's why I think simpler solution would be just to remove this inline
> optimization.
It's really, really not simpler, though, because of the fortify issue...
>> The *other* reason why I want to keep the inline optimization is that it
>> means I don't need to add __explicit_bzero_chk (which, because of
>> ifuncs, means futzing with *every sysdeps definition of memset*!). So
>> either way there's going to be a new exported symbol.
>
> I do not think this is really required, you can still add a default
> debug/explicit_bzero_chk.c which will call explicit_bzero/memset.
You missed the point; the point was that if we don't add
__glibc_read_memory then we have to add __explicit_bzero_chk, so
there's one new implementation-namespace exported symbol either way.
Anyway, it would be nice if that worked without modifying every
definition of memset, but it doesn't. The problem is not that
__explicit_bzero_chk itself would need to be an ifunc (I agree that
that would be an unnecessary optimization); the problem is that
__explicit_bzero_chk would need to call __memset_chk from inside
libc.so. There are currently no calls to __memset_chk inside libc.so,
which means there is no PLT bypass glue for __memset_chk. And because
_some_ architectures define __memset_chk as an ifunc, it's in sysdeps,
and _every_ memset.S has to be audited and possibly touched. This is
such a PITA that in
https://sourceware.org/ml/libc-alpha/2015-11/msg00467.html I appear to
have only done it for x86.
With the inline optimization, the fortified explicit_bzero can live
entirely within bits/string3.h and no modifications to __memset_chk
are required.
zw
On 19/08/2016 13:06, Zack Weinberg wrote:
> On Fri, Aug 19, 2016 at 10:00 AM, Adhemerval Zanella
> <adhemerval.zanella@linaro.org> wrote:
>> On 19/08/2016 10:00, Zack Weinberg wrote:
>>>
>>> OK, what should I be using instead?
>>
>> [... some options which I will look into ...]
>>
>> That's why I think simpler solution would be just to remove this inline
>> optimization.
>
> It's really, really not simpler, though, because of the fortify issue...
>
>>> The *other* reason why I want to keep the inline optimization is that it
>>> means I don't need to add __explicit_bzero_chk (which, because of
>>> ifuncs, means futzing with *every sysdeps definition of memset*!). So
>>> either way there's going to be a new exported symbol.
>>
>> I do not think this is really required, you can still add a default
>> debug/explicit_bzero_chk.c which will call explicit_bzero/memset.
>
> You missed the point; the point was that if we don't add
> __glibc_read_memory then we have to add __explicit_bzero_chk, so
> there's one new implementation-namespace exported symbol either way.
>
> Anyway, it would be nice if that worked without modifying every
> definition of memset, but it doesn't. The problem is not that
> __explicit_bzero_chk itself would need to be an ifunc (I agree that
> that would be an unnecessary optimization); the problem is that
> __explicit_bzero_chk would need to call __memset_chk from inside
> libc.so. There are currently no calls to __memset_chk inside libc.so,
> which means there is no PLT bypass glue for __memset_chk. And because
> _some_ architectures define __memset_chk as an ifunc, it's in sysdeps,
> and _every_ memset.S has to be audited and possibly touched. This is
> such a PITA that in
> https://sourceware.org/ml/libc-alpha/2015-11/msg00467.html I appear to
> have only done it for x86.
>
> With the inline optimization, the fortified explicit_bzero can live
> entirely within bits/string3.h and no modifications to __memset_chk
> are required.
Well, current memset_chk default implementation just does:
if (__glibc_unlikely (dstlen < len))
__chk_fail ();
So it would be feasible imho to just this add and call memset instead
of memset_chk.
The problem, as pointed out by Florian, is not the symbol being exported
itself, but the inline definition where all the 'inline' definition might
either not being supported by the target compiler or have non-expected
side effects (as for C++ with -O0).
The fortified version is mostly fine to use 'inline' definition because
it is already guarded by _FORTIFY_SOURCE, but I think the default
explicit_bzero guarded by __USE_MISC is not suffice.
On Fri, Aug 19, 2016 at 12:31 PM, Adhemerval Zanella
<adhemerval.zanella@linaro.org> wrote:
> Well, current memset_chk default implementation just does:
>
> if (__glibc_unlikely (dstlen < len))
> __chk_fail ();
>
> So it would be feasible imho to just this add and call memset instead
> of memset_chk.
For clarity, you are imagining this as the in-libc, out-of-line
implementation of __explicit_bzero_chk? Because as long as there's
*some* inline definition of explicit_bzero, we have to have the
exported __glibc_read_memory and then I don't see why we shouldn't
have a string2.h non-fortified inline as well.
> The problem, as pointed out by Florian, is not the symbol being exported
> itself, but the inline definition where all the 'inline' definition might
> either not being supported by the target compiler or have non-expected
> side effects (as for C++ with -O0).
Did you miss that there *is* an out-of-line non-fortified
explicit_bzero? Which means that the bug you pointed out should be a
non-issue.
zw
On 19/08/2016 16:54, Zack Weinberg wrote:
> On Fri, Aug 19, 2016 at 12:31 PM, Adhemerval Zanella
> <adhemerval.zanella@linaro.org> wrote:
>> Well, current memset_chk default implementation just does:
>>
>> if (__glibc_unlikely (dstlen < len))
>> __chk_fail ();
>>
>> So it would be feasible imho to just this add and call memset instead
>> of memset_chk.
>
> For clarity, you are imagining this as the in-libc, out-of-line
> implementation of __explicit_bzero_chk? Because as long as there's
> *some* inline definition of explicit_bzero, we have to have the
> exported __glibc_read_memory and then I don't see why we shouldn't
> have a string2.h non-fortified inline as well.
What I would like is, based on recent string inline headers cleanup,
is to avoid adding more implementation that in the future the compiler
can and would handle this transparently. Ideally it would be better if
we just aims to clean all the optimization done in string2/string3
headers (as we did for recent strspn, strbrk, etc. optimizations).
For this special case, I would advise go for the simple case: add a
explicit_bzero and __explicit_bzero_chk in-libc as the other implementations.
However I do not have a strong opinion here.
>
>> The problem, as pointed out by Florian, is not the symbol being exported
>> itself, but the inline definition where all the 'inline' definition might
>> either not being supported by the target compiler or have non-expected
>> side effects (as for C++ with -O0).
>
> Did you miss that there *is* an out-of-line non-fortified
> explicit_bzero? Which means that the bug you pointed out should be a
> non-issue.
The problem is not the existence of a out-of-line explicit_bzero, but
if __extern_inline would use or not the gnu_inline attribute. With current
guards for inclusion of string2.h (OPTIMIZE and !__cplusplus) the only
case of a possible issue I can think of is if someone building with
GCC lower than 4.2 with an optimized build and -fno-inline (this will
define __extern_inline to just extern __inline and possible create
multiple definitions). My inclination is this should not be a blocker
though.
@@ -99,6 +99,8 @@ libc_hidden_proto (memmem)
extern __typeof (memmem) __memmem;
libc_hidden_proto (__memmem)
libc_hidden_proto (__ffs)
+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)
@@ -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
@@ -41,13 +41,19 @@ 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 \
@@ -82,4 +82,11 @@ libc {
}
GLIBC_2.24 {
}
+ GLIBC_2.25 {
+ # used by inlines in string2.h
+ __glibc_read_memory;
+
+ # e*
+ explicit_bzero;
+ }
}
@@ -52,11 +52,23 @@
#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
+#ifdef __USE_MISC
+/* As bzero, but the compiler will not delete a call to this
+ function, even if S is dead after the call. Note: this function
+ has its own implementation file and should not be slurped into
+ string-inlines.o. */
+__extern_inline void
+explicit_bzero (void *__s, size_t __n)
+{
+ memset (__s, '\0', __n);
+ __glibc_read_memory (__s, __n);
+}
+#endif
#ifndef _HAVE_STRING_ARCH_strchr
extern void *__rawmemchr (const void *__s, int __c);
new file mode 100644
@@ -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);
+ __internal_glibc_read_memory (s, len);
+}
new file mode 100644
@@ -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)
@@ -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 inline version 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));
new file mode 100644
@@ -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"
@@ -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)
@@ -1843,6 +1843,8 @@ GLIBC_2.23 fts64_set 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
GLIBC_2.25 gnu_dev_minor F
@@ -2090,3 +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
@@ -2001,6 +2001,8 @@ GLIBC_2.23 fts64_set 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
GLIBC_2.3 __ctype_tolower_loc F
@@ -91,6 +91,8 @@ GLIBC_2.23 fts64_set 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
GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
@@ -1855,6 +1855,8 @@ GLIBC_2.23 fts64_set 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
GLIBC_2.3 __ctype_tolower_loc F
@@ -2013,6 +2013,8 @@ GLIBC_2.23 fts64_set 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
GLIBC_2.3 __ctype_tolower_loc F
@@ -1877,6 +1877,8 @@ GLIBC_2.23 fts64_set 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
GLIBC_2.3 __ctype_tolower_loc F
@@ -92,6 +92,8 @@ GLIBC_2.23 fts64_set 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
GLIBC_2.4 _IO_2_1_stderr_ D 0x98
@@ -1969,6 +1969,8 @@ GLIBC_2.23 fts64_set 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
GLIBC_2.3 __ctype_tolower_loc F
@@ -2090,3 +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
@@ -1944,6 +1944,8 @@ GLIBC_2.23 fts64_set 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
GLIBC_2.3 __ctype_tolower_loc F
@@ -1942,6 +1942,8 @@ GLIBC_2.23 fts64_set 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
GLIBC_2.3 __ctype_tolower_loc F
@@ -1940,6 +1940,8 @@ GLIBC_2.23 fts64_set 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
GLIBC_2.3 __ctype_tolower_loc F
@@ -1935,6 +1935,8 @@ GLIBC_2.23 fts64_set 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
GLIBC_2.3 __ctype_tolower_loc F
@@ -2131,3 +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
@@ -1973,6 +1973,8 @@ GLIBC_2.23 fts64_set 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
GLIBC_2.3 __ctype_tolower_loc F
@@ -1978,6 +1978,8 @@ GLIBC_2.23 fts64_set 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
GLIBC_2.3 __ctype_tolower_loc F
@@ -2178,3 +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
@@ -92,6 +92,8 @@ GLIBC_2.23 fts64_set 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
GLIBC_2.3 _IO_2_1_stderr_ D 0xe0
@@ -1973,6 +1973,8 @@ GLIBC_2.23 fts64_set 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
GLIBC_2.3 __ctype_tolower_loc F
@@ -1874,6 +1874,8 @@ GLIBC_2.23 fts64_set 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
GLIBC_2.3 __ctype_tolower_loc F
@@ -1859,6 +1859,8 @@ GLIBC_2.23 fts64_set 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
GLIBC_2.3 __ctype_tolower_loc F
@@ -1965,6 +1965,8 @@ GLIBC_2.23 fts64_set 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
GLIBC_2.3 __ctype_tolower_loc F
@@ -1903,6 +1903,8 @@ GLIBC_2.23 fts64_set 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
GLIBC_2.3 __ctype_tolower_loc F
@@ -2097,3 +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
@@ -2097,3 +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
@@ -2097,3 +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
@@ -1854,6 +1854,8 @@ GLIBC_2.23 fts64_set 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
GLIBC_2.3 __ctype_tolower_loc F
@@ -2097,3 +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