X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/6d2010ae8f7a6078e10b361c6962983bab233e0f..c7d2c2c6ee645e10cbccdd01c6191873ec77239d:/bsd/kern/kern_sig.c diff --git a/bsd/kern/kern_sig.c b/bsd/kern/kern_sig.c index de5455812..bf5507903 100644 --- a/bsd/kern/kern_sig.c +++ b/bsd/kern/kern_sig.c @@ -101,7 +101,6 @@ #include #include /* for coredump */ #include /* for APC support */ -#include #include /* extern void *get_bsdtask_info(task_t); */ #include #include @@ -112,6 +111,7 @@ #include #include +#include /* * Missing prototypes that Mach should export @@ -121,7 +121,6 @@ extern int thread_enable_fpe(thread_t act, int onoff); extern thread_t port_name_to_thread(mach_port_name_t port_name); extern kern_return_t get_signalact(task_t , thread_t *, int); -extern boolean_t thread_should_abort(thread_t); extern unsigned int get_useraddr(void); /* @@ -134,10 +133,11 @@ extern void doexception(int exc, mach_exception_code_t code, static void stop(proc_t, proc_t); int cansignal(proc_t, kauth_cred_t, proc_t, int, int); int killpg1(proc_t, int, int, int, int); -int setsigvec(proc_t, thread_t, int, struct __kern_sigaction *, boolean_t in_sigstart); static void psignal_uthread(thread_t, int); +static void psignal_try_thread(proc_t, thread_t, int signum); kern_return_t do_bsdexception(int, int, int); void __posix_sem_syscall_return(kern_return_t); +char *proc_name_address(void *p); /* implementations in osfmk/kern/sync_sema.c. We do not want port.h in this scope, so void * them */ kern_return_t semaphore_timedwait_signal_trap_internal(mach_port_name_t, mach_port_name_t, unsigned int, clock_res_t, void (*)(kern_return_t)); @@ -148,7 +148,7 @@ kern_return_t semaphore_wait_trap_internal(mach_port_name_t, void (*)(kern_retur static int filt_sigattach(struct knote *kn); static void filt_sigdetach(struct knote *kn); static int filt_signal(struct knote *kn, long hint); -static void filt_signaltouch(struct knote *kn, struct kevent64_s *kev, +static void filt_signaltouch(struct knote *kn, struct kevent_internal_s *kev, long type); struct filterops sig_filtops = { @@ -185,6 +185,7 @@ static kern_return_t get_signalthread(proc_t, int, thread_t *); #define PSIG_LOCKED 0x1 #define PSIG_VFORK 0x2 #define PSIG_THREAD 0x4 +#define PSIG_TRY_THREAD 0x8 static void psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum); @@ -305,6 +306,10 @@ cansignal(proc_t p, kauth_cred_t uc, proc_t q, int signum, int zombie) if (p == q) return(1); + /* you can't send launchd SIGKILL, even if root */ + if (signum == SIGKILL && q == initproc) + return(0); + if (!suser(uc, NULL)) return (1); /* root can always signal */ @@ -349,6 +354,53 @@ cansignal(proc_t p, kauth_cred_t uc, proc_t q, int signum, int zombie) return (0); } +/* + * Some signals can be restricted from being handled, + * forcing the default action for that signal. This behavior applies only to + * non-root (EUID != 0) processes, and is configured with the "sigrestrict=x" + * bootarg: + * + * 0 (default): Disallow use of restricted signals. Trying to register a handler + * returns ENOTSUP, which userspace may use to take special action (e.g. abort). + * 1: As above, but return EINVAL. Restricted signals behave similarly to SIGKILL. + * 2: Usual POSIX semantics. + */ +unsigned sigrestrict_arg = 0; + +#if PLATFORM_WatchOS +static int +sigrestrictmask(void) +{ + if (kauth_getuid() != 0 && sigrestrict_arg != 2) { + return SIGRESTRICTMASK; + } + return 0; +} + +static int +signal_is_restricted(proc_t p, int signum) +{ + if (sigmask(signum) & sigrestrictmask()) { + if (sigrestrict_arg == 0 && + task_get_apptype(p->task) == TASK_APPTYPE_APP_DEFAULT) { + return ENOTSUP; + } else { + return EINVAL; + } + } + return 0; +} + +#else + +static inline int +signal_is_restricted(proc_t p, int signum) +{ + (void)p; + (void)signum; + return 0; +} +#endif /* !PLATFORM_WatchOS */ /* * Returns: 0 Success @@ -375,9 +427,34 @@ sigaction(proc_t p, struct sigaction_args *uap, __unused int32_t *retval) signum = uap->signum; if (signum <= 0 || signum >= NSIG || - signum == SIGKILL || signum == SIGSTOP) + signum == SIGKILL || signum == SIGSTOP) return (EINVAL); + if (uap->nsa) { + if (IS_64BIT_PROCESS(p)) { + struct __user64_sigaction __vec64; + error = copyin(uap->nsa, &__vec64, sizeof(__vec64)); + __sigaction_user64_to_kern(&__vec64, &__vec); + } else { + struct __user32_sigaction __vec32; + error = copyin(uap->nsa, &__vec32, sizeof(__vec32)); + __sigaction_user32_to_kern(&__vec32, &__vec); + } + if (error) + return (error); + __vec.sa_flags &= SA_USERSPACE_MASK; /* Only pass on valid sa_flags */ + + if ((__vec.sa_flags & SA_SIGINFO) || __vec.sa_handler != SIG_DFL) { + if ((error = signal_is_restricted(p, signum))) { + if (error == ENOTSUP) { + printf("%s(%d): denied attempt to register action for signal %d\n", + proc_name_address(p), proc_pid(p), signum); + } + return error; + } + } + } + if (uap->osa) { sa->sa_handler = ps->ps_sigact[signum]; sa->sa_mask = ps->ps_catchmask[signum]; @@ -400,35 +477,21 @@ sigaction(proc_t p, struct sigaction_args *uap, __unused int32_t *retval) if (IS_64BIT_PROCESS(p)) { struct user64_sigaction vec64; - sigaction_kern_to_user64(sa, &vec64); error = copyout(&vec64, uap->osa, sizeof(vec64)); } else { struct user32_sigaction vec32; - sigaction_kern_to_user32(sa, &vec32); error = copyout(&vec32, uap->osa, sizeof(vec32)); } if (error) return (error); } + if (uap->nsa) { - if (IS_64BIT_PROCESS(p)) { - struct __user64_sigaction __vec64; - - error = copyin(uap->nsa, &__vec64, sizeof(__vec64)); - __sigaction_user64_to_kern(&__vec64, &__vec); - } else { - struct __user32_sigaction __vec32; - - error = copyin(uap->nsa, &__vec32, sizeof(__vec32)); - __sigaction_user32_to_kern(&__vec32, &__vec); - } - if (error) - return (error); - __vec.sa_flags &= SA_USERSPACE_MASK; /* Only pass on valid sa_flags */ error = setsigvec(p, current_thread(), signum, &__vec, FALSE); } + return (error); } @@ -655,7 +718,7 @@ siginit(proc_t p) { int i; - for (i = 0; i < NSIG; i++) + for (i = 1; i < NSIG; i++) if (sigprop[i] & SA_IGNORE && i != SIGCONT) p->p_sigignore |= sigmask(i); } @@ -1637,7 +1700,7 @@ threadsignal(thread_t sig_actthread, int signum, mach_exception_code_t code) p = (proc_t)(get_bsdtask_info(sig_task)); uth = get_bsdthread_info(sig_actthread); - if (uth && (uth->uu_flag & UT_VFORK)) + if (uth->uu_flag & UT_VFORK) p = uth->uu_proc; proc_lock(p); @@ -1654,6 +1717,18 @@ threadsignal(thread_t sig_actthread, int signum, mach_exception_code_t code) signal_setast(sig_actthread); } +/* + * get_signalthread + * + * Picks an appropriate thread from a process to target with a signal. + * + * Called with proc locked. + * Returns thread with BSD ast set. + * + * We attempt to deliver a proc-wide signal to the first thread in the task. + * This allows single threaded applications which use signals to + * be able to be linked with multithreaded libraries. + */ static kern_return_t get_signalthread(proc_t p, int signum, thread_t * thr) { @@ -1662,7 +1737,7 @@ get_signalthread(proc_t p, int signum, thread_t * thr) thread_t sig_thread; struct task * sig_task = p->task; kern_return_t kret; - + *thr = THREAD_NULL; if ((p->p_lflag & P_LINVFORK) && p->p_vforkact) { @@ -1673,20 +1748,17 @@ get_signalthread(proc_t p, int signum, thread_t * thr) return(KERN_SUCCESS); }else return(KERN_FAILURE); - } + } - proc_lock(p); TAILQ_FOREACH(uth, &p->p_uthlist, uu_list) { if(((uth->uu_flag & UT_NO_SIGMASK)== 0) && (((uth->uu_sigmask & mask) == 0) || (uth->uu_sigwait & mask))) { if (check_actforsig(p->task, uth->uu_context.vc_thread, 1) == KERN_SUCCESS) { *thr = uth->uu_context.vc_thread; - proc_unlock(p); return(KERN_SUCCESS); } } } - proc_unlock(p); if (get_signalact(p->task, thr, 1) == KERN_SUCCESS) { return(KERN_SUCCESS); } @@ -1711,10 +1783,10 @@ static void psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum) { int prop; - sig_t action = NULL; + user_addr_t action = USER_ADDR_NULL; proc_t sig_proc; thread_t sig_thread; - register task_t sig_task; + task_t sig_task; int mask; struct uthread *uth; kern_return_t kret; @@ -1723,7 +1795,8 @@ psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum) kauth_cred_t my_cred; if ((u_int)signum >= NSIG || signum == 0) - panic("psignal signal number"); + panic("psignal: bad signal number %d", signum); + mask = sigmask(signum); prop = sigprop[signum]; @@ -1733,6 +1806,12 @@ psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum) } #endif /* SIGNAL_DEBUG */ + /* catch unexpected initproc kills early for easier debuggging */ + if (signum == SIGKILL && p == initproc) + panic_plain("unexpected SIGKILL of %s %s", + (p->p_name[0] != '\0' ? p->p_name : "initproc"), + ((p->p_csflags & CS_KILLED) ? "(CS_KILLED)" : "")); + /* * We will need the task pointer later. Grab it now to * check for a zombie process. Also don't send signals @@ -1746,9 +1825,14 @@ psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum) sig_task = get_threadtask(thread); sig_thread = thread; sig_proc = (proc_t)get_bsdtask_info(sig_task); + } else if (flavor & PSIG_TRY_THREAD) { + assert((thread == current_thread()) && (p == current_proc())); + sig_task = p->task; + sig_thread = thread; + sig_proc = p; } else { sig_task = p->task; - sig_thread = (struct thread *)0; + sig_thread = THREAD_NULL; sig_proc = p; } @@ -1762,9 +1846,10 @@ psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum) * also no need to send a signal to a process that is in the middle * of being torn down. */ - if (ISSET(sig_proc->p_flag, P_REBOOT) || - ISSET(sig_proc->p_lflag, P_LEXIT)) + if (ISSET(sig_proc->p_flag, P_REBOOT) || ISSET(sig_proc->p_lflag, P_LEXIT)) { + DTRACE_PROC3(signal__discard, thread_t, sig_thread, proc_t, sig_proc, int, signum); return; + } if( (flavor & (PSIG_VFORK | PSIG_THREAD)) == 0) { proc_knote(sig_proc, NOTE_SIGNAL | signum); @@ -1773,26 +1858,36 @@ psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum) if ((flavor & PSIG_LOCKED)== 0) proc_signalstart(sig_proc, 0); - /* - * Deliver the signal to the first thread in the task. This - * allows single threaded applications which use signals to - * be able to be linked with multithreaded libraries. We have - * an implicit reference to the current thread, but need - * an explicit one otherwise. The thread reference keeps - * the corresponding task data structures around too. This - * reference is released by thread_deallocate. - */ - - + /* Don't send signals to a process that has ignored them. */ if (((flavor & PSIG_VFORK) == 0) && ((sig_proc->p_lflag & P_LTRACED) == 0) && (sig_proc->p_sigignore & mask)) { DTRACE_PROC3(signal__discard, thread_t, sig_thread, proc_t, sig_proc, int, signum); - goto psigout; + goto sigout_unlocked; } + /* + * The proc_lock prevents the targeted thread from being deallocated + * or handling the signal until we're done signaling it. + * + * Once the proc_lock is dropped, we have no guarantee the thread or uthread exists anymore. + * + * XXX: What if the thread goes inactive after the thread passes bsd ast point? + */ + proc_lock(sig_proc); + if (flavor & PSIG_VFORK) { action = SIG_DFL; act_set_astbsd(sig_thread); kret = KERN_SUCCESS; + } else if (flavor & PSIG_TRY_THREAD) { + uth = get_bsdthread_info(sig_thread); + if (((uth->uu_flag & UT_NO_SIGMASK) == 0) && + (((uth->uu_sigmask & mask) == 0) || (uth->uu_sigwait & mask)) && + ((kret = check_actforsig(sig_proc->task, sig_thread, 1)) == KERN_SUCCESS)) { + /* deliver to specified thread */ + } else { + /* deliver to any willing thread */ + kret = get_signalthread(sig_proc, signum, &sig_thread); + } } else if (flavor & PSIG_THREAD) { /* If successful return with ast set */ kret = check_actforsig(sig_task, sig_thread, 1); @@ -1800,14 +1895,13 @@ psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum) /* If successful return with ast set */ kret = get_signalthread(sig_proc, signum, &sig_thread); } + if (kret != KERN_SUCCESS) { -#if SIGNAL_DEBUG - ram_printf(1); -#endif /* SIGNAL_DEBUG */ - goto psigout; + DTRACE_PROC3(signal__discard, thread_t, sig_thread, proc_t, sig_proc, int, signum); + proc_unlock(sig_proc); + goto sigout_unlocked; } - uth = get_bsdthread_info(sig_thread); /* @@ -1826,7 +1920,8 @@ psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum) * action will be SIG_DFL here.) */ if (sig_proc->p_sigignore & mask) - goto psigout; + goto sigout_locked; + if (uth->uu_sigwait & mask) action = KERN_SIG_WAIT; else if (uth->uu_sigmask & mask) @@ -1838,9 +1933,7 @@ psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum) } } - - proc_lock(sig_proc); - + /* TODO: p_nice isn't hooked up to the scheduler... */ if (sig_proc->p_nice > NZERO && action == SIG_DFL && (prop & SA_KILL) && (sig_proc->p_lflag & P_LTRACED) == 0) sig_proc->p_nice = NZERO; @@ -1856,41 +1949,33 @@ psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum) * is default; don't stop the process below if sleeping, * and don't clear any pending SIGCONT. */ - proc_unlock(sig_proc); pg = proc_pgrp(sig_proc); if (prop & SA_TTYSTOP && pg->pg_jobc == 0 && action == SIG_DFL) { pg_rele(pg); - goto psigout; + goto sigout_locked; } pg_rele(pg); - proc_lock(sig_proc); uth->uu_siglist &= ~contsigmask; } uth->uu_siglist |= mask; - /* - * Repost AST incase sigthread has processed - * ast and missed signal post. - */ - if (action == KERN_SIG_CATCH) - act_set_astbsd(sig_thread); - /* * Defer further processing for signals which are held, * except that stopped processes must be continued by SIGCONT. */ /* vfork will not go thru as action is SIG_DFL */ - if ((action == KERN_SIG_HOLD) && ((prop & SA_CONT) == 0 || sig_proc->p_stat != SSTOP)) { - proc_unlock(sig_proc); - goto psigout; - } + if ((action == KERN_SIG_HOLD) && ((prop & SA_CONT) == 0 || sig_proc->p_stat != SSTOP)) + goto sigout_locked; + /* * SIGKILL priority twiddling moved here from above because * it needs sig_thread. Could merge it into large switch * below if we didn't care about priority for tracing * as SIGKILL's action is always SIG_DFL. + * + * TODO: p_nice isn't hooked up to the scheduler... */ if ((signum == SIGKILL) && (sig_proc->p_nice > NZERO)) { sig_proc->p_nice = NZERO; @@ -1904,11 +1989,10 @@ psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum) if (sig_proc->p_lflag & P_LTRACED) { if (sig_proc->p_stat != SSTOP) goto runlocked; - else { - proc_unlock(sig_proc); - goto psigout; - } + else + goto sigout_locked; } + if ((flavor & PSIG_VFORK) != 0) goto runlocked; @@ -1934,13 +2018,9 @@ psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum) if (prop & SA_CONT) { OSBitOrAtomic(P_CONTINUED, &sig_proc->p_flag); sig_proc->p_contproc = current_proc()->p_pid; - - proc_unlock(sig_proc); - (void) task_resume(sig_task); - goto psigout; + (void) task_resume_internal(sig_task); } - proc_unlock(sig_proc); - goto psigout; + goto sigout_locked; } if (action != SIG_DFL) { @@ -1951,13 +2031,10 @@ psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum) */ if (prop & SA_CONT) { OSBitOrAtomic(P_CONTINUED, &sig_proc->p_flag); - proc_unlock(sig_proc); - (void) task_resume(sig_task); - proc_lock(sig_proc); + (void) task_resume_internal(sig_task); sig_proc->p_stat = SRUN; } else if (sig_proc->p_stat == SSTOP) { - proc_unlock(sig_proc); - goto psigout; + goto sigout_locked; } /* * Fill out siginfo structure information to pass to the @@ -1972,9 +2049,7 @@ psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum) * Note: Avoid the SIGCHLD recursion case! */ if (signum != SIGCHLD) { - proc_unlock(sig_proc); r_uid = kauth_getruid(); - proc_lock(sig_proc); sig_proc->si_pid = current_proc()->p_pid; sig_proc->si_status = W_EXITCODE(signum, 0); @@ -1994,14 +2069,13 @@ psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum) * stopped from the keyboard. */ if (!(prop & SA_STOP) && sig_proc->p_pptr == initproc) { - proc_unlock(sig_proc); - psignal_locked(sig_proc, SIGKILL); - proc_lock(sig_proc); uth->uu_siglist &= ~mask; proc_unlock(sig_proc); - goto psigout; + /* siglock still locked, proc_lock not locked */ + psignal_locked(sig_proc, SIGKILL); + goto sigout_unlocked; } - + /* * Stop the task * if task hasn't already been stopped by @@ -2040,19 +2114,18 @@ psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum) psignal(pp, SIGCHLD); } - if (pp != PROC_NULL) + if (pp != PROC_NULL) { proc_parentdropref(pp, 0); - } else - proc_unlock(sig_proc); - goto psigout; + } + + goto sigout_unlocked; + } + + goto sigout_locked; } DTRACE_PROC3(signal__send, thread_t, sig_thread, proc_t, p, int, signum); - /* - * enters switch with sig_proc lock held but dropped when - * gets out of switch - */ switch (signum) { /* * Signals ignored by default have been dealt @@ -2069,7 +2142,6 @@ psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum) * Process will be running after 'run' */ sig_proc->p_stat = SRUN; - proc_unlock(sig_proc); /* * In scenarios where suspend/resume are racing * the signal we are missing AST_BSD by the time @@ -2080,7 +2152,7 @@ psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum) act_set_astbsd(sig_thread); thread_abort(sig_thread); - goto psigout; + goto sigout_locked; case SIGCONT: /* @@ -2090,9 +2162,8 @@ psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum) OSBitOrAtomic(P_CONTINUED, &sig_proc->p_flag); sig_proc->p_contproc = sig_proc->p_pid; - proc_unlock(sig_proc); - (void) task_resume(sig_task); - proc_lock(sig_proc); + (void) task_resume_internal(sig_task); + /* * When processing a SIGCONT, we need to check * to see if there are signals pending that @@ -2111,8 +2182,7 @@ psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum) uth->uu_siglist &= ~mask; sig_proc->p_stat = SRUN; - proc_unlock(sig_proc); - goto psigout; + goto sigout_locked; default: /* @@ -2122,9 +2192,8 @@ psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum) */ if (((flavor & (PSIG_VFORK|PSIG_THREAD)) == 0) && (action == SIG_DFL) && (prop & SA_KILL)) { sig_proc->p_stat = SRUN; - proc_unlock(sig_proc); thread_abort(sig_thread); - goto psigout; + goto sigout_locked; } /* @@ -2132,8 +2201,7 @@ psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum) * resume it. */ if (sig_proc->p_stat == SSTOP) { - proc_unlock(sig_proc); - goto psigout; + goto sigout_locked; } goto runlocked; } @@ -2147,22 +2215,25 @@ runlocked: */ if (sig_proc->p_stat == SSTOP) { if ((sig_proc->p_lflag & P_LTRACED) != 0 && sig_proc->p_xstat != 0) - uth->uu_siglist |= sigmask(sig_proc->p_xstat); + uth->uu_siglist |= sigmask(sig_proc->p_xstat); + if ((flavor & PSIG_VFORK) != 0) { sig_proc->p_stat = SRUN; } - proc_unlock(sig_proc); } else { /* * setrunnable(p) in BSD and * Wake up the thread if it is interruptible. */ sig_proc->p_stat = SRUN; - proc_unlock(sig_proc); if ((flavor & PSIG_VFORK) == 0) thread_abort_safely(sig_thread); } -psigout: + +sigout_locked: + proc_unlock(sig_proc); + +sigout_unlocked: if ((flavor & PSIG_LOCKED)== 0) { proc_signalend(sig_proc, 0); } @@ -2192,6 +2263,12 @@ psignal_uthread(thread_t thread, int signum) psignal_internal(PROC_NULL, TASK_NULL, thread, PSIG_THREAD, signum); } +/* same as psignal(), but prefer delivery to 'thread' if possible */ +static void +psignal_try_thread(proc_t p, thread_t thread, int signum) +{ + psignal_internal(p, NULL, thread, PSIG_TRY_THREAD, signum); +} /* * If the current process has received a signal (should be caught or cause @@ -2206,7 +2283,7 @@ psignal_uthread(thread_t thread, int signum) * postsig(signum); */ int -issignal(proc_t p) +issignal_locked(proc_t p) { int signum, mask, prop, sigbits; thread_t cur_act; @@ -2223,13 +2300,11 @@ issignal(proc_t p) ram_printf(3); } #endif /* SIGNAL_DEBUG */ - proc_lock(p); /* * Try to grab the signal lock. */ if (sig_try_locked(p) <= 0) { - proc_unlock(p); return(0); } @@ -2300,12 +2375,9 @@ issignal(proc_t p) /* * XXX Have to really stop for debuggers; * XXX stop() doesn't do the right thing. - * XXX Inline the task_suspend because we - * XXX have to diddle Unix state in the - * XXX middle of it. */ task = p->task; - task_suspend(task); + task_suspend_internal(task); proc_lock(p); p->sigwait = TRUE; @@ -2362,6 +2434,7 @@ issignal(proc_t p) KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_PROC, BSD_PROC_FRCEXIT) | DBG_FUNC_NONE, p->p_pid, W_EXITCODE(0, SIGKILL), 2, 0, 0); exit1(p, W_EXITCODE(0, SIGKILL), (int *)NULL); + proc_lock(p); return(0); } @@ -2399,21 +2472,6 @@ issignal(proc_t p) switch ((long)p->p_sigacts->ps_sigact[signum]) { case (long)SIG_DFL: - /* - * Don't take default actions on system processes. - */ - if (p->p_ppid == 0) { -#if DIAGNOSTIC - /* - * Are you sure you want to ignore SIGSEGV - * in init? XXX - */ - printf("Process (pid %d) got signal %d\n", - p->p_pid, signum); -#endif - break; /* == ignore */ - } - /* * If there is a pending stop signal to process * with default action, stop here, @@ -2503,7 +2561,6 @@ issignal(proc_t p) /* NOTREACHED */ out: proc_signalend(p, 1); - proc_unlock(p); return(retval); } @@ -2562,21 +2619,6 @@ CURSIG(proc_t p) switch ((long)p->p_sigacts->ps_sigact[signum]) { case (long)SIG_DFL: - /* - * Don't take default actions on system processes. - */ - if (p->p_ppid == 0) { -#if DIAGNOSTIC - /* - * Are you sure you want to ignore SIGSEGV - * in init? XXX - */ - printf("Process (pid %d) got signal %d\n", - p->p_pid, signum); -#endif - break; /* == ignore */ - } - /* * If there is a pending stop signal to process * with default action, stop here, @@ -2645,7 +2687,7 @@ stop(proc_t p, proc_t parent) wakeup((caddr_t)parent); proc_list_unlock(); } - (void) task_suspend(p->task); /*XXX*/ + (void) task_suspend_internal(p->task); } /* @@ -2653,7 +2695,7 @@ stop(proc_t p, proc_t parent) * from the current set of pending signals. */ void -postsig(int signum) +postsig_locked(int signum) { proc_t p = current_proc(); struct sigacts *ps = p->p_sigacts; @@ -2672,12 +2714,10 @@ postsig(int signum) panic("psig not on master"); #endif - proc_lock(p); /* * Try to grab the signal lock. */ if (sig_try_locked(p) <= 0) { - proc_unlock(p); return; } @@ -2698,7 +2738,7 @@ postsig(int signum) p->p_sigacts->ps_sig = signum; proc_signalend(p, 1); proc_unlock(p); - if (coredump(p) == 0) + if (coredump(p, 0, 0) == 0) signum |= WCOREFLAG; } else { proc_signalend(p, 1); @@ -2713,6 +2753,16 @@ postsig(int signum) ut->t_dtrace_siginfo.si_uid = p->si_uid; ut->t_dtrace_siginfo.si_status = WEXITSTATUS(p->si_status); + /* Fire DTrace proc:::fault probe when signal is generated by hardware. */ + switch (signum) { + case SIGILL: case SIGBUS: case SIGSEGV: case SIGFPE: case SIGTRAP: + DTRACE_PROC2(fault, int, (int)(ut->uu_code), siginfo_t *, &(ut->t_dtrace_siginfo)); + break; + default: + break; + } + + DTRACE_PROC3(signal__handle, int, signum, siginfo_t *, &(ut->t_dtrace_siginfo), void (*)(void), SIG_DFL); #endif @@ -2720,6 +2770,7 @@ postsig(int signum) KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_PROC, BSD_PROC_FRCEXIT) | DBG_FUNC_NONE, p->p_pid, W_EXITCODE(0, signum), 3, 0, 0); exit1(p, W_EXITCODE(0, signum), (int *)NULL); + proc_lock(p); return; } else { /* @@ -2767,7 +2818,6 @@ postsig(int signum) sendsig(p, catcher, signum, returnmask, code); } proc_signalend(p, 1); - proc_unlock(p); } /* @@ -2837,7 +2887,7 @@ filt_signal(struct knote *kn, long hint) } static void -filt_signaltouch(struct knote *kn, struct kevent64_s *kev, long type) +filt_signaltouch(struct knote *kn, struct kevent_internal_s *kev, long type) { proc_klist_lock(); switch (type) { @@ -2853,7 +2903,7 @@ filt_signaltouch(struct knote *kn, struct kevent64_s *kev, long type) } break; default: - panic("filt_machporttouch() - invalid type (%ld)", type); + panic("filt_signaltouch() - invalid type (%ld)", type); break; } proc_klist_unlock(); @@ -2888,7 +2938,7 @@ bsd_ast(thread_t thread) else task_vtimer_clear(p->task, TASK_VTIMER_USER); - psignal(p, SIGVTALRM); + psignal_try_thread(p, thread, SIGVTALRM); } } @@ -2903,7 +2953,7 @@ bsd_ast(thread_t thread) else task_vtimer_clear(p->task, TASK_VTIMER_PROF); - psignal(p, SIGPROF); + psignal_try_thread(p, thread, SIGPROF); } } @@ -2924,7 +2974,7 @@ bsd_ast(thread_t thread) task_vtimer_clear(p->task, TASK_VTIMER_RLIM); - psignal(p, SIGXCPU); + psignal_try_thread(p, thread, SIGXCPU); } } @@ -2940,7 +2990,7 @@ bsd_ast(thread_t thread) proc_lock(p); p->p_dtrace_stop = 1; proc_unlock(p); - (void)task_suspend(p->task); + (void)task_suspend_internal(p->task); } if (ut->t_dtrace_resumepid) { @@ -2952,7 +3002,7 @@ bsd_ast(thread_t thread) if (resumeproc->p_dtrace_stop) { resumeproc->p_dtrace_stop = 0; proc_unlock(resumeproc); - task_resume(resumeproc->task); + task_resume_internal(resumeproc->task); } else { proc_unlock(resumeproc); @@ -2963,10 +3013,12 @@ bsd_ast(thread_t thread) #endif /* CONFIG_DTRACE */ + proc_lock(p); if (CHECK_SIGNALS(p, current_thread(), ut)) { - while ( (signum = issignal(p)) ) - postsig(signum); + while ( (signum = issignal_locked(p)) ) + postsig_locked(signum); } + proc_unlock(p); if (!bsd_init_done) { bsd_init_done = 1; @@ -3083,6 +3135,10 @@ proc_signalstart(proc_t p, int locked) { if (!locked) proc_lock(p); + + if(p->p_signalholder == current_thread()) + panic("proc_signalstart: thread attempting to signal a process for which it holds the signal lock"); + p->p_sigwaitcnt++; while ((p->p_lflag & P_LINSIGNAL) == P_LINSIGNAL) msleep(&p->p_sigmask, &p->p_mlock, 0, "proc_signstart", NULL); @@ -3116,7 +3172,10 @@ sig_lock_to_exit(proc_t p) p->exit_thread = self; proc_unlock(p); - (void) task_suspend(p->task); + + task_hold(p->task); + task_wait(p->task, FALSE); + proc_lock(p); }