#include <sys/vm.h>
#include <sys/user.h> /* for coredump */
#include <kern/ast.h> /* for APC support */
-#include <kern/lock.h>
#include <kern/task.h> /* extern void *get_bsdtask_info(task_t); */
#include <kern/thread.h>
#include <kern/sched_prim.h>
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);
+extern kern_return_t task_suspend_internal(task_t);
+extern kern_return_t task_resume_internal(task_t);
/*
* ---
else
my_cred = proc_ucred(q);
- if (uc->cr_ruid == my_cred->cr_ruid ||
- uc->cr_ruid == my_cred->cr_svuid ||
- kauth_cred_getuid(uc) == my_cred->cr_ruid ||
- kauth_cred_getuid(uc) == my_cred->cr_svuid) {
+ if (kauth_cred_getruid(uc) == kauth_cred_getruid(my_cred) ||
+ kauth_cred_getruid(uc) == kauth_cred_getsvuid(my_cred) ||
+ kauth_cred_getuid(uc) == kauth_cred_getruid(my_cred) ||
+ kauth_cred_getuid(uc) == kauth_cred_getsvuid(my_cred)) {
if (zombie == 0)
kauth_cred_unref(&my_cred);
return (1);
* process/thread pair.
*
* We mark thread as unused to alow compilation without warning
- * onnon-PPC platforms.
+ * on non-PPC platforms.
*/
int
setsigvec(proc_t p, __unused thread_t thread, int signum, struct __kern_sigaction *sa, boolean_t in_sigstart)
OSBitAndAtomic(~((uint32_t)P_NOCLDWAIT), &p->p_flag);
}
-#ifdef __ppc__
- if (signum == SIGFPE) {
- if (sa->sa_handler == SIG_DFL || sa->sa_handler == SIG_IGN)
- thread_enable_fpe(thread, 0);
- else
- thread_enable_fpe(thread, 1);
- }
-#endif /* __ppc__ */
/*
* Set bit in p_sigignore for signals that are set to SIG_IGN,
* and for signals set to SIG_DFL where the default is to ignore.
{
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);
}
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);
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;
if (flavor & PSIG_VFORK) {
sig_task = task;
sig_thread = thread;
- sig_proc= p;
+ sig_proc = p;
} else if (flavor & PSIG_THREAD) {
sig_task = get_threadtask(thread);
sig_thread = thread;
sig_proc = (proc_t)get_bsdtask_info(sig_task);
} else {
sig_task = p->task;
- sig_proc = p;
sig_thread = (struct thread *)0;
+ sig_proc = p;
}
- if (((sig_task == TASK_NULL) || is_kerneltask(sig_task))) {
+
+ if ((sig_task == TASK_NULL) || is_kerneltask(sig_task))
return;
- }
/*
* do not send signals to the process that has the thread
* doing a reboot(). Not doing so will mark that thread aborted
- * and can cause IO failures wich will cause data loss.
+ * and can cause IO failures wich will cause data loss. There's
+ * 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)) {
+ if (ISSET(sig_proc->p_flag, P_REBOOT) ||
+ ISSET(sig_proc->p_lflag, P_LEXIT))
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);
sig_proc->p_contproc = current_proc()->p_pid;
proc_unlock(sig_proc);
- (void) task_resume(sig_task);
+ (void) task_resume_internal(sig_task);
goto psigout;
}
proc_unlock(sig_proc);
if (prop & SA_CONT) {
OSBitOrAtomic(P_CONTINUED, &sig_proc->p_flag);
proc_unlock(sig_proc);
- (void) task_resume(sig_task);
+ (void) task_resume_internal(sig_task);
proc_lock(sig_proc);
sig_proc->p_stat = SRUN;
} else if (sig_proc->p_stat == SSTOP) {
if (( pp != PROC_NULL) && ((pp->p_flag & P_NOCLDSTOP) == 0)) {
my_cred = kauth_cred_proc_ref(sig_proc);
- r_uid = my_cred->cr_ruid;
+ r_uid = kauth_cred_getruid(my_cred);
kauth_cred_unref(&my_cred);
proc_lock(sig_proc);
* 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
+ * we get here, set again to avoid races. This
+ * was the scenario with spindump enabled shutdowns.
+ * We would need to cover this approp down the line.
+ */
+ act_set_astbsd(sig_thread);
thread_abort(sig_thread);
+ proc_unlock(sig_proc);
goto psigout;
sig_proc->p_contproc = sig_proc->p_pid;
proc_unlock(sig_proc);
- (void) task_resume(sig_task);
+ (void) task_resume_internal(sig_task);
proc_lock(sig_proc);
/*
* When processing a SIGCONT, we need to check
* postsig(signum);
*/
int
-issignal(proc_t p)
+issignal_locked(proc_t p)
{
int signum, mask, prop, sigbits;
thread_t cur_act;
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);
}
} else {
proc_unlock(p);
my_cred = kauth_cred_proc_ref(p);
- r_uid = my_cred->cr_ruid;
+ r_uid = kauth_cred_getruid(my_cred);
kauth_cred_unref(&my_cred);
pp = proc_parentholdref(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;
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);
}
stop(p, pp);
if ((pp != PROC_NULL) && ((pp->p_flag & P_NOCLDSTOP) == 0)) {
my_cred = kauth_cred_proc_ref(p);
- r_uid = my_cred->cr_ruid;
+ r_uid = kauth_cred_getruid(my_cred);
kauth_cred_unref(&my_cred);
proc_lock(pp);
}
/* NOTREACHED */
out:
- proc_signalend(p,1);
- proc_unlock(p);
+ proc_signalend(p, 1);
return(retval);
}
signum = ffs((long)sigbits);
mask = sigmask(signum);
prop = sigprop[signum];
+ sigbits &= ~mask; /* take the signal out */
/*
* We should see pending but ignored signals
if (mask & p->p_sigignore && (p->p_lflag & P_LTRACED) == 0) {
continue;
}
+
if (p->p_lflag & P_LTRACED && (p->p_lflag & P_LPPWAIT) == 0) {
- /*
- * Put the new signal into p_siglist. If the
- * signal is being masked, look for other signals.
- */
- mask = sigmask(signum);
- if (ut->uu_sigmask & mask)
- continue;
return(signum);
}
*/
return (signum);
}
- sigbits &= ~mask; /* take the signal! */
}
/* NOTREACHED */
}
wakeup((caddr_t)parent);
proc_list_unlock();
}
- (void) task_suspend(p->task); /*XXX*/
+ (void) task_suspend_internal(p->task);
}
/*
* 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;
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;
}
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);
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
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 {
/*
ps->ps_siginfo &= ~mask;
ps->ps_signodefer &= ~mask;
}
-#ifdef __ppc__
- /* Needs to disable to run in user mode */
- if (signum == SIGFPE) {
- thread_enable_fpe(current_thread(), 0);
- }
-#endif /* __ppc__ */
if (ps->ps_sig != signum) {
code = 0;
sendsig(p, catcher, signum, returnmask, code);
}
proc_signalend(p, 1);
- proc_unlock(p);
}
/*
ut->t_dtrace_sig = 0;
psignal(p, dt_action_sig);
}
+
if (ut->t_dtrace_stop) {
- ut->t_dtrace_stop = 0;
- psignal(p, SIGSTOP);
+ ut->t_dtrace_stop = 0;
+ proc_lock(p);
+ p->p_dtrace_stop = 1;
+ proc_unlock(p);
+ (void)task_suspend_internal(p->task);
+ }
+
+ if (ut->t_dtrace_resumepid) {
+ proc_t resumeproc = proc_find(ut->t_dtrace_resumepid);
+ ut->t_dtrace_resumepid = 0;
+ if (resumeproc != PROC_NULL) {
+ proc_lock(resumeproc);
+ /* We only act on processes stopped by dtrace */
+ if (resumeproc->p_dtrace_stop) {
+ resumeproc->p_dtrace_stop = 0;
+ proc_unlock(resumeproc);
+ task_resume_internal(resumeproc->task);
+ }
+ else {
+ proc_unlock(resumeproc);
+ }
+ proc_rele(resumeproc);
+ }
}
+
#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;
proc_rele(p);
}
-
void
proc_signalstart(proc_t p, int locked)
{
- if (locked == 0)
+ if (!locked)
proc_lock(p);
- while ((p->p_lflag & P_LINSIGNAL) == P_LINSIGNAL) {
- p->p_lflag |= P_LSIGNALWAIT;
+
+ 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);
- }
+ p->p_sigwaitcnt--;
+
p->p_lflag |= P_LINSIGNAL;
-#if DIAGNOSTIC
-#if SIGNAL_DEBUG
-#ifdef __ppc__
- {
- int sp, *fp, numsaved;
-
- __asm__ volatile("mr %0,r1" : "=r" (sp));
-
- fp = (int *)*((int *)sp);
- for (numsaved = 0; numsaved < 3; numsaved++) {
- p->lockpc[numsaved] = fp[2];
- if ((int)fp <= 0)
- break;
- fp = (int *)*fp;
- }
- }
-#endif /* __ppc__ */
-#endif /* SIGNAL_DEBUG */
-#endif /* DIAGNOSTIC */
p->p_signalholder = current_thread();
- if (locked == 0)
+ if (!locked)
proc_unlock(p);
-
}
void
proc_signalend(proc_t p, int locked)
{
- if (locked == 0)
+ if (!locked)
proc_lock(p);
p->p_lflag &= ~P_LINSIGNAL;
-#if DIAGNOSTIC
-#if SIGNAL_DEBUG
-#ifdef __ppc__
- {
- int sp, *fp, numsaved;
-
- __asm__ volatile("mr %0,r1" : "=r" (sp));
-
- fp = (int *)*((int *)sp);
- for (numsaved = 0; numsaved < 3; numsaved++) {
- p->unlockpc[numsaved] = fp[2];
- if ((int)fp <= 0)
- break;
- fp = (int *)*fp;
- }
- }
-#endif /* __ppc__ */
-#endif /* SIGNAL_DEBUG */
-#endif /* DIAGNOSTIC */
-
- if ((p->p_lflag & P_LSIGNALWAIT) == P_LSIGNALWAIT) {
- p->p_lflag &= ~P_LSIGNALWAIT;
+ if (p->p_sigwaitcnt > 0)
wakeup(&p->p_sigmask);
- }
+
p->p_signalholder = NULL;
- if (locked == 0)
+ if (!locked)
proc_unlock(p);
}
-
void
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);
}