]>
Commit | Line | Data |
---|---|---|
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 | ||
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 | |
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 | |
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 | |
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 | |
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 | |
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 | ||
127 | static 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 | |
162 | static void | |
163 | csr_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 | } | |
211 | STARTUP(TUNABLES, STARTUP_RANK_FIRST, csr_bootstrap); | |
212 | ||
213 | int | |
214 | csr_get_active_config(csr_config_t * config) | |
215 | { | |
216 | *config = (csr_config & CSR_VALID_FLAGS); | |
217 | ||
218 | return 0; | |
219 | } | |
220 | ||
221 | int | |
222 | csr_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 | 252 | static 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 | |
261 | static void | |
262 | csr_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 |
270 | STARTUP(TUNABLES, STARTUP_RANK_FIRST, csr_bootstrap); |
271 | ||
fe8ab488 A |
272 | |
273 | int | |
274 | csr_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 | ||
286 | int | |
3e170ce0 | 287 | csr_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 | ||
326 | int syscall_csr_check(struct csrctl_args *args); | |
327 | int syscall_csr_get_active_config(struct csrctl_args *args); | |
328 | ||
329 | ||
330 | int | |
331 | syscall_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 | ||
348 | int | |
349 | syscall_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 | ||
370 | int | |
371 | csrctl(__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 | } |