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 */
49LCK_GRP_DECLARE(xnu_codesigning_lck_grp, "xnu_codesigning_lck_grp");
50
51#pragma mark Initialization
52
53static decl_lck_mtx_data(, compilation_service_lock);
54
55void
56code_signing_init()
57{
58 /* Initialize compilation service lock */
59 lck_mtx_init(lck: &compilation_service_lock, grp: &xnu_codesigning_lck_grp, attr: 0);
60}
61
62#pragma mark Developer Mode
63
64static bool developer_mode_storage = true;
65SECURITY_READ_ONLY_LATE(bool*) developer_mode_enabled = &developer_mode_storage;
66
67void
68xnu_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
77static uint8_t compilation_service_cdhash[CS_CDHASH_LEN] = {0};
78
79void
80xnu_set_compilation_service_cdhash(
81 const uint8_t cdhash[CS_CDHASH_LEN])
82{
83 lck_mtx_lock(lck: &compilation_service_lock);
84 memcpy(dst: compilation_service_cdhash, src: cdhash, n: CS_CDHASH_LEN);
85 lck_mtx_unlock(lck: &compilation_service_lock);
86}
87
88bool
89xnu_match_compilation_service_cdhash(
90 const uint8_t cdhash[CS_CDHASH_LEN])
91{
92 bool match = false;
93
94 lck_mtx_lock(lck: &compilation_service_lock);
95 if (bcmp(s1: compilation_service_cdhash, s2: cdhash, n: CS_CDHASH_LEN) == 0) {
96 match = true;
97 }
98 lck_mtx_unlock(lck: &compilation_service_lock);
99
100 return match;
101}
102
103static bool local_signing_key_set = false;
104static uint8_t local_signing_public_key[XNU_LOCAL_SIGNING_KEY_SIZE] = {0};
105
106void
107xnu_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(dst: local_signing_public_key, src: public_key, n: sizeof(local_signing_public_key));
125}
126
127uint8_t*
128xnu_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
141static uint8_t __attribute__((aligned(8)))
142_xnu_image4_storage[IMG4_PMAP_DATA_SIZE_RECOMMENDED] = {0};
143
144void*
145xnu_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
154void
155xnu_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
171void
172xnu_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
186errno_t
187xnu_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
211errno_t
212xnu_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
244errno_t
245xnu_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
290const void*
291xnu_image4_get_monitor_exports(void)
292{
293 printf("monitor exports not supported without a monitor\n");
294 return NULL;
295}
296
297errno_t
298xnu_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
310errno_t
311xnu_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
325kern_return_t
326xnu_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
334kern_return_t
335xnu_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
343errno_t
344xnu_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