*/
unsigned sigrestrict_arg = 0;
-#if PLATFORM_WatchOS || PLATFORM_AppleTVOS
+#if PLATFORM_WatchOS
static int
sigrestrictmask(void)
{
(void)signum;
return 0;
}
-#endif /* !(PLATFORM_WatchOS || PLATFORM_AppleTVOS) */
+#endif /* !PLATFORM_WatchOS */
/*
* Returns: 0 Success
signum == SIGKILL || signum == SIGSTOP)
return (EINVAL);
- 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);
+ 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;
+ }
}
- return error;
}
if (uap->osa) {
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);
}
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)
{
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);
}
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;
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];
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;
}
* 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);
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);
/* 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);
* 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)
}
}
- 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;
* 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;
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;
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_internal(sig_task);
- goto psigout;
}
- proc_unlock(sig_proc);
- goto psigout;
+ goto sigout_locked;
}
if (action != SIG_DFL) {
*/
if (prop & SA_CONT) {
OSBitOrAtomic(P_CONTINUED, &sig_proc->p_flag);
- proc_unlock(sig_proc);
(void) task_resume_internal(sig_task);
- proc_lock(sig_proc);
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
* 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);
* 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
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
*/
act_set_astbsd(sig_thread);
thread_abort(sig_thread);
- proc_unlock(sig_proc);
- goto psigout;
+ goto sigout_locked;
case SIGCONT:
/*
OSBitOrAtomic(P_CONTINUED, &sig_proc->p_flag);
sig_proc->p_contproc = sig_proc->p_pid;
- proc_unlock(sig_proc);
(void) task_resume_internal(sig_task);
- proc_lock(sig_proc);
+
/*
* When processing a SIGCONT, we need to check
* to see if there are signals pending that
uth->uu_siglist &= ~mask;
sig_proc->p_stat = SRUN;
- proc_unlock(sig_proc);
- goto psigout;
+ goto sigout_locked;
default:
/*
*/
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;
}
/*
* resume it.
*/
if (sig_proc->p_stat == SSTOP) {
- proc_unlock(sig_proc);
- goto psigout;
+ goto sigout_locked;
}
goto 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);
}