Skip to content

Commit

Permalink
c18n: Expose unified unwinding APIs to setjmp/longjmp and libunwind
Browse files Browse the repository at this point in the history
Previously, libunwind hard-codes knowledge about the layout of the
trusted frame and has read access to the trusted stack. This is fragile
and insecure.

Now, the task of extracting the relevant registers from the trusted
stack is delegated to RTLD, and libunwind no longer has access to the
trusted stack.

The unified unwinding APIs are declared as dl_c18n_* functions in
link.h. setjmp/longjmp have been updated to use them.

The previous API has been retained for compatibility with old libunwind.
  • Loading branch information
dpgao committed Aug 30, 2024
1 parent 53f014c commit f0c2c5d
Show file tree
Hide file tree
Showing 11 changed files with 182 additions and 120 deletions.
47 changes: 24 additions & 23 deletions lib/libc/aarch64/gen/_setjmp.S
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ ENTRY(_setjmp)
ldr x8, .Lmagic
mov REG(9), REGN(sp)
stp REG(8), REG(9), [REG(0)], #(REG_WIDTH * 2)
#ifdef CHERI_LIB_C18N
/* Store the trusted stack pointer */
stp c0, c30, [csp, #-0x20]!
bl dl_c18n_get_trusted_stk
ldp c0, c30, [csp], #0x20
add c0, c0, #REG_WIDTH
#endif

/* Store the general purpose registers and lr */
stp REG(19), REG(20), [REG(0)], #(REG_WIDTH * 2)
Expand All @@ -55,18 +62,8 @@ ENTRY(_setjmp)
#endif

/* Return value */
#ifdef CHERI_LIB_C18N
mov c1, c0
#endif
mov x0, #0
#ifdef CHERI_LIB_C18N
/*
* Tail-call to save Executive mode state
*/
b _rtld_setjmp
#else
RETURN
#endif
.align 3
.Lmagic:
.quad _JB_MAGIC__SETJMP
Expand All @@ -79,12 +76,26 @@ ENTRY(_longjmp)
cmp x8, x9
b.ne botch

#ifdef CHERI_LIB_C18N
/*
* Preserve the arguments in callee-saved registers instead of pushing
* them onto the stack because stack unwinding will switch the stack.
*/
mov c19, c0
mov c20, c1
/* Pass the target untrusted stack pointer and trusted stack pointer */
ldp c0, c1, [c0]
bl dl_c18n_unwind_trusted_stk
mov c0, c19
mov c1, c20
#endif

/* Restore the stack pointer */
ldr REG(8), [REG(0)], #(REG_WIDTH)
#ifdef CHERI_LIB_C18N
mov c2, c8
#else
mov REGN(sp), REG(8)
#ifdef CHERI_LIB_C18N
/* Skip the trusted stack pointer */
add c0, c0, #REG_WIDTH
#endif

/* Restore the general purpose registers and lr */
Expand All @@ -104,19 +115,9 @@ ENTRY(_longjmp)
#endif

/* Load the return value */
#ifdef CHERI_LIB_C18N
mov c3, c0
#endif
cmp x1, #0
csinc x0, x1, xzr, ne
#ifdef CHERI_LIB_C18N
/*
* Tail-call to restore Executive mode state
*/
b _rtld_longjmp
#else
RETURN
#endif

botch:
#ifdef _STANDALONE
Expand Down
52 changes: 24 additions & 28 deletions lib/libc/aarch64/gen/setjmp.S
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,6 @@
#include <machine/setjmp.h>
#include <sys/elf_common.h>

#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)]
Expand All @@ -54,6 +49,13 @@ ENTRY(setjmp)
ldr x8, .Lmagic
mov REG(9), REGN(sp)
stp REG(8), REG(9), [REG(0)], #(REG_WIDTH * 2)
#ifdef CHERI_LIB_C18N
/* Store the trusted stack pointer */
stp c0, c30, [csp, #-0x20]!
bl dl_c18n_get_trusted_stk
ldp c0, c30, [csp], #0x20
add c0, c0, #REG_WIDTH
#endif

/* Store the general purpose registers and lr */
stp REG(19), REG(20), [REG(0)], #(REG_WIDTH * 2)
Expand All @@ -70,24 +72,28 @@ ENTRY(setjmp)
stp d14, d15, [REG(0)], #16

/* Return value */
#ifdef CHERI_LIB_C18N
mov c1, c0
#endif
mov x0, #0
#ifdef CHERI_LIB_C18N
/*
* Tail-call to save Executive mode state
*/
b _rtld_setjmp
#else
RETURN
#endif
.align 3
.Lmagic:
.quad _JB_MAGIC_SETJMP
END(setjmp)

ENTRY(longjmp)
#ifdef CHERI_LIB_C18N
/*
* Preserve the arguments in callee-saved registers instead of pushing
* them onto the stack because stack unwinding will switch the stack.
*/
mov c19, c0
mov c20, c1
/* Pass the target untrusted stack pointer and trusted stack pointer */
ldp c0, c1, [c0, #(REG_WIDTH * 1)]
bl dl_c18n_unwind_trusted_stk
mov c0, c19
mov c1, c20
#endif

sub REGN(sp), REGN(sp), #(REG_WIDTH * 4)
stp REG(0), REGN(lr), [REGN(sp)]
str REG(1), [REGN(sp), #(REG_WIDTH * 2)]
Expand All @@ -110,10 +116,10 @@ ENTRY(longjmp)

/* Restore the stack pointer */
ldr REG(8), [REG(0)], #(REG_WIDTH)
#ifdef CHERI_LIB_C18N
mov c2, c8
#else
mov REGN(sp), REG(8)
#ifdef CHERI_LIB_C18N
/* Skip the trusted stack pointer */
add c0, c0, #REG_WIDTH
#endif

/* Restore the general purpose registers and lr */
Expand All @@ -131,19 +137,9 @@ ENTRY(longjmp)
ldp d14, d15, [REG(0)], #16

/* Load the return value */
#ifdef CHERI_LIB_C18N
mov c3, c0
#endif
cmp x1, #0
csinc x0, x1, xzr, ne
#ifdef CHERI_LIB_C18N
/*
* Tail-call to restore Executive mode state
*/
b _rtld_longjmp
#else
RETURN
#endif

botch:
bl _C_LABEL(longjmperror)
Expand Down
3 changes: 1 addition & 2 deletions lib/libgcc_s/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,9 @@ SRCS+= s_logbl.c
SRCS+= s_scalbnl.c
.endif

# LIBUNWIND_SANDBOX_OTYPES is only supported on aarch64 (Morello).
# c18n is only supported on Morello.
.if ${MACHINE_ABI:Mpurecap} && ${MACHINE_CPUARCH} == "aarch64"
SYMBOL_MAPS+= ${.CURDIR}/Symbol-c18n.map
CFLAGS+= -D_LIBUNWIND_CHERI_C18N_SUPPORT
.endif

.include <bsd.lib.mk>
7 changes: 4 additions & 3 deletions lib/libgcc_s/Symbol-c18n.map
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
FBSDprivate_1.0 {
_rtld_unw_getcontext;
_rtld_unw_setcontext;
_rtld_unw_getsealer;
dl_c18n_get_trusted_stk;
dl_c18n_unwind_trusted_stk;
dl_c18n_is_tramp;
dl_c18n_pop_trusted_stk;
};
8 changes: 4 additions & 4 deletions libexec/rtld-elf/Symbol-c18n.map
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ FBSDprivate_1.0 {
_rtld_setjmp;
_rtld_longjmp;
_rtld_unw_getcontext;
_rtld_unw_getcontext_unsealed;
_rtld_unw_setcontext;
_rtld_unw_setcontext_unsealed;
_rtld_unw_getsealer;
_rtld_safebox_code;
_rtld_sandbox_code;
dl_c18n_get_trusted_stk;
dl_c18n_unwind_trusted_stk;
dl_c18n_is_tramp;
dl_c18n_pop_trusted_stk;
};
3 changes: 3 additions & 0 deletions libexec/rtld-elf/aarch64/rtld_c18n_asm.S
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
* See rtld_c18n.h for an overview of the design.
*/

/*
* XXX: These assembly stubs are kept here for compatibility with old libunwind.
*/
/*
* The _rtld_unw_{get,set}context_epilogue functions are stack unwinding
* helpers. See the 'Stack unwinding' section in rtld_c18n.c.
Expand Down
34 changes: 1 addition & 33 deletions libexec/rtld-elf/aarch64/rtld_c18n_machdep.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ set_untrusted_stk(const void *sp)
}
#endif

struct trusted_frame {
struct dl_c18n_compart_state {
void *fp;
void *pc;
/*
Expand All @@ -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
Loading

0 comments on commit f0c2c5d

Please sign in to comment.