From 2729c8e9f0d4e8f24e4957abd0ca6f7b435f10af Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 30 Nov 2021 22:36:32 +0000 Subject: [PATCH 1/2] override add malloc_conceal api proposal --- src/mem/localalloc.h | 17 +++++++++--- src/override/malloc.cc | 19 +++++++++++++ src/pal/pal_consts.h | 6 ++++ src/pal/pal_freebsd.h | 5 ++++ src/pal/pal_linux.h | 5 ++++ src/pal/pal_open_enclave.h | 6 ++++ src/pal/pal_posix.h | 6 ++++ src/pal/pal_windows.h | 6 ++++ src/test/func/malloc/malloc.cc | 51 +++++++++++++++++++++++++++++----- 9 files changed, 110 insertions(+), 11 deletions(-) diff --git a/src/mem/localalloc.h b/src/mem/localalloc.h index b243290ec..ddd4f24d1 100644 --- a/src/mem/localalloc.h +++ b/src/mem/localalloc.h @@ -418,15 +418,18 @@ namespace snmalloc /** * Allocate memory of a dynamically known size. */ - template + template SNMALLOC_FAST_PATH ALLOCATOR void* alloc(size_t size) { + void* result = nullptr; #ifdef SNMALLOC_PASS_THROUGH // snmalloc guarantees a lot of alignment, so we can depend on this // make pass through call aligned_alloc with the alignment snmalloc // would guarantee. - void* result = external_alloc::aligned_alloc( + result = external_alloc::aligned_alloc( natural_alignment(size), round_size(size)); + if constexpr (core_dump == NoDump) + SharedStateHandle::Pal::nodump(result, size); if constexpr (zero_mem == YesZero) memset(result, 0, size); return result; @@ -438,11 +441,17 @@ namespace snmalloc { // Small allocations are more likely. Improve // branch prediction by placing this case first. - return capptr_reveal(small_alloc(size)); + result = capptr_reveal(small_alloc(size)); + if constexpr (core_dump == NoDump) + SharedStateHandle::Pal::nodump(result, size); + return result; } - return capptr_reveal(alloc_not_small(size)); + result = capptr_reveal(alloc_not_small(size)); + if constexpr (core_dump == NoDump) + SharedStateHandle::Pal::nodump(result, size); #endif + return result; } /** diff --git a/src/override/malloc.cc b/src/override/malloc.cc index 658e2badf..2298d0158 100644 --- a/src/override/malloc.cc +++ b/src/override/malloc.cc @@ -54,6 +54,25 @@ extern "C" return ThreadAlloc::get().alloc(sz); } +#if !defined(__OpenBSD__) + SNMALLOC_EXPORT void* SNMALLOC_NAME_MANGLE(malloc_conceal)(size_t size) + { + return ThreadAlloc::get().alloc(size); + } + + SNMALLOC_EXPORT void* + SNMALLOC_NAME_MANGLE(calloc_conceal)(size_t nmemb, size_t size) + { + bool overflow = false; + size_t sz = bits::umul(size, nmemb, overflow); + if (SNMALLOC_UNLIKELY(overflow)) + { + return SNMALLOC_NAME_MANGLE(snmalloc_set_error)(); + } + return ThreadAlloc::get().alloc(sz); + } +#endif + SNMALLOC_EXPORT size_t SNMALLOC_NAME_MANGLE(malloc_usable_size)( MALLOC_USABLE_SIZE_QUALIFIER void* ptr) diff --git a/src/pal/pal_consts.h b/src/pal/pal_consts.h index 31df5470b..22d6a3b82 100644 --- a/src/pal/pal_consts.h +++ b/src/pal/pal_consts.h @@ -94,6 +94,12 @@ namespace snmalloc YesZero }; + enum CoreDumpMem + { + NoDump, + YesDump + }; + /** * Default Tag ID for the Apple class */ diff --git a/src/pal/pal_freebsd.h b/src/pal/pal_freebsd.h index e17df290d..11788eb36 100644 --- a/src/pal/pal_freebsd.h +++ b/src/pal/pal_freebsd.h @@ -63,6 +63,11 @@ namespace snmalloc ~static_cast(CHERI_PERM_CHERIABI_VMMAP))); } # endif + + static void nodump(void* p, size_t size) noexcept + { + madvise(p, size, MADV_NOCORE); + } }; } // namespace snmalloc #endif diff --git a/src/pal/pal_linux.h b/src/pal/pal_linux.h index f597ff110..6ffa318d8 100644 --- a/src/pal/pal_linux.h +++ b/src/pal/pal_linux.h @@ -85,6 +85,11 @@ namespace snmalloc madvise(p, size, MADV_FREE); } } + + static void nodump(void* p, size_t size) noexcept + { + madvise(p, size, MADV_DONTDUMP); + } }; } // namespace snmalloc #endif diff --git a/src/pal/pal_open_enclave.h b/src/pal/pal_open_enclave.h index 276af8219..e078a69d4 100644 --- a/src/pal/pal_open_enclave.h +++ b/src/pal/pal_open_enclave.h @@ -41,6 +41,12 @@ namespace snmalloc oe_memset_s(p, size, 0, size); } + static void dump(void* p, size_t size) noexcept + { + UNUSED(p); + UNUSED(size); + } + /** * Source of Entropy */ diff --git a/src/pal/pal_posix.h b/src/pal/pal_posix.h index e75020da0..7f3635319 100644 --- a/src/pal/pal_posix.h +++ b/src/pal/pal_posix.h @@ -318,6 +318,12 @@ namespace snmalloc return nullptr; } + static void nodump(void* p, size_t size) noexcept + { + UNUSED(p); + UNUSED(size); + } + /** * Source of Entropy * diff --git a/src/pal/pal_windows.h b/src/pal/pal_windows.h index 1667dce9f..ab54e9bd1 100644 --- a/src/pal/pal_windows.h +++ b/src/pal/pal_windows.h @@ -195,6 +195,12 @@ namespace snmalloc return VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE); } + static void nodump(void* p, size_t size) noexcept + { + UNUSED(p); + UNUSED(size); + } + /** * Source of Entropy */ diff --git a/src/test/func/malloc/malloc.cc b/src/test/func/malloc/malloc.cc index 80667f32e..ddc80e1c3 100644 --- a/src/test/func/malloc/malloc.cc +++ b/src/test/func/malloc/malloc.cc @@ -87,11 +87,20 @@ void check_result(size_t size, size_t align, void* p, int err, bool null) our_free(p); } -void test_calloc(size_t nmemb, size_t size, int err, bool null) +void test_calloc( + void* (*calloc_fn)(size_t, size_t), + size_t nmemb, + size_t size, + int err, + bool null) { - printf("calloc(%zu, %zu) combined size %zu\n", nmemb, size, nmemb * size); + printf("calloc"); + if (calloc_fn == our_calloc_conceal) + printf("_conceal"); + + printf("(%zu, %zu) combined size %zu\n", nmemb, size, nmemb * size); errno = SUCCESS; - void* p = our_calloc(nmemb, size); + void* p = calloc_fn(nmemb, size); if (p != nullptr) { @@ -157,7 +166,7 @@ int main(int argc, char** argv) check_result(size + 1, 1, our_malloc(size + 1), SUCCESS, false); } - test_calloc(0, 0, SUCCESS, false); + test_calloc(our_calloc, 0, 0, SUCCESS, false); our_free(nullptr); @@ -173,10 +182,10 @@ int main(int argc, char** argv) if (overflow) break; - test_calloc(n, size, SUCCESS, false); - test_calloc(n, 0, SUCCESS, false); + test_calloc(our_calloc, n, size, SUCCESS, false); + test_calloc(our_calloc, n, 0, SUCCESS, false); } - test_calloc(0, size, SUCCESS, false); + test_calloc(our_calloc, 0, size, SUCCESS, false); } for (smallsizeclass_t sc = 0; sc < NUM_SMALL_SIZECLASSES; sc++) @@ -210,6 +219,34 @@ int main(int argc, char** argv) test_realloc(our_malloc(64), 4194304, SUCCESS, false); + for (smallsizeclass_t sc = 0; sc < (MAX_SMALL_SIZECLASS_BITS + 4); sc++) + { + const size_t size = bits::one_at_bit(sc); + printf("malloc_conceal: %zu\n", size); + errno = SUCCESS; + check_result(size, 1, our_malloc_conceal(size), SUCCESS, false); + errno = SUCCESS; + check_result(size + 1, 1, our_malloc_conceal(size + 1), SUCCESS, false); + } + + for (smallsizeclass_t sc = 0; sc < NUM_SMALL_SIZECLASSES; sc++) + { + const size_t size = sizeclass_to_size(sc); + + bool overflow = false; + for (size_t n = 1; + bits::umul(size, n, overflow) <= MAX_SMALL_SIZECLASS_SIZE; + n *= 5) + { + if (overflow) + break; + + test_calloc(our_calloc_conceal, n, size, SUCCESS, false); + test_calloc(our_calloc_conceal, n, 0, SUCCESS, false); + } + test_calloc(our_calloc_conceal, 0, size, SUCCESS, false); + } + test_posix_memalign(0, 0, EINVAL, true); test_posix_memalign(((size_t)-1) / 2, 0, EINVAL, true); test_posix_memalign(OS_PAGE_SIZE, sizeof(uintptr_t) / 2, EINVAL, true); From 51d6377350cb4789c8f702dd7685de691c0bfaf0 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 30 Nov 2021 23:13:12 +0000 Subject: [PATCH 2/2] adding freezero and quick tests --- src/override/malloc.cc | 16 ++++++++++++++++ src/pal/pal_freebsd_kernel.h | 6 ++++++ src/test/func/malloc/malloc.cc | 11 +++++++++++ 3 files changed, 33 insertions(+) diff --git a/src/override/malloc.cc b/src/override/malloc.cc index 2298d0158..9b03f0a4c 100644 --- a/src/override/malloc.cc +++ b/src/override/malloc.cc @@ -71,6 +71,22 @@ extern "C" } return ThreadAlloc::get().alloc(sz); } + + SNMALLOC_EXPORT void SNMALLOC_NAME_MANGLE(freezero)(void* p, size_t size) + { + if (SNMALLOC_UNLIKELY(p == nullptr)) + { + return; + } + + size_t sz = bits::min(size, ThreadAlloc::get().alloc_size(p)); + /* we are not trying to be fast, here but disallowing to potentially + * optimize away the memset call */ + void* (*volatile memset_fn)(void*, int, size_t) = memset; + memset_fn(p, 0, sz); + + ThreadAlloc::get().dealloc(p); + } #endif SNMALLOC_EXPORT diff --git a/src/pal/pal_freebsd_kernel.h b/src/pal/pal_freebsd_kernel.h index 72f84870c..a052e641e 100644 --- a/src/pal/pal_freebsd_kernel.h +++ b/src/pal/pal_freebsd_kernel.h @@ -92,6 +92,12 @@ namespace snmalloc } return get_vm_offset(addr); } + + static void nodump(void* p, size_t size) noexcept + { + UNUSED(p); + UNUSED(size); + } }; } #endif diff --git a/src/test/func/malloc/malloc.cc b/src/test/func/malloc/malloc.cc index ddc80e1c3..d01e49be4 100644 --- a/src/test/func/malloc/malloc.cc +++ b/src/test/func/malloc/malloc.cc @@ -229,6 +229,17 @@ int main(int argc, char** argv) check_result(size + 1, 1, our_malloc_conceal(size + 1), SUCCESS, false); } + our_freezero(nullptr, 1024); + void* p = our_malloc_conceal(64); + our_freezero(p, 128); + if (((uint8_t*)p)[63] != 0) + { + abort(); + } + + p = our_malloc_conceal(16); + our_freezero(p, 0); + for (smallsizeclass_t sc = 0; sc < NUM_SMALL_SIZECLASSES; sc++) { const size_t size = sizeclass_to_size(sc);