xref: /xnu-10002.41.9/bsd/kern/code_signing/xnu.c (revision 699cd48037512bf4380799317ca44ca453c82f57)
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 #endif /* !CODE_SIGNING_MONITOR */
324