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