X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/fe8ab488e9161c46dd9885d58fc52996dc0249ff..refs/heads/master:/bsd/kern/kern_csr.c diff --git a/bsd/kern/kern_csr.c b/bsd/kern/kern_csr.c index 7badfcc58..29f2d080c 100644 --- a/bsd/kern/kern_csr.c +++ b/bsd/kern/kern_csr.c @@ -2,7 +2,7 @@ * 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 @@ -11,10 +11,10 @@ * 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, @@ -22,7 +22,7 @@ * 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@ */ @@ -33,103 +33,242 @@ #include #include -/* allow everything by default? */ -/* XXX: set this to 0 later: */ -static int csr_allow_all = 1; +#if CONFIG_CSR_FROM_DT + +/* + * New style CSR for non-x86 platforms, using Per-OS Security Policy + * (POSP) + */ + +#include +#include + +#if defined(KERNEL_INTEGRITY_KTRR) || defined(KERNEL_INTEGRITY_CTRR) +#include +#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); + } -/* allow everything if CSR_ALLOW_APPLE_INTERNAL is set */ -static int csr_allow_internal = 1; + *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; -/* Current boot-arg policy: - * rootless=0 - * csr_allow_all = 1 - * rootless=1 - * csr_allow_all = 0 - * csr_allow_internal = 0 + 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. * - * After : - * rootless=0 - * no effect - * rootless=1 - * csr_allow_internal = 0 + * 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. * - * Enforcement policy: - * =============================== - * | csr_allow_internal - * | 0 1 - * =============================== - * csr_ 0 | always customer - * allow_ | - * all 1 | never never - * =============================== - * NB: "customer" means enforce when - * CSR_ALLOW_APPLE_INTERNAL not set */ - -void -csr_init(void) + * 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) { - boot_args *args = (boot_args *)PE_state.bootArgs; - if (args->flags & kBootArgsFlagCSRBoot) { - /* special booter; allow everything */ - csr_allow_all = 1; + 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; } - int rootless_boot_arg; - if (PE_parse_boot_argn("rootless", &rootless_boot_arg, sizeof(rootless_boot_arg))) { - /* XXX: set csr_allow_all to boot arg value for now - * (to be removed by ) */ - csr_allow_all = !rootless_boot_arg; - /* if rootless=1, do not allow everything when CSR_ALLOW_APPLE_INTERNAL is set */ - csr_allow_internal &= !rootless_boot_arg; + 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 -csrctl(__unused proc_t p, struct csrctl_args *uap, __unused int32_t *retval) +csr_get_active_config(csr_config_t * config) { - int error = 0; + *config = (csr_config & CSR_VALID_FLAGS); - if (uap->useraddr == 0) - return EINVAL; - if (uap->usersize != sizeof(csr_config_t)) - return EINVAL; + return 0; +} - switch (uap->op) { - case CSR_OP_CHECK: - { - csr_config_t mask; - error = copyin(uap->useraddr, &mask, sizeof(csr_config_t)); +int +csr_check(csr_config_t mask) +{ + csr_config_t config; + int ret = csr_get_active_config(&config); - if (error) - return error; + if (ret != 0) { + return ret; + } - error = csr_check(mask); - break; - } + // 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; + } - case CSR_OP_GET_ACTIVE_CONFIG: - case CSR_OP_GET_PENDING_CONFIG: /* fall through */ - { - csr_config_t config = 0; - if (uap->op == CSR_OP_GET_ACTIVE_CONFIG) - error = csr_get_active_config(&config); - else - error = csr_get_pending_config(&config); + return ((config & mask) == mask) ? 0 : EPERM; +} - if (error) - return error; +#else - error = copyout(&config, uap->useraddr, sizeof(csr_config_t)); - break; - } +/* + * Old style CSR for x86 platforms, using NVRAM values + */ - default: - error = EINVAL; - break; - } +#include + +/* enable enforcement by default */ +static SECURITY_READ_ONLY_LATE(int) csr_allow_all = 0; - return error; +/* + * 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) @@ -138,53 +277,105 @@ csr_get_active_config(csr_config_t *config) if (args->flags & kBootArgsFlagCSRActiveConfig) { *config = args->csrActiveConfig & CSR_VALID_FLAGS; } else { - /* XXX: change to 0 when is in the build */ - *config = CSR_ALLOW_APPLE_INTERNAL; + *config = 0; } return 0; } int -csr_get_pending_config(csr_config_t *config) +csr_check(csr_config_t mask) { boot_args *args = (boot_args *)PE_state.bootArgs; - if (args->flags & kBootArgsFlagCSRPendingConfig) { - *config = args->csrPendingConfig & CSR_VALID_FLAGS; - return 0; - } else { - return ENOENT; + 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 -csr_check(csr_config_t mask) +syscall_csr_check(struct csrctl_args *args) { - if (csr_allow_all) { - return 0; + csr_config_t mask = 0; + int error = 0; + + if (args->useraddr == 0 || args->usersize != sizeof(mask)) { + return EINVAL; } - csr_config_t config; - int error = csr_get_active_config(&config); + error = copyin(args->useraddr, &mask, sizeof(mask)); if (error) { return error; } - if (csr_allow_internal && (config & CSR_ALLOW_APPLE_INTERNAL)) { - return 0; + 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; } - if (mask == 0) { - /* pass 0 to check if Rootless enforcement is active */ - return -1; + error = csr_get_active_config(&config); + if (error) { + return error; } - error = (config & mask) ? 0 : EPERM; - return error; + return copyout(&config, args->useraddr, sizeof(config)); } -void -csr_set_allow_all(int value) +/* + * Syscall entrypoint + */ + +int +csrctl(__unused proc_t p, struct csrctl_args *args, __unused int32_t *retval) { - csr_allow_all = !!value; // force value to 0 or 1 + 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; + } }