void sendsig(struct proc *p, user_addr_t ua_catcher, int sig, int mask, __unused uint32_t code) { user_addr_t ua_sp; user_addr_t ua_sip; user_addr_t trampact; user_addr_t ua_uctxp; user_addr_t ua_mctxp; user_siginfo_t sinfo32; struct uthread *ut; struct mcontext mctx32; struct user_ucontext32 uctx32; struct sigacts *ps = p->p_sigacts; void *state; arm_thread_state_t *tstate32; mach_msg_type_number_t state_count; int stack_size = 0; int infostyle = UC_TRAD; int oonstack, flavor, error; proc_unlock(p); thread_t thread = current_thread(); ut = get_bsdthread_info(thread); /* * Set up thread state info. */ flavor = ARM_THREAD_STATE; state = (void *)&mctx32.ss; state_count = ARM_THREAD_STATE_COUNT; if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS) goto bad; flavor = ARM_EXCEPTION_STATE; state = (void *)&mctx32.es; state_count = ARM_EXCEPTION_STATE_COUNT; if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS) goto bad; flavor = ARM_VFP_STATE; state = (void *)&mctx32.fs; state_count = ARM_VFP_STATE_COUNT; if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS) goto bad; tstate32 = &mctx32.ss; /* * Set the signal style. */ if (p->p_sigacts->ps_siginfo & sigmask(sig)) infostyle = UC_FLAVOR; /* * Get the signal disposition. */ trampact = ps->ps_trampact[sig]; /* * Figure out where our new stack lives. */ oonstack = ut->uu_sigstk.ss_flags & SA_ONSTACK; if ((ut->uu_flag & UT_ALTSTACK) && !oonstack && (ps->ps_sigonstack & sigmask(sig))) { ua_sp = ut->uu_sigstk.ss_sp; ua_sp += ut->uu_sigstk.ss_size; stack_size = ut->uu_sigstk.ss_size; ut->uu_sigstk.ss_flags |= SA_ONSTACK; } else { ua_sp = tstate32->sp; } /* * Set up the stack. */ ua_sp -= UC_FLAVOR_SIZE; ua_mctxp = ua_sp; ua_sp -= sizeof(struct user_ucontext32); ua_uctxp = ua_sp; ua_sp -= sizeof(siginfo_t); ua_sip = ua_sp; /* * Align the stack pointer. */ ua_sp = TRUNC_DOWN32(ua_sp, C_32_STK_ALIGN); /* * Build the signal context to be used by sigreturn. */ uctx32.uc_onstack = oonstack; uctx32.uc_sigmask = mask; uctx32.uc_stack.ss_sp = ua_sp; uctx32.uc_stack.ss_size = stack_size; if (oonstack) uctx32.uc_stack.ss_flags |= SS_ONSTACK; uctx32.uc_link = 0; uctx32.uc_mcsize = UC_FLAVOR_SIZE; uctx32.uc_mcontext = ua_mctxp; /* * init siginfo */ bzero((caddr_t)&sinfo32, sizeof(user_siginfo_t)); sinfo32.si_signo = sig; sinfo32.pad[0] = tstate32->sp; sinfo32.si_addr = tstate32->lr; switch (sig) { case SIGILL: sinfo32.si_code = ILL_NOOP; break; case SIGFPE: sinfo32.si_code = FPE_NOOP; break; case SIGBUS: sinfo32.si_code = BUS_ADRALN; break; case SIGSEGV: sinfo32.si_code = SEGV_ACCERR; break; default: { int status_and_exitcode; /* * All other signals need to fill out a minimum set of * information for the siginfo structure passed into * the signal handler, if SA_SIGINFO was specified. * * p->si_status actually contains both the status and * the exit code; we save it off in its own variable * for later breakdown. */ proc_lock(p); sinfo32.si_pid = p->si_pid; p->si_pid = 0; status_and_exitcode = p->si_status; p->si_status = 0; sinfo32.si_uid = p->si_uid; p->si_uid = 0; sinfo32.si_code = p->si_code; p->si_code = 0; proc_unlock(p); if (sinfo32.si_code == CLD_EXITED) { if (WIFEXITED(status_and_exitcode)) sinfo32.si_code = CLD_EXITED; else if (WIFSIGNALED(status_and_exitcode)) { if (WCOREDUMP(status_and_exitcode)) { sinfo32.si_code = CLD_DUMPED; status_and_exitcode = W_EXITCODE(status_and_exitcode, status_and_exitcode); } else { sinfo32.si_code = CLD_KILLED; status_and_exitcode = W_EXITCODE(status_and_exitcode, status_and_exitcode); } } } /* * The recorded status contains the exit code and the * signal information, but the information to be passed * in the siginfo to the handler is supposed to only * contain the status, so we have to shift it out. */ sinfo32.si_status = WEXITSTATUS(status_and_exitcode); break; } } /* * Copy out context info. */ if (copyout((caddr_t)&uctx32, ua_uctxp, sizeof(struct user_ucontext32)) != KERN_SUCCESS) goto bad; if (copyout((caddr_t)&sinfo32, ua_sip, sizeof(user_siginfo_t)) != KERN_SUCCESS) goto bad; if (copyout((caddr_t)&mctx32, ua_mctxp, sizeof(struct mcontext)) != KERN_SUCCESS) goto bad; if (copyout((caddr_t)&ua_uctxp, ua_sp, sizeof(user_addr_t)) != KERN_SUCCESS) goto bad; /* * Set up regsiters for the trampoline. */ tstate32->r[0] = ua_catcher; tstate32->r[1] = infostyle; tstate32->r[2] = sig; tstate32->r[3] = ua_sip; tstate32->sp = ua_sp; if (trampact & 0x01) { tstate32->lr = trampact; tstate32->cpsr = 0x10; /* User mode */ } else { trampact &= ~0x01; tstate32->lr = trampact; tstate32->cpsr = 0x10; /* User mode */ tstate32->cpsr |= (1 << 5); /* T-bit */ } /* * Call the trampoline. */ flavor = ARM_THREAD_STATE; state_count = ARM_THREAD_STATE_COUNT; state = (void *)tstate32; if ((error = thread_setstatus(thread, flavor, (thread_state_t)state, state_count)) != KERN_SUCCESS) panic("sendsig: thread_setstatus failed, ret = %08X\n", error); proc_lock(p); return; bad: proc_lock(p); SIGACTION(p, SIGILL) = SIG_DFL; sig = sigmask(SIGILL); p->p_sigignore &= ~sig; p->p_sigcatch &= ~sig; ut->uu_sigmask &= ~sig; /* * sendsig is called with signal lock held */ proc_unlock(p); psignal_locked(p, SIGILL); proc_lock(p); return; }
/* * Send an interrupt to process. * */ void sendsig( struct proc * p, user_addr_t catcher, int sig, int mask, __unused uint32_t code ) { 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; #endif } user_frame; user_siginfo_t sinfo; 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_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)) infostyle = UC_FLAVOR; else infostyle = UC_TRAD; trampact = ps->ps_trampact[sig]; oonstack = ps->ps_sigstk.ss_flags & SA_ONSTACK; /* * Get sundry thread state. */ if (proc_is64bit_data(p)) { #ifdef __arm64__ 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."); #endif } else { if (sendsig_get_state32(th_act, &ts.ts32.ss, &user_frame.uf32.mctx) != 0) { goto bad2; } } /* * Figure out where our new stack lives. */ if ((ps->ps_flags & SAS_ALTSTACK) && !oonstack && (ps->ps_sigonstack & sigmask(sig))) { sp = ps->ps_sigstk.ss_sp; sp += ps->ps_sigstk.ss_size; stack_size = ps->ps_sigstk.ss_size; ps->ps_sigstk.ss_flags |= SA_ONSTACK; } else { /* * Get stack pointer, and allocate enough space * for signal handler data. */ if (proc_is64bit_data(p)) { #if defined(__arm64__) 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(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 */ #endif } } proc_unlock(p); /* * Fill in ucontext (points to mcontext, i.e. thread states). */ 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); #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); } /* * Setup siginfo. */ bzero((caddr_t) & sinfo, sizeof(sinfo)); sinfo.si_signo = sig; if (proc_is64bit_data(p)) { #if defined(__arm64__) 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 = 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))) sinfo.si_code = ILL_ILLOPC; 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))) sinfo.si_code = ILL_ILLTRP; else sinfo.si_code = ILL_NOOP; #else sinfo.si_code = ILL_ILLTRP; #endif break; case SIGFPE: break; case SIGBUS: if (proc_is64bit_data(p)) { #if defined(__arm64__) sinfo.si_addr = user_frame.uf64.mctx.es.far; #else panic("Shouldn't have 64-bit thread states on a 32-bit kernel."); #endif } else { sinfo.si_addr = user_frame.uf32.mctx.es.far; } sinfo.si_code = BUS_ADRALN; break; case SIGSEGV: if (proc_is64bit_data(p)) { #if defined(__arm64__) sinfo.si_addr = user_frame.uf64.mctx.es.far; #else panic("Shouldn't have 64-bit thread states on a 32-bit kernel."); #endif } else { sinfo.si_addr = user_frame.uf32.mctx.es.far; } #ifdef BER_XXX /* First check in srr1 and then in dsisr */ if (mctx.ss.srr1 & (1 << (31 - DSISR_PROT_BIT))) sinfo.si_code = SEGV_ACCERR; else if (mctx.es.dsisr & (1 << (31 - DSISR_PROT_BIT))) sinfo.si_code = SEGV_ACCERR; else sinfo.si_code = SEGV_MAPERR; #else sinfo.si_code = SEGV_ACCERR; #endif break; default: { int status_and_exitcode; /* * All other signals need to fill out a minimum set of * information for the siginfo structure passed into * the signal handler, if SA_SIGINFO was specified. * * p->si_status actually contains both the status and * the exit code; we save it off in its own variable * for later breakdown. */ proc_lock(p); sinfo.si_pid = p->si_pid; p->si_pid = 0; status_and_exitcode = p->si_status; p->si_status = 0; sinfo.si_uid = p->si_uid; p->si_uid = 0; sinfo.si_code = p->si_code; p->si_code = 0; proc_unlock(p); if (sinfo.si_code == CLD_EXITED) { if (WIFEXITED(status_and_exitcode)) sinfo.si_code = CLD_EXITED; 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); } else { sinfo.si_code = CLD_KILLED; status_and_exitcode = W_EXITCODE(status_and_exitcode,status_and_exitcode); } } } /* * The recorded status contains the exit code and the * signal information, but the information to be passed * in the siginfo to the handler is supposed to only * contain the status, so we have to shift it out. */ sinfo.si_status = (WEXITSTATUS(status_and_exitcode) & 0x00FFFFFF) | (((uint32_t)(p->p_xhighbits) << 24) & 0xFF000000); p->p_xhighbits = 0; break; } } #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_data(p)) { #if defined(__arm64__) user64_addr_t token; /* * 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; } 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."); #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, *pointer* * to uctx and token now. */ siginfo_user_to_user32(&sinfo, &user_frame.uf32.sinfo); 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; } 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); return; bad: proc_lock(p); bad2: SIGACTION(p, SIGILL) = SIG_DFL; sig = sigmask(SIGILL); p->p_sigignore &= ~sig; p->p_sigcatch &= ~sig; ut->uu_sigmask &= ~sig; /* sendsig is called with signal lock held */ proc_unlock(p); psignal_locked(p, SIGILL); proc_lock(p); }
void sendsig(struct proc *p, user_addr_t ua_catcher, int sig, int mask, __unused uint32_t code) { struct mcontext mctx; thread_t th_act; struct uthread *ut; void *tstate; int flavor; user_addr_t p_mctx = USER_ADDR_NULL; /* mcontext dest. */ int infostyle = UC_TRAD; mach_msg_type_number_t state_count; user_addr_t trampact; int oonstack; struct user_ucontext32 uctx; user_addr_t sp; user_addr_t p_uctx; /* user stack addr top copy ucontext */ user_siginfo_t sinfo; user_addr_t p_sinfo; /* user stack addr top copy siginfo */ struct sigacts *ps = p->p_sigacts; int stack_size = 0; kern_return_t kretn; th_act = current_thread(); kprintf("sendsig: Sending signal to thread %p, code %d.\n", th_act, sig); return; ut = get_bsdthread_info(th_act); if (p->p_sigacts->ps_siginfo & sigmask(sig)) { infostyle = UC_FLAVOR; } flavor = ARM_THREAD_STATE; tstate = (void *) &mctx.ss; state_count = ARM_THREAD_STATE_COUNT; if (thread_getstatus(th_act, flavor, (thread_state_t) tstate, &state_count) != KERN_SUCCESS) goto bad; trampact = ps->ps_trampact[sig]; oonstack = ut->uu_sigstk.ss_flags & SA_ONSTACK; /* * figure out where our new stack lives */ if ((ut->uu_flag & UT_ALTSTACK) && !oonstack && (ps->ps_sigonstack & sigmask(sig))) { sp = ut->uu_sigstk.ss_sp; sp += ut->uu_sigstk.ss_size; stack_size = ut->uu_sigstk.ss_size; ut->uu_sigstk.ss_flags |= SA_ONSTACK; } else { sp = CAST_USER_ADDR_T(mctx.ss.sp); } /* * context goes first on stack */ sp -= sizeof(struct ucontext); p_uctx = sp; /* * this is where siginfo goes on stack */ sp -= sizeof(user32_siginfo_t); p_sinfo = sp; /* * final stack pointer */ sp = TRUNC_DOWN32(sp, C_32_PARAMSAVE_LEN + C_32_LINKAGE_LEN, C_32_STK_ALIGN); uctx.uc_mcsize = (size_t) ((ARM_THREAD_STATE_COUNT) * sizeof(int)); uctx.uc_onstack = oonstack; uctx.uc_sigmask = mask; uctx.uc_stack.ss_sp = sp; uctx.uc_stack.ss_size = stack_size; if (oonstack) uctx.uc_stack.ss_flags |= SS_ONSTACK; uctx.uc_link = 0; /* * setup siginfo */ bzero((caddr_t) & sinfo, sizeof(sinfo)); sinfo.si_signo = sig; sinfo.si_addr = CAST_USER_ADDR_T(mctx.ss.pc); sinfo.pad[0] = CAST_USER_ADDR_T(mctx.ss.sp); switch (sig) { case SIGILL: sinfo.si_code = ILL_NOOP; break; case SIGFPE: sinfo.si_code = FPE_NOOP; break; case SIGBUS: sinfo.si_code = BUS_ADRALN; break; case SIGSEGV: sinfo.si_code = SEGV_ACCERR; break; default: { int status_and_exitcode; /* * All other signals need to fill out a minimum set of * information for the siginfo structure passed into * the signal handler, if SA_SIGINFO was specified. * * p->si_status actually contains both the status and * the exit code; we save it off in its own variable * for later breakdown. */ proc_lock(p); sinfo.si_pid = p->si_pid; p->si_pid = 0; status_and_exitcode = p->si_status; p->si_status = 0; sinfo.si_uid = p->si_uid; p->si_uid = 0; sinfo.si_code = p->si_code; p->si_code = 0; proc_unlock(p); if (sinfo.si_code == CLD_EXITED) { if (WIFEXITED(status_and_exitcode)) sinfo.si_code = CLD_EXITED; 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); } else { sinfo.si_code = CLD_KILLED; status_and_exitcode = W_EXITCODE(status_and_exitcode, status_and_exitcode); } } } /* * The recorded status contains the exit code and the * signal information, but the information to be passed * in the siginfo to the handler is supposed to only * contain the status, so we have to shift it out. */ sinfo.si_status = WEXITSTATUS(status_and_exitcode); break; } } if (copyout(&uctx, p_uctx, sizeof(struct user_ucontext32))) goto bad; if (copyout(&sinfo, p_sinfo, sizeof(sinfo))) goto bad; /* * set signal registers, these are probably wrong.. */ { mctx.ss.r[0] = CAST_DOWN(uint32_t, ua_catcher); mctx.ss.r[1] = (uint32_t) infostyle; mctx.ss.r[2] = (uint32_t) sig; mctx.ss.r[3] = CAST_DOWN(uint32_t, p_sinfo); mctx.ss.r[4] = CAST_DOWN(uint32_t, p_uctx); mctx.ss.pc = CAST_DOWN(uint32_t, trampact); mctx.ss.sp = CAST_DOWN(uint32_t, sp); state_count = ARM_THREAD_STATE_COUNT; printf("sendsig: Sending signal to thread %p, code %d, new pc 0x%08x\n", th_act, sig, trampact); if ((kretn = thread_setstatus(th_act, ARM_THREAD_STATE, (void *) &mctx.ss, state_count)) != KERN_SUCCESS) { panic("sendsig: thread_setstatus failed, ret = %08X\n", kretn); } } proc_lock(p); return; bad: proc_lock(p); SIGACTION(p, SIGILL) = SIG_DFL; sig = sigmask(SIGILL); p->p_sigignore &= ~sig; p->p_sigcatch &= ~sig; ut->uu_sigmask &= ~sig; /* * sendsig is called with signal lock held */ proc_unlock(p); psignal_locked(p, SIGILL); proc_lock(p); return; }