From 8d29f2cabf41f9c95a62a9eaa4be461fc2102111 Mon Sep 17 00:00:00 2001 From: Dapeng Gao Date: Thu, 21 Mar 2024 01:02:00 +0000 Subject: [PATCH] c18n: Remove assembly wrappers for _rtld_{setjmp,longjmp,unw_*} Instead, use the get_trusted_frame macro to obtain the trusted frame in C. --- lib/libc/aarch64/gen/_setjmp.S | 5 +- lib/libc/aarch64/gen/setjmp.S | 5 +- libexec/rtld-elf/aarch64/rtld_c18n_asm.S | 74 --------- libexec/rtld-elf/rtld_c18n.c | 203 +++++++++-------------- 4 files changed, 84 insertions(+), 203 deletions(-) diff --git a/lib/libc/aarch64/gen/_setjmp.S b/lib/libc/aarch64/gen/_setjmp.S index e574317fcc62..c789d2601e5d 100644 --- a/lib/libc/aarch64/gen/_setjmp.S +++ b/lib/libc/aarch64/gen/_setjmp.S @@ -82,7 +82,7 @@ ENTRY(_longjmp) /* Restore the stack pointer */ ldr REG(8), [REG(0)], #(REG_WIDTH) #if defined(__CHERI_PURE_CAPABILITY__) && defined(RTLD_SANDBOX) - mov c3, c8 + mov c2, c8 #else mov REGN(sp), REG(8) #endif @@ -105,12 +105,11 @@ ENTRY(_longjmp) /* Load the return value */ #if defined(__CHERI_PURE_CAPABILITY__) && defined(RTLD_SANDBOX) - mov c4, c0 + mov c3, c0 #endif cmp x1, #0 csinc x0, x1, xzr, ne #if defined(__CHERI_PURE_CAPABILITY__) && defined(RTLD_SANDBOX) - mov c1, c4 /* * Tail-call to restore Executive mode state */ diff --git a/lib/libc/aarch64/gen/setjmp.S b/lib/libc/aarch64/gen/setjmp.S index 12ade4aefc0e..70636ad2e8f0 100644 --- a/lib/libc/aarch64/gen/setjmp.S +++ b/lib/libc/aarch64/gen/setjmp.S @@ -111,7 +111,7 @@ ENTRY(longjmp) /* Restore the stack pointer */ ldr REG(8), [REG(0)], #(REG_WIDTH) #if defined(__CHERI_PURE_CAPABILITY__) && defined(RTLD_SANDBOX) - mov c3, c8 + mov c2, c8 #else mov REGN(sp), REG(8) #endif @@ -132,12 +132,11 @@ ENTRY(longjmp) /* Load the return value */ #if defined(__CHERI_PURE_CAPABILITY__) && defined(RTLD_SANDBOX) - mov c4, c0 + mov c3, c0 #endif cmp x1, #0 csinc x0, x1, xzr, ne #if defined(__CHERI_PURE_CAPABILITY__) && defined(RTLD_SANDBOX) - mov c1, c4 /* * Tail-call to restore Executive mode state */ diff --git a/libexec/rtld-elf/aarch64/rtld_c18n_asm.S b/libexec/rtld-elf/aarch64/rtld_c18n_asm.S index f161deb06b08..9085042b49b9 100644 --- a/libexec/rtld-elf/aarch64/rtld_c18n_asm.S +++ b/libexec/rtld-elf/aarch64/rtld_c18n_asm.S @@ -30,32 +30,6 @@ #include "rtld_c18n_machdep.h" #undef IN_ASM -ENTRY(_rtld_setjmp) -#ifdef __ARM_MORELLO_PURECAP_BENCHMARK_ABI - mrs c2, rcsp_el0 -#else - mov c2, csp -#endif - /* - * This function MUST preserve the value of c0 and clear unused return - * value registers. - */ - b _rtld_setjmp_impl -END(_rtld_setjmp) - -ENTRY(_rtld_longjmp) -#ifdef __ARM_MORELLO_PURECAP_BENCHMARK_ABI - mrs c2, rcsp_el0 -#else - mov c2, csp -#endif - /* - * This function MUST preserve the value of c0 and clear unused return - * value registers. - */ - b _rtld_longjmp_impl -END(_rtld_longjmp) - ENTRY(_rtld_thread_start) mov c1, csp sub csp, csp, #(CAP_WIDTH * 2) @@ -304,54 +278,6 @@ ENTRY(tramp_hook) #endif END(tramp_hook) -ENTRY(_rtld_unw_getcontext) - /* - * This function MUST preserve the value of c0. - */ -#ifdef __ARM_MORELLO_PURECAP_BENCHMARK_ABI - mrs c2, rcsp_el0 -#else - mov c2, csp -#endif - b _rtld_unw_getcontext_impl -END(_rtld_unw_getcontext) - -ENTRY(_rtld_unw_setcontext) - /* - * This function MUST preserve the value of c0, c1. - */ -#ifdef __ARM_MORELLO_PURECAP_BENCHMARK_ABI - mrs c2, rcsp_el0 -#else - mov c2, csp -#endif - b _rtld_unw_resume -END(_rtld_unw_setcontext) - -ENTRY(_rtld_unw_getcontext_unsealed) - /* - * This function MUST preserve the value of c0. - */ -#ifdef __ARM_MORELLO_PURECAP_BENCHMARK_ABI - mrs c2, rcsp_el0 -#else - mov c2, csp -#endif - b _rtld_unw_getcontext_impl_unsealed -END(_rtld_unw_getcontext) - -ENTRY(_rtld_unw_setcontext_unsealed) - /* - * This function MUST preserve the value of c0, c1. - */ -#ifdef __ARM_MORELLO_PURECAP_BENCHMARK_ABI - mrs c2, rcsp_el0 -#else - mov c2, csp -#endif - b _rtld_unw_resume_unsealed -END(_rtld_unw_setcontext) - /* * Trampoline templates are code but reside in rodata. Hence a new macro is * defined to describe them. diff --git a/libexec/rtld-elf/rtld_c18n.c b/libexec/rtld-elf/rtld_c18n.c index 251dd99d9d19..7c47af9cb351 100644 --- a/libexec/rtld-elf/rtld_c18n.c +++ b/libexec/rtld-elf/rtld_c18n.c @@ -733,19 +733,12 @@ allocate_rstk_impl(unsigned index) /* * Stack unwinding */ -/* - * Returning this struct allows us to control the content of unused return value - * registers. - */ -struct jmp_args { uintptr_t ret1; uintptr_t ret2; }; - -struct jmp_args _rtld_setjmp_impl(uintptr_t, void **, struct trusted_frame *); - -struct jmp_args -_rtld_setjmp_impl(uintptr_t ret, void **buf, struct trusted_frame *csp) +static void * +unwind_cursor(struct trusted_frame *tf) { /* - * Before setjmp is called, the top of the trusted stack contains: + * This helper is used by functions like setjmp. Before setjmp is + * called, the top of the trusted stack contains: * 0. Link to previous frame * setjmp does not push to the trusted stack. When _rtld_setjmp is * called, the following are pushed to the trusted stack: @@ -755,41 +748,47 @@ _rtld_setjmp_impl(uintptr_t ret, void **buf, struct trusted_frame *csp) * buffer. */ - *buf = cheri_seal(cheri_setaddress(csp, csp->next), sealer_jmpbuf); + return (cheri_setaddress(tf, tf->next)); +} + +uintptr_t _rtld_setjmp(uintptr_t, void **); +uintptr_t _rtld_unw_getcontext(uintptr_t, void **); +uintptr_t _rtld_unw_getcontext_unsealed(uintptr_t, void **); - return ((struct jmp_args) { .ret1 = ret }); +uintptr_t +_rtld_setjmp(uintptr_t ret, void **buf) +{ + *buf = cheri_seal(unwind_cursor(get_trusted_frame()), sealer_jmpbuf); + return (ret); } -#define UNWIND_EXEC_STACK(cur, target) \ - { \ - struct stk_bottom *stk; \ - do { \ - stk = cheri_setoffset(cur->o_sp, \ - cheri_getlen(cur->o_sp)); \ - --stk; \ - stk->top = cur->o_sp; \ - cur = cheri_setaddress(cur, cur->next); \ - } while (cur < target); \ - } +uintptr_t +_rtld_unw_getcontext(uintptr_t ret, void **buf) +{ + *buf = cheri_seal(unwind_cursor(get_trusted_frame()), sealer_unwbuf); + return (ret); +} -#define UNWIND_STORE_RCSP(csp, rcsp) \ - { \ - struct stk_bottom *stk; \ - stk = cheri_setoffset(rcsp, cheri_getlen(rcsp)); \ - --stk; \ - csp->o_sp = stk->top; \ - stk->top = rcsp; \ - } +uintptr_t +_rtld_unw_getcontext_unsealed(uintptr_t ret, void **buf) +{ + *buf = unwind_cursor(get_trusted_frame()); + return (ret); +} -struct jmp_args _rtld_longjmp_impl(uintptr_t, void **, struct trusted_frame *, - void *); +/* + * Returning this struct allows us to control the content of unused return value + * registers. + */ +struct jmp_args { uintptr_t ret1; uintptr_t ret2; }; -struct jmp_args -_rtld_longjmp_impl(uintptr_t ret, void **buf, struct trusted_frame *csp, - void *rcsp) +static struct jmp_args +unwind_stack(struct jmp_args ret, void *rcsp, struct trusted_frame *target, + struct trusted_frame *tf) { /* - * Before longjmp is called, the top of the trusted stack contains: + * Thie helper is used by functions like longjmp. Before longjmp is + * called, the top of the trusted stack contains: * 0. Link to previous frame * longjmp does not push to the trusted stack. When _rtld_longjmp is * called, the following are pushed to the trusted stack: @@ -800,125 +799,83 @@ _rtld_longjmp_impl(uintptr_t ret, void **buf, struct trusted_frame *csp, * frame. */ - struct trusted_frame *target, *cur = csp; + struct stk_bottom *stk; + struct trusted_frame *cur = tf; - target = cheri_unseal(*buf, sealer_jmpbuf); rtld_require(cheri_is_subset(cur, target) && cur < target, - "c18n: Illegal longjmp from %#p to %#p", cur, target); + "c18n: Illegal unwind from %#p to %#p", cur, target); /* * Unwind each frame before the target frame. */ - UNWIND_EXEC_STACK(cur, target); + do { + stk = cheri_setoffset(cur->n_sp, cheri_getlen(cur->n_sp)); + --stk; + + rtld_require((ptraddr_t)stk->top <= cur->o_sp, + "c18n: Cannot unwind %s from %#p to %p\n" + "tf: %#p -> %#p", comparts.data[stk->compart_id].name, + stk->top, (void *)(uintptr_t)cur->o_sp, tf, target); + + stk->top = cheri_setaddress(cur->n_sp, cur->o_sp); + cur = cheri_setaddress(cur, cur->next); + } while (cur < target); + rtld_require(cur == target, - "c18n: Illegal longjmp from %#p to %#p", cur, target); + "c18n: Illegal unwind from %#p to %#p", cur, target); /* * Set the next frame to the target frame. */ - csp->next = (ptraddr_t)cur; + tf->next = (ptraddr_t)cur; /* * Maintain the invariant of the trusted frame and the invariant of the * bottom of the target compartment's stack. */ - UNWIND_STORE_RCSP(csp, rcsp); - return ((struct jmp_args) { .ret1 = ret }); -} + stk = cheri_setoffset(rcsp, cheri_getlen(rcsp)); + --stk; -uintptr_t _rtld_unw_getsealer(void); -uintptr_t -_rtld_unw_getsealer(void) -{ + rtld_require(rcsp <= stk->top, + "c18n: Cannot complete unwind %s from %#p to %#p\n" + "tf: %#p -> %#p", comparts.data[stk->compart_id].name, + rcsp, stk->top, tf, target); - return (sealer_unwbuf); + tf->n_sp = rcsp; + tf->o_sp = (ptraddr_t)stk->top; + + return (ret); } -struct jmp_args _rtld_unw_getcontext_impl(uintptr_t, void **, - struct trusted_frame *); -struct jmp_args _rtld_unw_getcontext_impl_unsealed(uintptr_t, void **, - struct trusted_frame *); +struct jmp_args _rtld_longjmp(struct jmp_args, void *, void **); +struct jmp_args _rtld_unw_setcontext(struct jmp_args, void *, void **); +struct jmp_args _rtld_unw_setcontext_unsealed(struct jmp_args, void *, void **); struct jmp_args -_rtld_unw_getcontext_impl(uintptr_t ret, void **buf, struct trusted_frame *csp) +_rtld_longjmp(struct jmp_args ret, void *rcsp, void **buf) { - *buf = cheri_seal(cheri_setaddress(csp, csp->next), sealer_unwbuf); - return ((struct jmp_args) { .ret1 = ret }); + return (unwind_stack(ret, rcsp, cheri_unseal(*buf, sealer_jmpbuf), + get_trusted_frame())); } struct jmp_args -_rtld_unw_getcontext_impl_unsealed(uintptr_t ret, void **buf, - struct trusted_frame *csp) +_rtld_unw_setcontext(struct jmp_args ret, void *rcsp, void **buf) { - *buf = cheri_setaddress(csp, csp->next); - return ((struct jmp_args) { .ret1 = ret }); + return (unwind_stack(ret, rcsp, cheri_unseal(*buf, sealer_unwbuf), + get_trusted_frame())); } -struct jmp_args _rtld_unw_resume(uintptr_t, uintptr_t, struct trusted_frame *, - void **, void **); -struct jmp_args _rtld_unw_resume_unsealed(uintptr_t, uintptr_t, - struct trusted_frame *, void **, void **); - struct jmp_args -_rtld_unw_resume(uintptr_t ret1, uintptr_t ret2, struct trusted_frame *csp, - void **rcsp, void **buf) +_rtld_unw_setcontext_unsealed(struct jmp_args ret, void *rcsp, void **buf) { - struct trusted_frame *target, *cur = csp; - target = cheri_unseal(*buf, sealer_unwbuf); - - rtld_require(cheri_is_subset(cur, target) && - cur->next < (ptraddr_t)target, - "c18n: Illegal unw_resume from %#p to %#p", cur, target); - - /* - * Unwind each frame before the target frame. - */ - UNWIND_EXEC_STACK(cur, target); - rtld_require(cur == target, "c18n: Illegal unw_resume from %#p to %#p", - cur, target); - - /* - * Set the next frame to the target frame. - */ - csp->next = (ptraddr_t)cur; - - /* - * Maintain the invariant of the trusted frame and the invariant of the - * bottom of the target compartment's stack. - */ - UNWIND_STORE_RCSP(csp, rcsp); - return ((struct jmp_args) { .ret1 = ret1, .ret2 = ret2 }); + return (unwind_stack(ret, rcsp, *buf, get_trusted_frame())); } -struct jmp_args -_rtld_unw_resume_unsealed(uintptr_t ret1, uintptr_t ret2, - struct trusted_frame *csp, void **rcsp, void **buf) +uintptr_t _rtld_unw_getsealer(void); +uintptr_t +_rtld_unw_getsealer(void) { - struct trusted_frame *target, *cur = csp; - target = *buf; - - rtld_require(cheri_is_subset(cur, target) && - cur->next < (ptraddr_t)target, - "c18n: Illegal unw_resume from %#p to %#p", cur, target); - - /* - * Unwind each frame before the target frame. - */ - UNWIND_EXEC_STACK(cur, target); - rtld_require(cur == target, "c18n: Illegal unw_resume from %#p to %#p", - cur, target); - - /* - * Set the next frame to the target frame. - */ - csp->next = (ptraddr_t)cur; - - /* - * Maintain the invariant of the trusted frame and the invariant of the - * bottom of the target compartment's stack. - */ - UNWIND_STORE_RCSP(csp, rcsp); - return ((struct jmp_args) { .ret1 = ret1, .ret2 = ret2 }); + return (sealer_unwbuf); } /*