StrictProvenance support in Backend
Wrap the FrontendSlabMetadata with a struct that holds the Arena-bounded authority for Chunks that the Backend ships out to the Frontend or, for non-StrictProvenance architecture, encapsulates the sleight of hand that turns Chunk-bounded CapPtr-s to Arena-bounded ones.
This commit is contained in:
committed by
Nathaniel Filardo
parent
86124ba26c
commit
94957f0f72
@@ -246,6 +246,17 @@ namespace snmalloc
|
||||
|
||||
template<AalFeatures F, SNMALLOC_CONCEPT(ConceptAAL) AAL = Aal>
|
||||
constexpr static bool aal_supports = (AAL::aal_features & F) == F;
|
||||
|
||||
/*
|
||||
* The backend's leading-order response to StrictProvenance is entirely
|
||||
* within its data structures and not actually anything to do with the
|
||||
* architecture. Rather than test aal_supports<StrictProvenance> or
|
||||
* defined(__CHERI_PURE_CAPABILITY__) or such therein, using this
|
||||
* backend_strict_provenance flag makes it easy to test a lot of machinery
|
||||
* on non-StrictProvenance architectures.
|
||||
*/
|
||||
static constexpr bool backend_strict_provenance =
|
||||
aal_supports<StrictProvenance>;
|
||||
} // namespace snmalloc
|
||||
|
||||
#ifdef __POINTER_WIDTH__
|
||||
|
||||
@@ -22,6 +22,10 @@ namespace snmalloc
|
||||
using Pal = PAL;
|
||||
using SlabMetadata = typename PagemapEntry::SlabMetadata;
|
||||
|
||||
#ifdef __cpp_concepts
|
||||
static_assert(IsSlabMeta_Arena<SlabMetadata>);
|
||||
#endif
|
||||
|
||||
public:
|
||||
/**
|
||||
* Provide a block of meta-data with size and align.
|
||||
@@ -100,6 +104,7 @@ namespace snmalloc
|
||||
return {nullptr, nullptr};
|
||||
}
|
||||
|
||||
meta->arena_set(p);
|
||||
typename Pagemap::Entry t(meta, ras);
|
||||
Pagemap::set_metaentry(address_cast(p), size, t);
|
||||
|
||||
@@ -139,13 +144,16 @@ namespace snmalloc
|
||||
Pagemap::get_metaentry(address_cast(alloc)).get_slab_metadata());
|
||||
Pagemap::set_metaentry(address_cast(alloc), size, t);
|
||||
|
||||
/*
|
||||
* On CHERI, the passed alloc has had its bounds narrowed to just the
|
||||
* Chunk, and so we retrieve the Arena-bounded cap for use in the
|
||||
* remainder of the backend.
|
||||
*/
|
||||
capptr::Arena<void> arena = slab_metadata.arena_get(alloc);
|
||||
|
||||
local_state.get_meta_range().dealloc_range(
|
||||
capptr::Arena<void>::unsafe_from(&slab_metadata), sizeof(SlabMetadata));
|
||||
|
||||
// On non-CHERI platforms, we don't need to re-derive to get a pointer to
|
||||
// the chunk. On CHERI platforms this will need to be stored in the
|
||||
// SlabMetadata or similar.
|
||||
auto arena = capptr::Arena<void>::unsafe_from(alloc.unsafe_ptr());
|
||||
local_state.get_object_range()->dealloc_range(arena, size);
|
||||
}
|
||||
|
||||
|
||||
89
src/snmalloc/backend_helpers/cheri_slabmetadata_mixin.h
Normal file
89
src/snmalloc/backend_helpers/cheri_slabmetadata_mixin.h
Normal file
@@ -0,0 +1,89 @@
|
||||
#pragma once
|
||||
#include "../pal/pal.h"
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
/**
|
||||
* In CHERI, we must retain, internal to the allocator, the authority to
|
||||
* entire backing arenas, as there is no architectural mechanism to splice
|
||||
* together two capabilities. Additionally, these capabilities will retain
|
||||
* the VMAP software permission, conveying our authority to manipulate the
|
||||
* address space mappings for said arenas.
|
||||
*
|
||||
* We stash these pointers inside the SlabMetadata structures for parts of
|
||||
* the address space for which SlabMetadata exists. (In other parts of the
|
||||
* system, we will stash them directly in the pagemap.) This requires that
|
||||
* we inherit from the FrontendSlabMetadata.
|
||||
*/
|
||||
template<typename SlabMetadata>
|
||||
class StrictProvenanceSlabMetadataMixin : public SlabMetadata
|
||||
{
|
||||
template<
|
||||
SNMALLOC_CONCEPT(ConceptPAL) A1,
|
||||
typename A2,
|
||||
typename A3,
|
||||
typename A4>
|
||||
friend class BackendAllocator;
|
||||
|
||||
capptr::Arena<void> arena;
|
||||
|
||||
/* Set the arena pointer */
|
||||
void arena_set(capptr::Arena<void> a)
|
||||
{
|
||||
arena = a;
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve the stashed pointer for a chunk; the caller must ensure that
|
||||
* this is the correct arena for the indicated chunk. The latter is unused
|
||||
* except in debug builds, as there is no architectural amplification.
|
||||
*/
|
||||
capptr::Arena<void> arena_get(capptr::Alloc<void> c)
|
||||
{
|
||||
SNMALLOC_ASSERT(address_cast(arena) == address_cast(c));
|
||||
UNUSED(c);
|
||||
return arena;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A dummy implementation of StrictProvenanceBackendSlabMetadata that has no
|
||||
* computational content, for use on non-StrictProvenance architectures.
|
||||
*/
|
||||
template<typename SlabMetadata>
|
||||
struct LaxProvenanceSlabMetadataMixin : public SlabMetadata
|
||||
{
|
||||
/* On non-StrictProvenance architectures, there's nothing to do */
|
||||
void arena_set(capptr::Arena<void>) {}
|
||||
|
||||
/* Just a type sleight of hand, "amplifying" the non-existant bounds */
|
||||
capptr::Arena<void> arena_get(capptr::Alloc<void> c)
|
||||
{
|
||||
return capptr::Arena<void>::unsafe_from(c.unsafe_ptr());
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef __cpp_concepts
|
||||
/**
|
||||
* Rather than having the backend test backend_strict_provenance in several
|
||||
* places and doing sleights of hand with the type system, we encapsulate
|
||||
* the amplification
|
||||
*/
|
||||
template<typename T>
|
||||
concept IsSlabMeta_Arena = requires(T* t, capptr::Arena<void> p)
|
||||
{
|
||||
{
|
||||
t->arena_set(p)
|
||||
}
|
||||
->ConceptSame<void>;
|
||||
}
|
||||
&&requires(T* t, capptr::Alloc<void> p)
|
||||
{
|
||||
{
|
||||
t->arena_get(p)
|
||||
}
|
||||
->ConceptSame<capptr::Arena<void>>;
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace snmalloc
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../mem/mem.h"
|
||||
#include "cheri_slabmetadata_mixin.h"
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
@@ -63,6 +64,9 @@ namespace snmalloc
|
||||
SNMALLOC_FAST_PATH DefaultPagemapEntryT() = default;
|
||||
};
|
||||
|
||||
using DefaultPagemapEntry = DefaultPagemapEntryT<FrontendSlabMetadata>;
|
||||
using DefaultPagemapEntry = DefaultPagemapEntryT<std::conditional_t<
|
||||
backend_strict_provenance,
|
||||
StrictProvenanceSlabMetadataMixin<FrontendSlabMetadata>,
|
||||
LaxProvenanceSlabMetadataMixin<FrontendSlabMetadata>>>;
|
||||
|
||||
} // namespace snmalloc
|
||||
|
||||
Reference in New Issue
Block a user