]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/dev/arm/unix_signal.c
xnu-6153.121.1.tar.gz
[apple/xnu.git] / bsd / dev / arm / unix_signal.c
index 51c4d7e483d897c72eb0368bf1bc5f1aac6dc743..1e3bb03f9b356accc214bb9403d672305719a71e 100644 (file)
 #include <arm/proc_reg.h>
 
 #include <kern/assert.h>
+#include <kern/ast.h>
 #include <pexpert/pexpert.h>
 
 extern struct arm_saved_state *get_user_regs(thread_t);
 extern user_addr_t thread_get_cthread_self(void);
 extern kern_return_t thread_getstatus(thread_t act, int flavor,
-               thread_state_t tstate, mach_msg_type_number_t *count);
+    thread_state_t tstate, mach_msg_type_number_t *count);
+extern kern_return_t thread_getstatus_to_user(thread_t act, int flavor,
+    thread_state_t tstate, mach_msg_type_number_t *count);
+extern kern_return_t machine_thread_state_convert_to_user(thread_t act, int flavor,
+    thread_state_t tstate, mach_msg_type_number_t *count);
 extern kern_return_t thread_setstatus(thread_t thread, int flavor,
-               thread_state_t tstate, mach_msg_type_number_t count);
+    thread_state_t tstate, mach_msg_type_number_t count);
+extern kern_return_t thread_setstatus_from_user(thread_t thread, int flavor,
+    thread_state_t tstate, mach_msg_type_number_t count);
 /* XXX Put these someplace smarter... */
-typedef struct mcontext32 mcontext32_t; 
+typedef struct mcontext32 mcontext32_t;
 typedef struct mcontext64 mcontext64_t;
 
 /* Signal handler flavors supported */
 /* These defns should match the Libc implmn */
-#define UC_TRAD                        1
-#define UC_FLAVOR              30
+#define UC_TRAD                 1
+#define UC_FLAVOR               30
 
 /* The following are valid mcontext sizes */
 #define UC_FLAVOR_SIZE32 ((ARM_THREAD_STATE_COUNT + ARM_EXCEPTION_STATE_COUNT + ARM_VFP_STATE_COUNT) * sizeof(int))
 #define UC_FLAVOR_SIZE64 ((ARM_THREAD_STATE64_COUNT + ARM_EXCEPTION_STATE64_COUNT + ARM_NEON_STATE64_COUNT) * sizeof(int))
 
 #if __arm64__
-#define        C_64_REDZONE_LEN        128
+#define C_64_REDZONE_LEN        128
 #endif
 
 static int
-sendsig_get_state32(thread_t th_act, mcontext32_t *mcp)
+sendsig_get_state32(thread_t th_act, arm_thread_state_t *ts, mcontext32_t *mcp)
 {
        void *tstate;
        mach_msg_type_number_t state_count;
 
-       assert(!proc_is64bit(current_proc()));
+       assert(!proc_is64bit_data(current_proc()));
 
+       tstate = (void *) ts;
+       state_count = ARM_THREAD_STATE_COUNT;
+       if (thread_getstatus(th_act, ARM_THREAD_STATE, (thread_state_t) tstate, &state_count) != KERN_SUCCESS) {
+               return EINVAL;
+       }
+
+       mcp->ss = *ts;
        tstate = (void *) &mcp->ss;
        state_count = ARM_THREAD_STATE_COUNT;
-       if (thread_getstatus(th_act, ARM_THREAD_STATE, (thread_state_t) tstate, &state_count) != KERN_SUCCESS)
+       if (machine_thread_state_convert_to_user(th_act, ARM_THREAD_STATE, (thread_state_t) tstate, &state_count) != KERN_SUCCESS) {
                return EINVAL;
+       }
 
        tstate = (void *) &mcp->es;
        state_count = ARM_EXCEPTION_STATE_COUNT;
-       if (thread_getstatus(th_act, ARM_EXCEPTION_STATE, (thread_state_t) tstate, &state_count) != KERN_SUCCESS)
+       if (thread_getstatus(th_act, ARM_EXCEPTION_STATE, (thread_state_t) tstate, &state_count) != KERN_SUCCESS) {
                return EINVAL;
+       }
 
        tstate = (void *) &mcp->fs;
        state_count = ARM_VFP_STATE_COUNT;
-       if (thread_getstatus(th_act, ARM_VFP_STATE, (thread_state_t) tstate, &state_count) != KERN_SUCCESS)
+       if (thread_getstatus_to_user(th_act, ARM_VFP_STATE, (thread_state_t) tstate, &state_count) != KERN_SUCCESS) {
                return EINVAL;
+       }
 
        return 0;
 }
 
 #if defined(__arm64__)
 struct user_sigframe64 {
-       /* We can pass the last arg in a register for ARM64 */
-       user64_siginfo_t        sinfo;
-       struct user_ucontext64  uctx;
-       mcontext64_t            mctx;
+       /* We can pass the last two args in registers for ARM64 */
+       user64_siginfo_t        sinfo;
+       struct user_ucontext64  uctx;
+       mcontext64_t            mctx;
 };
 
 static int
