diff --git a/src/aal/aal.h b/src/aal/aal.h index 2ecac0f..fcff4dc 100644 --- a/src/aal/aal.h +++ b/src/aal/aal.h @@ -226,9 +226,17 @@ namespace snmalloc # include "aal_riscv.h" #endif +#if defined(__CHERI_PURE_CAPABILITY__) +# include "aal_cheri.h" +#endif + namespace snmalloc { +#if defined(__CHERI_PURE_CAPABILITY__) + using Aal = AAL_Generic>; +#else using Aal = AAL_Generic>; +#endif template constexpr static bool aal_supports = (AAL::aal_features & F) == F; diff --git a/src/aal/aal_cheri.h b/src/aal/aal_cheri.h new file mode 100644 index 0000000..866e0ad --- /dev/null +++ b/src/aal/aal_cheri.h @@ -0,0 +1,52 @@ +#pragma once + +#include "../ds/defines.h" + +#include + +namespace snmalloc +{ + /** + * A mixin AAL that applies CHERI to a `Base` architecture. Gives + * architectural teeth to the capptr_bound primitive. + */ + template + class AAL_CHERI : public Base + { + public: + /** + * CHERI pointers are not integers and come with strict provenance + * requirements. + */ + static constexpr uint64_t aal_features = + (Base::aal_features & ~IntegerPointers) | StrictProvenance; + + /** + * On CHERI-aware compilers, ptraddr_t is an integral type that is wide + * enough to hold any address that may be contained within a memory + * capability. It does not carry provenance: it is not a capability, but + * merely an address. + */ + typedef ptraddr_t address_t; + + template< + typename T, + SNMALLOC_CONCEPT(capptr::ConceptBound) BOut, + SNMALLOC_CONCEPT(capptr::ConceptBound) BIn, + typename U = T> + static SNMALLOC_FAST_PATH CapPtr + capptr_bound(CapPtr a, size_t size) noexcept + { + static_assert( + BIn::spatial > capptr::dimension::Spatial::Alloc, + "Refusing to re-bound Spatial::Alloc CapPtr"); + static_assert( + capptr::is_spatial_refinement(), + "capptr_bound must preserve non-spatial CapPtr dimensions"); + SNMALLOC_ASSERT(__builtin_cheri_tag_get(a.unsafe_ptr())); + + void* pb = __builtin_cheri_bounds_set_exact(a.unsafe_ptr(), size); + return CapPtr(static_cast(pb)); + } + }; +} // namespace snmalloc diff --git a/src/ds/address.h b/src/ds/address.h index 90b0bb4..13c6ed8 100644 --- a/src/ds/address.h +++ b/src/ds/address.h @@ -8,11 +8,8 @@ namespace snmalloc { /** - * The type used for an address. Currently, all addresses are assumed to be - * provenance-carrying values and so it is possible to cast back from the - * result of arithmetic on an address_t. Eventually, this will want to be - * separated into two types, one for raw addresses and one for addresses that - * can be cast back to pointers. + * The type used for an address. On CHERI, this is not a provenance-carrying + * value and so cannot be converted back to a pointer. */ using address_t = Aal::address_t; diff --git a/src/pal/pal_freebsd.h b/src/pal/pal_freebsd.h index 6248f7c..e17df29 100644 --- a/src/pal/pal_freebsd.h +++ b/src/pal/pal_freebsd.h @@ -3,6 +3,13 @@ #if defined(__FreeBSD__) && !defined(_KERNEL) # include "pal_bsd_aligned.h" +// On CHERI platforms, we need to know the value of CHERI_PERM_CHERIABI_VMMAP. +// This pollutes the global namespace a little, sadly, but I think only with +// symbols that begin with CHERI_, which is as close to namespaces as C offers. +# if defined(__CHERI_PURE_CAPABILITY__) +# include +# endif + namespace snmalloc { /** @@ -35,6 +42,27 @@ namespace snmalloc Aal::address_bits : (Aal::aal_name == RISCV ? 38 : Aal::address_bits); // TODO, if we ever backport to MIPS, this should yield 39 there. + +# if defined(__CHERI_PURE_CAPABILITY__) + static_assert( + aal_supports, + "CHERI purecap support requires StrictProvenance AAL"); + + /** + * On CheriBSD, exporting a pointer means stripping it of the authority to + * manage the address space it references by clearing the CHERIABI_VMMAP + * permission bit. + */ + template + static SNMALLOC_FAST_PATH CapPtr> + capptr_to_user_address_control(CapPtr p) + { + return CapPtr>( + __builtin_cheri_perms_and( + p.unsafe_ptr(), + ~static_cast(CHERI_PERM_CHERIABI_VMMAP))); + } +# endif }; } // namespace snmalloc #endif