From 97950a9fca7dd1b3a5def7fa40f8204ca8628f15 Mon Sep 17 00:00:00 2001 From: Nathaniel Wesley Filardo Date: Tue, 12 Oct 2021 02:11:57 +0100 Subject: [PATCH] Optionally consider RemoteAllocator heads Tame --- src/backend/commonconfig.h | 9 +++++++ src/mem/corealloc.h | 19 +++++++++++++- src/mem/remoteallocator.h | 51 ++++++++++++++++++++++++++++++++------ src/mem/remotecache.h | 12 ++++++++- 4 files changed, 81 insertions(+), 10 deletions(-) diff --git a/src/backend/commonconfig.h b/src/backend/commonconfig.h index abc3333..befb2e4 100644 --- a/src/backend/commonconfig.h +++ b/src/backend/commonconfig.h @@ -77,6 +77,15 @@ namespace snmalloc * for allocating core allocators. */ bool LocalAllocSupportsLazyInit = true; + + /** + * Are the front and back pointers to the message queue in a RemoteAllocator + * considered to be capptr_bounds::Wildness::Tame (as opposed to Wild)? + * That is, is it presumed that clients or other potentialadversaries cannot + * access the front and back pointers themselves, even if they can access + * the queue nodes themselves (which are always considered Wild)? + */ + bool QueueHeadsAreTame = true; }; /** diff --git a/src/mem/corealloc.h b/src/mem/corealloc.h index 0188e91..4ac256c 100644 --- a/src/mem/corealloc.h +++ b/src/mem/corealloc.h @@ -424,7 +424,24 @@ namespace snmalloc auto& entry = SharedStateHandle::Pagemap::get_metaentry( local_state, snmalloc::address_cast(p)); - auto r = message_queue().dequeue(key_global, domesticate); + std::pair r; + if constexpr (SharedStateHandle::Options.QueueHeadsAreTame) + { + /* + * The front of the queue has already been validated; just change the + * annotating type. + */ + auto domesticate_first = [](freelist::QueuePtr p) + SNMALLOC_FAST_PATH_LAMBDA { + return freelist::HeadPtr(p.unsafe_ptr()); + }; + r = + message_queue().dequeue(key_global, domesticate_first, domesticate); + } + else + { + r = message_queue().dequeue(key_global, domesticate, domesticate); + } if (unlikely(!r.second)) break; diff --git a/src/mem/remoteallocator.h b/src/mem/remoteallocator.h index f23f75b..6d6655b 100644 --- a/src/mem/remoteallocator.h +++ b/src/mem/remoteallocator.h @@ -29,6 +29,33 @@ namespace snmalloc */ inline static FreeListKey key_global(0xdeadbeef, 0xbeefdead, 0xdeadbeef); + /** + * + * A RemoteAllocator is the message queue of freed objects. It exposes a MPSC + * append-only atomic queue that uses one xchg per append. + * + * The internal pointers are considered QueuePtr-s to support deployment + * scenarios in which the RemoteAllocator itself is exposed to the client. + * This is excessively paranoid in the common case that the RemoteAllocator-s + * are as "hard" for the client to reach as the Pagemap, which we trust to + * store not just Tame CapPtr<>s but raw C++ pointers. + * + * While we could try to condition the types used here on a flag in the + * backend's `struct Flags Options` value, we instead expose two domesticator + * callbacks at the interface and are careful to use one for the front and + * back values and the other for pointers read from the queue itself. That's + * not ideal, but it lets the client condition its behavior appropriately and + * prevents us from accidentally following either of these pointers in generic + * code. + * + * `domesticate_head` is used for the pointer used to reach the of the queue, + * while `domesticate_queue` is used to traverse the first link in the queue + * itself. In the case that the RemoteAllocator is not easily accessible to + * the client, `domesticate_head` can just be a type coersion, and + * `domesticate_queue` should perform actual validation. If the + * RemoteAllocator is exposed to the client, both Domesticators should perform + * validation. + */ struct alignas(REMOTE_MIN_ALIGN) RemoteAllocator { using alloc_id_t = address_t; @@ -74,13 +101,16 @@ namespace snmalloc /** * Pushes a list of messages to the queue. Each message from first to * last should be linked together through their next pointers. + * + * The Domesticator here is used only on pointers read from the head. See + * the commentary on the class. */ - template + template void enqueue( freelist::HeadPtr first, freelist::HeadPtr last, const FreeListKey& key, - Domesticator domesticate) + Domesticator_head domesticate_head) { invariant(); freelist::Object::atomic_store_null(last, key); @@ -89,7 +119,7 @@ namespace snmalloc freelist::QueuePtr prev = back.exchange(capptr_rewild(last), std::memory_order_release); - freelist::Object::atomic_store_next(domesticate(prev), first, key); + freelist::Object::atomic_store_next(domesticate_head(prev), first, key); } freelist::QueuePtr peek() @@ -99,14 +129,19 @@ namespace snmalloc /** * Returns the front message, or null if not possible to return a message. + * + * Takes a domestication callback for each of "pointers read from head" and + * "pointers read from queue". See the commentary on the class. */ - template - std::pair - dequeue(const FreeListKey& key, Domesticator domesticate) + template + std::pair dequeue( + const FreeListKey& key, + Domesticator_head domesticate_head, + Domesticator_queue domesticate_queue) { invariant(); - freelist::HeadPtr first = domesticate(front); - freelist::HeadPtr next = first->atomic_read_next(key, domesticate); + freelist::HeadPtr first = domesticate_head(front); + freelist::HeadPtr next = first->atomic_read_next(key, domesticate_queue); if (next != nullptr) { diff --git a/src/mem/remotecache.h b/src/mem/remotecache.h index af48527..46cb428 100644 --- a/src/mem/remotecache.h +++ b/src/mem/remotecache.h @@ -103,7 +103,17 @@ namespace snmalloc auto [first, last] = list[i].extract_segment(key); MetaEntry entry = SharedStateHandle::Pagemap::get_metaentry( local_state, address_cast(first)); - entry.get_remote()->enqueue(first, last, key, domesticate); + if constexpr (SharedStateHandle::Options.QueueHeadsAreTame) + { + auto domesticate_nop = [](freelist::QueuePtr p) { + return freelist::HeadPtr(p.unsafe_ptr()); + }; + entry.get_remote()->enqueue(first, last, key, domesticate_nop); + } + else + { + entry.get_remote()->enqueue(first, last, key, domesticate); + } sent_something = true; } }