1*e3723e1fSApple OSS Distributions // Copyright (c) 2016-2020 Apple Computer, Inc. All rights reserved.
2*e3723e1fSApple OSS Distributions
3*e3723e1fSApple OSS Distributions #include <CoreSymbolication/CoreSymbolication.h>
4*e3723e1fSApple OSS Distributions #include <darwintest.h>
5*e3723e1fSApple OSS Distributions #include <dispatch/dispatch.h>
6*e3723e1fSApple OSS Distributions #include <execinfo.h>
7*e3723e1fSApple OSS Distributions #include <pthread.h>
8*e3723e1fSApple OSS Distributions #include <ptrauth.h>
9*e3723e1fSApple OSS Distributions #include <mach/mach.h>
10*e3723e1fSApple OSS Distributions #include <stdalign.h>
11*e3723e1fSApple OSS Distributions #include <sys/mman.h>
12*e3723e1fSApple OSS Distributions #include <sys/sysctl.h>
13*e3723e1fSApple OSS Distributions
14*e3723e1fSApple OSS Distributions T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true));
15*e3723e1fSApple OSS Distributions
16*e3723e1fSApple OSS Distributions enum test_scenario {
17*e3723e1fSApple OSS Distributions USER_SCENARIO = 0,
18*e3723e1fSApple OSS Distributions RESUME_SCENARIO = 1,
19*e3723e1fSApple OSS Distributions };
20*e3723e1fSApple OSS Distributions
21*e3723e1fSApple OSS Distributions enum kernel_test_scenario {
22*e3723e1fSApple OSS Distributions PACK_UNPACK_SCENARIO = 0,
23*e3723e1fSApple OSS Distributions PACKED_SCENARIO = 1,
24*e3723e1fSApple OSS Distributions };
25*e3723e1fSApple OSS Distributions
26*e3723e1fSApple OSS Distributions #define USER_FRAMES (12)
27*e3723e1fSApple OSS Distributions #define MAX_SYSCALL_SETUP_FRAMES (3)
28*e3723e1fSApple OSS Distributions #define NON_RECURSE_FRAMES (2)
29*e3723e1fSApple OSS Distributions #define ASYNC_FRAMES (2 + NON_RECURSE_FRAMES)
30*e3723e1fSApple OSS Distributions
31*e3723e1fSApple OSS Distributions static const char *user_bt[USER_FRAMES] = {
32*e3723e1fSApple OSS Distributions "backtrace_thread",
33*e3723e1fSApple OSS Distributions "recurse_a", "recurse_b", "recurse_a", "recurse_b",
34*e3723e1fSApple OSS Distributions "recurse_a", "recurse_b", "recurse_a", "recurse_b",
35*e3723e1fSApple OSS Distributions "recurse_a", "recurse_b", "expect_callstack",
36*e3723e1fSApple OSS Distributions };
37*e3723e1fSApple OSS Distributions
38*e3723e1fSApple OSS Distributions struct callstack_exp {
39*e3723e1fSApple OSS Distributions bool in_syscall_setup;
40*e3723e1fSApple OSS Distributions unsigned int syscall_frames;
41*e3723e1fSApple OSS Distributions const char **callstack;
42*e3723e1fSApple OSS Distributions size_t callstack_len;
43*e3723e1fSApple OSS Distributions unsigned int nchecked;
44*e3723e1fSApple OSS Distributions };
45*e3723e1fSApple OSS Distributions
46*e3723e1fSApple OSS Distributions #if __has_feature(ptrauth_calls)
47*e3723e1fSApple OSS Distributions #define __ptrauth_swift_async_context_parent \
48*e3723e1fSApple OSS Distributions __ptrauth(ptrauth_key_process_independent_data, 1, 0xbda2)
49*e3723e1fSApple OSS Distributions #define __ptrauth_swift_async_context_resume \
50*e3723e1fSApple OSS Distributions __ptrauth(ptrauth_key_function_pointer, 1, 0xd707)
51*e3723e1fSApple OSS Distributions #else
52*e3723e1fSApple OSS Distributions #define __ptrauth_swift_async_context_parent
53*e3723e1fSApple OSS Distributions #define __ptrauth_swift_async_context_resume
54*e3723e1fSApple OSS Distributions #endif
55*e3723e1fSApple OSS Distributions
56*e3723e1fSApple OSS Distributions // This struct fakes the Swift AsyncContext struct which is used by
57*e3723e1fSApple OSS Distributions // the Swift concurrency runtime. We only care about the first 2 fields.
58*e3723e1fSApple OSS Distributions struct fake_async_context {
59*e3723e1fSApple OSS Distributions struct fake_async_context* __ptrauth_swift_async_context_parent next;
60*e3723e1fSApple OSS Distributions void(*__ptrauth_swift_async_context_resume resume_pc)(void);
61*e3723e1fSApple OSS Distributions };
62*e3723e1fSApple OSS Distributions
63*e3723e1fSApple OSS Distributions static void
level1_func()64*e3723e1fSApple OSS Distributions level1_func()
65*e3723e1fSApple OSS Distributions {
66*e3723e1fSApple OSS Distributions }
67*e3723e1fSApple OSS Distributions static void
level2_func()68*e3723e1fSApple OSS Distributions level2_func()
69*e3723e1fSApple OSS Distributions {
70*e3723e1fSApple OSS Distributions }
71*e3723e1fSApple OSS Distributions
72*e3723e1fSApple OSS Distributions // Create a chain of fake async contexts
73*e3723e1fSApple OSS Distributions static alignas(16) struct fake_async_context level1 = { 0, level1_func };
74*e3723e1fSApple OSS Distributions static alignas(16) struct fake_async_context level2 = { &level1, level2_func };
75*e3723e1fSApple OSS Distributions
76*e3723e1fSApple OSS Distributions static const char *async_bt[ASYNC_FRAMES] = {
77*e3723e1fSApple OSS Distributions "level1_func", "level2_func", "backtrace_thread_async",
78*e3723e1fSApple OSS Distributions "expect_async_callstack",
79*e3723e1fSApple OSS Distributions };
80*e3723e1fSApple OSS Distributions
81*e3723e1fSApple OSS Distributions static void
expect_frame(struct callstack_exp * cs,CSSymbolRef symbol,unsigned long addr,unsigned int bt_idx)82*e3723e1fSApple OSS Distributions expect_frame(struct callstack_exp *cs, CSSymbolRef symbol,
83*e3723e1fSApple OSS Distributions unsigned long addr, unsigned int bt_idx)
84*e3723e1fSApple OSS Distributions {
85*e3723e1fSApple OSS Distributions if (CSIsNull(symbol)) {
86*e3723e1fSApple OSS Distributions if (!cs->in_syscall_setup) {
87*e3723e1fSApple OSS Distributions T_FAIL("invalid symbol for address %#lx at frame %d", addr,
88*e3723e1fSApple OSS Distributions bt_idx);
89*e3723e1fSApple OSS Distributions }
90*e3723e1fSApple OSS Distributions return;
91*e3723e1fSApple OSS Distributions }
92*e3723e1fSApple OSS Distributions
93*e3723e1fSApple OSS Distributions const char *name = CSSymbolGetName(symbol);
94*e3723e1fSApple OSS Distributions if (name) {
95*e3723e1fSApple OSS Distributions if (cs->in_syscall_setup) {
96*e3723e1fSApple OSS Distributions if (strcmp(name, cs->callstack[cs->callstack_len - 1]) == 0) {
97*e3723e1fSApple OSS Distributions cs->in_syscall_setup = false;
98*e3723e1fSApple OSS Distributions cs->syscall_frames = bt_idx;
99*e3723e1fSApple OSS Distributions T_LOG("found start of controlled stack at frame %u, expected "
100*e3723e1fSApple OSS Distributions "index %zu", cs->syscall_frames, cs->callstack_len - 1);
101*e3723e1fSApple OSS Distributions } else {
102*e3723e1fSApple OSS Distributions T_LOG("found syscall setup symbol %s at frame %u", name,
103*e3723e1fSApple OSS Distributions bt_idx);
104*e3723e1fSApple OSS Distributions }
105*e3723e1fSApple OSS Distributions }
106*e3723e1fSApple OSS Distributions if (!cs->in_syscall_setup) {
107*e3723e1fSApple OSS Distributions if (cs->nchecked >= cs->callstack_len) {
108*e3723e1fSApple OSS Distributions T_LOG("frame %2u: skipping system frame %s", bt_idx, name);
109*e3723e1fSApple OSS Distributions } else {
110*e3723e1fSApple OSS Distributions size_t frame_idx = cs->callstack_len - cs->nchecked - 1;
111*e3723e1fSApple OSS Distributions T_EXPECT_EQ_STR(name, cs->callstack[frame_idx],
112*e3723e1fSApple OSS Distributions "frame %2zu: saw '%s', expected '%s'",
113*e3723e1fSApple OSS Distributions frame_idx, name, cs->callstack[frame_idx]);
114*e3723e1fSApple OSS Distributions }
115*e3723e1fSApple OSS Distributions cs->nchecked++;
116*e3723e1fSApple OSS Distributions }
117*e3723e1fSApple OSS Distributions } else {
118*e3723e1fSApple OSS Distributions if (!cs->in_syscall_setup) {
119*e3723e1fSApple OSS Distributions T_ASSERT_NOTNULL(name, NULL, "symbol should not be NULL");
120*e3723e1fSApple OSS Distributions }
121*e3723e1fSApple OSS Distributions }
122*e3723e1fSApple OSS Distributions }
123*e3723e1fSApple OSS Distributions
124*e3723e1fSApple OSS Distributions static bool
is_kernel_64_bit(void)125*e3723e1fSApple OSS Distributions is_kernel_64_bit(void)
126*e3723e1fSApple OSS Distributions {
127*e3723e1fSApple OSS Distributions static dispatch_once_t k64_once;
128*e3723e1fSApple OSS Distributions static bool k64 = false;
129*e3723e1fSApple OSS Distributions dispatch_once(&k64_once, ^{
130*e3723e1fSApple OSS Distributions int errb;
131*e3723e1fSApple OSS Distributions int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, 0 /* kernproc */ };
132*e3723e1fSApple OSS Distributions
133*e3723e1fSApple OSS Distributions struct kinfo_proc kp;
134*e3723e1fSApple OSS Distributions size_t len = sizeof(kp);
135*e3723e1fSApple OSS Distributions
136*e3723e1fSApple OSS Distributions errb = sysctl(mib, sizeof(mib) / sizeof(mib[0]), &kp, &len, NULL, 0);
137*e3723e1fSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(errb,
138*e3723e1fSApple OSS Distributions "sysctl({ CTL_KERN, KERN_PROC, KERN_PROC_PID, 0})");
139*e3723e1fSApple OSS Distributions
140*e3723e1fSApple OSS Distributions k64 = kp.kp_proc.p_flag & P_LP64;
141*e3723e1fSApple OSS Distributions T_LOG("executing with a %s-bit kernel", k64 ? "64" : "32");
142*e3723e1fSApple OSS Distributions });
143*e3723e1fSApple OSS Distributions return k64;
144*e3723e1fSApple OSS Distributions }
145*e3723e1fSApple OSS Distributions
146*e3723e1fSApple OSS Distributions // Use an extra, non-inlineable function so that any frames after expect_stack
147*e3723e1fSApple OSS Distributions // can be safely ignored. This insulates the test from changes in how syscalls
148*e3723e1fSApple OSS Distributions // are called by Libc and the kernel.
149*e3723e1fSApple OSS Distributions static void __attribute__((noinline, not_tail_called))
backtrace_current_thread_wrapper(enum test_scenario scenario,uint64_t * bt,size_t * bt_filled)150*e3723e1fSApple OSS Distributions backtrace_current_thread_wrapper(enum test_scenario scenario, uint64_t *bt,
151*e3723e1fSApple OSS Distributions size_t *bt_filled)
152*e3723e1fSApple OSS Distributions {
153*e3723e1fSApple OSS Distributions int ret = sysctlbyname("kern.backtrace.user", bt, bt_filled, NULL,
154*e3723e1fSApple OSS Distributions scenario);
155*e3723e1fSApple OSS Distributions getpid(); // Really prevent tail calls.
156*e3723e1fSApple OSS Distributions if (ret == -1 && errno == ENOENT) {
157*e3723e1fSApple OSS Distributions T_SKIP("release kernel: kern.backtrace.user sysctl returned ENOENT");
158*e3723e1fSApple OSS Distributions }
159*e3723e1fSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "sysctlbyname(\"kern.backtrace.user\")");
160*e3723e1fSApple OSS Distributions T_LOG("kernel returned %zu frame backtrace", *bt_filled);
161*e3723e1fSApple OSS Distributions }
162*e3723e1fSApple OSS Distributions
163*e3723e1fSApple OSS Distributions static CSSymbolicatorRef
get_symbolicator(void)164*e3723e1fSApple OSS Distributions get_symbolicator(void)
165*e3723e1fSApple OSS Distributions {
166*e3723e1fSApple OSS Distributions static CSSymbolicatorRef user_symb;
167*e3723e1fSApple OSS Distributions static dispatch_once_t expect_stack_once;
168*e3723e1fSApple OSS Distributions dispatch_once(&expect_stack_once, ^{
169*e3723e1fSApple OSS Distributions user_symb = CSSymbolicatorCreateWithTask(mach_task_self());
170*e3723e1fSApple OSS Distributions T_QUIET; T_ASSERT_FALSE(CSIsNull(user_symb), NULL);
171*e3723e1fSApple OSS Distributions T_QUIET; T_ASSERT_TRUE(CSSymbolicatorIsTaskValid(user_symb), NULL);
172*e3723e1fSApple OSS Distributions });
173*e3723e1fSApple OSS Distributions return user_symb;
174*e3723e1fSApple OSS Distributions }
175*e3723e1fSApple OSS Distributions
176*e3723e1fSApple OSS Distributions static void __attribute__((noinline, not_tail_called))
expect_callstack(enum test_scenario scenario)177*e3723e1fSApple OSS Distributions expect_callstack(enum test_scenario scenario)
178*e3723e1fSApple OSS Distributions {
179*e3723e1fSApple OSS Distributions uint64_t bt[USER_FRAMES + MAX_SYSCALL_SETUP_FRAMES] = { 0 };
180*e3723e1fSApple OSS Distributions
181*e3723e1fSApple OSS Distributions CSSymbolicatorRef user_symb = get_symbolicator();
182*e3723e1fSApple OSS Distributions size_t bt_filled = USER_FRAMES + MAX_SYSCALL_SETUP_FRAMES;
183*e3723e1fSApple OSS Distributions backtrace_current_thread_wrapper(scenario, bt, &bt_filled);
184*e3723e1fSApple OSS Distributions
185*e3723e1fSApple OSS Distributions unsigned int bt_len = (unsigned int)bt_filled;
186*e3723e1fSApple OSS Distributions T_EXPECT_GE(bt_len, (unsigned int)USER_FRAMES,
187*e3723e1fSApple OSS Distributions "at least %u frames should be present in backtrace", USER_FRAMES);
188*e3723e1fSApple OSS Distributions T_EXPECT_LE(bt_len, (unsigned int)USER_FRAMES + MAX_SYSCALL_SETUP_FRAMES,
189*e3723e1fSApple OSS Distributions "at most %u frames should be present in backtrace",
190*e3723e1fSApple OSS Distributions USER_FRAMES + MAX_SYSCALL_SETUP_FRAMES);
191*e3723e1fSApple OSS Distributions
192*e3723e1fSApple OSS Distributions struct callstack_exp callstack = {
193*e3723e1fSApple OSS Distributions .in_syscall_setup = true,
194*e3723e1fSApple OSS Distributions .syscall_frames = 0,
195*e3723e1fSApple OSS Distributions .callstack = user_bt,
196*e3723e1fSApple OSS Distributions .callstack_len = USER_FRAMES,
197*e3723e1fSApple OSS Distributions .nchecked = 0,
198*e3723e1fSApple OSS Distributions };
199*e3723e1fSApple OSS Distributions for (unsigned int i = 0; i < bt_len; i++) {
200*e3723e1fSApple OSS Distributions uintptr_t addr;
201*e3723e1fSApple OSS Distributions #if !defined(__LP64__)
202*e3723e1fSApple OSS Distributions // Backtrace frames come out as kernel words; convert them back to user
203*e3723e1fSApple OSS Distributions // uintptr_t for 32-bit processes.
204*e3723e1fSApple OSS Distributions if (is_kernel_64_bit()) {
205*e3723e1fSApple OSS Distributions addr = (uintptr_t)(bt[i]);
206*e3723e1fSApple OSS Distributions } else {
207*e3723e1fSApple OSS Distributions addr = (uintptr_t)(((uint32_t *)bt)[i]);
208*e3723e1fSApple OSS Distributions }
209*e3723e1fSApple OSS Distributions #else // defined(__LP32__)
210*e3723e1fSApple OSS Distributions addr = (uintptr_t)bt[i];
211*e3723e1fSApple OSS Distributions #endif // defined(__LP32__)
212*e3723e1fSApple OSS Distributions
213*e3723e1fSApple OSS Distributions CSSymbolRef symbol = CSSymbolicatorGetSymbolWithAddressAtTime(
214*e3723e1fSApple OSS Distributions user_symb, addr, kCSNow);
215*e3723e1fSApple OSS Distributions expect_frame(&callstack, symbol, addr, i);
216*e3723e1fSApple OSS Distributions }
217*e3723e1fSApple OSS Distributions
218*e3723e1fSApple OSS Distributions T_EXPECT_GE(callstack.nchecked, USER_FRAMES,
219*e3723e1fSApple OSS Distributions "checked enough frames for correct symbols");
220*e3723e1fSApple OSS Distributions }
221*e3723e1fSApple OSS Distributions
222*e3723e1fSApple OSS Distributions static int __attribute__((noinline, not_tail_called))
223*e3723e1fSApple OSS Distributions recurse_a(enum test_scenario, unsigned int frames);
224*e3723e1fSApple OSS Distributions static int __attribute__((noinline, not_tail_called))
225*e3723e1fSApple OSS Distributions recurse_b(enum test_scenario, unsigned int frames);
226*e3723e1fSApple OSS Distributions
227*e3723e1fSApple OSS Distributions static int __attribute__((noinline, not_tail_called))
recurse_a(enum test_scenario scenario,unsigned int frames)228*e3723e1fSApple OSS Distributions recurse_a(enum test_scenario scenario, unsigned int frames)
229*e3723e1fSApple OSS Distributions {
230*e3723e1fSApple OSS Distributions if (frames == 1) {
231*e3723e1fSApple OSS Distributions expect_callstack(scenario);
232*e3723e1fSApple OSS Distributions getpid(); // Really prevent tail calls.
233*e3723e1fSApple OSS Distributions return 0;
234*e3723e1fSApple OSS Distributions }
235*e3723e1fSApple OSS Distributions
236*e3723e1fSApple OSS Distributions return recurse_b(scenario, frames - 1) + 1;
237*e3723e1fSApple OSS Distributions }
238*e3723e1fSApple OSS Distributions
239*e3723e1fSApple OSS Distributions static int __attribute__((noinline, not_tail_called))
recurse_b(enum test_scenario scenario,unsigned int frames)240*e3723e1fSApple OSS Distributions recurse_b(enum test_scenario scenario, unsigned int frames)
241*e3723e1fSApple OSS Distributions {
242*e3723e1fSApple OSS Distributions if (frames == 1) {
243*e3723e1fSApple OSS Distributions expect_callstack(scenario);
244*e3723e1fSApple OSS Distributions getpid(); // Really prevent tail calls.
245*e3723e1fSApple OSS Distributions return 0;
246*e3723e1fSApple OSS Distributions }
247*e3723e1fSApple OSS Distributions
248*e3723e1fSApple OSS Distributions return recurse_a(scenario, frames - 1) + 1;
249*e3723e1fSApple OSS Distributions }
250*e3723e1fSApple OSS Distributions
251*e3723e1fSApple OSS Distributions static void __attribute__((noinline, not_tail_called))
expect_async_callstack(void)252*e3723e1fSApple OSS Distributions expect_async_callstack(void)
253*e3723e1fSApple OSS Distributions {
254*e3723e1fSApple OSS Distributions uint64_t bt[ASYNC_FRAMES + MAX_SYSCALL_SETUP_FRAMES] = { 0 };
255*e3723e1fSApple OSS Distributions
256*e3723e1fSApple OSS Distributions CSSymbolicatorRef user_symb = get_symbolicator();
257*e3723e1fSApple OSS Distributions size_t bt_filled = ASYNC_FRAMES + MAX_SYSCALL_SETUP_FRAMES;
258*e3723e1fSApple OSS Distributions backtrace_current_thread_wrapper(USER_SCENARIO, bt, &bt_filled);
259*e3723e1fSApple OSS Distributions
260*e3723e1fSApple OSS Distributions unsigned int bt_len = (unsigned int)bt_filled;
261*e3723e1fSApple OSS Distributions T_EXPECT_GE(bt_len, (unsigned int)ASYNC_FRAMES,
262*e3723e1fSApple OSS Distributions "at least %u frames should be present in backtrace", ASYNC_FRAMES);
263*e3723e1fSApple OSS Distributions T_EXPECT_LE(bt_len, (unsigned int)ASYNC_FRAMES + MAX_SYSCALL_SETUP_FRAMES,
264*e3723e1fSApple OSS Distributions "at most %u frames should be present in backtrace",
265*e3723e1fSApple OSS Distributions ASYNC_FRAMES + MAX_SYSCALL_SETUP_FRAMES);
266*e3723e1fSApple OSS Distributions
267*e3723e1fSApple OSS Distributions struct callstack_exp callstack = {
268*e3723e1fSApple OSS Distributions .in_syscall_setup = true,
269*e3723e1fSApple OSS Distributions .syscall_frames = 0,
270*e3723e1fSApple OSS Distributions .callstack = async_bt,
271*e3723e1fSApple OSS Distributions .callstack_len = ASYNC_FRAMES,
272*e3723e1fSApple OSS Distributions .nchecked = 0,
273*e3723e1fSApple OSS Distributions };
274*e3723e1fSApple OSS Distributions for (unsigned int i = 0; i < bt_len; i++) {
275*e3723e1fSApple OSS Distributions uintptr_t addr;
276*e3723e1fSApple OSS Distributions #if !defined(__LP64__)
277*e3723e1fSApple OSS Distributions // Backtrace frames come out as kernel words; convert them back to user
278*e3723e1fSApple OSS Distributions // uintptr_t for 32-bit processes.
279*e3723e1fSApple OSS Distributions if (is_kernel_64_bit()) {
280*e3723e1fSApple OSS Distributions addr = (uintptr_t)(bt[i]);
281*e3723e1fSApple OSS Distributions } else {
282*e3723e1fSApple OSS Distributions addr = (uintptr_t)(((uint32_t *)bt)[i]);
283*e3723e1fSApple OSS Distributions }
284*e3723e1fSApple OSS Distributions #else // defined(__LP32__)
285*e3723e1fSApple OSS Distributions addr = (uintptr_t)bt[i];
286*e3723e1fSApple OSS Distributions #endif // defined(__LP32__)
287*e3723e1fSApple OSS Distributions
288*e3723e1fSApple OSS Distributions CSSymbolRef symbol = CSSymbolicatorGetSymbolWithAddressAtTime(
289*e3723e1fSApple OSS Distributions user_symb, addr, kCSNow);
290*e3723e1fSApple OSS Distributions expect_frame(&callstack, symbol, addr, i);
291*e3723e1fSApple OSS Distributions }
292*e3723e1fSApple OSS Distributions
293*e3723e1fSApple OSS Distributions T_EXPECT_GE(callstack.nchecked, ASYNC_FRAMES,
294*e3723e1fSApple OSS Distributions "checked enough frames for correct symbols");
295*e3723e1fSApple OSS Distributions }
296*e3723e1fSApple OSS Distributions
297*e3723e1fSApple OSS Distributions static void *
backtrace_thread_async(void * __unused arg)298*e3723e1fSApple OSS Distributions backtrace_thread_async(void * __unused arg)
299*e3723e1fSApple OSS Distributions {
300*e3723e1fSApple OSS Distributions uint64_t *fp = __builtin_frame_address(0);
301*e3723e1fSApple OSS Distributions // We cannot use a variable of pointer type, because this ABI is valid
302*e3723e1fSApple OSS Distributions // on arm64_32 where pointers are 32bits, but the context pointer will
303*e3723e1fSApple OSS Distributions // still be stored in a 64bits slot on the stack.
304*e3723e1fSApple OSS Distributions #if __has_feature(ptrauth_calls)
305*e3723e1fSApple OSS Distributions #define __stack_context_auth __ptrauth(ptrauth_key_process_dependent_data, 1, \
306*e3723e1fSApple OSS Distributions 0xc31a)
307*e3723e1fSApple OSS Distributions struct fake_async_context * __stack_context_auth ctx = &level2;
308*e3723e1fSApple OSS Distributions #else // __has_feature(ptrauth_calls)
309*e3723e1fSApple OSS Distributions /* struct fake_async_context * */uint64_t ctx = (uintptr_t)&level2;
310*e3723e1fSApple OSS Distributions #endif // !__has_feature(ptrauth_calls)
311*e3723e1fSApple OSS Distributions
312*e3723e1fSApple OSS Distributions // The signature of an async frame on the OS stack is:
313*e3723e1fSApple OSS Distributions // [ <AsyncContext address>, <Saved FP | (1<<60)>, <return address> ]
314*e3723e1fSApple OSS Distributions // The Async context must be right before the saved FP on the stack. This
315*e3723e1fSApple OSS Distributions // should happen naturally in an optimized build as it is the only
316*e3723e1fSApple OSS Distributions // variable on the stack.
317*e3723e1fSApple OSS Distributions // This function cannot use T_ASSERT_* becuse it changes the stack
318*e3723e1fSApple OSS Distributions // layout.
319*e3723e1fSApple OSS Distributions assert((uintptr_t)fp - (uintptr_t)&ctx == 8);
320*e3723e1fSApple OSS Distributions
321*e3723e1fSApple OSS Distributions // Modify the saved FP on the stack to include the async frame marker
322*e3723e1fSApple OSS Distributions *fp |= (0x1ULL << 60);
323*e3723e1fSApple OSS Distributions expect_async_callstack();
324*e3723e1fSApple OSS Distributions return NULL;
325*e3723e1fSApple OSS Distributions }
326*e3723e1fSApple OSS Distributions
327*e3723e1fSApple OSS Distributions static void *
backtrace_thread(void * arg)328*e3723e1fSApple OSS Distributions backtrace_thread(void *arg)
329*e3723e1fSApple OSS Distributions {
330*e3723e1fSApple OSS Distributions unsigned int calls;
331*e3723e1fSApple OSS Distributions enum test_scenario scenario = (enum test_scenario)arg;
332*e3723e1fSApple OSS Distributions
333*e3723e1fSApple OSS Distributions // backtrace_thread, recurse_a, recurse_b, ..., __sysctlbyname
334*e3723e1fSApple OSS Distributions //
335*e3723e1fSApple OSS Distributions // Always make one less call for this frame (backtrace_thread).
336*e3723e1fSApple OSS Distributions calls = USER_FRAMES - NON_RECURSE_FRAMES;
337*e3723e1fSApple OSS Distributions
338*e3723e1fSApple OSS Distributions T_LOG("backtrace thread calling into %d frames (already at %d frames)",
339*e3723e1fSApple OSS Distributions calls, NON_RECURSE_FRAMES);
340*e3723e1fSApple OSS Distributions (void)recurse_a(scenario, calls);
341*e3723e1fSApple OSS Distributions return NULL;
342*e3723e1fSApple OSS Distributions }
343*e3723e1fSApple OSS Distributions
344*e3723e1fSApple OSS Distributions T_DECL(backtrace_user, "test that the kernel can backtrace user stacks",
345*e3723e1fSApple OSS Distributions T_META_CHECK_LEAKS(false), T_META_ALL_VALID_ARCHS(true), T_META_TAG_VM_PREFERRED)
346*e3723e1fSApple OSS Distributions {
347*e3723e1fSApple OSS Distributions pthread_t thread;
348*e3723e1fSApple OSS Distributions
349*e3723e1fSApple OSS Distributions // Run the test from a different thread to insulate it from libdarwintest
350*e3723e1fSApple OSS Distributions // setup.
351*e3723e1fSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(pthread_create(&thread, NULL, backtrace_thread,
352*e3723e1fSApple OSS Distributions (void *)USER_SCENARIO), "create additional thread to backtrace");
353*e3723e1fSApple OSS Distributions
354*e3723e1fSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(pthread_join(thread, NULL), NULL);
355*e3723e1fSApple OSS Distributions }
356*e3723e1fSApple OSS Distributions
357*e3723e1fSApple OSS Distributions T_DECL(backtrace_user_bounds,
358*e3723e1fSApple OSS Distributions "test that the kernel doesn't write frames out of expected bounds", T_META_TAG_VM_PREFERRED)
359*e3723e1fSApple OSS Distributions {
360*e3723e1fSApple OSS Distributions uint64_t bt_init[USER_FRAMES] = {};
361*e3723e1fSApple OSS Distributions size_t bt_filled = USER_FRAMES, bt_filled_after = 0;
362*e3723e1fSApple OSS Distributions int error = 0;
363*e3723e1fSApple OSS Distributions kern_return_t kr = KERN_FAILURE;
364*e3723e1fSApple OSS Distributions void *bt_page = NULL;
365*e3723e1fSApple OSS Distributions void *guard_page = NULL;
366*e3723e1fSApple OSS Distributions void *bt_start = NULL;
367*e3723e1fSApple OSS Distributions
368*e3723e1fSApple OSS Distributions // The backtrace addresses come back as kernel words.
369*e3723e1fSApple OSS Distributions size_t kword_size = is_kernel_64_bit() ? 8 : 4;
370*e3723e1fSApple OSS Distributions
371*e3723e1fSApple OSS Distributions // Get an idea of how many frames to expect.
372*e3723e1fSApple OSS Distributions int ret = sysctlbyname("kern.backtrace.user", bt_init, &bt_filled, NULL, 0);
373*e3723e1fSApple OSS Distributions if (ret == -1 && errno == ENOENT) {
374*e3723e1fSApple OSS Distributions T_SKIP("release kernel: kern.backtrace.user missing");
375*e3723e1fSApple OSS Distributions }
376*e3723e1fSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(error, "sysctlbyname(\"kern.backtrace.user\")");
377*e3723e1fSApple OSS Distributions
378*e3723e1fSApple OSS Distributions // Allocate two pages -- a first one that's valid and a second that
379*e3723e1fSApple OSS Distributions // will be non-writeable to catch a copyout that's too large.
380*e3723e1fSApple OSS Distributions bt_page = mmap(NULL, vm_page_size * 2, PROT_READ | PROT_WRITE,
381*e3723e1fSApple OSS Distributions MAP_ANON | MAP_PRIVATE, -1, 0);
382*e3723e1fSApple OSS Distributions T_WITH_ERRNO;
383*e3723e1fSApple OSS Distributions T_ASSERT_NE(bt_page, MAP_FAILED, "allocated backtrace pages");
384*e3723e1fSApple OSS Distributions guard_page = (char *)bt_page + vm_page_size;
385*e3723e1fSApple OSS Distributions
386*e3723e1fSApple OSS Distributions error = mprotect(guard_page, vm_page_size, PROT_READ);
387*e3723e1fSApple OSS Distributions T_ASSERT_POSIX_SUCCESS(error, "mprotect(..., PROT_READ) guard page");
388*e3723e1fSApple OSS Distributions
389*e3723e1fSApple OSS Distributions // Ensure the pages are set up as expected.
390*e3723e1fSApple OSS Distributions kr = vm_write(mach_task_self(), (vm_address_t)bt_page,
391*e3723e1fSApple OSS Distributions (vm_offset_t)&(int){ 12345 }, sizeof(int));
392*e3723e1fSApple OSS Distributions T_ASSERT_MACH_SUCCESS(kr,
393*e3723e1fSApple OSS Distributions "should succeed in writing to backtrace page");
394*e3723e1fSApple OSS Distributions kr = vm_write(mach_task_self(), (vm_address_t)guard_page,
395*e3723e1fSApple OSS Distributions (vm_offset_t)&(int){ 12345 }, sizeof(int));
396*e3723e1fSApple OSS Distributions T_ASSERT_NE(kr, KERN_SUCCESS, "should fail to write to guard page");
397*e3723e1fSApple OSS Distributions
398*e3723e1fSApple OSS Distributions // Ask the kernel to write the backtrace just before the guard page.
399*e3723e1fSApple OSS Distributions bt_start = (char *)guard_page - (kword_size * bt_filled);
400*e3723e1fSApple OSS Distributions bt_filled_after = bt_filled;
401*e3723e1fSApple OSS Distributions
402*e3723e1fSApple OSS Distributions error = sysctlbyname("kern.backtrace.user", bt_start, &bt_filled_after,
403*e3723e1fSApple OSS Distributions NULL, 0);
404*e3723e1fSApple OSS Distributions T_EXPECT_POSIX_SUCCESS(error,
405*e3723e1fSApple OSS Distributions "sysctlbyname(\"kern.backtrace.user\") just before guard page");
406*e3723e1fSApple OSS Distributions T_EXPECT_EQ(bt_filled, bt_filled_after,
407*e3723e1fSApple OSS Distributions "both calls to backtrace should have filled in the same number of "
408*e3723e1fSApple OSS Distributions "frames");
409*e3723e1fSApple OSS Distributions
410*e3723e1fSApple OSS Distributions // Expect the kernel to fault when writing too far.
411*e3723e1fSApple OSS Distributions bt_start = (char *)bt_start + 1;
412*e3723e1fSApple OSS Distributions bt_filled_after = bt_filled;
413*e3723e1fSApple OSS Distributions error = sysctlbyname("kern.backtrace.user", bt_start, &bt_filled_after,
414*e3723e1fSApple OSS Distributions (void *)USER_SCENARIO, 0);
415*e3723e1fSApple OSS Distributions T_EXPECT_POSIX_FAILURE(error, EFAULT,
416*e3723e1fSApple OSS Distributions "sysctlbyname(\"kern.backtrace.user\") should fault one byte into "
417*e3723e1fSApple OSS Distributions "guard page");
418*e3723e1fSApple OSS Distributions }
419*e3723e1fSApple OSS Distributions
420*e3723e1fSApple OSS Distributions T_DECL(backtrace_user_async,
421*e3723e1fSApple OSS Distributions "test that the kernel can backtrace user async stacks",
422*e3723e1fSApple OSS Distributions T_META_CHECK_LEAKS(false), T_META_ALL_VALID_ARCHS(false), T_META_TAG_VM_PREFERRED)
423*e3723e1fSApple OSS Distributions {
424*e3723e1fSApple OSS Distributions #if !defined(__LP64__)
425*e3723e1fSApple OSS Distributions T_SKIP("unsupported on LP32");
426*e3723e1fSApple OSS Distributions #else // __LP32__
427*e3723e1fSApple OSS Distributions pthread_t thread;
428*e3723e1fSApple OSS Distributions // Run the test from a different thread to insulate it from libdarwintest
429*e3723e1fSApple OSS Distributions // setup.
430*e3723e1fSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(pthread_create(&thread, NULL,
431*e3723e1fSApple OSS Distributions backtrace_thread_async, NULL),
432*e3723e1fSApple OSS Distributions "create additional thread to backtrace");
433*e3723e1fSApple OSS Distributions
434*e3723e1fSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(pthread_join(thread, NULL), NULL);
435*e3723e1fSApple OSS Distributions #endif // !__LP32__
436*e3723e1fSApple OSS Distributions }
437*e3723e1fSApple OSS Distributions
438*e3723e1fSApple OSS Distributions T_DECL(backtrace_user_resume,
439*e3723e1fSApple OSS Distributions "test that the kernel can resume a backtrace into a smaller buffer",
440*e3723e1fSApple OSS Distributions T_META_CHECK_LEAKS(false), T_META_ALL_VALID_ARCHS(false), T_META_TAG_VM_PREFERRED)
441*e3723e1fSApple OSS Distributions {
442*e3723e1fSApple OSS Distributions pthread_t thread;
443*e3723e1fSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(pthread_create(&thread, NULL, backtrace_thread,
444*e3723e1fSApple OSS Distributions (void *)RESUME_SCENARIO), "create additional thread to backtrace");
445*e3723e1fSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(pthread_join(thread, NULL), NULL);
446*e3723e1fSApple OSS Distributions }
447*e3723e1fSApple OSS Distributions
448*e3723e1fSApple OSS Distributions T_DECL(backtrace_kernel_pack_unpack,
449*e3723e1fSApple OSS Distributions "test that a kernel backtrace can be packed and unpacked losslessly",
450*e3723e1fSApple OSS Distributions T_META_CHECK_LEAKS(false), T_META_ALL_VALID_ARCHS(false), T_META_TAG_VM_PREFERRED)
451*e3723e1fSApple OSS Distributions {
452*e3723e1fSApple OSS Distributions int error = sysctlbyname("kern.backtrace.kernel_tests", NULL, NULL,
453*e3723e1fSApple OSS Distributions (void *)PACK_UNPACK_SCENARIO, 0);
454*e3723e1fSApple OSS Distributions T_EXPECT_POSIX_SUCCESS(error,
455*e3723e1fSApple OSS Distributions "sysctlbyname(\"kern.backtrace.kernel_tests\", PACK_UNPACK)");
456*e3723e1fSApple OSS Distributions }
457*e3723e1fSApple OSS Distributions
458*e3723e1fSApple OSS Distributions T_DECL(backtrace_kernel_packed,
459*e3723e1fSApple OSS Distributions "test that a kernel backtrace can be recorded as packed losslessly",
460*e3723e1fSApple OSS Distributions T_META_CHECK_LEAKS(false), T_META_ALL_VALID_ARCHS(false), T_META_TAG_VM_PREFERRED)
461*e3723e1fSApple OSS Distributions {
462*e3723e1fSApple OSS Distributions int error = sysctlbyname("kern.backtrace.kernel_tests", NULL, NULL,
463*e3723e1fSApple OSS Distributions (void *)PACKED_SCENARIO, 0);
464*e3723e1fSApple OSS Distributions T_EXPECT_POSIX_SUCCESS(error,
465*e3723e1fSApple OSS Distributions "sysctlbyname(\"kern.backtrace.kernel_tests\", PACKED)");
466*e3723e1fSApple OSS Distributions }
467*e3723e1fSApple OSS Distributions
468*e3723e1fSApple OSS Distributions #pragma mark - utilities
469*e3723e1fSApple OSS Distributions
470*e3723e1fSApple OSS Distributions static void __attribute__((noinline, not_tail_called))
spin_forever(void)471*e3723e1fSApple OSS Distributions spin_forever(void)
472*e3723e1fSApple OSS Distributions {
473*e3723e1fSApple OSS Distributions while (true) {
474*e3723e1fSApple OSS Distributions ;
475*e3723e1fSApple OSS Distributions }
476*e3723e1fSApple OSS Distributions }
477*e3723e1fSApple OSS Distributions
478*e3723e1fSApple OSS Distributions static void
check_stack(uintptr_t fp,uintptr_t ctx)479*e3723e1fSApple OSS Distributions check_stack(uintptr_t fp, uintptr_t ctx)
480*e3723e1fSApple OSS Distributions {
481*e3723e1fSApple OSS Distributions if ((fp - ctx) != 0x8) {
482*e3723e1fSApple OSS Distributions fprintf(stderr, "stack frame is not set up properly: "
483*e3723e1fSApple OSS Distributions "%#lx, %#lx is %lx bytes away\n", fp, ctx, fp - ctx);
484*e3723e1fSApple OSS Distributions exit(1);
485*e3723e1fSApple OSS Distributions }
486*e3723e1fSApple OSS Distributions }
487*e3723e1fSApple OSS Distributions
488*e3723e1fSApple OSS Distributions static void __attribute__((noinline, not_tail_called))
spin_backtrace_async(void)489*e3723e1fSApple OSS Distributions spin_backtrace_async(void)
490*e3723e1fSApple OSS Distributions {
491*e3723e1fSApple OSS Distributions uint64_t *fp = __builtin_frame_address(0);
492*e3723e1fSApple OSS Distributions #if __has_feature(ptrauth_calls)
493*e3723e1fSApple OSS Distributions struct fake_async_context * __stack_context_auth ctx = &level2;
494*e3723e1fSApple OSS Distributions #else // __has_feature(ptrauth_calls)
495*e3723e1fSApple OSS Distributions /* struct fake_async_context * */uint64_t ctx = (uintptr_t)&level2;
496*e3723e1fSApple OSS Distributions #endif // !__has_feature(ptrauth_calls)
497*e3723e1fSApple OSS Distributions check_stack((uintptr_t)fp, (uintptr_t)&ctx);
498*e3723e1fSApple OSS Distributions *fp |= (0x1ULL << 60);
499*e3723e1fSApple OSS Distributions
500*e3723e1fSApple OSS Distributions spin_forever();
501*e3723e1fSApple OSS Distributions }
502*e3723e1fSApple OSS Distributions
503*e3723e1fSApple OSS Distributions T_DECL(backtrace_user_async_spin_forever,
504*e3723e1fSApple OSS Distributions "try spinning forever with an async call stack set up",
505*e3723e1fSApple OSS Distributions T_META_ENABLED(false), T_META_CHECK_LEAKS(false),
506*e3723e1fSApple OSS Distributions T_META_ALL_VALID_ARCHS(false), T_META_TAG_VM_PREFERRED)
507*e3723e1fSApple OSS Distributions {
508*e3723e1fSApple OSS Distributions #if !defined(__LP64__)
509*e3723e1fSApple OSS Distributions T_SKIP("unsupported on LP32");
510*e3723e1fSApple OSS Distributions #else // __LP32__
511*e3723e1fSApple OSS Distributions spin_backtrace_async();
512*e3723e1fSApple OSS Distributions #endif // !__LP32__
513*e3723e1fSApple OSS Distributions }
514