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 #pragma mark Developer Mode
63
64 static bool developer_mode_storage = true;
65 SECURITY_READ_ONLY_LATE(bool*) developer_mode_enabled = &developer_mode_storage;
66
67 void
xnu_toggle_developer_mode(bool state)68 xnu_toggle_developer_mode(
69 bool state)
70 {
71 /* No extra validation needed within XNU */
72 os_atomic_store(developer_mode_enabled, state, relaxed);
73 }
74
75 #pragma mark Code Signing
76
77 static uint8_t compilation_service_cdhash[CS_CDHASH_LEN] = {0};
78
79 void
xnu_set_compilation_service_cdhash(const uint8_t cdhash[CS_CDHASH_LEN])80 xnu_set_compilation_service_cdhash(
81 const uint8_t cdhash[CS_CDHASH_LEN])
82 {
83 lck_mtx_lock(&compilation_service_lock);
84 memcpy(compilation_service_cdhash, cdhash, CS_CDHASH_LEN);
85 lck_mtx_unlock(&compilation_service_lock);
86 }
87
88 bool
xnu_match_compilation_service_cdhash(const uint8_t cdhash[CS_CDHASH_LEN])89 xnu_match_compilation_service_cdhash(
90 const uint8_t cdhash[CS_CDHASH_LEN])
91 {
92 bool match = false;
93
94 lck_mtx_lock(&compilation_service_lock);
95 if (bcmp(compilation_service_cdhash, cdhash, CS_CDHASH_LEN) == 0) {
96 match = true;
97 }
98 lck_mtx_unlock(&compilation_service_lock);
99
100 return match;
101 }
102
103 static bool local_signing_key_set = false;
104 static uint8_t local_signing_public_key[XNU_LOCAL_SIGNING_KEY_SIZE] = {0};
105
106 void
xnu_set_local_signing_public_key(const uint8_t public_key[XNU_LOCAL_SIGNING_KEY_SIZE])107 xnu_set_local_signing_public_key(
108 const uint8_t public_key[XNU_LOCAL_SIGNING_KEY_SIZE])
109 {
110 bool key_set = false;
111
112 /*
113 * os_atomic_cmpxchg returns true in case the exchange was successful. For us,
114 * a successful exchange means that the local signing public key has _not_ been
115 * set. In case the key has been set, we panic as we would never expect the
116 * kernel to attempt to set the key more than once.
117 */
118 key_set = !os_atomic_cmpxchg(&local_signing_key_set, false, true, relaxed);
119
120 if (key_set) {
121 panic("attempted to set the local signing public key multiple times");
122 }
123
124 memcpy(local_signing_public_key, public_key, sizeof(local_signing_public_key));
125 }
126
127 uint8_t*
xnu_get_local_signing_public_key(void)128 xnu_get_local_signing_public_key(void)
129 {
130 bool key_set = os_atomic_load(&local_signing_key_set, relaxed);
131
132 if (key_set) {
133 return local_signing_public_key;
134 }
135
136 return NULL;
137 }
138
139 #pragma mark Image4
140
141 static uint8_t __attribute__((aligned(8)))
142 _xnu_image4_storage[IMG4_PMAP_DATA_SIZE_RECOMMENDED] = {0};
143
144 void*
xnu_image4_storage_data(size_t * allocated_size)145 xnu_image4_storage_data(
146 size_t *allocated_size)
147 {
148 if (allocated_size) {
149 *allocated_size = sizeof(_xnu_image4_storage);
150 }
151 return _xnu_image4_storage;
152 }
153
154 void
xnu_image4_set_nonce(const img4_nonce_domain_index_t ndi,const img4_nonce_t * nonce)155 xnu_image4_set_nonce(
156 const img4_nonce_domain_index_t ndi,
157 const img4_nonce_t *nonce)
158 {
159 /*
160 * As a hold over from legacy code, AppleImage4 only ever manages nonces
161 * from the kernel interface through the PMAP_CS runtime. So even though
162 * we don't have a PMAP_CS monitor, we still pass in the PMAP_CS runtime.
163 */
164
165 IMG4_RUNTIME_PMAP_CS->i4rt_set_nonce(
166 IMG4_RUNTIME_PMAP_CS,
167 ndi,
168 nonce);
169 }
170
171 void
xnu_image4_roll_nonce(const img4_nonce_domain_index_t ndi)172 xnu_image4_roll_nonce(
173 const img4_nonce_domain_index_t ndi)
174 {
175 /*
176 * As a hold over from legacy code, AppleImage4 only ever manages nonces
177 * from the kernel interface through the PMAP_CS runtime. So even though
178 * we don't have a PMAP_CS monitor, we still pass in the PMAP_CS runtime.
179 */
180
181 IMG4_RUNTIME_PMAP_CS->i4rt_roll_nonce(
182 IMG4_RUNTIME_PMAP_CS,
183 ndi);
184 }
185
186 errno_t
xnu_image4_copy_nonce(const img4_nonce_domain_index_t ndi,img4_nonce_t * nonce_out)187 xnu_image4_copy_nonce(
188 const img4_nonce_domain_index_t ndi,
189 img4_nonce_t *nonce_out)
190 {
191 errno_t ret = EPERM;
192
193 /*
194 * As a hold over from legacy code, AppleImage4 only ever manages nonces
195 * from the kernel interface through the PMAP_CS runtime. So even though
196 * we don't have a PMAP_CS monitor, we still pass in the PMAP_CS runtime.
197 */
198
199 ret = IMG4_RUNTIME_PMAP_CS->i4rt_copy_nonce(
200 IMG4_RUNTIME_PMAP_CS,
201 ndi,
202 nonce_out);
203
204 if (ret != 0) {
205 printf("unable to copy image4 nonce: %llu | %d\n", ndi, ret);
206 }
207
208 return ret;
209 }
210
211 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)212 xnu_image4_execute_object(
213 img4_runtime_object_spec_index_t obj_spec_index,
214 const img4_buff_t *payload,
215 const img4_buff_t *manifest)
216 {
217 errno_t ret = EPERM;
218 const img4_runtime_object_spec_t *obj_spec = NULL;
219
220 obj_spec = image4_get_object_spec_from_index(obj_spec_index);
221 if (obj_spec == NULL) {
222 return ENOENT;
223 }
224
225 /*
226 * As a hold over from legacy code, AppleImage4 only ever executes objects
227 * through the kernel interface through the PMAP_CS runtime. So even though
228 * we don't have a PMAP_CS monitor, we still pass in the PMAP_CS runtime.
229 */
230
231 ret = img4_runtime_execute_object(
232 IMG4_RUNTIME_PMAP_CS,
233 obj_spec,
234 payload,
235 manifest);
236
237 if (ret != 0) {
238 printf("unable to execute image4 object: %d\n", ret);
239 }
240
241 return ret;
242 }
243
244 errno_t
xnu_image4_copy_object(img4_runtime_object_spec_index_t obj_spec_index,vm_address_t object_out,size_t * object_length)245 xnu_image4_copy_object(
246 img4_runtime_object_spec_index_t obj_spec_index,
247 vm_address_t object_out,
248 size_t *object_length)
249 {
250 errno_t ret = EPERM;
251 img4_buff_t object_payload = IMG4_BUFF_INIT;
252 size_t object_payload_length = 0;
253 const img4_runtime_object_spec_t *obj_spec = NULL;
254
255 obj_spec = image4_get_object_spec_from_index(obj_spec_index);
256 if (obj_spec == NULL) {
257 return ENOENT;
258 }
259
260 /*
261 * The object length is used as an in/out parameter, so we require that this parameter
262 * is used to specify the length of the buffer.
263 */
264 object_payload_length = *object_length;
265
266 object_payload.i4b_bytes = (void*)object_out;
267 object_payload.i4b_len = object_payload_length;
268
269 /*
270 * As a hold over from legacy code, AppleImage4 only ever copies objects
271 * through the kernel interface through the PMAP_CS runtime. So even though
272 * we don't have a PMAP_CS monitor, we still pass in the PMAP_CS runtime.
273 */
274
275 ret = img4_runtime_copy_object(
276 IMG4_RUNTIME_PMAP_CS,
277 obj_spec,
278 &object_payload,
279 &object_payload_length);
280 if (ret != 0) {
281 printf("unable to copy image4 object: %d\n", ret);
282 }
283
284 /* Update the length with what we received from the image4 runtime */
285 *object_length = object_payload_length;
286
287 return ret;
288 }
289
290 const void*
xnu_image4_get_monitor_exports(void)291 xnu_image4_get_monitor_exports(void)
292 {
293 printf("monitor exports not supported without a monitor\n");
294 return NULL;
295 }
296
297 errno_t
xnu_image4_set_release_type(__unused const char * release_type)298 xnu_image4_set_release_type(
299 __unused const char *release_type)
300 {
301 /*
302 * We don't need to inform the monitor about the release type when there
303 * is no monitor environment available.
304 */
305
306 printf("explicit release-type-set not supported without a monitor\n");
307 return ENOTSUP;
308 }
309
310 errno_t
xnu_image4_set_bnch_shadow(__unused const img4_nonce_domain_index_t ndi)311 xnu_image4_set_bnch_shadow(
312 __unused const img4_nonce_domain_index_t ndi)
313 {
314 /*
315 * We don't need to inform the monitor about the BNCH shadow when there
316 * is no monitor environment available.
317 */
318
319 printf("explicit BNCH-shadow-set not supported without a monitor\n");
320 return ENOTSUP;
321 }
322
323 #pragma mark Image4 - New
324
325 kern_return_t
xnu_image4_transfer_region(image4_cs_trap_t selector,__unused vm_address_t region_addr,__unused vm_size_t region_size)326 xnu_image4_transfer_region(
327 image4_cs_trap_t selector,
328 __unused vm_address_t region_addr,
329 __unused vm_size_t region_size)
330 {
331 panic("image4 dispatch: transfer without code signing monitor: %llu", selector);
332 }
333
334 kern_return_t
xnu_image4_reclaim_region(image4_cs_trap_t selector,__unused vm_address_t region_addr,__unused vm_size_t region_size)335 xnu_image4_reclaim_region(
336 image4_cs_trap_t selector,
337 __unused vm_address_t region_addr,
338 __unused vm_size_t region_size)
339 {
340 panic("image4 dispatch: reclaim without code signing monitor: %llu", selector);
341 }
342
343 errno_t
xnu_image4_monitor_trap(image4_cs_trap_t selector,__unused const void * input_data,__unused size_t input_size)344 xnu_image4_monitor_trap(
345 image4_cs_trap_t selector,
346 __unused const void *input_data,
347 __unused size_t input_size)
348 {
349 panic("image4 dispatch: trap without code signing monitor: %llu", selector);
350 }
351
352 #endif /* !CODE_SIGNING_MONITOR */
353