]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/arm64/status.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / osfmk / arm64 / status.c
index 28f87b0a1e034f89d73719a998fb49e43e1d1f83..c1a77bf66e4b914eec30d15e42b7ebb32cf95b9d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2020 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
 #include <kern/kalloc.h>
 #include <arm/vmparam.h>
 #include <arm/cpu_data_internal.h>
+#include <arm/misc_protos.h>
 #include <arm64/proc_reg.h>
 #if __has_feature(ptrauth_calls)
 #include <ptrauth.h>
 #endif
 
+
 struct arm_vfpv2_state {
        __uint32_t __r[32];
        __uint32_t __fpscr;
@@ -53,6 +55,7 @@ typedef struct arm_vfpv2_state arm_vfpv2_state_t;
  */
 void thread_set_child(thread_t child, int pid);
 void thread_set_parent(thread_t parent, int pid);
+static void free_debug_state(thread_t thread);
 
 /*
  * Maps state flavor to number of words in the state:
@@ -105,17 +108,43 @@ thread_state64_to_saved_state(const arm_thread_state64_t * ts64,
     arm_saved_state_t *          saved_state)
 {
        uint32_t i;
+#if __has_feature(ptrauth_calls)
+       boolean_t intr = ml_set_interrupts_enabled(FALSE);
+#endif /* __has_feature(ptrauth_calls) */
 
        assert(is_saved_state64(saved_state));
 
+#if __has_feature(ptrauth_calls)
+       MANIPULATE_SIGNED_THREAD_STATE(saved_state,
+           "and        w2, w2, %w[not_psr64_user_mask] \n"
+           "mov        w6, %w[cpsr]                                    \n"
+           "and        w6, w6, %w[psr64_user_mask]             \n"
+           "orr        w2, w2, w6                                              \n"
+           "str        w2, [x0, %[SS64_CPSR]]                  \n",
+           [cpsr] "r"(ts64->cpsr),
+           [psr64_user_mask] "i"(PSR64_USER_MASK),
+           [not_psr64_user_mask] "i"(~PSR64_USER_MASK)
+           );
+       /*
+        * Make writes to ts64->cpsr visible first, since it's useful as a
+        * canary to detect thread-state corruption.
+        */
+       __builtin_arm_dmb(DMB_ST);
+#else
+       set_saved_state_cpsr(saved_state,
+           (get_saved_state_cpsr(saved_state) & ~PSR64_USER_MASK) | (ts64->cpsr & PSR64_USER_MASK));
+#endif /* __has_feature(ptrauth_calls) */
        set_saved_state_fp(saved_state, ts64->fp);
        set_saved_state_lr(saved_state, ts64->lr);
        set_saved_state_sp(saved_state, ts64->sp);
        set_saved_state_pc(saved_state, ts64->pc);
-       set_saved_state_cpsr(saved_state, (ts64->cpsr & ~PSR64_MODE_MASK) | PSR64_MODE_RW_64);
        for (i = 0; i < 29; i++) {
                set_saved_state_reg(saved_state, i, ts64->x[i]);
        }
+
+#if __has_feature(ptrauth_calls)
+       ml_set_interrupts_enabled(intr);
+#endif /* __has_feature(ptrauth_calls) */
 }
 
 #endif /* __arm64__ */
