From 71bb4cad2f4834e9f6ec7ee9285b3ccc2fce1277 Mon Sep 17 00:00:00 2001 From: Dapeng Gao Date: Wed, 17 Apr 2024 17:09:05 +0100 Subject: [PATCH 1/3] c18n: Do not get trusted stack when c18n is disabled --- libexec/rtld-elf/aarch64/rtld_c18n_asm.S | 9 +++++++++ libexec/rtld-elf/rtld_c18n.c | 22 +++++++++++++++------- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/libexec/rtld-elf/aarch64/rtld_c18n_asm.S b/libexec/rtld-elf/aarch64/rtld_c18n_asm.S index 5ee347c6400d..d5fb7f1b1953 100644 --- a/libexec/rtld-elf/aarch64/rtld_c18n_asm.S +++ b/libexec/rtld-elf/aarch64/rtld_c18n_asm.S @@ -127,6 +127,15 @@ ENTRY(_rtld_dispatch_signal_unsafe) b dispatch_signal_end END(_rtld_dispatch_signal_unsafe) +ENTRY(_rtld_unw_getcontext_epilogue) + /* + * FIXME: llvm-libunwind specific ABI. This should be better specified. + */ + mov c2, csp + str c2, [c1] + RETURN +END(_rtld_unw_getcontext_epilogue) + ENTRY(_rtld_unw_setcontext_epilogue) /* * FIXME: llvm-libunwind specific ABI. This should be better specified. diff --git a/libexec/rtld-elf/rtld_c18n.c b/libexec/rtld-elf/rtld_c18n.c index 02ab7b384946..2d31dc062689 100644 --- a/libexec/rtld-elf/rtld_c18n.c +++ b/libexec/rtld-elf/rtld_c18n.c @@ -767,6 +767,13 @@ allocate_rstk_impl(unsigned index) /* * Stack unwinding */ +/* + * Assembly functions that are tail-called when compartmentalisation is + * disabled. + */ +uintptr_t _rtld_unw_getcontext_epilogue(uintptr_t, void **); +struct jmp_args _rtld_unw_setcontext_epilogue(struct jmp_args, void *, void **); + static void * unwind_cursor(struct trusted_frame *tf) { @@ -799,6 +806,10 @@ _rtld_setjmp(uintptr_t ret, void **buf) uintptr_t _rtld_unw_getcontext(uintptr_t ret, void **buf) { + if (!C18N_ENABLED) { + __attribute__((musttail)) + return (_rtld_unw_getcontext_epilogue(ret, buf)); + } *buf = cheri_seal(unwind_cursor(get_trusted_stk()), sealer_unwbuf); return (ret); } @@ -806,6 +817,10 @@ _rtld_unw_getcontext(uintptr_t ret, void **buf) uintptr_t _rtld_unw_getcontext_unsealed(uintptr_t ret, void **buf) { + if (!C18N_ENABLED) { + __attribute__((musttail)) + return (_rtld_unw_getcontext_epilogue(ret, buf)); + } *buf = unwind_cursor(get_trusted_stk()); return (ret); } @@ -900,13 +915,6 @@ _rtld_longjmp(struct jmp_args ret, void *rcsp, void **buf) get_trusted_stk())); } -/* - * An assembly function that is called to complete the unwind when - * compartmentalisation is disabled. The call must be a tail-call so that - * registers are not clobbered. - */ -struct jmp_args _rtld_unw_setcontext_epilogue(struct jmp_args, void *, void **); - struct jmp_args _rtld_unw_setcontext(struct jmp_args ret, void *rcsp, void **buf) { From 3ce5b2577a401d1ef4718eb123c30dc5bd63d78a Mon Sep 17 00:00:00 2001 From: Dapeng Gao Date: Fri, 12 Apr 2024 14:07:42 +0100 Subject: [PATCH 2/3] c18n: Reallocate trampoline tables with malloc instead of mmap --- libexec/rtld-elf/rtld_c18n.c | 52 ++++++++++++++---------------------- 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/libexec/rtld-elf/rtld_c18n.c b/libexec/rtld-elf/rtld_c18n.c index 2d31dc062689..9fe04bedfc19 100644 --- a/libexec/rtld-elf/rtld_c18n.c +++ b/libexec/rtld-elf/rtld_c18n.c @@ -1000,11 +1000,10 @@ tramp_pg_push(struct tramp_pg *pg, size_t len) return (tramp); } -typedef ssize_t slot_idx_t; +typedef int32_t slot_idx_t; static struct { _Alignas(CACHE_LINE_SIZE) _Atomic(slot_idx_t) size; - size_t back; int exp; const struct tramp_header **data; struct tramp_map_kv { @@ -1029,33 +1028,24 @@ tramp_table_max_load(int exp) } static void -tramp_table_expand(int exp) +expand_tramp_table(int exp) { - char *buffer; - size_t back, map_offset; + /* + * The lower bound ensures that the maximum load can be calculated + * without underflow. The upper bound ensures that the hash function + * does not underflow. + */ + assert(3 <= exp && exp <= 31); - /* The data array only needs to be as large as the MAX_LOAD. */ - back = sizeof(*tramp_table.data) * tramp_table_max_load(exp); - back = map_offset = roundup2(back, _Alignof(typeof(*tramp_table.map))); - back += sizeof(*tramp_table.map) << exp; + free(tramp_table.map); - buffer = mmap(NULL, back, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0); - if (buffer == MAP_FAILED) - rtld_fatal("mmap failed"); - - if (tramp_table.data != NULL) { - memcpy(buffer, tramp_table.data, - sizeof(*tramp_table.data) * - atomic_load_explicit(&tramp_table.size, - memory_order_relaxed)); - if (munmap(tramp_table.data, tramp_table.back) != 0) - rtld_fatal("munmap failed"); - } - - tramp_table.back = back; tramp_table.exp = exp; - tramp_table.data = (void *)buffer; - tramp_table.map = (void *)(buffer + map_offset); + /* + * The data array only needs to be as large as the maximum load. + */ + tramp_table.data = realloc(tramp_table.data, + sizeof(*tramp_table.data) * tramp_table_max_load(exp)); + tramp_table.map = xmalloc(sizeof(*tramp_table.map) << exp); for (size_t i = 0; i < (1 << exp); ++i) tramp_table.map[i] = (struct tramp_map_kv) { @@ -1066,7 +1056,7 @@ tramp_table_expand(int exp) /* Public domain. Taken from https://github.com/skeeto/hash-prospector */ static uint32_t -pointer_hash(uint64_t key) +hash_pointer(ptraddr_t key) { uint32_t x = key ^ (key >> 32); @@ -1096,15 +1086,13 @@ resize_table(int exp) uint32_t hash; slot_idx_t size, slot; - assert(0 < exp && exp < 32); - - tramp_table_expand(exp); + expand_tramp_table(exp); size = atomic_load_explicit(&tramp_table.size, memory_order_relaxed); for (slot_idx_t idx = 0; idx < size; ++idx) { key = (ptraddr_t)tramp_table.data[idx]->target; - hash = pointer_hash(key); + hash = hash_pointer(key); slot = hash; do { @@ -1280,7 +1268,7 @@ tramp_intern(const Obj_Entry *reqobj, const struct tramp_data *data) RtldLockState lockstate; const struct tramp_header *header; ptraddr_t target = (ptraddr_t)data->target; - const uint32_t hash = pointer_hash(target); + const uint32_t hash = hash_pointer(target); slot_idx_t slot, idx, writers; ptraddr_t key; int exp; @@ -1576,7 +1564,7 @@ c18n_init(Obj_Entry *obj_rtld) /* * Initialise trampoline table */ - tramp_table_expand(exp); + expand_tramp_table(exp); atomic_store_explicit(&tramp_pgs.head, tramp_pg_new(NULL), memory_order_relaxed); From 187bfb5e21dd6ee2bbd73cd62fb9598c9eca9f82 Mon Sep 17 00:00:00 2001 From: Dapeng Gao Date: Thu, 18 Apr 2024 13:40:01 +0100 Subject: [PATCH 3/3] c18n: Block all signals when creating a new thread --- lib/libthr/thread/thr_create.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/libthr/thread/thr_create.c b/lib/libthr/thread/thr_create.c index 1dc6fe773a61..71af366cb38d 100644 --- a/lib/libthr/thread/thr_create.c +++ b/lib/libthr/thread/thr_create.c @@ -152,7 +152,15 @@ _pthread_create(pthread_t * __restrict thread, new_thread->flags = THR_FLAGS_NEED_SUSPEND; create_suspended = 1; } else { +#if defined(__CHERI_PURE_CAPABILITY__) && defined(RTLD_SANDBOX) + /* + * c18n: Always block all signals when creating a new thread to + * allow RTLD to set up the environment to handle signals. + */ + create_suspended = 1; +#else create_suspended = 0; +#endif } new_thread->state = PS_RUNNING; @@ -289,8 +297,15 @@ static void thread_start(struct pthread *curthread) { sigset_t set; + bool restore_sigmask; + +#if defined(__CHERI_PURE_CAPABILITY__) && defined(RTLD_SANDBOX) + restore_sigmask = true; +#else + restore_sigmask = curthread->attr.suspend == THR_CREATE_SUSPENDED; +#endif - if (curthread->attr.suspend == THR_CREATE_SUSPENDED) + if (restore_sigmask) set = curthread->sigmask; _thr_signal_block_setup(curthread); @@ -305,7 +320,7 @@ thread_start(struct pthread *curthread) if (curthread->force_exit) _pthread_exit(PTHREAD_CANCELED); - if (curthread->attr.suspend == THR_CREATE_SUSPENDED) { + if (restore_sigmask) { #if 0 /* Done in THR_UNLOCK() */ _thr_ast(curthread);