public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
From: Carlos O'Donell <carlos@redhat.com>
To: Rich Felker <dalias@libc.org>
Cc: libc-alpha <libc-alpha@sourceware.org>
Subject: Re: RFC: malloc and secure memory.
Date: Sun, 27 Sep 2020 10:04:13 -0400	[thread overview]
Message-ID: <7cc72452-778a-94b5-fee5-dc5015f800b1@redhat.com> (raw)
In-Reply-To: <20200926170710.GR3265@brightrain.aerifal.cx>

On 9/26/20 1:07 PM, Rich Felker wrote:
> On Thu, Sep 24, 2020 at 04:56:59PM -0400, Carlos O'Donell via Libc-alpha wrote:
>> In reviewing this discussion:
>> https://github.com/systemd/systemd/pull/14213
>>
>> The request is for a way to mark some allocations as "secure"
>> and to give them special properties.
>>
>> I wonder if we can't do this in some generic way:
>>
>> - Make arenas a first class construct.
>>
>> /* Get arena with special properties.  */
>> malloc_arena *secure_arena = NULL;
>> /* Get a handle to an arena that has secure heaps.  If glibc can make this
>>    kind of arena and heap then it does, otherwise it returns NULL.  */
>> secure_arena = malloc_arena_get (HEAP_SECURE);
>> /* Does this glibc support his kind of arena?  */
>> if (secure_arena == NULL)
>>   abort();
>>
>> - Bind the malloc call site to a specific arena with specific properties.
> 
> I don't see any plausible motivation for why a caller would want to do
> this rather than just calling mmap. It's far less portable, more
> error-prone (since it doesn't look like it would catch use of one type
> where you meant the other, as opposed to with direct mmap where
> passing it to free or vice versa would trap at some point), and more
> complex to program for.

I agree with all of your points.

However, if you have existing legacy APIs and by their semantics the
caller can free some allocations later with free() and you want to
transparently apply some kind of additional semantics, then you need:

* At the call site of the allocation the extra properties need to be
  applied.

* At the call site of the deallocation the caller may no longer be
  aware of the extra properties and the deallocation should proceed
  as expected.

Don't get me wrong, applying a design like this yields problems, and
you and I point them out. In summary:

* New API is not as portable as mmap.

* New API yields problems for interposed allocators.

* New API could yield problems if down-stack callers imply that they
  can free/malloc (realloc might work) the allocation without loosing
  the additional properties.

> Is the answer just "for systemd reasons"?

Having a public conversation about something and coming up with valid
reasons NOT to do it is just as important as having a conversation for
all the things you WOULD do.

The only way I see to have such a conversation is to put together an
RFC, discuss it, and reject the proposal with rationale given.

I might also have raised this issue on libc-coord actually, now that
you mention "reasons."

>> For example:
>>
>>   /* malloc_arena takes an opaque arena pointer that is a global
>>      variable that the implementation provides, a function pointer
>>      the memory allocator routine e.g. malloc, and a size.  */
>>   password_storage = malloc_arena (secure_arena, malloc, size);
> 
> Is the function pointer merely being used as a lookup key here? Or is
> the intend that it would be implemented by changing some thread-local
> context, calling the pointed-to function, then restoring it? I don't
> see what you get by having this weird interface since the signature
> has to match to make the call, and there are no other malloc-family
> functions that match malloc's signature anyway.

I mention the primary rationale here in the downthread post, but let
me elucidate the problem a bit more:

(1) glibc implements an general purpose system allocator.

(2) Various APIs all use the allocator, and as such their
    returned pointers are compatible with the allocator's unadorned
    free() API.

(3) Other developers implement interposed allocators and as such
    there may be a mix of new/old interposers and new/old glibc.

(4) Users expect interposted allocators to work.

It turns out that over time supporting (4) creates a strong incentive
to avoid changing the implemented allocator APIs.

Why? If you add any API to (1) and (3) doesn't support it, then
when you add in code that uses a new allocator API and attempt (4)
it will likely fail as chunks cross allocator boundaries because
(3) didn't interpose the new APIs.

Today it basically means we can't extend the allocator APIs anymore
because of prevalent use of special-purpose allocators designed to
optimize for specific workloads e.g. jemalloc, tcmalloc, new-tcmalloc.

To avoid problematic scenarios we need to provide entirely new APIs
that users would never mix with the original allocator APIs.

One suggestion is to provide a way to bind the allocation and
deallocation sides together at compile time, and I have no solutions
for that today.

My last idea is, as proposed above, to pass in the pointer to the
expected malloc, and if the allocator can prove that this malloc
does not match e.g. detect interposition, then it can declare that
the free is equally unsafe and return NULL for the allocation
to indicate that such memory with such properties cannot be allocated.

In summary:
- Supporting allocator interposition has created a composability
  problem with adding new allocation/deallocation APIs.
- glibc is effectively unable to add new APIs easily that aren't
  just in the form of hints to mallopt().
- If we have composability problems then we should just use new
  APIs from other allocator libraries and leave glibc's malloc
  for applications that need those exact semantics.
- New libraries can provide a superset of glibc's APIs and that
  would be safe because the application would require that specific
  library to operate.

Do you agree with that summary?

-- 
Cheers,
Carlos.


  reply	other threads:[~2020-09-27 14:04 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-09-24 20:56 Carlos O'Donell
2020-09-25  6:39 ` Florian Weimer
2020-09-25 16:10   ` Carlos O'Donell
2020-09-25 23:39 ` Stefan O'Rear
2020-09-27 12:39   ` Carlos O'Donell
2020-09-26 17:07 ` Rich Felker
2020-09-27 14:04   ` Carlos O'Donell [this message]
2020-09-27 20:29   ` Florian Weimer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=7cc72452-778a-94b5-fee5-dc5015f800b1@redhat.com \
    --to=carlos@redhat.com \
    --cc=dalias@libc.org \
    --cc=libc-alpha@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).