@@ -291,8 +320,8 @@ machine_thread_state_convert_to_user(
 
        // Note that kernel threads never have disable_user_jop set
        if (current_thread()->machine.disable_user_jop || !thread_is_64bit_addr(current_thread()) ||
-           thread->machine.disable_user_jop || !thread_is_64bit_addr(thread) ||
-           (BootArgs->bootFlags & kBootFlagsDisableUserThreadStateJOP)) {
+           thread->machine.disable_user_jop || !thread_is_64bit_addr(thread)
+           ) {
                ts64->flags = __DARWIN_ARM_THREAD_STATE64_FLAGS_NO_PTRAUTH;
                return KERN_SUCCESS;
        }
@@ -310,25 +339,29 @@ machine_thread_state_convert_to_user(
                // will round-trip correctly even if IA-signed again below (and IA-authd later)
        }
 
-       if (BootArgs->bootFlags & kBootFlagsDisableUserJOP) {
+       if (arm_user_jop_disabled()) {
                return KERN_SUCCESS;
        }
 
        if (ts64->pc) {
                ts64->pc = (uintptr_t)pmap_sign_user_ptr((void*)ts64->pc,
-                   ptrauth_key_process_independent_code, ptrauth_string_discriminator("pc"));
+                   ptrauth_key_process_independent_code, ptrauth_string_discriminator("pc"),
+                   thread->machine.jop_pid);
        }
        if (ts64->lr && !(ts64->flags & __DARWIN_ARM_THREAD_STATE64_FLAGS_IB_SIGNED_LR)) {
                ts64->lr = (uintptr_t)pmap_sign_user_ptr((void*)ts64->lr,
-                   ptrauth_key_process_independent_code, ptrauth_string_discriminator("lr"));
+                   ptrauth_key_process_independent_code, ptrauth_string_discriminator("lr"),
+                   thread->machine.jop_pid);
        }
        if (ts64->sp) {
                ts64->sp = (uintptr_t)pmap_sign_user_ptr((void*)ts64->sp,
-                   ptrauth_key_process_independent_data, ptrauth_string_discriminator("sp"));
+                   ptrauth_key_process_independent_data, ptrauth_string_discriminator("sp"),
+                   thread->machine.jop_pid);
        }
        if (ts64->fp) {
                ts64->fp = (uintptr_t)pmap_sign_user_ptr((void*)ts64->fp,
-                   ptrauth_key_process_independent_data, ptrauth_string_discriminator("fp"));
+                   ptrauth_key_process_independent_data, ptrauth_string_discriminator("fp"),
+                   thread->machine.jop_pid);
        }
 
        return KERN_SUCCESS;
@@ -387,8 +420,8 @@ machine_thread_state_convert_from_user(
        }
 
        if (ts64->flags & __DARWIN_ARM_THREAD_STATE64_FLAGS_NO_PTRAUTH) {
-               if (thread->machine.disable_user_jop || !thread_is_64bit_addr(thread) ||
-                   (BootArgs->bootFlags & kBootFlagsDisableUserThreadStateJOP)) {
+               if (thread->machine.disable_user_jop || !thread_is_64bit_addr(thread)
+                   ) {
                        return KERN_SUCCESS;
                }
                // Disallow setting unsigned thread state on JOP-enabled processes.
@@ -411,25 +444,29 @@ machine_thread_state_convert_from_user(
                // correctly below.
        }
 
-       if (BootArgs->bootFlags & kBootFlagsDisableUserJOP) {
+       if (arm_user_jop_disabled()) {
                return KERN_SUCCESS;
        }
 
        if (ts64->pc) {
                ts64->pc = (uintptr_t)pmap_auth_user_ptr((void*)ts64->pc,
-                   ptrauth_key_process_independent_code, ptrauth_string_discriminator("pc"));
+                   ptrauth_key_process_independent_code, ptrauth_string_discriminator("pc"),
+                   thread->machine.jop_pid);
        }
        if (ts64->lr && !(ts64->flags & __DARWIN_ARM_THREAD_STATE64_FLAGS_IB_SIGNED_LR)) {
                ts64->lr = (uintptr_t)pmap_auth_user_ptr((void*)ts64->lr,
-                   ptrauth_key_process_independent_code, ptrauth_string_discriminator("lr"));
+                   ptrauth_key_process_independent_code, ptrauth_string_discriminator("lr"),
+                   thread->machine.jop_pid);
        }
        if (ts64->sp) {
                ts64->sp = (uintptr_t)pmap_auth_user_ptr((void*)ts64->sp,
-                   ptrauth_key_process_independent_data, ptrauth_string_discriminator("sp"));
+                   ptrauth_key_process_independent_data, ptrauth_string_discriminator("sp"),
+                   thread->machine.jop_pid);
        }
        if (ts64->fp) {
                ts64->fp = (uintptr_t)pmap_auth_user_ptr((void*)ts64->fp,
-                   ptrauth_key_process_independent_data, ptrauth_string_discriminator("fp"));
+                   ptrauth_key_process_independent_data, ptrauth_string_discriminator("fp"),
+                   thread->machine.jop_pid);
        }
 
        return KERN_SUCCESS;
