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