diff --git a/lib/libc/aarch64/gen/_setjmp.S b/lib/libc/aarch64/gen/_setjmp.S index b0f9c97236d9..ce8a7fe0ad3b 100644 --- a/lib/libc/aarch64/gen/_setjmp.S +++ b/lib/libc/aarch64/gen/_setjmp.S @@ -63,7 +63,7 @@ ENTRY(_setjmp) /* * Tail-call to save Executive mode state */ - b _rtld_setjmp + b c18n_get_trusted_stk #else RETURN #endif @@ -112,7 +112,7 @@ ENTRY(_longjmp) /* * Tail-call to restore Executive mode state */ - b _rtld_longjmp + b c18n_unwind_trusted_stk #else RETURN #endif diff --git a/lib/libc/aarch64/gen/setjmp.S b/lib/libc/aarch64/gen/setjmp.S index aefc6bffc094..47fc275c527a 100644 --- a/lib/libc/aarch64/gen/setjmp.S +++ b/lib/libc/aarch64/gen/setjmp.S @@ -32,11 +32,6 @@ #include #include -#ifdef CHERI_LIB_C18N -.weak _rtld_setjmp -.weak _rtld_longjmp -#endif - ENTRY(setjmp) sub REGN(sp), REGN(sp), #(REG_WIDTH * 2) stp REG(0), REGN(lr), [REGN(sp)] @@ -78,7 +73,7 @@ ENTRY(setjmp) /* * Tail-call to save Executive mode state */ - b _rtld_setjmp + b c18n_get_trusted_stk #else RETURN #endif @@ -139,7 +134,7 @@ ENTRY(longjmp) /* * Tail-call to restore Executive mode state */ - b _rtld_longjmp + b c18n_unwind_trusted_stk #else RETURN #endif diff --git a/lib/libgcc_s/Symbol-c18n.map b/lib/libgcc_s/Symbol-c18n.map index 6cddda834561..d9aa2213192d 100644 --- a/lib/libgcc_s/Symbol-c18n.map +++ b/lib/libgcc_s/Symbol-c18n.map @@ -1,5 +1,7 @@ FBSDprivate_1.0 { - _rtld_unw_getcontext; - _rtld_unw_setcontext; - _rtld_unw_getsealer; + c18n_get_trusted_stk; + c18n_unwind_trusted_stk; + c18n_is_enabled; + c18n_is_tramp; + c18n_pop_trusted_stk; }; diff --git a/libexec/rtld-elf/Symbol-c18n.map b/libexec/rtld-elf/Symbol-c18n.map index 2081b927e800..2e7fe32e69b7 100644 --- a/libexec/rtld-elf/Symbol-c18n.map +++ b/libexec/rtld-elf/Symbol-c18n.map @@ -8,9 +8,9 @@ FBSDprivate_1.0 { _rtld_sighandler; _rtld_siginvoke; _rtld_sigaction; - _rtld_setjmp; - _rtld_longjmp; - _rtld_unw_getcontext; - _rtld_unw_setcontext; - _rtld_unw_getsealer; + c18n_get_trusted_stk; + c18n_unwind_trusted_stk; + c18n_is_enabled; + c18n_is_tramp; + c18n_pop_trusted_stk; }; diff --git a/libexec/rtld-elf/aarch64/rtld_c18n_machdep.h b/libexec/rtld-elf/aarch64/rtld_c18n_machdep.h index 5e2607f42f08..bd1330ea55c9 100644 --- a/libexec/rtld-elf/aarch64/rtld_c18n_machdep.h +++ b/libexec/rtld-elf/aarch64/rtld_c18n_machdep.h @@ -133,7 +133,7 @@ set_untrusted_stk(const void *sp) } #endif -struct trusted_frame { +struct compart_state { void *fp; void *pc; /* @@ -145,38 +145,6 @@ struct trusted_frame { * caller made the call. */ void *sp; - /* - * INVARIANT: This field contains the top of the caller's stack when the - * caller was last entered. - */ - void *osp; - /* - * Address of the previous trusted frame - */ - struct trusted_frame *previous; - /* - * Compartment ID of the caller - */ - stk_table_index caller; - /* - * Zeros - */ - uint16_t zeros; - /* - * Compartment ID of the callee - */ - stk_table_index callee; - /* - * Number of return value registers, encoded in enum tramp_ret_args - */ - uint8_t ret_args : 2; - uint16_t reserved : 14; - /* - * This field contains the code address in the trampoline that the - * callee should return to. This is used by trampolines to detect cross- - * compartment tail-calls. - */ - ptraddr_t landing; }; #endif #endif diff --git a/libexec/rtld-elf/rtld_c18n.c b/libexec/rtld-elf/rtld_c18n.c index 3c6a3c8cb3a0..82f1e48018ff 100644 --- a/libexec/rtld-elf/rtld_c18n.c +++ b/libexec/rtld-elf/rtld_c18n.c @@ -87,7 +87,7 @@ _Static_assert( TRUSTED_FRAME_SIZE * sizeof(uintptr_t) == sizeof(struct trusted_frame), "Unexpected struct trusted_frame size"); _Static_assert( - TRUSTED_FRAME_SP_OSP == offsetof(struct trusted_frame, sp), + TRUSTED_FRAME_SP_OSP == offsetof(struct trusted_frame, state.sp), "Unexpected struct trusted_frame member offset"); _Static_assert( TRUSTED_FRAME_PREV == offsetof(struct trusted_frame, previous), @@ -117,8 +117,7 @@ _Static_assert( * Sealers for RTLD privileged information */ static uintptr_t sealer_tcb; -static uintptr_t sealer_jmpbuf; -static uintptr_t sealer_unwbuf; +static uintptr_t sealer_trusted_stk; uintptr_t sealer_pltgot, sealer_tramp; @@ -859,9 +858,19 @@ resolve_untrusted_stk_impl(stk_table_index index) /* * Stack unwinding + * + * APIs exposed to stack unwinders (e.g., libc setjmp/longjmp and libunwind) */ -static void * -unwind_cursor(void) +uintptr_t c18n_get_trusted_stk(uintptr_t, struct trusted_frame **); +uintptr_t c18n_unwind_trusted_stk(uintptr_t, void *, struct trusted_frame *); + +bool c18n_is_enabled(void); +bool c18n_is_tramp(ptraddr_t, struct trusted_frame *); +struct trusted_frame *c18n_pop_trusted_stk(struct compart_state *, + struct trusted_frame *); + +uintptr_t +c18n_get_trusted_stk(uintptr_t ret, struct trusted_frame **buf) { /* * This helper is used by functions like setjmp. Before setjmp is @@ -875,30 +884,14 @@ unwind_cursor(void) * buffer. */ - return (get_trusted_stk()->previous); -} - -uintptr_t _rtld_setjmp(uintptr_t, void **); -uintptr_t _rtld_unw_getcontext(uintptr_t, void **); -uintptr_t _rtld_unw_getcontext_unsealed(uintptr_t, void **); - -uintptr_t -_rtld_setjmp(uintptr_t ret, void **buf) -{ - *buf = cheri_seal(unwind_cursor(), sealer_jmpbuf); - return (ret); -} - -uintptr_t -_rtld_unw_getcontext(uintptr_t ret, void **buf) -{ if (C18N_ENABLED) - *buf = cheri_seal(unwind_cursor(), sealer_unwbuf); + *buf = cheri_seal(get_trusted_stk()->previous, + sealer_trusted_stk); return (ret); } -static uintptr_t -unwind_stack(uintptr_t ret, void *rcsp, struct trusted_frame *target) +uintptr_t +c18n_unwind_trusted_stk(uintptr_t ret, void *rcsp, struct trusted_frame *target) { /* * This helper is used by functions like longjmp. Before longjmp is @@ -920,6 +913,9 @@ unwind_stack(uintptr_t ret, void *rcsp, struct trusted_frame *target) struct trusted_frame *cur, *tf; sigset_t nset, oset; + if (!C18N_ENABLED) + return (ret); + /* * Make the function re-entrant by blocking all signals. */ @@ -927,6 +923,7 @@ unwind_stack(uintptr_t ret, void *rcsp, struct trusted_frame *target) sigprocmask(SIG_SETMASK, &nset, &oset); tf = get_trusted_stk(); + target = cheri_unseal(target, sealer_trusted_stk); if (!cheri_is_subset(tf, target) || tf->previous >= target) { rtld_fdprintf(STDERR_FILENO, @@ -974,7 +971,7 @@ unwind_stack(uintptr_t ret, void *rcsp, struct trusted_frame *target) abort(); } - tf->sp = rcsp; + tf->state.sp = rcsp; tf->osp = *ospp; tf->previous = cur; tf->caller = index; @@ -984,28 +981,25 @@ unwind_stack(uintptr_t ret, void *rcsp, struct trusted_frame *target) return (ret); } -uintptr_t _rtld_longjmp(uintptr_t, void *, void *); -uintptr_t _rtld_unw_setcontext(uintptr_t, void *, void *); - -uintptr_t -_rtld_longjmp(uintptr_t ret, void *rcsp, void *csp) +bool +c18n_is_enabled(void) { - return (unwind_stack(ret, rcsp, cheri_unseal(csp, sealer_jmpbuf))); + return (C18N_ENABLED); } -uintptr_t -_rtld_unw_setcontext(uintptr_t ret, void *rcsp, void *csp) +bool +c18n_is_tramp(ptraddr_t pc, struct trusted_frame *tf) { - if (C18N_ENABLED) - ret = unwind_stack(ret, rcsp, cheri_unseal(csp, sealer_unwbuf)); - return (ret); + tf = cheri_unseal(tf, sealer_trusted_stk); + return (pc == tf->landing); } -uintptr_t _rtld_unw_getsealer(void); -uintptr_t -_rtld_unw_getsealer(void) +struct trusted_frame * +c18n_pop_trusted_stk(struct compart_state *state, struct trusted_frame *tf) { - return (sealer_unwbuf); + tf = cheri_unseal(tf, sealer_trusted_stk); + *state = tf->state; + return (cheri_seal(tf->previous, sealer_trusted_stk)); } /* @@ -1195,9 +1189,9 @@ tramp_hook_impl(int event, const struct tramp_header *hdr, memcpy(ut.sig, C18N_UTRACE_SIG, C18N_UTRACE_SIG_SZ); ut.event = event; ut.symnum = hdr->symnum; - ut.fp = tf->fp; - ut.pc = tf->pc; - ut.sp = tf->sp; + ut.fp = tf->state.fp; + ut.pc = tf->state.pc; + ut.sp = tf->state.sp; ut.osp = tf->osp; ut.previous = tf->previous; memcpy(&ut.fsig, &hdr->sig, sizeof(ut.fsig)); @@ -1616,10 +1610,7 @@ c18n_init2(void) sealer_tcb = cheri_setboundsexact(sealer, 1); sealer += 1; - sealer_jmpbuf = cheri_setboundsexact(sealer, 1); - sealer += 1; - - sealer_unwbuf = cheri_setboundsexact(sealer, 1); + sealer_trusted_stk = cheri_setboundsexact(sealer, 1); sealer += 1; sealer_tramp = cheri_setboundsexact(sealer, C18N_FUNC_SIG_COUNT); @@ -1942,7 +1933,9 @@ _rtld_sighandler_impl(int sig, siginfo_t *info, ucontext_t *ucp, void *nsp) */ ntf = tf - 2; *ntf = (struct trusted_frame) { - .sp = nsp, + .state = (struct compart_state) { + .sp = nsp + }, .osp = osp, .previous = tf, .caller = intr_idx, @@ -1997,7 +1990,7 @@ _rtld_sighandler_impl(int sig, siginfo_t *info, ucontext_t *ucp, void *nsp) * compartment. */ #ifndef __ARM_MORELLO_PURECAP_BENCHMARK_ABI - set_untrusted_stk(ntf->sp); + set_untrusted_stk(ntf->state.sp); #endif } diff --git a/libexec/rtld-elf/rtld_c18n.h b/libexec/rtld-elf/rtld_c18n.h index 9ebe627f98f5..e3aefcd3cdde 100644 --- a/libexec/rtld-elf/rtld_c18n.h +++ b/libexec/rtld-elf/rtld_c18n.h @@ -120,6 +120,48 @@ struct stk_table { #include "rtld_c18n_machdep.h" +struct trusted_frame { + /* + * Architecture-specific callee-saved registers, including fp, sp, and + * the return address + */ + struct compart_state state; + /* + * INVARIANT: This field contains the top of the caller's stack when the + * caller was last entered. + */ + void *osp; + /* + * Address of the previous trusted frame + */ + struct trusted_frame *previous; + /* + * Compartment ID of the caller + */ + stk_table_index caller; + /* + * This padding space must be filled with zeros so that an optimised + * trampoline can use a wide load to load multiple fields of the trusted + * frame and then use a word-sized register to extract the caller field. + */ + uint16_t zeros; + /* + * Compartment ID of the callee + */ + stk_table_index callee; + /* + * Number of return value registers, encoded in enum tramp_ret_args + */ + uint8_t ret_args : 2; + uint16_t reserved : 14; + /* + * This field contains the code address in the trampoline that the + * callee should return to. This is used by trampolines to detect cross- + * compartment tail-calls. + */ + ptraddr_t landing; +}; + struct tcb *c18n_allocate_tcb(struct tcb *); void c18n_free_tcb(void); @@ -217,8 +259,8 @@ func_sig_legal(struct func_sig sig) /* * This macro can only be used in a function directly invoked by a trampoline. */ -#define c18n_return_address() \ - (C18N_ENABLED ? get_trusted_stk()->pc : __builtin_return_address(0)) +#define c18n_return_address() (C18N_ENABLED ? \ + get_trusted_stk()->state.pc : __builtin_return_address(0)) void *_rtld_sandbox_code(void *, struct func_sig); void *_rtld_safebox_code(void *, struct func_sig); diff --git a/libexec/rtld-elf/rtld_c18n_policy.txt b/libexec/rtld-elf/rtld_c18n_policy.txt index d373837982ab..a3840600ddd3 100644 --- a/libexec/rtld-elf/rtld_c18n_policy.txt +++ b/libexec/rtld-elf/rtld_c18n_policy.txt @@ -56,11 +56,15 @@ export to [TCB] _rtld_sighandler _rtld_siginvoke _rtld_sigaction - _rtld_setjmp - _rtld_longjmp + +callee [RTLD] +export to [TCB] +export to [libunwind] + c18n_get_trusted_stk + c18n_unwind_trusted_stk callee [RTLD] export to [libunwind] - _rtld_unw_getcontext - _rtld_unw_setcontext - _rtld_unw_getsealer + c18n_is_enabled + c18n_is_tramp + c18n_pop_trusted_stk