Skip to content

Commit 530305d

Browse files
committed
c18n: Expose unified unwinding APIs to setjmp/longjmp and libunwind
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.
1 parent 53f014c commit 530305d

File tree

12 files changed

+150
-229
lines changed

12 files changed

+150
-229
lines changed

lib/libc/aarch64/gen/_setjmp.S

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ ENTRY(_setjmp)
3737
ldr x8, .Lmagic
3838
mov REG(9), REGN(sp)
3939
stp REG(8), REG(9), [REG(0)], #(REG_WIDTH * 2)
40+
#ifdef CHERI_LIB_C18N
41+
/* Allocate space to store the trusted stack pointer */
42+
mov c1, c0
43+
add c0, c0, #REG_WIDTH
44+
#endif
4045

4146
/* Store the general purpose registers and lr */
4247
stp REG(19), REG(20), [REG(0)], #(REG_WIDTH * 2)
@@ -55,15 +60,10 @@ ENTRY(_setjmp)
5560
#endif
5661

5762
/* Return value */
58-
#ifdef CHERI_LIB_C18N
59-
mov c1, c0
60-
#endif
6163
mov x0, #0
6264
#ifdef CHERI_LIB_C18N
63-
/*
64-
* Tail-call to save Executive mode state
65-
*/
66-
b _rtld_setjmp
65+
/* Tail-call to save the trusted stack pointer */
66+
b dl_c18n_get_trusted_stk
6767
#else
6868
RETURN
6969
#endif
@@ -79,12 +79,18 @@ ENTRY(_longjmp)
7979
cmp x8, x9
8080
b.ne botch
8181

82+
#ifdef CHERI_LIB_C18N
83+
/* Pass the target untrusted stack pointer and trusted stack pointer */
84+
ldp c2, c3, [c0]
85+
bl dl_c18n_unwind_trusted_stk
86+
#endif
87+
8288
/* Restore the stack pointer */
8389
ldr REG(8), [REG(0)], #(REG_WIDTH)
84-
#ifdef CHERI_LIB_C18N
85-
mov c2, c8
86-
#else
8790
mov REGN(sp), REG(8)
91+
#ifdef CHERI_LIB_C18N
92+
/* Skip the trusted stack pointer */
93+
add c0, c0, #REG_WIDTH
8894
#endif
8995

9096
/* Restore the general purpose registers and lr */
@@ -104,19 +110,9 @@ ENTRY(_longjmp)
104110
#endif
105111

106112
/* Load the return value */
107-
#ifdef CHERI_LIB_C18N
108-
mov c3, c0
109-
#endif
110113
cmp x1, #0
111114
csinc x0, x1, xzr, ne
112-
#ifdef CHERI_LIB_C18N
113-
/*
114-
* Tail-call to restore Executive mode state
115-
*/
116-
b _rtld_longjmp
117-
#else
118115
RETURN
119-
#endif
120116

121117
botch:
122118
#ifdef _STANDALONE

lib/libc/aarch64/gen/setjmp.S

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,6 @@
3232
#include <machine/setjmp.h>
3333
#include <sys/elf_common.h>
3434

35-
#ifdef CHERI_LIB_C18N
36-
.weak _rtld_setjmp
37-
.weak _rtld_longjmp
38-
#endif
39-
4035
ENTRY(setjmp)
4136
sub REGN(sp), REGN(sp), #(REG_WIDTH * 2)
4237
stp REG(0), REGN(lr), [REGN(sp)]
@@ -54,6 +49,11 @@ ENTRY(setjmp)
5449
ldr x8, .Lmagic
5550
mov REG(9), REGN(sp)
5651
stp REG(8), REG(9), [REG(0)], #(REG_WIDTH * 2)
52+
#ifdef CHERI_LIB_C18N
53+
/* Allocate space to store the trusted stack pointer */
54+
mov c1, c0
55+
add c0, c0, #REG_WIDTH
56+
#endif
5757

5858
/* Store the general purpose registers and lr */
5959
stp REG(19), REG(20), [REG(0)], #(REG_WIDTH * 2)
@@ -70,15 +70,10 @@ ENTRY(setjmp)
7070
stp d14, d15, [REG(0)], #16
7171

7272
/* Return value */
73-
#ifdef CHERI_LIB_C18N
74-
mov c1, c0
75-
#endif
7673
mov x0, #0
7774
#ifdef CHERI_LIB_C18N
78-
/*
79-
* Tail-call to save Executive mode state
80-
*/
81-
b _rtld_setjmp
75+
/* Tail-call to save the trusted stack pointer */
76+
b dl_c18n_get_trusted_stk
8277
#else
8378
RETURN
8479
#endif
@@ -88,6 +83,12 @@ ENTRY(setjmp)
8883
END(setjmp)
8984