-sendsig_get_state64(thread_t th_act, mcontext64_t *mcp)
+sendsig_get_state64(thread_t th_act, arm_thread_state64_t *ts, mcontext64_t *mcp)
 {
        void *tstate;
        mach_msg_type_number_t state_count;
 
-       assert(proc_is64bit(current_proc()));
+       assert(proc_is64bit_data(current_proc()));
+
+       tstate = (void *) ts;
+       state_count = ARM_THREAD_STATE64_COUNT;
+       if (thread_getstatus(th_act, ARM_THREAD_STATE64, (thread_state_t) tstate, &state_count) != KERN_SUCCESS) {
+               return EINVAL;
+       }
 
+       mcp->ss = *ts;
        tstate = (void *) &mcp->ss;
        state_count = ARM_THREAD_STATE64_COUNT;
-       if (thread_getstatus(th_act, ARM_THREAD_STATE64, (thread_state_t) tstate, &state_count) != KERN_SUCCESS)
+       if (machine_thread_state_convert_to_user(th_act, ARM_THREAD_STATE64, (thread_state_t) tstate, &state_count) != KERN_SUCCESS) {
                return EINVAL;
+       }
 
        tstate = (void *) &mcp->es;
        state_count = ARM_EXCEPTION_STATE64_COUNT;
-       if (thread_getstatus(th_act, ARM_EXCEPTION_STATE64, (thread_state_t) tstate, &state_count) != KERN_SUCCESS)
+       if (thread_getstatus(th_act, ARM_EXCEPTION_STATE64, (thread_state_t) tstate, &state_count) != KERN_SUCCESS) {
                return EINVAL;
+       }
 
        tstate = (void *) &mcp->ns;
        state_count = ARM_NEON_STATE64_COUNT;
-       if (thread_getstatus(th_act, ARM_NEON_STATE64, (thread_state_t) tstate, &state_count) != KERN_SUCCESS)
+       if (thread_getstatus_to_user(th_act, ARM_NEON_STATE64, (thread_state_t) tstate, &state_count) != KERN_SUCCESS) {
                return EINVAL;
+       }
 
        return 0;
 }
@@ -115,27 +142,29 @@ sendsig_fill_uctx64(user_ucontext64_t *uctx, int oonstack, int mask, user64_addr
        bzero(uctx, sizeof(*uctx));
        uctx->uc_onstack = oonstack;
        uctx->uc_sigmask = mask;
-       uctx->uc_stack.ss_sp = sp; 
+       uctx->uc_stack.ss_sp = sp;
        uctx->uc_stack.ss_size = stack_size;
-       if (oonstack)
+       if (oonstack) {
                uctx->uc_stack.ss_flags |= SS_ONSTACK;
+       }
        uctx->uc_link = (user64_addr_t)0;
-       uctx->uc_mcsize = (user64_size_t) UC_FLAVOR_SIZE64; 
+       uctx->uc_mcsize = (user64_size_t) UC_FLAVOR_SIZE64;
        uctx->uc_mcontext64 = (user64_addr_t) p_mctx;
 }
 
 static kern_return_t
