xref: /xnu-10063.101.15/osfmk/kern/exclaves_panic.c (revision 94d3b452840153a99b38a3a9659680b2a006908e)
1 /*
2  * Copyright (c) 2023 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 #if CONFIG_EXCLAVES
30 
31 #include <kern/assert.h>
32 #include <kern/misc_protos.h>
33 #include <kern/thread.h>
34 
35 #include <mach/exclaves_l4.h>
36 
37 #include <uuid/uuid.h>
38 #include <vm/pmap.h>
39 
40 #include <xnuproxy/messages.h>
41 #include <xnuproxy/panic.h>
42 
43 #include "exclaves_debug.h"
44 #include "exclaves_panic.h"
45 
46 /* Use the new version of xnuproxy_msg_t. */
47 #define xnuproxy_msg_t xnuproxy_msg_new_t
48 
49 #define EXCLAVES_PANIC_FOUR_CC_FORMAT   "%c%c%c%c"
50 #define EXCLAVES_PANIC_FOUR_CC_CHARS(c) \
51     (((c) >> 24) & 0xFF),               \
52     (((c) >> 16) & 0xFF),               \
53     (((c) >>  8) & 0xFF),               \
54     (((c) >>  0) & 0xFF)
55 #define EXCLAVE_PANIC_MESSAGE_MARKER    "[Exclaves]"
56 
57 // Adding 64 bytes here to accommodate the PC and LR in the panic string
58 #define EXCLAVES_PANIC_STRING_SIZE     \
59     (sizeof(EXCLAVE_PANIC_MESSAGE_MARKER) + XNUPROXY_PANIC_MESSAGE_LEN + XNUPROXY_PANIC_NAME_BYTES + 64)
60 
61 static char exclaves_panic_string[EXCLAVES_PANIC_STRING_SIZE];
62 static xnuproxy_panic_buffer_t *exclaves_panic_buffer;
63 static int exclaves_panic_thread_wait_forever;
64 
65 static void
exclaves_xnu_proxy_panic_thread(void * arg __unused,wait_result_t wr __unused)66 exclaves_xnu_proxy_panic_thread(void *arg __unused, wait_result_t wr __unused)
67 {
68 	kern_return_t kr = KERN_SUCCESS;
69 	Exclaves_L4_Word_t spawned_scid = 0;
70 	thread_t thread;
71 
72 	xnuproxy_msg_t msg = {
73 		.cmd = XNUPROXY_CMD_PANIC_SETUP,
74 	};
75 
76 	extern kern_return_t exclaves_xnu_proxy_send(xnuproxy_msg_t *,
77 	    Exclaves_L4_Word_t *);
78 	kr = exclaves_xnu_proxy_send(&msg, &spawned_scid);
79 	if (kr != KERN_SUCCESS) {
80 		exclaves_debug_printf(show_errors,
81 		    "exclaves: panic thread init: xnu proxy send failed.");
82 		return;
83 	}
84 
85 	exclaves_panic_buffer = (xnuproxy_panic_buffer_t *)
86 	    phystokv(msg.cmd_panic_setup.response.physical_address);
87 
88 	thread = current_thread();
89 	thread->th_exclaves_scheduling_context_id = spawned_scid;
90 
91 	while (1) {
92 		extern kern_return_t exclaves_scheduler_resume_scheduling_context(Exclaves_L4_Word_t,
93 		    Exclaves_L4_Word_t *);
94 		kr = exclaves_scheduler_resume_scheduling_context(spawned_scid, NULL);
95 		assert3u(kr, ==, KERN_SUCCESS);
96 	}
97 }
98 
99 static void
exclaves_append_panic_backtrace(void)100 exclaves_append_panic_backtrace(void)
101 {
102 	uuid_string_t uuid_string;
103 	xnuproxy_panic_backtrace_word_t *words;
104 
105 	if ((exclaves_panic_buffer->panicked_thread.backtrace.frames >
106 	    XNUPROXY__PANIC_BACKTRACE_WORDS)) {
107 		return;
108 	}
109 
110 	words = exclaves_panic_buffer->backtrace.words;
111 	paniclog_append_noflush("Exclaves backtrace:\n");
112 	for (size_t i = 0; i < exclaves_panic_buffer->panicked_thread.backtrace.frames; i++) {
113 		uuid_unparse_upper(
114 			(const unsigned char *)exclaves_panic_buffer->backtrace.images[words[i].image].uuid,
115 			uuid_string);
116 		paniclog_append_noflush("\t\t%s 0x%016zx\n", uuid_string,
117 		    exclaves_panic_buffer->backtrace.words[i].offset);
118 	}
119 
120 	paniclog_append_noflush("\n");
121 	return;
122 }
123 
124 static void
exclaves_append_panic_addl_info(xnuproxy_panicked_thread_t * ex_thread)125 exclaves_append_panic_addl_info(xnuproxy_panicked_thread_t *ex_thread)
126 {
127 	char component_name[XNUPROXY_PANIC_NAME_BYTES] = {0};
128 
129 	strlcpy(component_name, ex_thread->component.name, sizeof(component_name));
130 
131 	paniclog_append_noflush(
132 		"\t\tAddress space ID: 0x%llx\n"
133 		"\t\tComponent:\n"
134 		"\t\t\tName: %s\n"
135 		"\t\t\tID: 0x%llx\n"
136 		"\t\t\tSelector: 0x%llx\n"
137 		"\t\tspace.component.endpoint.thread: " EXCLAVES_PANIC_FOUR_CC_FORMAT "."
138 		EXCLAVES_PANIC_FOUR_CC_FORMAT "."
139 		EXCLAVES_PANIC_FOUR_CC_FORMAT "."
140 		EXCLAVES_PANIC_FOUR_CC_FORMAT "\n"
141 		"\t\tThread Context:\n"
142 		"\t\t\tAddress: 0x%zx\n"
143 		"\t\t\tTSS Base: 0x%zx\n"
144 		"\t\t\tIPC Buffer 0x%zx\n"
145 		"\t\t\tSCID 0x%zx\n"
146 		"\t\t\tECID: 0x%zx\n"
147 		"\t\t\tEPID: 0x%zx\n"
148 		"\t\t\tStack:\n"
149 		"\t\t\t\tStart: 0x%zx\n"
150 		"\t\t\t\tSize: 0x%zx\n"
151 		"\t\t\t\tCall base: 0x%zx\n"
152 		"\t\t\tRegisters:\n"
153 		"\t\t\t\tLR: 0x%zx\n"
154 		"\t\t\t\tPC: 0x%zx\n"
155 		"\t\t\t\tSP: 0x%zx\n"
156 		"\t\t\t\tCPSR: 0x%zx\n",
157 		ex_thread->address_space_id, component_name,
158 		ex_thread->component.numeric_id, ex_thread->component.selector,
159 		EXCLAVES_PANIC_FOUR_CC_CHARS(ex_thread->four_cc.space),
160 		EXCLAVES_PANIC_FOUR_CC_CHARS(ex_thread->four_cc.component),
161 		EXCLAVES_PANIC_FOUR_CC_CHARS(ex_thread->four_cc.endpoint),
162 		EXCLAVES_PANIC_FOUR_CC_CHARS(ex_thread->four_cc.thread),
163 		ex_thread->thread.address, ex_thread->thread.tss_base,
164 		ex_thread->thread.ipc_buffer, ex_thread->thread.scheduling_context_id,
165 		ex_thread->thread.execution_context_id, ex_thread->thread.endpoint_id,
166 		ex_thread->thread.stack.start, ex_thread->thread.stack.size,
167 		ex_thread->thread.stack.call_base, ex_thread->thread.registers.lr,
168 		ex_thread->thread.registers.pc, ex_thread->thread.registers.sp,
169 		ex_thread->thread.registers.cpsr);
170 }
171 
172 kern_return_t
exclaves_panic_get_string(char ** string)173 exclaves_panic_get_string(char **string)
174 {
175 	uint32_t status = 0;
176 	char component_name[XNUPROXY_PANIC_NAME_BYTES] = {0};
177 
178 	if (exclaves_panic_buffer == NULL) {
179 		return KERN_FAILURE;
180 	}
181 
182 	xnuproxy_panicked_thread_t *ex_thread =
183 	    &exclaves_panic_buffer->panicked_thread;
184 
185 	strlcpy(component_name, ex_thread->component.name, sizeof(component_name));
186 
187 	status = os_atomic_load(&ex_thread->status, seq_cst);
188 	if (status == XNUPROXY_PANIC_UNSET) {
189 		return KERN_FAILURE;
190 	}
191 
192 	snprintf(exclaves_panic_string, sizeof(exclaves_panic_string),
193 	    "%s %s:%s at PC: 0x%zx, LR: 0x%zx", EXCLAVE_PANIC_MESSAGE_MARKER,
194 	    component_name, exclaves_panic_buffer->message,
195 	    ex_thread->thread.registers.pc, ex_thread->thread.registers.lr);
196 	exclaves_panic_string[sizeof(exclaves_panic_string) - 1] = '\0';
197 	*string = exclaves_panic_string;
198 
199 	return KERN_SUCCESS;
200 }
201 
202 void
exclaves_panic_append_info(void)203 exclaves_panic_append_info(void)
204 {
205 	uint32_t status = 0;
206 	char *status_str;
207 	if (exclaves_panic_buffer == NULL) {
208 		return;
209 	}
210 
211 	xnuproxy_panicked_thread_t *ex_thread =
212 	    &exclaves_panic_buffer->panicked_thread;
213 
214 	status = os_atomic_load(&ex_thread->status, seq_cst);
215 
216 	switch (status) {
217 	case XNUPROXY_PANIC_PARTIAL:
218 		status_str = "PARTIAL";
219 		break;
220 	case XNUPROXY_PANIC_COMPLETE:
221 		status_str = "COMPLETE";
222 		break;
223 	default:
224 		return;
225 	}
226 
227 	panic_info->eph_panic_flags |= EMBEDDED_PANIC_HEADER_FLAG_EXCLAVE_PANIC;
228 
229 	paniclog_append_noflush("Exclaves additional info: STATUS: %s\n", status_str);
230 	exclaves_append_panic_addl_info(ex_thread);
231 
232 	exclaves_append_panic_backtrace();
233 }
234 
235 __attribute__((noinline, noreturn))
236 void
exclaves_panic_thread_wait(void)237 exclaves_panic_thread_wait(void)
238 {
239 	assert_wait((event_t)&exclaves_panic_thread_wait_forever, THREAD_UNINT);
240 	(void) thread_block(THREAD_CONTINUE_NULL);
241 
242 	/* NOT REACHABLE */
243 	panic("Exclaves panic thread woken up");
244 }
245 
246 kern_return_t
exclaves_panic_thread_setup(void)247 exclaves_panic_thread_setup(void)
248 {
249 	thread_t thread = THREAD_NULL;
250 	kern_return_t kr = KERN_FAILURE;
251 
252 	kr = kernel_thread_start_priority(exclaves_xnu_proxy_panic_thread, NULL,
253 	    BASEPRI_DEFAULT, &thread);
254 	if (kr != KERN_SUCCESS) {
255 		return kr;
256 	}
257 
258 	thread_set_thread_name(thread, "EXCLAVES_PANIC_WAIT_THREAD");
259 	thread_deallocate(thread);
260 
261 	return KERN_SUCCESS;
262 }
263 
264 #endif /* CONFIG_ EXCLAVES */
265