9085
ENTRY(longjmp)
86+
#ifdef CHERI_LIB_C18N
87+
/* Pass the target untrusted stack pointer and trusted stack pointer */
88+
ldp c2, c3, [c0, #(REG_WIDTH * 1)]
89+
bl dl_c18n_unwind_trusted_stk
90+
#endif
91+
9192
sub REGN(sp), REGN(sp), #(REG_WIDTH * 4)
9293
stp REG(0), REGN(lr), [REGN(sp)]
9394
str REG(1), [REGN(sp), #(REG_WIDTH * 2)]
@@ -110,10 +111,10 @@ ENTRY(longjmp)
110111

111112
/* Restore the stack pointer */
112113
ldr REG(8), [REG(0)], #(REG_WIDTH)
113-
#ifdef CHERI_LIB_C18N
114-
mov c2, c8
115-
#else
116114
mov REGN(sp), REG(8)
115+
#ifdef CHERI_LIB_C18N
116+
/* Skip the trusted stack pointer */
117+
add c0, c0, #REG_WIDTH
117118
#endif
118119

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

133134
/* Load the return value */
134-
#ifdef CHERI_LIB_C18N
135-
mov c3, c0
136-
#endif
137135
cmp x1, #0
138136
csinc x0, x1, xzr, ne
139-
#ifdef CHERI_LIB_C18N
140-
/*
141-
* Tail-call to restore Executive mode state
142-
*/
143-
b _rtld_longjmp
144-
#else
145137
RETURN
146-
#endif
147138

148139
botch:
149140
bl _C_LABEL(longjmperror)

lib/libgcc_s/Makefile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,9 @@ SRCS+= s_logbl.c
5353
SRCS+= s_scalbnl.c
5454
.endif
5555

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

6261
.include <bsd.lib.mk>

lib/libgcc_s/Symbol-c18n.map

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
FBSDprivate_1.0 {
2-
_rtld_unw_getcontext;
3-
_rtld_unw_setcontext;
4-
_rtld_unw_getsealer;
2+
dl_c18n_get_trusted_stk;
3+
dl_c18n_unwind_trusted_stk;
4+
dl_c18n_is_tramp;
5+
dl_c18n_pop_trusted_stk;
56
};

libexec/rtld-elf/Symbol-c18n.map

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,8 @@ FBSDprivate_1.0 {
88
_rtld_sighandler;
99
_rtld_siginvoke;
1010
_rtld_sigaction;
11-
_rtld_setjmp;
12-
_rtld_longjmp;
13-
_rtld_unw_getcontext;
14-
_rtld_unw_getcontext_unsealed;
15-
_rtld_unw_setcontext;
16-
_rtld_unw_setcontext_unsealed;
17-
_rtld_unw_getsealer;
18-
_rtld_safebox_code;
19-
_rtld_sandbox_code;
11+
dl_c18n_get_trusted_stk;
12+
dl_c18n_unwind_trusted_stk;
13+
dl_c18n_is_tramp;
14+
dl_c18n_pop_trusted_stk;
2015
};

libexec/rtld-elf/aarch64/rtld_c18n_asm.S

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -34,46 +34,6 @@
3434
* See rtld_c18n.h for an overview of the design.
3535
*/
3636

37-
/*
38-
* The _rtld_unw_{get,set}context_epilogue functions are stack unwinding
39-
* helpers. See the 'Stack unwinding' section in rtld_c18n.c.
40-
*/
41-
ENTRY(_rtld_unw_getcontext_epilogue)
42-
/*
43-
* FIXME: llvm-libunwind specific ABI. This should be better specified.
44-
*/
45-
mov c2, csp
46-
str c2, [c1]
47-
RETURN
48-
END(_rtld_unw_getcontext_epilogue)
49-
50-
/*
51-
* XXX: If compartmentalisation is not enabled, _rtld_unw_setcontext_ptr is NULL
52-
* and we simply restore a few registers and return via retr (back to Restricted
53-
* mode). Otherwise, call _rtld_unw_setcontext_impl via a trampoline.
54-
*/
55-
ENTRY(_rtld_unw_setcontext)
56-
ldr c16, _rtld_unw_setcontext_ptr
57-
cbnz w16, 1f
58-
/*
59-
* FIXME: llvm-libunwind specific ABI. This should be better specified.
60-
*/
61-
mov c16, c2
62-
ldp c2, c3, [c3, #(-0x210 + 0x20)]
63-
mov csp, c16
64-
#ifdef __ARM_MORELLO_PURECAP_BENCHMARK_ABI
65-
RETURN
66-
#else
67-
retr c30
68-
#endif
69-
1:
70-
#ifdef __ARM_MORELLO_PURECAP_BENCHMARK_ABI
71-
br x16
72-
#else
73-
br c16
74-
#endif
75-
END(_rtld_unw_setcontext)
76-
7737
/*
7838
* The _rtld_sighandler function is the actual signal handler passed to the
7939
* kernel when the user calls sigaction. It dispatches the signal to the

libexec/rtld-elf/aarch64/rtld_c18n_machdep.h

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ set_untrusted_stk(const void *sp)
133133
}
134134
#endif
135135

136-
struct trusted_frame {
136+
struct dl_c18n_compart_state {
137137
void *fp;
138138
void *pc;
139139
/*
@@ -145,38 +145,6 @@ struct trusted_frame {
145145
* caller made the call.
146146
*/
147147
void *sp;
148-
/*
149-
* INVARIANT: This field contains the top of the caller's stack when the
150-
* caller was last entered.
151-
*/
152-
void *osp;
153-
/*
154-
* Address of the previous trusted frame
155-
*/
156-
struct trusted_frame *previous;
157-
/*
158-
* Compartment ID of the caller
159-
*/
160-
stk_table_index caller;
161-
/*
162-
* Zeros
163-
*/
164-
uint16_t zeros;
165-
/*
166-
* Compartment ID of the callee
167-
*/
168-
stk_table_index callee;
169-
/*
170-
* Number of return value registers, encoded in enum tramp_ret_args
171-
*/
172-
uint8_t ret_args : 2;
173-
uint16_t reserved : 14;
174-
/*
175-
* This field contains the code address in the trampoline that the
176-
* callee should return to. This is used by trampolines to detect cross-
177-
* compartment tail-calls.
178-
*/
179-
ptraddr_t landing;
180148
};
181149
#endif
182150
#endif

libexec/rtld-elf/rtld.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1066,7 +1066,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
10661066

10671067
#ifdef CHERI_LIB_C18N
10681068
if (C18N_ENABLED)
1069-
c18n_init2(&obj_rtld);
1069+
c18n_init2();
10701070
#endif
10711071

10721072
/*

0 commit comments

Comments
 (0)