xref: /xnu-12377.61.12/bsd/kern/kern_csr.c (revision 4d495c6e23c53686cf65f45067f79024cf5dcee8)
1 /*
2  * Copyright (c) 2014 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 #include <pexpert/pexpert.h>
30 #include <sys/csr.h>
31 #include <sys/errno.h>
32 #include <sys/sysproto.h>
33 #include <sys/systm.h>
34 #include <sys/types.h>
35 
36 #if CONFIG_CSR_FROM_DT
37 
38 /*
39  * New style CSR for non-x86 platforms, using Per-OS Security Policy
40  * (POSP)
41  */
42 
43 #include <libkern/section_keywords.h>
44 #include <pexpert/device_tree.h>
45 
46 #if defined(KERNEL_INTEGRITY_KTRR) || defined(KERNEL_INTEGRITY_CTRR) || defined(KERNEL_INTEGRITY_PV_CTRR)
47 #include <arm64/amcc_rorgn.h>
48 #endif
49 
50 static SECURITY_READ_ONLY_LATE(csr_config_t) csr_config = 0;
51 
52 // WARNING: Used extremely early during boot. See csr_bootstrap().
53 static bool
_csr_get_dt_bool(DTEntry * entry,char const * name,bool * out)54 _csr_get_dt_bool(DTEntry *entry, char const *name, bool *out)
55 {
56 	const uint32_t     *value;
57 	unsigned int size;
58 
59 	if (SecureDTGetProperty(*entry, name, (const void**)&value, &size) != kSuccess) {
60 		return false;
61 	}
62 
63 	if (size != sizeof(uint32_t)) {
64 		panic("unexpected size %xu for bool property '%s'", size, name);
65 	}
66 
67 	*out = (bool)*value;
68 	return true;
69 }
70 
71 // WARNING: Used extremely early during boot. See csr_bootstrap().
72 static bool
_csr_get_dt_uint64(DTEntry * entry,char const * name,uint64_t * out)73 _csr_get_dt_uint64(DTEntry *entry, char const *name, uint64_t *out)
74 {
75 	const uint64_t     *value;
76 	unsigned int size;
77 
78 	if (SecureDTGetProperty(*entry, name, (const void**)&value, &size) != kSuccess) {
79 		return false;
80 	}
81 
82 	if (size != sizeof(uint64_t)) {
83 		panic("unexpected size %xu for uint64 property '%s'", size, name);
84 	}
85 
86 	*out = *value;
87 	return true;
88 }
89 
90 // WARNING: Used extremely early during boot. See csr_bootstrap().
91 static bool
_csr_dt_string_is_equal(DTEntry * entry,const char * name,const char * str)92 _csr_dt_string_is_equal(DTEntry *entry, const char *name, const char *str)
93 {
94 	const void       *value;
95 	unsigned         size;
96 	size_t           str_size;
97 
98 	str_size = strlen(str) + 1;
99 	return entry != NULL &&
100 	       SecureDTGetProperty(*entry, name, &value, &size) == kSuccess &&
101 	       value != NULL &&
102 	       size == str_size &&
103 	       strncmp(str, value, str_size) == 0;
104 }
105 
106 static bool
_csr_is_recovery_environment(void)107 _csr_is_recovery_environment(void)
108 {
109 	DTEntry chosen;
110 
111 	return SecureDTLookupEntry(0, "/chosen", &chosen) == kSuccess &&
112 	       _csr_dt_string_is_equal(&chosen, "osenvironment", "recoveryos");
113 }
114 
115 static bool
_csr_is_restore_environment(void)116 _csr_is_restore_environment(void)
117 {
118 	int notused;
119 
120 	return PE_parse_boot_argn("-restore", &notused, sizeof(notused));
121 }
122 
123 static bool
_csr_is_darwinos_ramdisk(void)124 _csr_is_darwinos_ramdisk(void)
125 {
126 	DTEntry chosen;
127 
128 	return SecureDTLookupEntry(0, "/chosen", &chosen) == kSuccess &&
129 	       _csr_dt_string_is_equal(&chosen, "osenvironment", "darwinos-ramdisk");
130 }
131 
132 static bool
_csr_is_iuou_or_iuos_device(void)133 _csr_is_iuou_or_iuos_device(void)
134 {
135 	DTEntry entry;
136 	bool    bool_value;
137 
138 	return (SecureDTLookupEntry(0, "/chosen", &entry) == kSuccess &&
139 	       (_csr_get_dt_bool(&entry, "internal-use-only-unit", &bool_value) && bool_value)) ||
140 	       (SecureDTLookupEntry(0, "/chosen/manifest-properties", &entry) == kSuccess &&
141 	       (_csr_get_dt_bool(&entry, "iuos", &bool_value) && bool_value));
142 }
143 
144 static bool
_csr_should_allow_device_configuration(void)145 _csr_should_allow_device_configuration(void)
146 {
147 	/*
148 	 * Allow CSR_ALLOW_DEVICE_CONFIGURATION if the device is running in a
149 	 * restore environment, or if the "csr-allow-device-configuration"
150 	 * property is set in the device tree.
151 	 */
152 	DTEntry chosen;
153 	bool    bool_value;
154 
155 	return _csr_is_recovery_environment() || (
156 		SecureDTLookupEntry(0, "/chosen", &chosen) == kSuccess &&
157 		_csr_get_dt_bool(&chosen, "csr-allow-device-configuration", &bool_value) && bool_value);
158 }
159 
160 /*
161  * Initialize CSR from the Device Tree.
162  *
163  * WARNING: csr_bootstrap() is called extremely early in the kernel
164  * startup process in kernel_startup_bootstrap(), which happens
165  * before even the vm or pmap layer are initialized.
166  *
167  * It is marked as STARTUP_RANK_FIRST so that it is called before panic_init(),
168  * which runs during STARTUP_RANK_MIDDLE. This is necessary because panic_init()
169  * calls csr_check() to determine whether the device is configured to allow
170  * kernel debugging.
171  *
172  * Only do things here that don't require any dynamic memory (other
173  * than the stack). Parsing boot-args, walking the device tree and
174  * setting global variables is fine, most other things are not. Defer
175  * those other things with global variables, if necessary.
176  *
177  */
178 __startup_func
179 static void
csr_bootstrap(void)180 csr_bootstrap(void)
181 {
182 	DTEntry         entry;
183 	uint64_t        uint64_value;
184 	bool            config_active   = false;
185 	bool            bool_value;
186 
187 	csr_config = 0;                // start out fully restrictive
188 
189 	if (SecureDTLookupEntry(0, "/chosen/asmb", &entry) == kSuccess &&
190 	    _csr_get_dt_uint64(&entry, "lp-sip0", &uint64_value)) {
191 		csr_config = (uint32_t)uint64_value;    // Currently only 32 bits used.
192 		config_active = true;
193 	}
194 
195 	/*
196 	 * If the device is an Internal Use Only Unit (IUOU) or if it is running a
197 	 * build that is signed with the Internal Use Only Software (IUOS) tag, then
198 	 * allow the preservation of the CSR_ALLOW_APPLE_INTERNAL bit. Otherwise,
199 	 * forcefully remove the bit on boot.
200 	 */
201 	if (!_csr_is_iuou_or_iuos_device()) {
202 		csr_config &= ~CSR_ALLOW_APPLE_INTERNAL;
203 	} else if (!config_active) {
204 		// If there is no custom configuration present, infer the AppleInternal
205 		// bit on IUOU or IUOS devices.
206 		csr_config |= CSR_ALLOW_APPLE_INTERNAL;
207 	}
208 
209 	// Unrestrict filesystem access in recovery and restore OS.
210 	// This is required so the MSU stack can mount/unmount the update volume
211 	// during paired recovery.
212 	if (_csr_is_recovery_environment() ||
213 	    _csr_is_restore_environment() ||
214 	    _csr_is_darwinos_ramdisk()) {
215 		csr_config |= CSR_ALLOW_UNRESTRICTED_FS;
216 	}
217 
218 	if (_csr_should_allow_device_configuration()) {
219 		csr_config |= CSR_ALLOW_DEVICE_CONFIGURATION;
220 	}
221 
222 	// The CSR_ALLOW_UNAUTHENTICATED_ROOT flag must be synthesized from sip1
223 	// in the local boot policy.
224 	if (_csr_get_dt_bool(&entry, "lp-sip1", &bool_value) && bool_value) {
225 		csr_config |= CSR_ALLOW_UNAUTHENTICATED_ROOT;
226 	} else {
227 		csr_config &= ~CSR_ALLOW_UNAUTHENTICATED_ROOT;
228 	}
229 }
230 STARTUP(TUNABLES, STARTUP_RANK_FIRST, csr_bootstrap);
231 
232 int
csr_get_active_config(csr_config_t * config)233 csr_get_active_config(csr_config_t * config)
234 {
235 	*config = (csr_config & CSR_VALID_FLAGS);
236 
237 	return 0;
238 }
239 
240 int
csr_check(csr_config_t mask)241 csr_check(csr_config_t mask)
242 {
243 	csr_config_t config;
244 	int ret = csr_get_active_config(&config);
245 
246 	if (ret != 0) {
247 		return ret;
248 	}
249 
250 	// CSR_ALLOW_KERNEL_DEBUGGER needs to be allowed when SIP is disabled
251 	// to allow 3rd-party developers to debug their kexts.  Use
252 	// CSR_ALLOW_UNTRUSTED_KEXTS as a proxy for "SIP is disabled" on the
253 	// grounds that you can do the same damage with a kernel debugger as
254 	// you can with an untrusted kext.
255 	if ((config & (CSR_ALLOW_UNTRUSTED_KEXTS | CSR_ALLOW_APPLE_INTERNAL)) != 0) {
256 		config |= CSR_ALLOW_KERNEL_DEBUGGER;
257 	}
258 
259 	return ((config & mask) == mask) ? 0 : EPERM;
260 }
261 
262 #else
263 
264 /*
265  * Old style CSR for x86 platforms, using NVRAM values
266  */
267 
268 #include <libkern/section_keywords.h>
269 
270 /* enable enforcement by default */
271 static SECURITY_READ_ONLY_LATE(int) csr_allow_all = 0;
272 
273 /*
274  * Initialize csr_allow_all from device boot state.
275  *
276  * Needs to be run before panic_init() since panic_init()
277  * calls into csr_check() and runs during STARTUP_RANK_MIDDLE.
278  */
279 __startup_func
280 static void
csr_bootstrap(void)281 csr_bootstrap(void)
282 {
283 	boot_args *args = (boot_args *)PE_state.bootArgs;
284 	if (args->flags & kBootArgsFlagCSRBoot) {
285 		/* special booter; allow everything */
286 		csr_allow_all = 1;
287 	}
288 }
289 STARTUP(TUNABLES, STARTUP_RANK_FIRST, csr_bootstrap);
290 
291 
292 int
csr_get_active_config(csr_config_t * config)293 csr_get_active_config(csr_config_t *config)
294 {
295 	boot_args *args = (boot_args *)PE_state.bootArgs;
296 	if (args->flags & kBootArgsFlagCSRActiveConfig) {
297 		*config = args->csrActiveConfig & CSR_VALID_FLAGS;
298 	} else {
299 		*config = 0;
300 	}
301 
302 	return 0;
303 }
304 
305 int
csr_check(csr_config_t mask)306 csr_check(csr_config_t mask)
307 {
308 	boot_args *args = (boot_args *)PE_state.bootArgs;
309 	if (mask & CSR_ALLOW_DEVICE_CONFIGURATION) {
310 		return (args->flags & kBootArgsFlagCSRConfigMode) ? 0 : EPERM;
311 	}
312 
313 	csr_config_t config;
314 	int ret = csr_get_active_config(&config);
315 	if (ret) {
316 		return ret;
317 	}
318 
319 	// CSR_ALLOW_KERNEL_DEBUGGER needs to be allowed when SIP is disabled
320 	// to allow 3rd-party developers to debug their kexts.  Use
321 	// CSR_ALLOW_UNTRUSTED_KEXTS as a proxy for "SIP is disabled" on the
322 	// grounds that you can do the same damage with a kernel debugger as
323 	// you can with an untrusted kext.
324 	if ((config & (CSR_ALLOW_UNTRUSTED_KEXTS | CSR_ALLOW_APPLE_INTERNAL)) != 0) {
325 		config |= CSR_ALLOW_KERNEL_DEBUGGER;
326 	}
327 
328 	ret = ((config & mask) == mask) ? 0 : EPERM;
329 	if (ret == EPERM) {
330 		// Override the return value if booted from the BaseSystem and the mask does not contain any flag that should always be enforced.
331 		if (csr_allow_all && (mask & CSR_ALWAYS_ENFORCED_FLAGS) == 0) {
332 			ret = 0;
333 		}
334 	}
335 
336 	return ret;
337 }
338 
339 #endif /* CONFIG_CSR_FROM_DT */
340 
341 /*
342  * Syscall stubs
343  */
344 
345 int syscall_csr_check(struct csrctl_args *args);
346 int syscall_csr_get_active_config(struct csrctl_args *args);
347 
348 
349 int
syscall_csr_check(struct csrctl_args * args)350 syscall_csr_check(struct csrctl_args *args)
351 {
352 	csr_config_t mask = 0;
353 	int error = 0;
354 
355 	if (args->useraddr == 0 || args->usersize != sizeof(mask)) {
356 		return EINVAL;
357 	}
358 
359 	error = copyin(args->useraddr, &mask, sizeof(mask));
360 	if (error) {
361 		return error;
362 	}
363 
364 	return csr_check(mask);
365 }
366 
367 int
syscall_csr_get_active_config(struct csrctl_args * args)368 syscall_csr_get_active_config(struct csrctl_args *args)
369 {
370 	csr_config_t config = 0;
371 	int error = 0;
372 
373 	if (args->useraddr == 0 || args->usersize != sizeof(config)) {
374 		return EINVAL;
375 	}
376 
377 	error = csr_get_active_config(&config);
378 	if (error) {
379 		return error;
380 	}
381 
382 	return copyout(&config, args->useraddr, sizeof(config));
383 }
384 
385 /*
386  * Syscall entrypoint
387  */
388 
389 int
csrctl(__unused proc_t p,struct csrctl_args * args,__unused int32_t * retval)390 csrctl(__unused proc_t p, struct csrctl_args *args, __unused int32_t *retval)
391 {
392 	switch (args->op) {
393 	case CSR_SYSCALL_CHECK:
394 		return syscall_csr_check(args);
395 	case CSR_SYSCALL_GET_ACTIVE_CONFIG:
396 		return syscall_csr_get_active_config(args);
397 	default:
398 		return ENOSYS;
399 	}
400 }
401