From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Renlord Date: Sun, 20 Oct 2019 08:17:11 +1100 Subject: [PATCH] add secondary stack randomization Signed-off-by: anupritaisno1 --- libc/bionic/pthread_create.cpp | 32 +++++++++++++++++++++++++++----- libc/include/sys/cdefs.h | 1 + 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp index 627fbb25b..1dc32be32 100644 --- a/libc/bionic/pthread_create.cpp +++ b/libc/bionic/pthread_create.cpp @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -201,12 +202,24 @@ int __init_thread(pthread_internal_t* thread) { ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_size) { const StaticTlsLayout& layout = __libc_shared_globals()->static_tls_layout; + // round up if the given stack size is not in multiples of PAGE_SIZE + stack_size = __BIONIC_ALIGN(stack_size, PAGE_SIZE); size_t thread_page_size = __BIONIC_ALIGN(sizeof(pthread_internal_t), PAGE_SIZE); - // Allocate in order: stack guard, stack, guard page, pthread_internal_t, static TLS, guard page. + // Place a randomly sized gap above the stack, up to 10% as large as the stack + // on 32-bit and 50% on 64-bit where virtual memory is plentiful. +#if __LP64__ + size_t max_gap_size = stack_size / 2; +#else + size_t max_gap_size = stack_size / 10; +#endif + // Make sure random stack top guard size are multiples of PAGE_SIZE. + size_t gap_size = __BIONIC_ALIGN(arc4random_uniform(max_gap_size), PAGE_SIZE); + + // Allocate in order: stack guard, stack, (random) guard page(s), pthread_internal_t, static TLS, guard page. size_t mmap_size; if (__builtin_add_overflow(stack_size, stack_guard_size, &mmap_size)) return {}; - if (__builtin_add_overflow(mmap_size, PTHREAD_GUARD_SIZE, &mmap_size)) return {}; + if (__builtin_add_overflow(mmap_size, gap_size, &mmap_size)) return {}; if (__builtin_add_overflow(mmap_size, thread_page_size, &mmap_size)) return {}; if (__builtin_add_overflow(mmap_size, layout.size(), &mmap_size)) return {}; if (__builtin_add_overflow(mmap_size, PTHREAD_GUARD_SIZE, &mmap_size)) return {}; @@ -228,15 +241,21 @@ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_si return {}; } - if (mprotect(space + stack_guard_size, stack_size, PROT_READ | PROT_WRITE) != 0) { + // Stack is at the lower end of mapped space, stack guard region is at the lower end of stack. + // Make the usable portion of the stack between the guard region and random gap readable and + // writable. + if (mprotect((space + stack_guard_size), stack_size, PROT_READ | PROT_WRITE) == -1) { async_safe_format_log(ANDROID_LOG_WARN, "libc", "pthread_create failed: couldn't mprotect R+W %zu-byte thread mapping region: %s", stack_size, strerror(errno)); munmap(space, mmap_size); return {}; } + prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, space, stack_guard_size, "stack guard"); + char* const stack_top_guard = space + stack_guard_size + stack_size; + prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, stack_top_guard, gap_size, "stack top guard"); - char* const thread = space + stack_guard_size + stack_size + PTHREAD_GUARD_SIZE; + char* const thread = space + stack_guard_size + stack_size + gap_size; char* const static_tls_space = thread + thread_page_size; if (mprotect(thread, thread_page_size + layout.size(), PROT_READ | PROT_WRITE) != 0) { @@ -254,7 +273,10 @@ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_si result.mmap_size_unguarded = mmap_size - stack_guard_size - PTHREAD_GUARD_SIZE; result.static_tls = static_tls_space; result.stack_base = space; - result.stack_top = space + stack_guard_size + stack_size; + // Choose a random base within the first page of the stack. Waste no more + // than the space originally wasted by pthread_internal_t for compatibility. + result.stack_top = space + stack_guard_size + stack_size - arc4random_uniform(sizeof(pthread_internal_t)); + result.stack_top = reinterpret_cast(__BIONIC_ALIGN_DOWN(reinterpret_cast(result.stack_top), 16)); return result; } diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h index 5b9d99b3a..aa6c0040a 100644 --- a/libc/include/sys/cdefs.h +++ b/libc/include/sys/cdefs.h @@ -61,6 +61,7 @@ #endif #define __BIONIC_ALIGN(__value, __alignment) (((__value) + (__alignment)-1) & ~((__alignment)-1)) +#define __BIONIC_ALIGN_DOWN(value, alignment) ((value) & ~((alignment) - 1)) /* * The __CONCAT macro is used to concatenate parts of symbol names, e.g.