Commit Graph

22 Commits

Author SHA1 Message Date
Nathaniel Wesley Filardo
3109ae9f72 NFC: Accumulated nits in comments
Mostly, promote some inline commentary to doc comments.  A typo and some stale
text can go, too.
2021-10-13 16:30:41 +01:00
Matthew Parkinson
bba66e4f7e Randomise slab filling (#397)
# Free List builder track length

This commit makes the free list builder track the length of the lists in
the Random case.

# Refactor free list creation.

Minor refactoring to share code between the new free list and existing
path.

# Randomise slab filling

Knowing when a slab is going to become full makes it easier to by pass
the free list entries as protection for OOB writes.  This commit
randomises when a slab will become full.

This commit changes two things

* the free list builder can return some fraction of the deallocations
  on a slab.
* when there is a single free slab, we can with some probability
  allocate an additional slab.

These two combine to make it difficult to predict when a slab will be
free.

# Apply suggestions from code review

Co-authored-by: Nathaniel Wesley Filardo <nfilardo@microsoft.com>
2021-10-07 15:51:18 +01:00
Matthew Parkinson
0af1ee3bef Tidy TODOs from Free List
* Add extra key to freelist.  This follows the encoding Cedric suggested
  for a signature of two things. Free list key now has a pair of keys
  for encoding previous pointer. This makes it harder to extract the
  underlying keys out of the multiplication.

* Apply SFINAE to the extract_segment.
2021-09-27 10:25:43 +01:00
Matthew Parkinson
81bf341732 XOR encoded next_object
This commit adds a simple XOR encoding to the next_object pointer in
FreeObjects.  This removes the trivial way of getting hold of a physical
address from the system by observing the free list pointers in
deallocated objects.
2021-07-26 15:32:32 +01:00
Matthew Parkinson
9df0101dfd Enable guard pages in CHECK_CLIENT
Change the behaviour to use PROT_NONE for reservations in CHECK_CLIENT
mode.  This means that we only provide access once data is actually
being used.
2021-07-21 09:36:06 +01:00
Matthew Parkinson
b501da69db Implements protection on remote messages queues
This extends the freelist protection to the remote message queues. They
effectively perform doubly linked list entries for the message queue
with the enqueue operation first linking in the previous pointer, and
then then atomically setting the next.  This ensures that the visible
states always satisfy the invariant that the forward and backward
pointers are correct for any visisble object.

There is a key_global that is used for all remote deallocations. The
remote cache uses the same protection to build the temporary lists
before forwarding to the next allocator.

The mpscq is integrated into the remoteallocator as it is no longer
a reusable datastructure, but a special purpose implementation.
2021-07-19 12:57:03 +01:00
Matthew Parkinson
de8ef3efc7 Cleaner implementation of signed pointers. (#347)
* Cleaner implementation of signed pointers.

This encodes a back pointer in each node.  The back pointer is stored
in an encoded form so that it is hard to corrupt and trick the allocator
into following incorrect pointers.

This changes the encoding from previously being a Feistel network on
the next pointer that was using the prev as part of the key, to now
effectively using a doubly linked queue, where the back pointers are
scrambled, so it is hard to forge them.

This has the positive effects of
 - Not needing to store previous while building the list, as the append
   nows, curr and next at the point of writing into next, and does not
   need an additional previous.
 - The encoding is not affecting the actual next value, so more
   instructions can be executed in parallel by the CPU.

Future extensions, store a changing key in the FreeListBuilder so it
becomes harder to try to forge the previous token.

This approach can also be applied to the remote list, and will in a
subsequent PR.  This enables the idea to be tested.

* Remove unused header.

* Apply suggestions from code review

Co-authored-by: Nathaniel Wesley Filardo <VP331RHQ115POU58JFRLKB7OPA0L18E3@cmx.ietfng.org>

Co-authored-by: Nathaniel Wesley Filardo <VP331RHQ115POU58JFRLKB7OPA0L18E3@cmx.ietfng.org>
2021-07-15 18:31:28 +01:00
Matthew Parkinson
f0e2ab702a Major refactor of snmalloc (#343)
# Pagemap
 
The Pagemap now stores all the meta-data for the object allocation. The meta-data in the pagemap is effectively a triple of the sizeclass, the remote allocator, and a pointer to a 64 byte block of meta-data for this chunk of memory. By storing the pointer to a block, it allows the pagemap to handle multiple slab sizes without branching on the fast path. There is one entry in the pagemap per 16KiB of address space, but by using the same entry in the pagemap for 4 adjacent entries, then we can treat a 64KiB range can be treated as a single slab of allocations.

This change also means there is almost no capability amplification required by the implementation on CHERI for finding meta-data. The only amplification is required, when we change the way a chunk is used to a size of object allocation.


# Backend

There is a second major aspect of the refactor that there is now a narrow API that abstracts the Pagemap, PAL and address space management. This should better enable the compartmentalisation and makes it easier to produce alternative backends for various research directions. This is a template parameter that can be used to specialised by the front-end in different ways.

# Thread local state

The thread local state has been refactored into two components, one (called 'localalloc') that is stored directly in the TLS and is constant initialised, and one that is allocated in the address space (called 'coreallloc') which is lazily created and pooled.

# Difference

This removes Superslabs/Medium slabs as there meta-data is now part of the pagemap.
2021-07-12 15:53:36 +01:00
Matthew Parkinson
e77a5d9c58 Remove cache-friendly offset. 2021-05-18 14:58:15 +01:00
Matthew Parkinson
b3796c123e Move remote cache out of alloc.h
Consolidate the remote code into a single file.
2021-05-18 14:58:15 +01:00
Nathaniel Filardo
c673b2e0ba SP: pass CBChunk, not CBArena, down to Superslab ops 2021-04-09 12:39:29 +01:00
Nathaniel Filardo
95871ff8a1 SP: free lists and remote queues are CBAlloc
Continue tightening the screws on pointer bounds.

Notably, pointers in remote queues are bounded to the free objects.  While we
believe that something like MTE is required to make in-band metadata safe, this
is a kind of defense in depth for StrictProvenance architectures: UAF for small
and medium objects expose mostly other (free) small or medium objects and not
allocator metadata (modulo some potential aliasing when Superslabs and
Mediumslabs interconvert).  This might shift the burdon on an attacker from
simply holding a UAF pointer to having had to farm several heap pointers.

The policy of bounding remote queue pointers may make the allocator's behavior
for small objects unexpected: while initial object construction during
allocation (that is, when the free list is empty) continues to cleave out
exportable pointers from elevated pointers to internal slabs, reuse pulls from
free lists of *already-bounded* objects.  These objects are queued by the
deallocation side, of course, but these paths now include "parallel
reconstruction" of a pointer to the free object from the amplified view of the
returned pointer, rather than queueing amplified pointers and leaving
reconstruction to the allocation side.

Medium objects are possibly similarly mysterious with the added twist that
medium slabs do not store pointers but rather always cleave from their
self-reference (but their interface has always operated using pointers).
Nevertheless, pointers to medium objects end up in remote queues, so we continue
to engage in "parallel reconstruction" in the deallocation paths.
2021-04-09 12:39:29 +01:00
Nathaniel Filardo
f7821e11eb SP: LargeAlloc return CBChunk & chase consequences
Even if we opt not to bound these pointers internally (if they aren't headed out
to the user program or we later derive bounded pointers), they should still be
annotated as something other than CBArena, ensuring that we do not attempt to
use them for general amplification.
2021-04-09 12:39:29 +01:00
Nathaniel Filardo
c5aff8ed74 SP: plumb CapPtr through cache_friendly functions
Change these functions from being void* to void* to either consuming or
producing FreeObject*-s as appropriate.
2021-04-09 12:39:29 +01:00
Nathaniel Filardo
005f5787ef SP: start plumbing CapPtr<>s 2021-04-09 12:39:29 +01:00
Matthew Parkinson
9ca73b8153 Implementing full permutation of slab
Allocate slab is randomly in all possible permutations. This increases
the entropy of the order considerably.  This uses an algorithm to build
a random cycle in a slab, and then use this to build the free list.

We disable the per-slab randomisation in the non-CHECK_CLIENT builds.
2021-04-07 11:43:53 +01:00
Matthew Parkinson
f15dc6ee2e Expose Entropy
Define various parts of random that can be used to make the layout of
memory more random.  Thread this through the allocator.

Expose the concept as part of the Pal. Subsequent commits will expose
that on different platforms.
2021-04-06 14:09:18 +01:00
Nathaniel Filardo
c5b65d07b8 FreeObject: hide harder from the compiler, tweak types
On CHERI, the compiler will always issue a warning for
`reinterpret_cast<T*>(ptraddr_t)` and similar expressions, and of course, if the
compiler can see far enough into the types, the presence of `if constexpr` will
not save us.  Therefore, lift the conditional out to two definitions of
`FreeObject::encode` using `std::enable_if_t` to gate which is used.
2021-03-26 11:43:06 +00:00
Matthew Parkinson
afc6283e01 Threshold freelist wakeup
When a slab has been fully allocated, then we no longer
check it has entries until something returns an allocation to this slab.
However, it is possible that only a single allocation is available, and
then we can end up frequently on the slow path.

This change only considers free lists that cover at least 1/8 of a slab.
This means that we will hit the slow path less frequently.  This also
means that the randomisation changes will have more entropy: with a
single element free list there is only one order.

For large small sizes it can still be a single element, as 1/8 is of the
slab capacity is below 1. We max out the trigger at 31 elements to
reduce unneeded wasted space.
2021-03-25 12:04:36 +00:00
Matthew Parkinson
578abd8db4 Randomise slab allocation pattern (#304)
The slab allocation pattern is randomised based on the deallocation
pattern.  This achieved by using two queues to enqueue free elements
onto.  We pick "randomly", which queue to add to, and then when we take
the free_queue to use, we splice the two queues together.
2021-03-24 16:12:22 +00:00
Matthew Parkinson
ed615eade9 Refactor checks to improve codegen. 2021-03-19 11:28:39 +00:00
Matthew Parkinson
50f412157f Protect free list pointers stored in object space
Free list pointers can be exploited by attackers. This commit implements
a simple encoding scheme to detect corruption of the pointers.  This can
be used to detect UAF and double free.

This does not currently address anything for Medium or Large
allocations.  It also does not address cross thread deallocations.

Co-authored-by: Nathaniel Wesley Filardo <nfilardo@microsoft.com>
2021-03-19 11:28:39 +00:00