xref: /xnu-12377.81.4/osfmk/kdp/output_stages/out_aea.c (revision 043036a2b3718f7f0be807e2870f8f47d3fa0796)
1 /*
2  * Copyright (c) 2021 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 #ifdef CONFIG_KDP_INTERACTIVE_DEBUGGING
30 
31 #include <mach/mach_types.h>
32 #include <IOKit/IOTypes.h>
33 #include <kdp/output_stages/output_stages.h>
34 #include <kdp/kdp_core.h>
35 #include <kdp/processor_core.h>
36 #include <machine/param.h>
37 #include <libkern/apple_encrypted_archive/apple_encrypted_archive.h>
38 #include <vm/vm_kern_xnu.h>
39 
40 struct aea_stage_data {
41 	bool     encryption_open;
42 	uint64_t starting_corefile_offset;;
43 	uint64_t current_corefile_offset;
44 	size_t   state_size;
45 	char     state[];
46 };
47 
48 static ssize_t
aea_write_callback(void * context,const void * buffer,size_t length,off_t offset)49 aea_write_callback(void *context, const void *buffer, size_t length, off_t offset)
50 {
51 	kern_return_t            err = KERN_SUCCESS;
52 	struct kdp_output_stage *stage = (struct kdp_output_stage *) context;
53 	struct kdp_output_stage *next_stage = STAILQ_NEXT(stage, kos_next);
54 	struct aea_stage_data   *stage_data = (struct aea_stage_data *) stage->kos_data;
55 	uint64_t absolute_corefile_offset = stage_data->starting_corefile_offset + offset;
56 
57 	err = disk_stage_write(next_stage, absolute_corefile_offset, length, buffer);
58 
59 	if (KERN_SUCCESS != err) {
60 		kern_coredump_log(NULL, "(aea_write_callback) next stage outproc returned 0x%x\n", err);
61 		return -1;
62 	}
63 
64 	stage_data->current_corefile_offset = absolute_corefile_offset + length;
65 	if (offset + length > stage->kos_bytes_written) {
66 		stage->kos_bytes_written = offset + length;
67 		next_stage->kos_bytes_written = stage->kos_bytes_written;
68 	}
69 
70 	return length;
71 }
72 
73 static ssize_t
aea_read_callback(void * context,void * buffer,size_t length,off_t offset)74 aea_read_callback(void *context, void *buffer, size_t length, off_t offset)
75 {
76 	kern_return_t            err = KERN_SUCCESS;
77 	struct kdp_output_stage *stage = (struct kdp_output_stage *) context;
78 	struct kdp_output_stage *next_stage = STAILQ_NEXT(stage, kos_next);
79 	struct aea_stage_data   *stage_data = (struct aea_stage_data *) stage->kos_data;
80 	uint64_t absolute_corefile_offset = stage_data->starting_corefile_offset + offset;
81 
82 	err = disk_stage_read(next_stage, absolute_corefile_offset, length, buffer);
83 	if (KERN_SUCCESS != err) {
84 		kern_coredump_log(NULL, "(aea_read_callback) next stage read proc returned 0x%x\n", err);
85 		return -1;
86 	}
87 
88 	stage_data->current_corefile_offset = absolute_corefile_offset + length;
89 
90 	return length;
91 }
92 
93 static kern_return_t
aea_stage_reset(struct kdp_output_stage * stage,__unused const char * corename,__unused kern_coredump_type_t coretype)94 aea_stage_reset(struct kdp_output_stage *stage, __unused const char *corename, __unused kern_coredump_type_t coretype)
95 {
96 	int aea_ret = 0;
97 	struct aea_stage_data *stage_data = (struct aea_stage_data *) stage->kos_data;
98 
99 	if (stage_data->encryption_open) {
100 		aea_ret = apple_encrypted_archive->aea_close(stage_data->state, stage_data->state_size);
101 		if (aea_ret != 0) {
102 			kern_coredump_log(NULL, "(aea_stage_reset) aea_close() returned %d\n", aea_ret);
103 			// TODO return the error?
104 		} else {
105 			stage_data->encryption_open = false;
106 		}
107 	}
108 
109 	stage->kos_bypass = false;
110 	stage->kos_bytes_written = 0;
111 
112 	return KERN_SUCCESS;
113 }
114 
115 static kern_return_t
aea_stage_outproc(struct kdp_output_stage * stage,unsigned int request,__unused char * corename,uint64_t length,void * panic_data)116 aea_stage_outproc(struct kdp_output_stage *stage, unsigned int request,
117     __unused char *corename, uint64_t length, void *panic_data)
118 {
119 	kern_return_t            err = KERN_SUCCESS;
120 	int                      aea_ret = 0;
121 	struct aea_stage_data   *stage_data = (struct aea_stage_data *) stage->kos_data;
122 	struct kdp_output_stage *next_stage = STAILQ_NEXT(stage, kos_next);
123 	size_t                   chunk = 0;
124 
125 	assert(next_stage != NULL);
126 
127 	switch (request) {
128 	case KDP_SEEK:
129 		stage->kos_bypass = true;
130 		if (stage_data->encryption_open) {
131 			aea_ret = apple_encrypted_archive->aea_close(stage_data->state, stage_data->state_size);
132 			if (aea_ret != 0) {
133 				kern_coredump_log(NULL, "(aea_stage_outproc) aea_close() returned %d\n", aea_ret);
134 				err = KERN_FAILURE;
135 			} else {
136 				stage_data->encryption_open = false;
137 			}
138 		}
139 		if (KERN_SUCCESS == err) {
140 			err = next_stage->kos_funcs.kosf_outproc(next_stage, request, corename, length, panic_data);
141 		}
142 		if (KERN_SUCCESS == err) {
143 			stage_data->starting_corefile_offset = *((uint64_t *) panic_data);
144 			stage_data->current_corefile_offset = stage_data->starting_corefile_offset;
145 		}
146 		break;
147 	case KDP_DATA:
148 		if (!stage->kos_bypass) {
149 			if (!length && !panic_data) {
150 				// Flush
151 				if (stage_data->encryption_open) {
152 					aea_ret = apple_encrypted_archive->aea_close(stage_data->state, stage_data->state_size);
153 					if (aea_ret != 0) {
154 						kern_coredump_log(NULL, "(aea_stage_outproc) aea_close() returned %d\n", aea_ret);
155 						err = KERN_FAILURE;
156 					} else {
157 						stage_data->encryption_open = false;
158 					}
159 				}
160 			} else {
161 				if (stage_data->encryption_open == false) {
162 					aea_ret = apple_encrypted_archive->aea_open(stage_data->state, stage_data->state_size, (void *) stage, aea_write_callback, aea_read_callback);
163 					if (aea_ret != 0) {
164 						kern_coredump_log(NULL, "(aea_stage_outproc) aea_open() returned %d\n", aea_ret);
165 						err = KERN_FAILURE;
166 					} else {
167 						stage_data->encryption_open = true;
168 					}
169 				}
170 				if (KERN_SUCCESS == err) {
171 					do{
172 						ssize_t write_result;
173 
174 						if (length <= UINT32_MAX) {
175 							chunk = (size_t) length;
176 						} else {
177 							chunk = UINT32_MAX;
178 						}
179 						write_result = apple_encrypted_archive->aea_write(stage_data->state, stage_data->state_size, panic_data, chunk);
180 						if (write_result != chunk) {
181 							kern_coredump_log(NULL, "(aea_stage_outproc) aea_write() returned %zd\n", write_result);
182 							err = KERN_FAILURE;
183 						}
184 
185 						length -= chunk;
186 
187 						if (panic_data) {
188 							panic_data = (void *) (((uintptr_t) panic_data) + chunk);
189 						}
190 					} while (length && (KERN_SUCCESS == err));
191 				}
192 			}
193 		} else {
194 			err = next_stage->kos_funcs.kosf_outproc(next_stage, request, corename, length, panic_data);
195 		}
196 		break;
197 	case KDP_WRQ:
198 	/* Fall-through */
199 	case KDP_FLUSH:
200 	/* Fall-through */
201 	case KDP_EOF:
202 		err = next_stage->kos_funcs.kosf_outproc(next_stage, request, corename, length, panic_data);
203 		break;
204 	default:
205 		break;
206 	}
207 
208 	return err;
209 }
210 
211 static void
aea_stage_free(struct kdp_output_stage * stage)212 aea_stage_free(struct kdp_output_stage *stage)
213 {
214 	kmem_free(kernel_map, (vm_offset_t) stage->kos_data, stage->kos_data_size);
215 
216 	stage->kos_data = NULL;
217 	stage->kos_data_size = 0;
218 	stage->kos_initialized = false;
219 }
220 
221 kern_return_t
aea_stage_initialize(struct kdp_output_stage * stage,const void * recipient_public_key,size_t recipient_public_key_size)222 aea_stage_initialize(struct kdp_output_stage *stage, const void *recipient_public_key, size_t recipient_public_key_size)
223 {
224 	kern_return_t ret = KERN_SUCCESS;
225 	int aea_ret = 0;
226 	struct aea_stage_data *data = NULL;
227 	size_t state_size = 0;
228 
229 	assert(apple_encrypted_archive != NULL);
230 	assert(stage != NULL);
231 	assert(stage->kos_initialized == false);
232 	assert(stage->kos_data == NULL);
233 	assert(recipient_public_key != NULL);
234 	assert(recipient_public_key_size != 0);
235 
236 	state_size = apple_encrypted_archive->aea_get_state_size();
237 	if (0 == state_size) {
238 		printf("AEA kext returned an error while calculating state size.");
239 		ret = KERN_FAILURE;
240 		return ret;
241 	}
242 	stage->kos_data_size = sizeof(struct aea_stage_data) + state_size;
243 	ret = kmem_alloc(kernel_map, (vm_offset_t*) &stage->kos_data, stage->kos_data_size,
244 	    KMA_DATA_SHARED, VM_KERN_MEMORY_DIAG);
245 	if (KERN_SUCCESS != ret) {
246 		printf("Failed to allocate memory (%zu bytes) for the AEA stage. Error 0x%x\n", stage->kos_data_size, ret);
247 		return ret;
248 	}
249 
250 	data = (struct aea_stage_data *) stage->kos_data;
251 	data->encryption_open = false;
252 	data->starting_corefile_offset = 0;
253 	data->current_corefile_offset = 0;
254 	data->state_size = state_size;
255 
256 	aea_ret = apple_encrypted_archive->aea_initialize_state(data->state, data->state_size, (const uint8_t *)recipient_public_key, recipient_public_key_size);
257 	if (aea_ret != 0) {
258 		printf("WARNING: Coredump encryption failed to initialize. aea_initialize_state() returned %d\n", aea_ret);
259 		aea_stage_free(stage);
260 		return KERN_FAILURE;
261 	}
262 
263 	stage->kos_funcs.kosf_reset = aea_stage_reset;
264 	stage->kos_funcs.kosf_outproc = aea_stage_outproc;
265 	stage->kos_funcs.kosf_free = aea_stage_free;
266 
267 	stage->kos_initialized = true;
268 
269 	return ret;
270 }
271 
272 static void
aea_availability_callback(void)273 aea_availability_callback(void)
274 {
275 	kern_return_t ret = kdp_core_handle_encryption_available();
276 	if (KERN_SUCCESS != ret) {
277 		printf("(aea_availability_callback) Failed to handle availability of encryption. Error 0x%x\n", ret);
278 	}
279 }
280 
281 void
aea_stage_monitor_availability(void)282 aea_stage_monitor_availability(void)
283 {
284 	apple_encrypted_archive_interface_set_registration_callback(aea_availability_callback);
285 }
286 
287 bool
aea_stage_is_available(void)288 aea_stage_is_available(void)
289 {
290 	return apple_encrypted_archive != NULL;
291 }
292 
293 #endif /* CONFIG_KDP_INTERACTIVE_DEBUGGING */
294