]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/kern_sig.c
xnu-2782.40.9.tar.gz
[apple/xnu.git] / bsd / kern / kern_sig.c
index e0ded6e4c4b37a34f9c2767b4ca8d2cf935f0e9e..bb44111fe96b4f051793d3502dcd884f4bacf6f0 100644 (file)
 #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);
 
 /*
  * ---
@@ -334,10 +334,10 @@ cansignal(proc_t p, kauth_cred_t uc, proc_t q, int signum, int zombie)
        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);
@@ -566,7 +566,7 @@ set_procsigmask(proc_t p,  int bit)
  *             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)
@@ -623,14 +623,6 @@ setsigvec(proc_t p, __unused thread_t thread, int signum, struct __kern_sigactio
                        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.
@@ -663,7 +655,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);
 }
@@ -1645,7 +1637,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);
@@ -1719,7 +1711,7 @@ 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;
@@ -1749,34 +1741,35 @@ psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum)
        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);
 
@@ -1943,7 +1936,7 @@ psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum)
                        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);
@@ -1959,7 +1952,7 @@ 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);
+                       (void) task_resume_internal(sig_task);
                        proc_lock(sig_proc);
                        sig_proc->p_stat = SRUN;
                }  else if (sig_proc->p_stat == SSTOP) {
@@ -2027,7 +2020,7 @@ psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum)
                                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);
@@ -2076,8 +2069,16 @@ 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
+                        * 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;
 
@@ -2090,7 +2091,7 @@ psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum)
                        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
@@ -2205,7 +2206,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;
@@ -2222,13 +2223,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);
        }
 
@@ -2281,7 +2280,7 @@ issignal(proc_t p)
                        } 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);
@@ -2299,12 +2298,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;
@@ -2361,6 +2357,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);
                        }
 
@@ -2445,7 +2442,7 @@ issignal(proc_t p)
                                        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);
@@ -2501,8 +2498,7 @@ issignal(proc_t p)
                }
        /* NOTREACHED */
 out:
-       proc_signalend(p,1);
-       proc_unlock(p);
+       proc_signalend(p, 1);
        return(retval);
 }
 
@@ -2538,6 +2534,7 @@ CURSIG(proc_t p)
                signum = ffs((long)sigbits);
                mask = sigmask(signum);
                prop = sigprop[signum];
+               sigbits &= ~mask;               /* take the signal out */
 
                /*
                 * We should see pending but ignored signals
@@ -2546,14 +2543,8 @@ CURSIG(proc_t p)
                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);
                }
 
@@ -2631,7 +2622,6 @@ CURSIG(proc_t p)
                         */
                        return (signum);
                }
-               sigbits &= ~mask;               /* take the signal! */
        }
        /* NOTREACHED */
 }
@@ -2650,7 +2640,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);
 }
 
 /*
@@ -2658,7 +2648,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;
@@ -2677,12 +2667,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;
        }
 
@@ -2703,7 +2691,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);
@@ -2718,6 +2706,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
@@ -2725,6 +2723,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 {
                /*
@@ -2761,12 +2760,6 @@ postsig(int signum)
                        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;
@@ -2778,7 +2771,6 @@ postsig(int signum)
                sendsig(p, catcher, signum, returnmask, code);
        }
        proc_signalend(p, 1);
-       proc_unlock(p);
 }
 
 /*
@@ -2945,16 +2937,41 @@ bsd_ast(thread_t thread)
            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;
@@ -3066,79 +3083,41 @@ pgsigio(pid_t pgid, int sig)
                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)
 {
@@ -3146,7 +3125,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);
 }