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 void
aea_stage_reset(struct kdp_output_stage * stage)94 aea_stage_reset(struct kdp_output_stage *stage)
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
113 static kern_return_t
aea_stage_outproc(struct kdp_output_stage * stage,unsigned int request,__unused char * corename,uint64_t length,void * panic_data)114 aea_stage_outproc(struct kdp_output_stage *stage, unsigned int request,
115 __unused char *corename, uint64_t length, void *panic_data)
116 {
117 kern_return_t err = KERN_SUCCESS;
118 int aea_ret = 0;
119 struct aea_stage_data *stage_data = (struct aea_stage_data *) stage->kos_data;
120 struct kdp_output_stage *next_stage = STAILQ_NEXT(stage, kos_next);
121 size_t chunk = 0;
122
123 assert(next_stage != NULL);
124
125 switch (request) {
126 case KDP_SEEK:
127 stage->kos_bypass = true;
128 if (stage_data->encryption_open) {
129 aea_ret = apple_encrypted_archive->aea_close(stage_data->state, stage_data->state_size);
130 if (aea_ret != 0) {
131 kern_coredump_log(NULL, "(aea_stage_outproc) aea_close() returned %d\n", aea_ret);
132 err = KERN_FAILURE;
133 } else {
134 stage_data->encryption_open = false;
135 }
136 }
137 if (KERN_SUCCESS == err) {
138 err = next_stage->kos_funcs.kosf_outproc(next_stage, request, corename, length, panic_data);
139 }
140 if (KERN_SUCCESS == err) {
141 stage_data->starting_corefile_offset = *((uint64_t *) panic_data);
142 stage_data->current_corefile_offset = stage_data->starting_corefile_offset;
143 }
144 break;
145 case KDP_DATA:
146 if (!stage->kos_bypass) {
147 if (!length && !panic_data) {
148 // Flush
149 if (stage_data->encryption_open) {
150 aea_ret = apple_encrypted_archive->aea_close(stage_data->state, stage_data->state_size);
151 if (aea_ret != 0) {
152 kern_coredump_log(NULL, "(aea_stage_outproc) aea_close() returned %d\n", aea_ret);
153 err = KERN_FAILURE;
154 } else {
155 stage_data->encryption_open = false;
156 }
157 }
158 } else {
159 if (stage_data->encryption_open == false) {
160 aea_ret = apple_encrypted_archive->aea_open(stage_data->state, stage_data->state_size, (void *) stage, aea_write_callback, aea_read_callback);
161 if (aea_ret != 0) {
162 kern_coredump_log(NULL, "(aea_stage_outproc) aea_open() returned %d\n", aea_ret);
163 err = KERN_FAILURE;
164 } else {
165 stage_data->encryption_open = true;
166 }
167 }
168 if (KERN_SUCCESS == err) {
169 do{
170 ssize_t write_result;
171
172 if (length <= UINT32_MAX) {
173 chunk = (size_t) length;
174 } else {
175 chunk = UINT32_MAX;
176 }
177 write_result = apple_encrypted_archive->aea_write(stage_data->state, stage_data->state_size, panic_data, chunk);
178 if (write_result != chunk) {
179 kern_coredump_log(NULL, "(aea_stage_outproc) aea_write() returned %zd\n", write_result);
180 err = KERN_FAILURE;
181 }
182
183 length -= chunk;
184
185 if (panic_data) {
186 panic_data = (void *) (((uintptr_t) panic_data) + chunk);
187 }
188 } while (length && (KERN_SUCCESS == err));
189 }
190 }
191 } else {
192 err = next_stage->kos_funcs.kosf_outproc(next_stage, request, corename, length, panic_data);
193 }
194 break;
195 case KDP_WRQ:
196 /* Fall-through */
197 case KDP_FLUSH:
198 /* Fall-through */
199 case KDP_EOF:
200 err = next_stage->kos_funcs.kosf_outproc(next_stage, request, corename, length, panic_data);
201 break;
202 default:
203 break;
204 }
205
206 return err;
207 }
208
209 static void
aea_stage_free(struct kdp_output_stage * stage)210 aea_stage_free(struct kdp_output_stage *stage)
211 {
212 kmem_free(kernel_map, (vm_offset_t) stage->kos_data, stage->kos_data_size);
213
214 stage->kos_data = NULL;
215 stage->kos_data_size = 0;
216 stage->kos_initialized = false;
217 }
218
219 kern_return_t
aea_stage_initialize(struct kdp_output_stage * stage,const void * recipient_public_key,size_t recipient_public_key_size)220 aea_stage_initialize(struct kdp_output_stage *stage, const void *recipient_public_key, size_t recipient_public_key_size)
221 {
222 kern_return_t ret = KERN_SUCCESS;
223 int aea_ret = 0;
224 struct aea_stage_data *data = NULL;
225 size_t state_size = 0;
226
227 assert(apple_encrypted_archive != NULL);
228 assert(stage != NULL);
229 assert(stage->kos_initialized == false);
230 assert(stage->kos_data == NULL);
231 assert(recipient_public_key != NULL);
232 assert(recipient_public_key_size != 0);
233
234 state_size = apple_encrypted_archive->aea_get_state_size();
235 if (0 == state_size) {
236 printf("AEA kext returned an error while calculating state size.");
237 ret = KERN_FAILURE;
238 return ret;
239 }
240 stage->kos_data_size = sizeof(struct aea_stage_data) + state_size;
241 ret = kmem_alloc(kernel_map, (vm_offset_t*) &stage->kos_data, stage->kos_data_size,
242 KMA_DATA, VM_KERN_MEMORY_DIAG);
243 if (KERN_SUCCESS != ret) {
244 printf("Failed to allocate memory (%zu bytes) for the AEA stage. Error 0x%x\n", stage->kos_data_size, ret);
245 return ret;
246 }
247
248 data = (struct aea_stage_data *) stage->kos_data;
249 data->encryption_open = false;
250 data->starting_corefile_offset = 0;
251 data->current_corefile_offset = 0;
252 data->state_size = state_size;
253
254 aea_ret = apple_encrypted_archive->aea_initialize_state(data->state, data->state_size, (const uint8_t *)recipient_public_key, recipient_public_key_size);
255 if (aea_ret != 0) {
256 printf("WARNING: Coredump encryption failed to initialize. aea_initialize_state() returned %d\n", aea_ret);
257 aea_stage_free(stage);
258 return KERN_FAILURE;
259 }
260
261 stage->kos_funcs.kosf_reset = aea_stage_reset;
262 stage->kos_funcs.kosf_outproc = aea_stage_outproc;
263 stage->kos_funcs.kosf_free = aea_stage_free;
264
265 stage->kos_initialized = true;
266
267 return ret;
268 }
269
270 static void
aea_availability_callback(void)271 aea_availability_callback(void)
272 {
273 kern_return_t ret = kdp_core_handle_encryption_available();
274 if (KERN_SUCCESS != ret) {
275 printf("(aea_availability_callback) Failed to handle availability of encryption. Error 0x%x\n", ret);
276 }
277 }
278
279 void
aea_stage_monitor_availability(void)280 aea_stage_monitor_availability(void)
281 {
282 apple_encrypted_archive_interface_set_registration_callback(aea_availability_callback);
283 }
284
285 bool
aea_stage_is_available(void)286 aea_stage_is_available(void)
287 {
288 return apple_encrypted_archive != NULL;
289 }
290
291 #endif /* CONFIG_KDP_INTERACTIVE_DEBUGGING */
292