xref: /xnu-11215/bsd/kern/code_signing/xnu.c (revision 8d741a5d)
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