@@ -446,7 +483,7 @@ machine_thread_state_convert_from_user(
 
 kern_return_t
 machine_thread_siguctx_pointer_convert_to_user(
-       __assert_only thread_t thread,
+       thread_t thread,
        user_addr_t *uctxp)
 {
 #if __has_feature(ptrauth_calls)
@@ -455,13 +492,14 @@ machine_thread_siguctx_pointer_convert_to_user(
                return KERN_SUCCESS;
        }
 
-       if (BootArgs->bootFlags & kBootFlagsDisableUserJOP) {
+       if (arm_user_jop_disabled()) {
                return KERN_SUCCESS;
        }
 
        if (*uctxp) {
                *uctxp = (uintptr_t)pmap_sign_user_ptr((void*)*uctxp,
-                   ptrauth_key_process_independent_data, ptrauth_string_discriminator("uctx"));
+                   ptrauth_key_process_independent_data, ptrauth_string_discriminator("uctx"),
+                   thread->machine.jop_pid);
        }
 
        return KERN_SUCCESS;
@@ -478,7 +516,7 @@ machine_thread_siguctx_pointer_convert_to_user(
 
 kern_return_t
 machine_thread_function_pointers_convert_from_user(
-       __assert_only thread_t thread,
+       thread_t thread,
        user_addr_t *fptrs,
        uint32_t count)
 {
@@ -488,14 +526,14 @@ machine_thread_function_pointers_convert_from_user(
                return KERN_SUCCESS;
        }
 
-       if (BootArgs->bootFlags & kBootFlagsDisableUserJOP) {
+       if (arm_user_jop_disabled()) {
                return KERN_SUCCESS;
        }
 
        while (count--) {
                if (*fptrs) {
                        *fptrs = (uintptr_t)pmap_auth_user_ptr((void*)*fptrs,
-                           ptrauth_key_function_pointer, 0);
+                           ptrauth_key_function_pointer, 0, thread->machine.jop_pid);
                }
                fptrs++;
        }
@@ -583,10 +621,14 @@ machine_thread_get_state(thread_t                 thread,
                        return KERN_INVALID_ARGUMENT;
                }
 
-               kern_return_t rn = handle_get_arm64_thread_state(tstate, count, thread->machine.upcb);
+               const arm_saved_state_t *current_state = thread->machine.upcb;
+
+               kern_return_t rn = handle_get_arm64_thread_state(tstate, count,
+                   current_state);
                if (rn) {
                        return rn;
                }
+
                break;
        }
 #endif
@@ -774,6 +816,7 @@ machine_thread_get_state(thread_t                 thread,
                assert(sizeof(*state) == sizeof(*thread_state));
                bcopy(thread_state, state, sizeof(arm_neon_state64_t));
 
+
                *count = ARM_NEON_STATE64_COUNT;
                break;
        }
@@ -918,6 +961,7 @@ machine_thread_set_state(thread_t               thread,
                        return KERN_INVALID_ARGUMENT;
                }
 
+
                rn = handle_set_arm64_thread_state(tstate, count, thread->machine.upcb);
                if (rn) {
                        return rn;
@@ -974,22 +1018,13 @@ machine_thread_set_state(thread_t               thread,
                }
 
                if (!enabled) {
-                       arm_debug_state32_t *thread_state = find_debug_state32(thread);
-                       if (thread_state != NULL) {
-                               void *pTmp = thread->machine.DebugData;
-                               thread->machine.DebugData = NULL;
-                               zfree(ads_zone, pTmp);
-                       }
+                       free_debug_state(thread);
                } else {
-                       arm_debug_state32_t *thread_state = find_debug_state32(thread);
+                       arm_debug_state32_t *thread_state = find_or_allocate_debug_state32(thread);
+
                        if (thread_state == NULL) {
-                               thread->machine.DebugData = zalloc(ads_zone);
-                               bzero(thread->machine.DebugData, sizeof *(thread->machine.DebugData));
-                               thread->machine.DebugData->dsh.flavor = ARM_DEBUG_STATE32;
-                               thread->machine.DebugData->dsh.count = ARM_DEBUG_STATE32_COUNT;
-                               thread_state = find_debug_state32(thread);
+                               return KERN_FAILURE;
                        }
-                       assert(NULL != thread_state);
 
                        for (i = 0; i < 16; i++) {
                                /* set appropriate privilege; mask out unknown bits */
@@ -1037,7 +1072,7 @@ machine_thread_set_state(thread_t               thread,
 
                state = (arm_debug_state32_t *) tstate;
 
-               if (state->mdscr_el1 & 0x1) {
+               if (state->mdscr_el1 & MDSCR_SS) {
                        enabled = TRUE;
                }
 
@@ -1056,27 +1091,18 @@ machine_thread_set_state(thread_t               thread,
                }
 
                if (!enabled) {
-                       arm_debug_state32_t *thread_state = find_debug_state32(thread);
-                       if (thread_state != NULL) {
-                               void *pTmp = thread->machine.DebugData;
-                               thread->machine.DebugData = NULL;
-                               zfree(ads_zone, pTmp);
-                       }
+                       free_debug_state(thread);
                } else {
-                       arm_debug_state32_t *thread_state = find_debug_state32(thread);
+                       arm_debug_state32_t * thread_state = find_or_allocate_debug_state32(thread);
+
                        if (thread_state == NULL) {
-                               thread->machine.DebugData = zalloc(ads_zone);
-                               bzero(thread->machine.DebugData, sizeof *(thread->machine.DebugData));
-                               thread->machine.DebugData->dsh.flavor = ARM_DEBUG_STATE32;
-                               thread->machine.DebugData->dsh.count = ARM_DEBUG_STATE32_COUNT;
-                               thread_state = find_debug_state32(thread);
+                               return KERN_FAILURE;
                        }
-                       assert(NULL != thread_state);
 
-                       if (state->mdscr_el1 & 0x1) {
-                               thread_state->mdscr_el1 |= 0x1;
+                       if (state->mdscr_el1 & MDSCR_SS) {
+                               thread_state->mdscr_el1 |= MDSCR_SS;
                        } else {
-                               thread_state->mdscr_el1 &= ~0x1;
+                               thread_state->mdscr_el1 &= ~MDSCR_SS;
                        }
 
                        for (i = 0; i < 16; i++) {
@@ -1123,7 +1149,7 @@ machine_thread_set_state(thread_t               thread,
 
                state = (arm_debug_state64_t *) tstate;
 
-               if (state->mdscr_el1 & 0x1) {
+               if (state->mdscr_el1 & MDSCR_SS) {
                        enabled = TRUE;
                }
 
@@ -1141,27 +1167,18 @@ machine_thread_set_state(thread_t               thread,
                }
 
                if (!enabled) {
-                       arm_debug_state64_t *thread_state = find_debug_state64(thread);
-                       if (thread_state != NULL) {
-                               void *pTmp = thread->machine.DebugData;
-                               thread->machine.DebugData = NULL;
-                               zfree(ads_zone, pTmp);
-                       }
+                       free_debug_state(thread);
                } else {
-                       arm_debug_state64_t *thread_state = find_debug_state64(thread);
+                       arm_debug_state64_t *thread_state = find_or_allocate_debug_state64(thread);
+
                        if (thread_state == NULL) {
-                               thread->machine.DebugData = zalloc(ads_zone);
-                               bzero(thread->machine.DebugData, sizeof *(thread->machine.DebugData));
-                               thread->machine.DebugData->dsh.flavor = ARM_DEBUG_STATE64;
-                               thread->machine.DebugData->dsh.count = ARM_DEBUG_STATE64_COUNT;
-                               thread_state = find_debug_state64(thread);
+                               return KERN_FAILURE;
                        }
-                       assert(NULL != thread_state);
 
-                       if (state->mdscr_el1 & 0x1) {
-                               thread_state->mdscr_el1 |= 0x1;
+                       if (state->mdscr_el1 & MDSCR_SS) {
+                               thread_state->mdscr_el1 |= MDSCR_SS;
                        } else {
-                               thread_state->mdscr_el1 &= ~0x1;
+                               thread_state->mdscr_el1 &= ~MDSCR_SS;
                        }
 
                        for (i = 0; i < 16; i++) {
@@ -1260,6 +1277,7 @@ machine_thread_set_state(thread_t               thread,
                assert(sizeof(*state) == sizeof(*thread_state));
                bcopy(state, thread_state, sizeof(arm_neon_state64_t));
 
+
                thread->machine.uNeon->nsh.flavor = ARM_NEON_SAVED_STATE64;
                thread->machine.uNeon->nsh.count = ARM_NEON_SAVED_STATE64_COUNT;
                break;
@@ -1316,7 +1334,9 @@ machine_thread_state_initialize(thread_t thread)
 #if defined(HAS_APPLE_PAC)
        /* Sign the initial user-space thread state */
        if (thread->machine.upcb != NULL) {
+               boolean_t intr = ml_set_interrupts_enabled(FALSE);
                ml_sign_thread_state(thread->machine.upcb, 0, 0, 0, 0, 0);
+               ml_set_interrupts_enabled(intr);
        }
 #endif /* defined(HAS_APPLE_PAC) */
 
@@ -1412,6 +1432,73 @@ find_debug_state64(thread_t thread)
        }
 }
 
+/**
+ *  Finds the debug state for the given 64 bit thread, allocating one if it
+ *  does not exist.
+ *
+ *  @param thread 64 bit thread to find or allocate debug state for
+ *
+ *  @returns A pointer to the given thread's 64 bit debug state or a null
+ *           pointer if the given thread is null or the allocation of a new
+ *           debug state fails.
+ */
+arm_debug_state64_t *
+find_or_allocate_debug_state64(thread_t thread)
+{
+       arm_debug_state64_t *thread_state = find_debug_state64(thread);
+       if (thread != NULL && thread_state == NULL) {
+               thread->machine.DebugData = zalloc(ads_zone);
+               if (thread->machine.DebugData != NULL) {
+                       bzero(thread->machine.DebugData, sizeof *(thread->machine.DebugData));
+                       thread->machine.DebugData->dsh.flavor = ARM_DEBUG_STATE64;
+                       thread->machine.DebugData->dsh.count = ARM_DEBUG_STATE64_COUNT;
+                       thread_state = find_debug_state64(thread);
+               }
+       }
+       return thread_state;
+}
+
+/**
+ *  Finds the debug state for the given 32 bit thread, allocating one if it
+ *  does not exist.
+ *
+ *  @param thread 32 bit thread to find or allocate debug state for
+ *
+ *  @returns A pointer to the given thread's 32 bit debug state or a null
+ *           pointer if the given thread is null or the allocation of a new
+ *           debug state fails.
+ */
+arm_debug_state32_t *
+find_or_allocate_debug_state32(thread_t thread)
+{
+       arm_debug_state32_t *thread_state = find_debug_state32(thread);
+       if (thread != NULL && thread_state == NULL) {
+               thread->machine.DebugData = zalloc(ads_zone);
+               if (thread->machine.DebugData != NULL) {
+                       bzero(thread->machine.DebugData, sizeof *(thread->machine.DebugData));
+                       thread->machine.DebugData->dsh.flavor = ARM_DEBUG_STATE32;
+                       thread->machine.DebugData->dsh.count = ARM_DEBUG_STATE32_COUNT;
+                       thread_state = find_debug_state32(thread);
+               }
+       }
+       return thread_state;
+}
+
+/**
+ *     Frees a thread's debug state if allocated. Otherwise does nothing.
+ *
+ *  @param thread thread to free the debug state of
+ */
+static inline void
+free_debug_state(thread_t thread)
+{
+       if (thread != NULL && thread->machine.DebugData != NULL) {
+               void *pTmp = thread->machine.DebugData;
+               thread->machine.DebugData = NULL;
+               zfree(ads_zone, pTmp);
+       }
+}
+
 /*
  * Routine: thread_userstack
  *
@@ -1443,7 +1530,8 @@ thread_userstack(__unused thread_t  thread,
                        break;
                }
 
-       /* INTENTIONAL FALL THROUGH (see machine_thread_set_state) */
+               /* INTENTIONAL FALL THROUGH (see machine_thread_set_state) */
+               OS_FALLTHROUGH;
        case ARM_THREAD_STATE32:
                if (count != ARM_THREAD_STATE32_COUNT) {
                        return KERN_INVALID_ARGUMENT;
@@ -1525,7 +1613,7 @@ thread_setuserstack(thread_t          thread,
  * Routine: thread_adjuserstack
  *
  */
-uint64_t
+user_addr_t
 thread_adjuserstack(thread_t thread,
     int      adjust)
 {
@@ -1541,6 +1629,7 @@ thread_adjuserstack(thread_t thread,
        return sp;
 }
 
+
 /*
  * Routine: thread_setentrypoint
  *
@@ -1566,7 +1655,7 @@ kern_return_t
 thread_entrypoint(__unused thread_t  thread,
     int                flavor,
     thread_state_t     tstate,
-    unsigned int       count __unused,
+    unsigned int       count,
     mach_vm_offset_t * entry_point
     )
 {
@@ -1575,6 +1664,10 @@ thread_entrypoint(__unused thread_t  thread,
        {
                struct arm_thread_state *state;
 
+               if (count != ARM_THREAD_STATE_COUNT) {
+                       return KERN_INVALID_ARGUMENT;
+               }
+
                state = (struct arm_thread_state *) tstate;
 
                /*
@@ -1592,6 +1685,10 @@ thread_entrypoint(__unused thread_t  thread,
        {
                struct arm_thread_state64 *state;
 
+               if (count != ARM_THREAD_STATE64_COUNT) {
+                       return KERN_INVALID_ARGUMENT;
+               }
+
                state = (struct arm_thread_state64*) tstate;
 
                /*