-sendsig_set_thread_state64(arm_thread_state64_t *regs, 
-               user64_addr_t catcher, int infostyle, int sig, user64_addr_t p_sinfo, 
-               user64_addr_t p_uctx, user64_addr_t trampact, user64_addr_t sp, thread_t th_act)
+sendsig_set_thread_state64(arm_thread_state64_t *regs,
+    user64_addr_t catcher, int infostyle, int sig, user64_addr_t p_sinfo,
+    user64_addr_t p_uctx, user64_addr_t token, user64_addr_t trampact, user64_addr_t sp, thread_t th_act)
 {
-       assert(proc_is64bit(current_proc()));
+       assert(proc_is64bit_data(current_proc()));
 
        regs->x[0] = catcher;
        regs->x[1] = infostyle;
        regs->x[2] = sig;
        regs->x[3] = p_sinfo;
        regs->x[4] = p_uctx;
+       regs->x[5] = token;
        regs->pc = trampact;
        regs->cpsr = PSR64_USER64_DEFAULT;
        regs->sp = sp;
@@ -150,22 +179,22 @@ sendsig_fill_uctx32(user_ucontext32_t *uctx, int oonstack, int mask, user_addr_t
        bzero(uctx, sizeof(*uctx));
        uctx->uc_onstack = oonstack;
        uctx->uc_sigmask = mask;
-       uctx->uc_stack.ss_sp = (user32_addr_t) sp; 
+       uctx->uc_stack.ss_sp = (user32_addr_t) sp;
        uctx->uc_stack.ss_size = (user32_size_t) stack_size;
-       if (oonstack)
+       if (oonstack) {
                uctx->uc_stack.ss_flags |= SS_ONSTACK;
+       }
        uctx->uc_link = (user32_addr_t)0;
-       uctx->uc_mcsize = (user32_size_t) UC_FLAVOR_SIZE32; 
+       uctx->uc_mcsize = (user32_size_t) UC_FLAVOR_SIZE32;
        uctx->uc_mcontext = (user32_addr_t) p_mctx;
 }
 
 static kern_return_t
-sendsig_set_thread_state32(arm_thread_state_t *regs, 
-               user32_addr_t catcher, int infostyle, int sig, user32_addr_t p_sinfo, 
-               user32_addr_t trampact, user32_addr_t sp, thread_t th_act)
+sendsig_set_thread_state32(arm_thread_state_t *regs,
+    user32_addr_t catcher, int infostyle, int sig, user32_addr_t p_sinfo,
+    user32_addr_t trampact, user32_addr_t sp, thread_t th_act)
 {
-
-       assert(!proc_is64bit(current_proc()));
+       assert(!proc_is64bit_data(current_proc()));
 
        regs->r[0] = catcher;
        regs->r[1] = infostyle;
@@ -193,14 +222,14 @@ sendsig_set_thread_state32(arm_thread_state_t *regs,
 static void
 sendsig_do_dtrace(uthread_t ut, user_siginfo_t *sinfo, int sig, user_addr_t catcher)
 {
-        bzero((caddr_t)&(ut->t_dtrace_siginfo), sizeof(ut->t_dtrace_siginfo));
+       bzero((caddr_t)&(ut->t_dtrace_siginfo), sizeof(ut->t_dtrace_siginfo));
 
        ut->t_dtrace_siginfo.si_signo = sinfo->si_signo;
        ut->t_dtrace_siginfo.si_code = sinfo->si_code;
        ut->t_dtrace_siginfo.si_pid = sinfo->si_pid;
        ut->t_dtrace_siginfo.si_uid = sinfo->si_uid;
        ut->t_dtrace_siginfo.si_status = sinfo->si_status;
-           /* XXX truncates faulting address to void *  */
+       /* XXX truncates faulting address to void *  */
        ut->t_dtrace_siginfo.si_addr = CAST_DOWN_EXPLICIT(void *, sinfo->si_addr);
 
        /* Fire DTrace proc:::fault probe when signal is generated by hardware. */
@@ -211,18 +240,19 @@ sendsig_do_dtrace(uthread_t ut, user_siginfo_t *sinfo, int sig, user_addr_t catc
        default:
                break;
        }
-       
+
        /* XXX truncates faulting address to uintptr_t  */
        DTRACE_PROC3(signal__handle, int, sig, siginfo_t *, &(ut->t_dtrace_siginfo),
            void (*)(void), CAST_DOWN(sig_t, catcher));
 }
-#endif 
-       
+#endif
+
 struct user_sigframe32 {
-       user32_addr_t           puctx;
-       user32_siginfo_t        sinfo;
-       struct user_ucontext32  uctx;
-       mcontext32_t            mctx;
+       user32_addr_t           puctx;
+       user32_addr_t           token;
+       user32_siginfo_t        sinfo;
+       struct user_ucontext32  uctx;
+       mcontext32_t            mctx;
 };
 
 /*
@@ -235,10 +265,21 @@ sendsig(
        user_addr_t catcher,
        int sig,
        int mask,
-       __unused uint32_t code
-)
+       __unused uint32_t code,
+       sigset_t siginfo
+       )
 {
-       union { 
+       union {
+               struct ts32 {
+                       arm_thread_state_t ss;
+               } ts32;
+#if defined(__arm64__)
+               struct ts64 {
+                       arm_thread_state64_t ss;
+               } ts64;
+#endif
+       } ts;
+       union {
                struct user_sigframe32 uf32;
 #if defined(__arm64__)
                struct user_sigframe64 uf64;
@@ -246,22 +287,26 @@ sendsig(
        } user_frame;
 
        user_siginfo_t sinfo;
-       user_addr_t     sp = 0, trampact;
+       user_addr_t     sp = 0, trampact;
        struct sigacts *ps = p->p_sigacts;
        int             oonstack, infostyle;
        thread_t        th_act;
        struct uthread *ut;
-       user_size_t     stack_size = 0;
+       user_size_t     stack_size = 0;
+       user_addr_t     p_uctx, token_uctx;
+       kern_return_t   kr;
 
        th_act = current_thread();
        ut = get_bsdthread_info(th_act);
 
+       bzero(&ts, sizeof(ts));
        bzero(&user_frame, sizeof(user_frame));
 
-       if (p->p_sigacts->ps_siginfo & sigmask(sig))
+       if (siginfo & sigmask(sig)) {
                infostyle = UC_FLAVOR;
-       else
+       } else {
                infostyle = UC_TRAD;
+       }
 
        trampact = ps->ps_trampact[sig];
        oonstack = ps->ps_sigstk.ss_flags & SA_ONSTACK;
@@ -269,16 +314,16 @@ sendsig(
        /*
         * Get sundry thread state.
         */
-       if (proc_is64bit(p)) {
+       if (proc_is64bit_data(p)) {
 #ifdef __arm64__
-               if (sendsig_get_state64(th_act, &user_frame.uf64.mctx) != 0) {
+               if (sendsig_get_state64(th_act, &ts.ts64.ss, &user_frame.uf64.mctx) != 0) {
                        goto bad2;
                }
 #else
-       panic("Shouldn't have 64-bit thread states on a 32-bit kernel.");
+               panic("Shouldn't have 64-bit thread states on a 32-bit kernel.");
 #endif
        } else {
-               if (sendsig_get_state32(th_act, &user_frame.uf32.mctx) != 0) {
+               if (sendsig_get_state32(th_act, &ts.ts32.ss, &user_frame.uf32.mctx) != 0) {
                        goto bad2;
                }
        }
@@ -297,15 +342,15 @@ sendsig(
                 * Get stack pointer, and allocate enough space
                 * for signal handler data.
                 */
-               if (proc_is64bit(p)) {
+               if (proc_is64bit_data(p)) {
 #if defined(__arm64__)
-                       sp = CAST_USER_ADDR_T(user_frame.uf64.mctx.ss.sp);
+                       sp = CAST_USER_ADDR_T(ts.ts64.ss.sp);
                        sp = (sp - sizeof(user_frame.uf64) - C_64_REDZONE_LEN) & ~0xf; /* Make sure to align to 16 bytes and respect red zone */
 #else
                        panic("Shouldn't have 64-bit thread states on a 32-bit kernel.");
 #endif
                } else {
-                       sp = CAST_USER_ADDR_T(user_frame.uf32.mctx.ss.sp);
+                       sp = CAST_USER_ADDR_T(ts.ts32.ss.sp);
                        sp -= sizeof(user_frame.uf32);
 #if defined(__arm__) && (__BIGGEST_ALIGNMENT__ > 4)
                        sp &= ~0xf; /* Make sure to align to 16 bytes for armv7k */
@@ -318,57 +363,82 @@ sendsig(
        /*
         * Fill in ucontext (points to mcontext, i.e. thread states).
         */
-       if (proc_is64bit(p)) {
+       if (proc_is64bit_data(p)) {
 #if defined(__arm64__)
                sendsig_fill_uctx64(&user_frame.uf64.uctx, oonstack, mask, sp, (user64_size_t)stack_size,
-                               (user64_addr_t)&((struct user_sigframe64*)sp)->mctx);
+                   (user64_addr_t)&((struct user_sigframe64*)sp)->mctx);
 #else
                panic("Shouldn't have 64-bit thread states on a 32-bit kernel.");
 #endif
        } else {
-               sendsig_fill_uctx32(&user_frame.uf32.uctx, oonstack, mask, sp, (user32_size_t)stack_size, 
-                               (user32_addr_t)&((struct user_sigframe32*)sp)->mctx);
+               sendsig_fill_uctx32(&user_frame.uf32.uctx, oonstack, mask, sp, (user32_size_t)stack_size,
+                   (user32_addr_t)&((struct user_sigframe32*)sp)->mctx);
        }
 
        /*
         * Setup siginfo.
         */
-       bzero((caddr_t) & sinfo, sizeof(sinfo));
+       bzero((caddr_t) &sinfo, sizeof(sinfo));
        sinfo.si_signo = sig;
 
-       if (proc_is64bit(p)) {
+       if (proc_is64bit_data(p)) {
 #if defined(__arm64__)
-               sinfo.si_addr = user_frame.uf64.mctx.ss.pc;
-               sinfo.pad[0] = user_frame.uf64.mctx.ss.sp;
+               sinfo.si_addr = ts.ts64.ss.pc;
+               sinfo.pad[0] = ts.ts64.ss.sp;
 #else
                panic("Shouldn't have 64-bit thread states on a 32-bit kernel.");
 #endif
        } else {
-               sinfo.si_addr = user_frame.uf32.mctx.ss.pc;
-               sinfo.pad[0] = user_frame.uf32.mctx.ss.sp;
+               sinfo.si_addr = ts.ts32.ss.pc;
+               sinfo.pad[0] = ts.ts32.ss.sp;
        }
 
        switch (sig) {
        case SIGILL:
-#ifdef BER_XXX
-               if (mctx.ss.srr1 & (1 << (31 - SRR1_PRG_ILL_INS_BIT)))
+#ifdef  BER_XXX
+               if (mctx.ss.srr1 & (1 << (31 - SRR1_PRG_ILL_INS_BIT))) {
                        sinfo.si_code = ILL_ILLOPC;
-               else if (mctx.ss.srr1 & (1 << (31 - SRR1_PRG_PRV_INS_BIT)))
+               } else if (mctx.ss.srr1 & (1 << (31 - SRR1_PRG_PRV_INS_BIT))) {
                        sinfo.si_code = ILL_PRVOPC;
-               else if (mctx.ss.srr1 & (1 << (31 - SRR1_PRG_TRAP_BIT)))
+               } else if (mctx.ss.srr1 & (1 << (31 - SRR1_PRG_TRAP_BIT))) {
                        sinfo.si_code = ILL_ILLTRP;
-               else
+               } else {
                        sinfo.si_code = ILL_NOOP;
+               }
 #else
                sinfo.si_code = ILL_ILLTRP;
 #endif
                break;
 
        case SIGFPE:
+               switch (ut->uu_code) {
+               case EXC_ARM_FP_UF:
+                       sinfo.si_code = FPE_FLTUND;
+                       break;
+               case EXC_ARM_FP_OF:
+                       sinfo.si_code = FPE_FLTOVF;
+                       break;
+               case EXC_ARM_FP_IO:
+                       sinfo.si_code = FPE_FLTINV;
+                       break;
+               case EXC_ARM_FP_DZ:
+                       sinfo.si_code = FPE_FLTDIV;
+                       break;
+               case EXC_ARM_FP_ID:
+                       sinfo.si_code = FPE_FLTINV;
+                       break;
+               case EXC_ARM_FP_IX:
+                       sinfo.si_code = FPE_FLTRES;
+                       break;
+               default:
+                       sinfo.si_code = FPE_NOOP;
+                       break;
+               }
+
                break;
 
        case SIGBUS:
-               if (proc_is64bit(p)) {
+               if (proc_is64bit_data(p)) {
 #if defined(__arm64__)
                        sinfo.si_addr = user_frame.uf64.mctx.es.far;
 #else
@@ -382,7 +452,7 @@ sendsig(
                break;
 
        case SIGSEGV:
-               if (proc_is64bit(p)) {
+               if (proc_is64bit_data(p)) {
 #if defined(__arm64__)
                        sinfo.si_addr = user_frame.uf64.mctx.es.far;
 #else
@@ -392,14 +462,15 @@ sendsig(
                        sinfo.si_addr = user_frame.uf32.mctx.es.far;
                }
 
-#ifdef BER_XXX
+#ifdef  BER_XXX
                /* First check in srr1 and then in dsisr */
-               if (mctx.ss.srr1 & (1 << (31 - DSISR_PROT_BIT)))
+               if (mctx.ss.srr1 & (1 << (31 - DSISR_PROT_BIT))) {
                        sinfo.si_code = SEGV_ACCERR;
-               else if (mctx.es.dsisr & (1 << (31 - DSISR_PROT_BIT)))
+               } else if (mctx.es.dsisr & (1 << (31 - DSISR_PROT_BIT))) {
                        sinfo.si_code = SEGV_ACCERR;
-               else
+               } else {
                        sinfo.si_code = SEGV_MAPERR;
+               }
 #else
                sinfo.si_code = SEGV_ACCERR;
 #endif
@@ -429,15 +500,15 @@ sendsig(
                p->si_code = 0;
                proc_unlock(p);
                if (sinfo.si_code == CLD_EXITED) {
-                       if (WIFEXITED(status_and_exitcode))
+                       if (WIFEXITED(status_and_exitcode)) {
                                sinfo.si_code = CLD_EXITED;
-                       else if (WIFSIGNALED(status_and_exitcode)) {
+                       else if (WIFSIGNALED(status_and_exitcode)) {
                                if (WCOREDUMP(status_and_exitcode)) {
                                        sinfo.si_code = CLD_DUMPED;
-                                       status_and_exitcode = W_EXITCODE(status_and_exitcode,status_and_exitcode);
+                                       status_and_exitcode = W_EXITCODE(status_and_exitcode, status_and_exitcode);
                                } else {
                                        sinfo.si_code = CLD_KILLED;
-                                       status_and_exitcode = W_EXITCODE(status_and_exitcode,status_and_exitcode);
+                                       status_and_exitcode = W_EXITCODE(status_and_exitcode, status_and_exitcode);
                                }
                        }
                }
@@ -453,50 +524,76 @@ sendsig(
        }
        }
 
-#if CONFIG_DTRACE      
+#if CONFIG_DTRACE
        sendsig_do_dtrace(ut, &sinfo, sig, catcher);
 #endif /* CONFIG_DTRACE */
 
-       /* 
+       /*
         * Copy signal-handling frame out to user space, set thread state.
         */
-       if (proc_is64bit(p)) {
+       if (proc_is64bit_data(p)) {
 #if defined(__arm64__)
+               user64_addr_t token;
+
                /*
-                * mctx filled in when we get state.  uctx filled in by 
+                * mctx filled in when we get state.  uctx filled in by
                 * sendsig_fill_uctx64(). We fill in the sinfo now.
                 */
                siginfo_user_to_user64(&sinfo, &user_frame.uf64.sinfo);
 
+               p_uctx = (user_addr_t)&((struct user_sigframe64*)sp)->uctx;
+               /*
+                * Generate the validation token for sigreturn
+                */
+               token_uctx = p_uctx;
+               kr = machine_thread_siguctx_pointer_convert_to_user(th_act, &token_uctx);
+               assert(kr == KERN_SUCCESS);
+               token = (user64_addr_t)token_uctx ^ (user64_addr_t)ps->ps_sigreturn_token;
+
                if (copyout(&user_frame.uf64, sp, sizeof(user_frame.uf64)) != 0) {
-                       goto bad; 
-               } 
+                       goto bad;
+               }
 
-               if (sendsig_set_thread_state64(&user_frame.uf64.mctx.ss,
-                       catcher, infostyle, sig, (user64_addr_t)&((struct user_sigframe64*)sp)->sinfo,
-                       (user64_addr_t)&((struct user_sigframe64*)sp)->uctx, trampact, sp, th_act) != KERN_SUCCESS)
+               if (sendsig_set_thread_state64(&ts.ts64.ss,
+                   catcher, infostyle, sig, (user64_addr_t)&((struct user_sigframe64*)sp)->sinfo,
+                   (user64_addr_t)p_uctx, token, trampact, sp, th_act) != KERN_SUCCESS) {
                        goto bad;
+               }
 
 #else
-       panic("Shouldn't have 64-bit thread states on a 32-bit kernel.");
+               panic("Shouldn't have 64-bit thread states on a 32-bit kernel.");
 #endif
        } else {
+               user32_addr_t token;
+
                /*
-                * mctx filled in when we get state.  uctx filled in by 
-                * sendsig_fill_uctx32(). We fill in the sinfo and *pointer* 
-                * to uctx now.
+                * mctx filled in when we get state.  uctx filled in by
+                * sendsig_fill_uctx32(). We fill in the sinfo, *pointer*
+                * to uctx and token now.
                 */
                siginfo_user_to_user32(&sinfo, &user_frame.uf32.sinfo);
-               user_frame.uf32.puctx = (user32_addr_t) &((struct user_sigframe32*)sp)->uctx;
+
+               p_uctx = (user_addr_t)&((struct user_sigframe32*)sp)->uctx;
+               /*
+                * Generate the validation token for sigreturn
+                */
+               token_uctx = (user_addr_t)p_uctx;
+               kr = machine_thread_siguctx_pointer_convert_to_user(th_act, &token_uctx);
+               assert(kr == KERN_SUCCESS);
+               token = (user32_addr_t)token_uctx ^ (user32_addr_t)ps->ps_sigreturn_token;
+
+               user_frame.uf32.puctx = (user32_addr_t)p_uctx;
+               user_frame.uf32.token = token;
 
                if (copyout(&user_frame.uf32, sp, sizeof(user_frame.uf32)) != 0) {
-                       goto bad; 
-               } 
+                       goto bad;
+               }
 
-               if (sendsig_set_thread_state32(&user_frame.uf32.mctx.ss,
-                       CAST_DOWN_EXPLICIT(user32_addr_t, catcher), infostyle, sig, (user32_addr_t)&((struct user_sigframe32*)sp)->sinfo,
-                       CAST_DOWN_EXPLICIT(user32_addr_t, trampact), CAST_DOWN_EXPLICIT(user32_addr_t, sp), th_act) != KERN_SUCCESS)
+               if (sendsig_set_thread_state32(&ts.ts32.ss,
+                   CAST_DOWN_EXPLICIT(user32_addr_t, catcher), infostyle, sig, (user32_addr_t)&((struct user_sigframe32*)sp)->sinfo,
+                   CAST_DOWN_EXPLICIT(user32_addr_t, trampact), CAST_DOWN_EXPLICIT(user32_addr_t, sp), th_act) != KERN_SUCCESS) {
                        goto bad;
+               }
        }
 
        proc_lock(p);
@@ -530,11 +627,11 @@ sigreturn_copyin_ctx32(struct user_ucontext32 *uctx, mcontext32_t *mctx, user_ad
 {
        int error;
 
-       assert(!proc_is64bit(current_proc()));
+       assert(!proc_is64bit_data(current_proc()));
 
        error = copyin(uctx_addr, uctx, sizeof(*uctx));
        if (error) {
-               return (error);
+               return error;
        }
 
        /* validate the machine context size */
@@ -542,22 +639,22 @@ sigreturn_copyin_ctx32(struct user_ucontext32 *uctx, mcontext32_t *mctx, user_ad
        case UC_FLAVOR_SIZE32:
                break;
        default:
-               return (EINVAL);
+               return EINVAL;
        }
 
        assert(uctx->uc_mcsize == sizeof(*mctx));
        error = copyin((user_addr_t)uctx->uc_mcontext, mctx, uctx->uc_mcsize);
        if (error) {
-               return (error);
+               return error;
        }
 
        return 0;
 }
 
 static int
-sigreturn_set_state32(thread_t th_act, mcontext32_t *mctx) 
+sigreturn_set_state32(thread_t th_act, mcontext32_t *mctx)
 {
-       assert(!proc_is64bit(current_proc()));
+       assert(!proc_is64bit_data(current_proc()));
 
        /* validate the thread state, set/reset appropriate mode bits in cpsr */
 #if defined(__arm__)
@@ -568,11 +665,11 @@ sigreturn_set_state32(thread_t th_act, mcontext32_t *mctx)
 #error Unknown architecture.
 #endif
 
-       if (thread_setstatus(th_act, ARM_THREAD_STATE, (void *)&mctx->ss, ARM_THREAD_STATE_COUNT) != KERN_SUCCESS) {
-               return (EINVAL);
+       if (thread_setstatus_from_user(th_act, ARM_THREAD_STATE, (void *)&mctx->ss, ARM_THREAD_STATE_COUNT) != KERN_SUCCESS) {
+               return EINVAL;
        }
-       if (thread_setstatus(th_act, ARM_VFP_STATE, (void *)&mctx->fs, ARM_VFP_STATE_COUNT) != KERN_SUCCESS) {
-               return (EINVAL);
+       if (thread_setstatus_from_user(th_act, ARM_VFP_STATE, (void *)&mctx->fs, ARM_VFP_STATE_COUNT) != KERN_SUCCESS) {
+               return EINVAL;
        }
 
        return 0;
@@ -584,11 +681,11 @@ sigreturn_copyin_ctx64(struct user_ucontext64 *uctx, mcontext64_t *mctx, user_ad
 {
        int error;
 
-       assert(proc_is64bit(current_proc()));
+       assert(proc_is64bit_data(current_proc()));
 
        error = copyin(uctx_addr, uctx, sizeof(*uctx));
        if (error) {
-               return (error);
+               return error;
        }
 
        /* validate the machine context size */
@@ -596,31 +693,31 @@ sigreturn_copyin_ctx64(struct user_ucontext64 *uctx, mcontext64_t *mctx, user_ad
        case UC_FLAVOR_SIZE64:
                break;
        default:
-               return (EINVAL);
+               return EINVAL;
        }
 
        assert(uctx->uc_mcsize == sizeof(*mctx));
        error = copyin((user_addr_t)uctx->uc_mcontext64, mctx, uctx->uc_mcsize);
        if (error) {
-               return (error);
+               return error;
        }
 
        return 0;
 }
 
 static int
-sigreturn_set_state64(thread_t th_act, mcontext64_t *mctx) 
+sigreturn_set_state64(thread_t th_act, mcontext64_t *mctx)
 {
-       assert(proc_is64bit(current_proc()));
+       assert(proc_is64bit_data(current_proc()));
 
        /* validate the thread state, set/reset appropriate mode bits in cpsr */
        mctx->ss.cpsr = (mctx->ss.cpsr & ~PSR64_MODE_MASK) | PSR64_USER64_DEFAULT;
 
-       if (thread_setstatus(th_act, ARM_THREAD_STATE64, (void *)&mctx->ss, ARM_THREAD_STATE64_COUNT) != KERN_SUCCESS) {
-               return (EINVAL);
+       if (thread_setstatus_from_user(th_act, ARM_THREAD_STATE64, (void *)&mctx->ss, ARM_THREAD_STATE64_COUNT) != KERN_SUCCESS) {
+               return EINVAL;
        }
-       if (thread_setstatus(th_act, ARM_NEON_STATE64, (void *)&mctx->ns, ARM_NEON_STATE64_COUNT) != KERN_SUCCESS) {
-               return (EINVAL);
+       if (thread_setstatus_from_user(th_act, ARM_NEON_STATE64, (void *)&mctx->ns, ARM_NEON_STATE64_COUNT) != KERN_SUCCESS) {
+               return EINVAL;
        }
 
        return 0;
@@ -630,9 +727,9 @@ sigreturn_set_state64(thread_t th_act, mcontext64_t *mctx)
 /* ARGSUSED */
 int
 sigreturn(
-         struct proc * p,
-         struct sigreturn_args * uap,
-         __unused int *retval)
+       struct proc * p,
+       struct sigreturn_args * uap,
+       __unused int *retval)
 {
        union {
                user_ucontext32_t uc32;
@@ -641,21 +738,28 @@ sigreturn(
 #endif
        } uctx;
 
-       union { 
+       union {
                mcontext32_t mc32;
 #if defined(__arm64__)
                mcontext64_t mc64;
 #endif
        } mctx;
 
+       struct sigacts *ps = p->p_sigacts;
        int             error, sigmask = 0, onstack = 0;
        thread_t        th_act;
        struct uthread *ut;
+       uint32_t        sigreturn_validation;
+       user_addr_t     token_uctx;
+       kern_return_t   kr;
 
        th_act = current_thread();
        ut = (struct uthread *) get_bsdthread_info(th_act);
 
-       if (proc_is64bit(p)) {
+       /* see osfmk/kern/restartable.c */
+       act_set_ast_reset_pcs(th_act);
+
+       if (proc_is64bit_data(p)) {
 #if defined(__arm64__)
                error = sigreturn_copyin_ctx64(&uctx.uc64, &mctx.mc64, uap->uctx);
                if (error != 0) {
@@ -677,61 +781,88 @@ sigreturn(
                sigmask = uctx.uc32.uc_sigmask;
        }
 
-       if ((onstack & 01))
+       if ((onstack & 01)) {
                p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK;
-       else
+       } else {
                p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK;
+       }
 
        ut->uu_sigmask = sigmask & ~sigcantmask;
-       if (ut->uu_siglist & ~ut->uu_sigmask)
+       if (ut->uu_siglist & ~ut->uu_sigmask) {
                signal_setast(current_thread());
+       }
+
+       sigreturn_validation = atomic_load_explicit(
+               &ps->ps_sigreturn_validation, memory_order_relaxed);
+       token_uctx = uap->uctx;
+       kr = machine_thread_siguctx_pointer_convert_to_user(th_act, &token_uctx);
+       assert(kr == KERN_SUCCESS);
 
-       if (proc_is64bit(p)) {
+       if (proc_is64bit_data(p)) {
 #if defined(__arm64__)
+               user64_addr_t token;
+               token = (user64_addr_t)token_uctx ^ (user64_addr_t)ps->ps_sigreturn_token;
+               if ((user64_addr_t)uap->token != token) {
+#if DEVELOPMENT || DEBUG
+                       printf("process %s[%d] sigreturn token mismatch: received 0x%llx expected 0x%llx\n",
+                           p->p_comm, p->p_pid, (user64_addr_t)uap->token, token);
+#endif /* DEVELOPMENT || DEBUG */
+                       if (sigreturn_validation != PS_SIGRETURN_VALIDATION_DISABLED) {
+                               return EINVAL;
+                       }
+               }
                error = sigreturn_set_state64(th_act, &mctx.mc64);
                if (error != 0) {
+#if DEVELOPMENT || DEBUG
+                       printf("process %s[%d] sigreturn set_state64 error %d\n",
+                           p->p_comm, p->p_pid, error);
+#endif /* DEVELOPMENT || DEBUG */
                        return error;
                }
 #else
                panic("Shouldn't have 64-bit thread states on a 32-bit kernel.");
 #endif
        } else {
+               user32_addr_t token;
+               token = (user32_addr_t)token_uctx ^ (user32_addr_t)ps->ps_sigreturn_token;
+               if ((user32_addr_t)uap->token != token) {
+#if DEVELOPMENT || DEBUG
+                       printf("process %s[%d] sigreturn token mismatch: received 0x%x expected 0x%x\n",
+                           p->p_comm, p->p_pid, (user32_addr_t)uap->token, token);
+#endif /* DEVELOPMENT || DEBUG */
+                       if (sigreturn_validation != PS_SIGRETURN_VALIDATION_DISABLED) {
+                               return EINVAL;
+                       }
+               }
                error = sigreturn_set_state32(th_act, &mctx.mc32);
                if (error != 0) {
+#if DEVELOPMENT || DEBUG
+                       printf("process %s[%d] sigreturn sigreturn_set_state32 error %d\n",
+                           p->p_comm, p->p_pid, error);
+#endif /* DEVELOPMENT || DEBUG */
                        return error;
                }
        }
 
-       return (EJUSTRETURN);
+       return EJUSTRETURN;
 }
 
 /*
- * machine_exception() performs MD translation
- * of a mach exception to a unix signal and code.
+ * machine_exception() performs machine-dependent translation
+ * of a mach exception to a unix signal.
  */
-
-boolean_t
-machine_exception(
-                 int exception,
-                 mach_exception_subcode_t code,
-                 __unused mach_exception_subcode_t subcode,
-                 int *unix_signal,
-                 mach_exception_subcode_t * unix_code
-)
+int
+machine_exception(int                           exception,
+    __unused mach_exception_code_t         code,
+    __unused mach_exception_subcode_t      subcode)
 {
        switch (exception) {
        case EXC_BAD_INSTRUCTION:
-               *unix_signal = SIGILL;
-               *unix_code = code;
-               break;
+               return SIGILL;
 
        case EXC_ARITHMETIC:
-               *unix_signal = SIGFPE;
-               *unix_code = code;
-               break;
-
-       default:
-               return (FALSE);
+               return SIGFPE;
        }
-       return (TRUE);
+
+       return 0;
 }