diff --git a/src/aal/aal.h b/src/aal/aal.h index 471b460..d1a71c8 100644 --- a/src/aal/aal.h +++ b/src/aal/aal.h @@ -1,11 +1,13 @@ #pragma once #include "../ds/concept.h" #include "../ds/defines.h" +#include "../ds/ptrwrap.h" #include "aal_concept.h" #include "aal_consts.h" #include #include +#include #if defined(__i386__) || defined(_M_IX86) || defined(_X86_) || \ defined(__amd64__) || defined(__x86_64__) || defined(_M_X64) || \ @@ -113,6 +115,48 @@ namespace snmalloc } }; + template + class AAL_NoStrictProvenance : public Arch + { + static_assert( + (Arch::aal_features & StrictProvenance) == 0, + "AAL_NoStrictProvenance requires what it says on the tin"); + + public: + /** + * For architectures which do not enforce StrictProvenance, we can just + * perform an underhanded bit of type-casting. + */ + template< + typename T, + enum capptr_bounds nbounds, + enum capptr_bounds obounds, + typename U = T> + static SNMALLOC_FAST_PATH CapPtr + capptr_bound(CapPtr a, size_t size) noexcept + { + // Impose constraints on bounds annotations. + static_assert( + obounds == CBArena || obounds == CBChunkD || obounds == CBChunk || + obounds == CBChunkE); + static_assert(capptr_is_bounds_refinement()); + + UNUSED(size); + return CapPtr(a.template as_static().unsafe_capptr); + } + + /** + * For architectures which do not enforce StrictProvenance, there's nothing + * to be done, so just return the pointer unmodified with new annotation. + */ + template + static SNMALLOC_FAST_PATH CapPtr + capptr_rebound(CapPtr a, CapPtr r) noexcept + { + UNUSED(a); + return CapPtr(r.unsafe_capptr); + } + }; } // namespace snmalloc #if defined(PLATFORM_IS_X86) @@ -129,7 +173,7 @@ namespace snmalloc namespace snmalloc { - using Aal = AAL_Generic; + using Aal = AAL_Generic>; template constexpr static bool aal_supports = (AAL::aal_features & F) == F; diff --git a/src/aal/aal_concept.h b/src/aal/aal_concept.h index e199e07..6b85772 100644 --- a/src/aal/aal_concept.h +++ b/src/aal/aal_concept.h @@ -2,6 +2,7 @@ #ifdef __cpp_concepts # include "../ds/concept.h" +# include "../ds/ptrwrap.h" # include "aal_consts.h" # include @@ -38,11 +39,31 @@ namespace snmalloc { AAL::tick() } noexcept -> ConceptSame; }; + template + concept ConceptAAL_capptr_methods = + requires(CapPtr auth, CapPtr ret, size_t sz) + { + /** + * Produce a pointer with reduced authority from a more privilged pointer. + * The resulting pointer will have base at auth's address and length of + * exactly sz. auth+sz must not exceed auth's limit. + */ + { AAL::template capptr_bound(auth, sz) } noexcept + -> ConceptSame>; + + /** + * Construct a copy of auth with its target set to that of ret. + */ + { AAL::capptr_rebound(auth, ret) } noexcept + -> ConceptSame>; + }; + template concept ConceptAAL = ConceptAAL_static_members && ConceptAAL_prefetch && - ConceptAAL_tick; + ConceptAAL_tick && + ConceptAAL_capptr_methods; } // namespace snmalloc #endif diff --git a/src/pal/pal.h b/src/pal/pal.h index cceb135..03d12c6 100644 --- a/src/pal/pal.h +++ b/src/pal/pal.h @@ -69,6 +69,30 @@ namespace snmalloc // Used to keep Superslab metadata committed. static constexpr size_t OS_PAGE_SIZE = Pal::page_size; + /** + * Perform platform-specific adjustment of return pointers. + * + * This is here, rather than in every PAL proper, merely to minimize + * disruption to PALs for platforms that do not support StrictProvenance AALs. + */ + template + static SNMALLOC_FAST_PATH typename std::enable_if_t< + !aal_supports, + CapPtr()>> + capptr_export(CapPtr p) + { + return CapPtr()>(p.unsafe_capptr); + } + + template + static SNMALLOC_FAST_PATH typename std::enable_if_t< + aal_supports, + CapPtr()>> + capptr_export(CapPtr p) + { + return PAL::capptr_export(p); + } + /** * A convenience wrapper that avoids the need to litter unsafe accesses with * every call to PAL::zero.