This is the mail archive of the
mailing list for the glibc project.
Re: [RFC] [PATCH] Support explicit_bzero, memset_s, memzero_explicit, or similar.
- From: Rich Felker <dalias at libc dot org>
- To: Nick Mathewson <nickm at torproject dot org>
- Cc: libc-alpha at sourceware dot org
- Date: Tue, 16 Dec 2014 00:26:17 -0500
- Subject: Re: [RFC] [PATCH] Support explicit_bzero, memset_s, memzero_explicit, or similar.
- Authentication-results: sourceware.org; auth=none
- References: <CAKDKvuzWYf3GcXYs4ED8XLyy58nzmvxRV84xwsKKZjPpVSFQug at mail dot gmail dot com> <20141215173527 dot GJ4574 at brightrain dot aerifal dot cx> <CAKDKvuyhgr4CmkkD+0LzSNqRUW=gUhpERoknAT3e3H7ooqpaDw at mail dot gmail dot com>
On Mon, Dec 15, 2014 at 05:57:02PM -0500, Nick Mathewson wrote:
> (sorry; sent this before, but from the wrong address.)
> On Mon, Dec 15, 2014 at 12:35 PM, Rich Felker <firstname.lastname@example.org> wrote:
> Thanks for the reply, Rich!
> >> Different operating systems, libraries, and standards have
> >> approached this problem differently. Windows provides
> >> SecureZeroMemory(void *, size_t);
> >> The BSD family is moving towards
> >> explicit_bzero(void *, size_t);
> >> And the C11 standard defines
> >> memset_s(void *, rsize_t, int, size_t);
> >> And OpenSSL (along with LibreSSL and BoringSSL) provide:
> >> OPENSSL_cleanse(void *, size_t);
> >> And in the Linux kernel these says, they're using:
> >> memzero_explicit(void *, size_t);
> > None of these solve the problem, because the compiler is free to have
> > copied part of all of this buffer into other temporary storage on the
> > stack or registers. This is especially the case if SIMD optimizations
> > are used. Solving the problem (which isn't really even a problem, just
> > a hardening consideration) correctly requires compiler features.
> I agree that a *complete* solution would require compiler features.
> But nonetheless, a non-removable memset() equivalent is useful for
> some hardening. At the very least, we could make sure that the
> documentation explains this point.
> It's not clear to me from your response, whether you think including
> an explicit_bzero() or a memset_s() implementation is "worse than
> nothing" because of the register and spilling issue, or whether you
> think it would be worth providing anyway with appropriate caveats?
I don't think it's necessarily "worse than nothing" as long as it's
documented that it does not solve the problem.
> >> Now, at first glance it would seem that that memset_s() is the
> >> obvious choice, since it's the one supported by a standard. But
> >> it's a part of a much larger pile of bounds-checking variants of
> >> other C functions (C11 Annex K). It's *possible* to
> >> implement memset_s() without the rest of Annex K, but it requires a
> >> bit of infrastructure to be fully compliant. (Like, we would need
> >> an rsize_t, and a set_constraint_handler_s(). I do not believe we
> >> would need a full implementation of Annex K.)
> > errno_t is defined (by Annex K) as int and rsize_t is defined as
> > size_t, so we could just omit these types entirely and use the
> > standard types (int and size_t) and still not conflict with the Annex
> > K definition. There's no reason to use or even provide the ugly and
> > useless MS/Annex K typedefs.
> Attached is an approximate (probably buggy, I am new to glibc)
> implementation of the memset_s variant. I dedicate it (and this email)
> to the public domain.
I don't think the implementation as written is valid -- at least, not
if you allow LTO. The compiler barrier does not prevent the memset
from being optimized out unless the address of the buffer being memset
has been leaked to code the compiler cannot see. As long as it sees
that the asm has no way of observing the output of the memset, it can
optimize out the memset. Simply making the memset buffer visible to
the asm by passing its address (or better yet, it as a memory object)
in an asm constraint would probably fix this, but I'd like to have
someone from the GCC side confirm this.