From 78ab0a79375ccfa7546349aa4ce45dacc99208e9 Mon Sep 17 00:00:00 2001 From: Nathaniel Filardo Date: Sat, 6 Mar 2021 18:36:11 +0000 Subject: [PATCH] SP: external_pointer should not leak authority Work with high-authority pointers internally, but then copy the address onto to the low-authority pointer originally given to us (using the same primitive as amplification, just backwards). This ensures that clients cannot behave non-monotonically even if they have access to external_pointer(). That is, we are not an amplification oracle, though we might reveal the address of an object somewhere clients cannot otherwise access. Notably, we might reveal if a {Super,Medium,}Slab has changed sizeclass (or been repurposed as or from a Largealloc), forming a covert channel for data but not capabilities. Of course, if the pointer provided to external_alloc() is still useful, the implied UAF in these scenarios is still its own problem. --- src/mem/alloc.h | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/mem/alloc.h b/src/mem/alloc.h index 931798a..85c8236 100644 --- a/src/mem/alloc.h +++ b/src/mem/alloc.h @@ -379,7 +379,8 @@ namespace snmalloc auto meta = super->get_meta(slab); sizeclass_t sc = meta->sizeclass(); - auto slab_end = pointer_offset(slab, SLAB_SIZE); + auto slab_end = + Aal::capptr_rebound(p_ret, pointer_offset(slab, SLAB_SIZE)); return capptr_reveal(external_pointer(p_ret, sc, slab_end)); } @@ -388,17 +389,18 @@ namespace snmalloc auto slab = Mediumslab::get(p_auth); sizeclass_t sc = slab->get_sizeclass(); - auto slab_end = pointer_offset(slab, SUPERSLAB_SIZE); + auto slab_end = + Aal::capptr_rebound(p_ret, pointer_offset(slab, SUPERSLAB_SIZE)); return capptr_reveal(external_pointer(p_ret, sc, slab_end)); } - auto ss = super.unsafe_capptr; + auto ss = super.as_void(); while (chunkmap_slab_kind >= CMLargeRangeMin) { // This is a large alloc redirect. - ss = pointer_offset_signed( + ss = pointer_offset_signed( ss, -(static_cast(1) << (chunkmap_slab_kind - CMLargeRangeMin + SUPERSLAB_BITS))); @@ -419,13 +421,18 @@ namespace snmalloc (chunkmap_slab_kind >= CMLargeMin) && (chunkmap_slab_kind <= CMLargeMax)); + CapPtr retss = Aal::capptr_rebound(p_ret, ss); + CapPtr ret; + // This is a large alloc, mask off to the slab size. if constexpr (location == Start) - return ss; + ret = retss; else if constexpr (location == End) - return pointer_offset(ss, (bits::one_at_bit(chunkmap_slab_kind)) - 1); + ret = pointer_offset(retss, (bits::one_at_bit(chunkmap_slab_kind)) - 1); else - return pointer_offset(ss, bits::one_at_bit(chunkmap_slab_kind)); + ret = pointer_offset(retss, bits::one_at_bit(chunkmap_slab_kind)); + + return capptr_reveal(ret); #endif } @@ -814,7 +821,7 @@ namespace snmalloc static CapPtr external_pointer( CapPtr p_ret, sizeclass_t sizeclass, - CapPtr end_point) + CapPtr end_point) { size_t rsize = sizeclass_to_size(sizeclass); @@ -829,10 +836,8 @@ namespace snmalloc size_t end_to_end = round_by_sizeclass(sizeclass, offset_from_end); - auto ret_auth = pointer_offset_signed( + return pointer_offset_signed( end_point_correction, -static_cast(end_to_end)); - - return CapPtr(ret_auth.unsafe_capptr); } void init_message_queue()