]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_csr.c
xnu-7195.81.3.tar.gz
[apple/xnu.git] / bsd / kern / kern_csr.c
CommitLineData
fe8ab488
A
1/*
2 * Copyright (c) 2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
490019cf 5 *
fe8ab488
A
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.
490019cf 14 *
fe8ab488
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
490019cf 17 *
fe8ab488
A
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.
490019cf 25 *
fe8ab488
A
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
f427ee49
A
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)
47#include <arm64/amcc_rorgn.h>
48#endif
49
50static SECURITY_READ_ONLY_LATE(csr_config_t) csr_config = 0;
51
52// WARNING: Used extremely early during boot. See csr_bootstrap().
53static bool
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().
72static bool
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().
91static bool
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
106static bool
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
115static bool
116_csr_is_iuou_or_iuos_device(void)
117{
118 DTEntry entry;
119 bool bool_value;
120
121 return (SecureDTLookupEntry(0, "/chosen", &entry) == kSuccess &&
122 (_csr_get_dt_bool(&entry, "internal-use-only-unit", &bool_value) && bool_value)) ||
123 (SecureDTLookupEntry(0, "/chosen/manifest-properties", &entry) == kSuccess &&
124 (_csr_get_dt_bool(&entry, "iuos", &bool_value) && bool_value));
125}
126
127static bool
128_csr_should_allow_device_configuration(void)
129{
130 /*
131 * Allow CSR_ALLOW_DEVICE_CONFIGURATION if the device is running in a
132 * restore environment, or if the "csr-allow-device-configuration"
133 * property is set in the device tree.
134 */
135 DTEntry chosen;
136 bool bool_value;
137
138 return _csr_is_recovery_environment() || (
139 SecureDTLookupEntry(0, "/chosen", &chosen) == kSuccess &&
140 _csr_get_dt_bool(&chosen, "csr-allow-device-configuration", &bool_value) && bool_value);
141}
142
143/*
144 * Initialize CSR from the Device Tree.
145 *
146 * WARNING: csr_bootstrap() is called extremely early in the kernel
147 * startup process in kernel_startup_bootstrap(), which happens
148 * before even the vm or pmap layer are initialized.
149 *
150 * It is marked as STARTUP_RANK_FIRST so that it is called before panic_init(),
151 * which runs during STARTUP_RANK_MIDDLE. This is necessary because panic_init()
152 * calls csr_check() to determine whether the device is configured to allow
153 * kernel debugging.
154 *
155 * Only do things here that don't require any dynamic memory (other
156 * than the stack). Parsing boot-args, walking the device tree and
157 * setting global variables is fine, most other things are not. Defer
158 * those other things with global variables, if necessary.
159 *
160 */
161__startup_func
162static void
163csr_bootstrap(void)
164{
165 DTEntry entry;
166 uint64_t uint64_value;
167 bool config_active = false;
168 bool bool_value;
169
170 csr_config = 0; // start out fully restrictive
171
172 if (SecureDTLookupEntry(0, "/chosen/asmb", &entry) == kSuccess &&
173 _csr_get_dt_uint64(&entry, "lp-sip0", &uint64_value)) {
174 csr_config = (uint32_t)uint64_value; // Currently only 32 bits used.
175 config_active = true;
176 }
177
178 /*
179 * If the device is an Internal Use Only Unit (IUOU) or if it is running a
180 * build that is signed with the Internal Use Only Software (IUOS) tag, then
181 * allow the preservation of the CSR_ALLOW_APPLE_INTERNAL bit. Otherwise,
182 * forcefully remove the bit on boot.
183 */
184 if (!_csr_is_iuou_or_iuos_device()) {
185 csr_config &= ~CSR_ALLOW_APPLE_INTERNAL;
186 } else if (!config_active) {
187 // If there is no custom configuration present, infer the AppleInternal
188 // bit on IUOU or IUOS devices.
189 csr_config |= CSR_ALLOW_APPLE_INTERNAL;
190 }
191
192 if (_csr_should_allow_device_configuration()) {
193 csr_config |= CSR_ALLOW_DEVICE_CONFIGURATION;
194 }
195
196 // The CSR_ALLOW_UNAUTHENTICATED_ROOT flag must be synthesized from sip1
197 // in the local boot policy.
198 if (_csr_get_dt_bool(&entry, "lp-sip1", &bool_value) && bool_value) {
199 csr_config |= CSR_ALLOW_UNAUTHENTICATED_ROOT;
200 } else {
201 csr_config &= ~CSR_ALLOW_UNAUTHENTICATED_ROOT;
202 }
203
204#if defined(KERNEL_INTEGRITY_KTRR) || defined(KERNEL_INTEGRITY_CTRR)
205 // Check whether we have to disable CTRR.
206 // lp-sip2 in the local boot policy is the bit driving this,
207 // which csrutil also sets implicitly when e.g. requesting kernel debugging.
208 csr_unsafe_kernel_text = _csr_get_dt_bool(&entry, "lp-sip2", &bool_value) && bool_value;
209#endif
210}
211STARTUP(TUNABLES, STARTUP_RANK_FIRST, csr_bootstrap);
212
213int
214csr_get_active_config(csr_config_t * config)
215{
216 *config = (csr_config & CSR_VALID_FLAGS);
217
218 return 0;
219}
220
221int
222csr_check(csr_config_t mask)
223{
224 csr_config_t config;
225 int ret = csr_get_active_config(&config);
226
227 if (ret != 0) {
228 return ret;
229 }
230
231 // CSR_ALLOW_KERNEL_DEBUGGER needs to be allowed when SIP is disabled
232 // to allow 3rd-party developers to debug their kexts. Use
233 // CSR_ALLOW_UNTRUSTED_KEXTS as a proxy for "SIP is disabled" on the
234 // grounds that you can do the same damage with a kernel debugger as
235 // you can with an untrusted kext.
236 if ((config & (CSR_ALLOW_UNTRUSTED_KEXTS | CSR_ALLOW_APPLE_INTERNAL)) != 0) {
237 config |= CSR_ALLOW_KERNEL_DEBUGGER;
238 }
239
240 return ((config & mask) == mask) ? 0 : EPERM;
241}
242
243#else
244
245/*
246 * Old style CSR for x86 platforms, using NVRAM values
247 */
248
249#include <libkern/section_keywords.h>
250
3e170ce0 251/* enable enforcement by default */
f427ee49 252static SECURITY_READ_ONLY_LATE(int) csr_allow_all = 0;
fe8ab488 253
f427ee49
A
254/*
255 * Initialize csr_allow_all from device boot state.
256 *
257 * Needs to be run before panic_init() since panic_init()
258 * calls into csr_check() and runs during STARTUP_RANK_MIDDLE.
259 */
260__startup_func
261static void
262csr_bootstrap(void)
fe8ab488
A
263{
264 boot_args *args = (boot_args *)PE_state.bootArgs;
265 if (args->flags & kBootArgsFlagCSRBoot) {
266 /* special booter; allow everything */
267 csr_allow_all = 1;
268 }
fe8ab488 269}
f427ee49
A
270STARTUP(TUNABLES, STARTUP_RANK_FIRST, csr_bootstrap);
271
fe8ab488
A
272
273int
274csr_get_active_config(csr_config_t *config)
275{
276 boot_args *args = (boot_args *)PE_state.bootArgs;
277 if (args->flags & kBootArgsFlagCSRActiveConfig) {
278 *config = args->csrActiveConfig & CSR_VALID_FLAGS;
279 } else {
3e170ce0 280 *config = 0;
fe8ab488
A
281 }
282
283 return 0;
284}
285
286int
3e170ce0 287csr_check(csr_config_t mask)
fe8ab488
A
288{
289 boot_args *args = (boot_args *)PE_state.bootArgs;
0a7de745 290 if (mask & CSR_ALLOW_DEVICE_CONFIGURATION) {
813fb2f6 291 return (args->flags & kBootArgsFlagCSRConfigMode) ? 0 : EPERM;
0a7de745 292 }
fe8ab488
A
293
294 csr_config_t config;
813fb2f6
A
295 int ret = csr_get_active_config(&config);
296 if (ret) {
297 return ret;
fe8ab488
A
298 }
299
5ba3f43e
A
300 // CSR_ALLOW_KERNEL_DEBUGGER needs to be allowed when SIP is disabled
301 // to allow 3rd-party developers to debug their kexts. Use
302 // CSR_ALLOW_UNTRUSTED_KEXTS as a proxy for "SIP is disabled" on the
303 // grounds that you can do the same damage with a kernel debugger as
304 // you can with an untrusted kext.
0a7de745 305 if ((config & (CSR_ALLOW_UNTRUSTED_KEXTS | CSR_ALLOW_APPLE_INTERNAL)) != 0) {
5ba3f43e 306 config |= CSR_ALLOW_KERNEL_DEBUGGER;
0a7de745 307 }
5ba3f43e
A
308
309 ret = ((config & mask) == mask) ? 0 : EPERM;
813fb2f6
A
310 if (ret == EPERM) {
311 // Override the return value if booted from the BaseSystem and the mask does not contain any flag that should always be enforced.
0a7de745 312 if (csr_allow_all && (mask & CSR_ALWAYS_ENFORCED_FLAGS) == 0) {
813fb2f6 313 ret = 0;
0a7de745 314 }
fe8ab488
A
315 }
316
813fb2f6 317 return ret;
fe8ab488
A
318}
319
f427ee49
A
320#endif /* CONFIG_CSR_FROM_DT */
321
3e170ce0
A
322/*
323 * Syscall stubs
324 */
325
326int syscall_csr_check(struct csrctl_args *args);
327int syscall_csr_get_active_config(struct csrctl_args *args);
328
329
330int
331syscall_csr_check(struct csrctl_args *args)
332{
333 csr_config_t mask = 0;
334 int error = 0;
335
0a7de745 336 if (args->useraddr == 0 || args->usersize != sizeof(mask)) {
3e170ce0 337 return EINVAL;
0a7de745 338 }
3e170ce0
A
339
340 error = copyin(args->useraddr, &mask, sizeof(mask));
0a7de745 341 if (error) {
3e170ce0 342 return error;
0a7de745 343 }
3e170ce0
A
344
345 return csr_check(mask);
346}
347
348int
349syscall_csr_get_active_config(struct csrctl_args *args)
350{
351 csr_config_t config = 0;
352 int error = 0;
353
0a7de745 354 if (args->useraddr == 0 || args->usersize != sizeof(config)) {
3e170ce0 355 return EINVAL;
0a7de745 356 }
3e170ce0
A
357
358 error = csr_get_active_config(&config);
0a7de745 359 if (error) {
3e170ce0 360 return error;
0a7de745 361 }
3e170ce0
A
362
363 return copyout(&config, args->useraddr, sizeof(config));
364}
365
366/*
367 * Syscall entrypoint
368 */
369
370int
371csrctl(__unused proc_t p, struct csrctl_args *args, __unused int32_t *retval)
372{
373 switch (args->op) {
0a7de745
A
374 case CSR_SYSCALL_CHECK:
375 return syscall_csr_check(args);
376 case CSR_SYSCALL_GET_ACTIVE_CONFIG:
377 return syscall_csr_get_active_config(args);
378 default:
379 return ENOSYS;
3e170ce0
A
380 }
381}