1 /*
2 * Copyright (c) 2022 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23 #include <os/overflow.h>
24 #include <machine/atomic.h>
25 #include <mach/vm_param.h>
26 #include <vm/vm_kern.h>
27 #include <kern/zalloc.h>
28 #include <kern/kalloc.h>
29 #include <kern/assert.h>
30 #include <kern/locks.h>
31 #include <kern/lock_rw.h>
32 #include <libkern/libkern.h>
33 #include <libkern/section_keywords.h>
34 #include <libkern/coretrust/coretrust.h>
35 #include <pexpert/pexpert.h>
36 #include <sys/vm.h>
37 #include <sys/proc.h>
38 #include <sys/codesign.h>
39 #include <sys/code_signing.h>
40 #include <uuid/uuid.h>
41 #include <IOKit/IOBSD.h>
42
43 #if !CODE_SIGNING_MONITOR
44 /*
45 * We don't have a monitor environment available. This means someone with a kernel
46 * memory exploit will be able to corrupt code signing state. There is not much we
47 * can do here, since this is older HW.
48 */
49 LCK_GRP_DECLARE(xnu_codesigning_lck_grp, "xnu_codesigning_lck_grp");
50
51 #pragma mark Initialization
52
53 static decl_lck_mtx_data(, compilation_service_lock);
54
55 void
code_signing_init()56 code_signing_init()
57 {
58 /* Initialize compilation service lock */
59 lck_mtx_init(&compilation_service_lock, &xnu_codesigning_lck_grp, 0);
60 }
61
62 kern_return_t
xnu_secure_channel_shared_page(__unused uint64_t * secure_channel_phys,__unused size_t * secure_channel_size)63 xnu_secure_channel_shared_page(
64 __unused uint64_t *secure_channel_phys,
65 __unused size_t *secure_channel_size)
66 {
67 return KERN_NOT_SUPPORTED;
68 }
69
70 #pragma mark Developer Mode
71
72 static bool developer_mode_storage = true;
73 SECURITY_READ_ONLY_LATE(bool*) developer_mode_enabled = &developer_mode_storage;
74
75 void
xnu_toggle_developer_mode(bool state)76 xnu_toggle_developer_mode(
77 bool state)
78 {
79 /* No extra validation needed within XNU */
80 os_atomic_store(developer_mode_enabled, state, relaxed);
81 }
82
83 #pragma mark Restricted Execution Mode
84
85 kern_return_t
xnu_rem_enable(void)86 xnu_rem_enable(void)
87 {
88 return KERN_NOT_SUPPORTED;
89 }
90
91 kern_return_t
xnu_rem_state(void)92 xnu_rem_state(void)
93 {
94 return KERN_NOT_SUPPORTED;
95 }
96
97 #pragma mark Device State
98
99 void
xnu_update_device_state(void)100 xnu_update_device_state(void)
101 {
102 /* Does nothing */
103 }
104
105 void
xnu_complete_security_boot_mode(__unused uint32_t security_boot_mode)106 xnu_complete_security_boot_mode(
107 __unused uint32_t security_boot_mode)
108 {
109 /* Does nothing */
110 }
111
112 #pragma mark Code Signing
113
114 static uint8_t compilation_service_cdhash[CS_CDHASH_LEN] = {0};
115
116 void
xnu_set_compilation_service_cdhash(const uint8_t cdhash[CS_CDHASH_LEN])117 xnu_set_compilation_service_cdhash(
118 const uint8_t cdhash[CS_CDHASH_LEN])
119 {
120 lck_mtx_lock(&compilation_service_lock);
121 memcpy(compilation_service_cdhash, cdhash, CS_CDHASH_LEN);
122 lck_mtx_unlock(&compilation_service_lock);
123 }
124
125 bool
xnu_match_compilation_service_cdhash(const uint8_t cdhash[CS_CDHASH_LEN])126 xnu_match_compilation_service_cdhash(
127 const uint8_t cdhash[CS_CDHASH_LEN])
128 {
129 bool match = false;
130
131 lck_mtx_lock(&compilation_service_lock);
132 if (bcmp(compilation_service_cdhash, cdhash, CS_CDHASH_LEN) == 0) {
133 match = true;
134 }
135 lck_mtx_unlock(&compilation_service_lock);
136
137 return match;
138 }
139
140 static bool local_signing_key_set = false;
141 static uint8_t local_signing_public_key[XNU_LOCAL_SIGNING_KEY_SIZE] = {0};
142
143 void
xnu_set_local_signing_public_key(const uint8_t public_key[XNU_LOCAL_SIGNING_KEY_SIZE])144 xnu_set_local_signing_public_key(
145 const uint8_t public_key[XNU_LOCAL_SIGNING_KEY_SIZE])
146 {
147 bool key_set = false;
148
149 /*
150 * os_atomic_cmpxchg returns true in case the exchange was successful. For us,
151 * a successful exchange means that the local signing public key has _not_ been
152 * set. In case the key has been set, we panic as we would never expect the
153 * kernel to attempt to set the key more than once.
154 */
155 key_set = !os_atomic_cmpxchg(&local_signing_key_set, false, true, relaxed);
156
157 if (key_set) {
158 panic("attempted to set the local signing public key multiple times");
159 }
160
161 memcpy(local_signing_public_key, public_key, sizeof(local_signing_public_key));
162 }
163
164 uint8_t*
xnu_get_local_signing_public_key(void)165 xnu_get_local_signing_public_key(void)
166 {
167 bool key_set = os_atomic_load(&local_signing_key_set, relaxed);
168
169 if (key_set) {
170 return local_signing_public_key;
171 }
172
173 return NULL;
174 }
175
176 #pragma mark Image4
177
178 static uint8_t __attribute__((aligned(8)))
179 _xnu_image4_storage[IMG4_PMAP_DATA_SIZE_RECOMMENDED] = {0};
180
181 void*
xnu_image4_storage_data(size_t * allocated_size)182 xnu_image4_storage_data(
183 size_t *allocated_size)
184 {
185 if (allocated_size) {
186 *allocated_size = sizeof(_xnu_image4_storage);
187 }
188 return _xnu_image4_storage;
189 }
190
191 void
xnu_image4_set_nonce(const img4_nonce_domain_index_t ndi,const img4_nonce_t * nonce)192 xnu_image4_set_nonce(
193 const img4_nonce_domain_index_t ndi,
194 const img4_nonce_t *nonce)
195 {
196 /*
197 * As a hold over from legacy code, AppleImage4 only ever manages nonces
198 * from the kernel interface through the PMAP_CS runtime. So even though
199 * we don't have a PMAP_CS monitor, we still pass in the PMAP_CS runtime.
200 */
201
202 IMG4_RUNTIME_PMAP_CS->i4rt_set_nonce(
203 IMG4_RUNTIME_PMAP_CS,
204 ndi,
205 nonce);
206 }
207
208 void
xnu_image4_roll_nonce(const img4_nonce_domain_index_t ndi)209 xnu_image4_roll_nonce(
210 const img4_nonce_domain_index_t ndi)
211 {
212 /*
213 * As a hold over from legacy code, AppleImage4 only ever manages nonces
214 * from the kernel interface through the PMAP_CS runtime. So even though
215 * we don't have a PMAP_CS monitor, we still pass in the PMAP_CS runtime.
216 */
217
218 IMG4_RUNTIME_PMAP_CS->i4rt_roll_nonce(
219 IMG4_RUNTIME_PMAP_CS,
220 ndi);
221 }
222
223 errno_t
xnu_image4_copy_nonce(const img4_nonce_domain_index_t ndi,img4_nonce_t * nonce_out)224 xnu_image4_copy_nonce(
225 const img4_nonce_domain_index_t ndi,
226 img4_nonce_t *nonce_out)
227 {
228 errno_t ret = EPERM;
229
230 /*
231 * As a hold over from legacy code, AppleImage4 only ever manages nonces
232 * from the kernel interface through the PMAP_CS runtime. So even though
233 * we don't have a PMAP_CS monitor, we still pass in the PMAP_CS runtime.
234 */
235
236 ret = IMG4_RUNTIME_PMAP_CS->i4rt_copy_nonce(
237 IMG4_RUNTIME_PMAP_CS,
238 ndi,
239 nonce_out);
240
241 if (ret != 0) {
242 printf("unable to copy image4 nonce: %llu | %d\n", ndi, ret);
243 }
244
245 return ret;
246 }
247
248 errno_t
xnu_image4_execute_object(img4_runtime_object_spec_index_t obj_spec_index,const img4_buff_t * payload,const img4_buff_t * manifest)249 xnu_image4_execute_object(
250 img4_runtime_object_spec_index_t obj_spec_index,
251 const img4_buff_t *payload,
252 const img4_buff_t *manifest)
253 {
254 errno_t ret = EPERM;
255 const img4_runtime_object_spec_t *obj_spec = NULL;
256
257 obj_spec = image4_get_object_spec_from_index(obj_spec_index);
258 if (obj_spec == NULL) {
259 return ENOENT;
260 }
261
262 /*
263 * As a hold over from legacy code, AppleImage4 only ever executes objects
264 * through the kernel interface through the PMAP_CS runtime. So even though
265 * we don't have a PMAP_CS monitor, we still pass in the PMAP_CS runtime.
266 */
267
268 ret = img4_runtime_execute_object(
269 IMG4_RUNTIME_PMAP_CS,
270 obj_spec,
271 payload,
272 manifest);
273
274 if (ret != 0) {
275 printf("unable to execute image4 object: %d\n", ret);
276 }
277
278 return ret;
279 }
280
281 errno_t
xnu_image4_copy_object(img4_runtime_object_spec_index_t obj_spec_index,vm_address_t object_out,size_t * object_length)282 xnu_image4_copy_object(
283 img4_runtime_object_spec_index_t obj_spec_index,
284 vm_address_t object_out,
285 size_t *object_length)
286 {
287 errno_t ret = EPERM;
288 img4_buff_t object_payload = IMG4_BUFF_INIT;
289 size_t object_payload_length = 0;
290 const img4_runtime_object_spec_t *obj_spec = NULL;
291
292 obj_spec = image4_get_object_spec_from_index(obj_spec_index);
293 if (obj_spec == NULL) {
294 return ENOENT;
295 }
296
297 /*
298 * The object length is used as an in/out parameter, so we require that this parameter
299 * is used to specify the length of the buffer.
300 */
301 object_payload_length = *object_length;
302
303 object_payload.i4b_bytes = (void*)object_out;
304 object_payload.i4b_len = object_payload_length;
305
306 /*
307 * As a hold over from legacy code, AppleImage4 only ever copies objects
308 * through the kernel interface through the PMAP_CS runtime. So even though
309 * we don't have a PMAP_CS monitor, we still pass in the PMAP_CS runtime.
310 */
311
312 ret = img4_runtime_copy_object(
313 IMG4_RUNTIME_PMAP_CS,
314 obj_spec,
315 &object_payload,
316 &object_payload_length);
317 if (ret != 0) {
318 printf("unable to copy image4 object: %d\n", ret);
319 }
320
321 /* Update the length with what we received from the image4 runtime */
322 *object_length = object_payload_length;
323
324 return ret;
325 }
326
327 const void*
xnu_image4_get_monitor_exports(void)328 xnu_image4_get_monitor_exports(void)
329 {
330 printf("monitor exports not supported without a monitor\n");
331 return NULL;
332 }
333
334 errno_t
xnu_image4_set_release_type(__unused const char * release_type)335 xnu_image4_set_release_type(
336 __unused const char *release_type)
337 {
338 /*
339 * We don't need to inform the monitor about the release type when there
340 * is no monitor environment available.
341 */
342
343 printf("explicit release-type-set not supported without a monitor\n");
344 return ENOTSUP;
345 }
346
347 errno_t
xnu_image4_set_bnch_shadow(__unused const img4_nonce_domain_index_t ndi)348 xnu_image4_set_bnch_shadow(
349 __unused const img4_nonce_domain_index_t ndi)
350 {
351 /*
352 * We don't need to inform the monitor about the BNCH shadow when there
353 * is no monitor environment available.
354 */
355
356 printf("explicit BNCH-shadow-set not supported without a monitor\n");
357 return ENOTSUP;
358 }
359
360 #pragma mark Image4 - New
361
362 kern_return_t
xnu_image4_transfer_region(image4_cs_trap_t selector,__unused vm_address_t region_addr,__unused vm_size_t region_size)363 xnu_image4_transfer_region(
364 image4_cs_trap_t selector,
365 __unused vm_address_t region_addr,
366 __unused vm_size_t region_size)
367 {
368 panic("image4 dispatch: transfer without code signing monitor: %llu", selector);
369 }
370
371 kern_return_t
xnu_image4_reclaim_region(image4_cs_trap_t selector,__unused vm_address_t region_addr,__unused vm_size_t region_size)372 xnu_image4_reclaim_region(
373 image4_cs_trap_t selector,
374 __unused vm_address_t region_addr,
375 __unused vm_size_t region_size)
376 {
377 panic("image4 dispatch: reclaim without code signing monitor: %llu", selector);
378 }
379
380 errno_t
xnu_image4_monitor_trap(image4_cs_trap_t selector,__unused const void * input_data,__unused size_t input_size)381 xnu_image4_monitor_trap(
382 image4_cs_trap_t selector,
383 __unused const void *input_data,
384 __unused size_t input_size)
385 {
386 panic("image4 dispatch: trap without code signing monitor: %llu", selector);
387 }
388
389 #endif /* !CODE_SIGNING_MONITOR */
390