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 authored and bsdjhb committed Dec 10, 2024
1 parent b143311 commit 6959da2
Show file tree
Hide file tree
Showing 14 changed files with 297 additions and 155 deletions.
49 changes: 26 additions & 23 deletions lib/libc/aarch64/gen/_setjmp.S
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ 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]!
mov c0, c30
bl dl_c18n_get_trusted_stack
ldp c1, c30, [csp], #0x20
str c0, [c1], #REG_WIDTH
mov c0, c1
#endif

/* Store the general purpose registers and lr */
stp REG(19), REG(20), [REG(0)], #(REG_WIDTH * 2)
Expand All @@ -55,18 +64,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 +78,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_stack
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 +117,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
54 changes: 26 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,15 @@ 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]!
mov c0, c30
bl dl_c18n_get_trusted_stack
ldp c1, c30, [csp], #0x20
str c0, [c1], #REG_WIDTH
mov c0, c1
#endif

/* Store the general purpose registers and lr */
stp REG(19), REG(20), [REG(0)], #(REG_WIDTH * 2)
Expand All @@ -70,24 +74,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_stack
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 +118,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 +139,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
6 changes: 6 additions & 0 deletions lib/libc/gen/Symbol.map
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ FBSD_1.0 {
dlvsym;
dlinfo;
dl_iterate_phdr;
#if defined(__CHERI_PURE_CAPABILITY__) && defined(__aarch64__)
dl_c18n_get_trusted_stack;
dl_c18n_unwind_trusted_stack;
dl_c18n_is_trampoline;
dl_c18n_pop_trusted_stack;
#endif
drand48;
erand48;
err_set_file;
Expand Down
26 changes: 26 additions & 0 deletions lib/libc/gen/dlfcn.c
Original file line number Diff line number Diff line change
Expand Up @@ -377,4 +377,30 @@ _rtld_is_dlopened(void *arg __unused)
return (0);
}

#if defined(__CHERI_PURE_CAPABILITY__) && defined(__aarch64__)
#pragma weak dl_c18n_get_trusted_stack
void *
dl_c18n_get_trusted_stack(uintptr_t pc __unused) {
return (NULL);
}

#pragma weak dl_c18n_unwind_trusted_stack
void
dl_c18n_unwind_trusted_stack(void *sp __unused, void *target __unused) {
}

#pragma weak dl_c18n_is_trampoline
int
dl_c18n_is_trampoline(uintptr_t pc __unused, void *tfs __unused) {
return (0);
}

#pragma weak dl_c18n_pop_trusted_stack
void *
dl_c18n_pop_trusted_stack(struct dl_c18n_compart_state *state __unused,
void *tfs __unused) {
return (NULL);
}
#endif

#endif /* !defined(IN_LIBDL) || defined(PIC) */
4 changes: 1 addition & 3 deletions lib/libgcc_s/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,8 @@ SRCS+= s_logbl.c
SRCS+= s_scalbnl.c
.endif

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

.include <bsd.lib.mk>
5 changes: 0 additions & 5 deletions lib/libgcc_s/Symbol-c18n.map

This file was deleted.

11 changes: 7 additions & 4 deletions libexec/rtld-elf/Symbol-c18n.map
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ 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;
};

FBSD_1.0 {
dl_c18n_get_trusted_stack;
dl_c18n_unwind_trusted_stack;
dl_c18n_is_trampoline;
dl_c18n_pop_trusted_stack;
};
4 changes: 4 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,10 @@
* See rtld_c18n.h for an overview of the design.
*/

/*
* XXX Dapeng: These assembly stubs are kept here for compatibility with old
* libc and libunwind.
*/
/*
* The _rtld_unw_{get,set}context_epilogue functions are stack unwinding
* helpers. See the 'Stack unwinding' section in rtld_c18n.c.
Expand Down
46 changes: 0 additions & 46 deletions libexec/rtld-elf/aarch64/rtld_c18n_machdep.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,51 +132,5 @@ set_untrusted_stk(const void *sp)
asm ("msr " __XSTRING(UNTRUSTED_STACK) ", %0" :: "C" (sp));
}
#endif

struct trusted_frame {
void *fp;
void *pc;
/*
* c19 to c28
*/
void *regs[10];
/*
* INVARIANT: This field contains the top of the caller's stack when the
* 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 6959da2

Please sign in to comment.