+ bool skip_wqthreads = true;
+
+ *thr = THREAD_NULL;
+
+ if ((p->p_lflag & P_LINVFORK) && p->p_vforkact) {
+ sig_thread = p->p_vforkact;
+ kret = check_actforsig(sig_task, sig_thread, 1);
+ if (kret == KERN_SUCCESS) {
+ *thr = sig_thread;
+ return KERN_SUCCESS;
+ } else {
+ return KERN_FAILURE;
+ }
+ }
+
+again:
+ 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))) {
+ thread_t th = uth->uu_context.vc_thread;
+ if (skip_wqthreads && (thread_get_tag(th) & THREAD_TAG_WORKQUEUE)) {
+ /* Workqueue threads may be parked in the kernel unable to
+ * deliver signals for an extended period of time, so skip them
+ * in favor of pthreads in a first pass. (rdar://50054475). */
+ } else if (check_actforsig(p->task, th, 1) == KERN_SUCCESS) {
+ *thr = th;
+ return KERN_SUCCESS;
+ }
+ }
+ }
+ if (skip_wqthreads) {
+ skip_wqthreads = false;
+ goto again;
+ }
+ if (get_signalact(p->task, thr, 1) == KERN_SUCCESS) {
+ return KERN_SUCCESS;
+ }
+
+ return KERN_FAILURE;
+}
+
+static os_reason_t
+build_signal_reason(int signum, const char *procname)
+{
+ os_reason_t signal_reason = OS_REASON_NULL;
+ proc_t sender_proc = current_proc();
+ uint32_t reason_buffer_size_estimate = 0, proc_name_length = 0;
+ const char *default_sender_procname = "unknown";
+ mach_vm_address_t data_addr;
+ int ret;
+
+ signal_reason = os_reason_create(OS_REASON_SIGNAL, signum);
+ if (signal_reason == OS_REASON_NULL) {
+ printf("build_signal_reason: unable to allocate signal reason structure.\n");
+ return signal_reason;
+ }
+
+ reason_buffer_size_estimate = kcdata_estimate_required_buffer_size(2, sizeof(sender_proc->p_name) +
+ sizeof(sender_proc->p_pid));
+
+ ret = os_reason_alloc_buffer_noblock(signal_reason, reason_buffer_size_estimate);
+ if (ret != 0) {
+ printf("build_signal_reason: unable to allocate signal reason buffer.\n");
+ return signal_reason;
+ }
+
+ if (KERN_SUCCESS == kcdata_get_memory_addr(&signal_reason->osr_kcd_descriptor, KCDATA_TYPE_PID,
+ sizeof(sender_proc->p_pid), &data_addr)) {
+ kcdata_memcpy(&signal_reason->osr_kcd_descriptor, data_addr, &sender_proc->p_pid,
+ sizeof(sender_proc->p_pid));
+ } else {
+ printf("build_signal_reason: exceeded space in signal reason buf, unable to log PID\n");
+ }
+
+ proc_name_length = sizeof(sender_proc->p_name);
+ if (KERN_SUCCESS == kcdata_get_memory_addr(&signal_reason->osr_kcd_descriptor, KCDATA_TYPE_PROCNAME,
+ proc_name_length, &data_addr)) {
+ if (procname) {
+ char truncated_procname[proc_name_length];
+ strncpy((char *) &truncated_procname, procname, proc_name_length);
+ truncated_procname[proc_name_length - 1] = '\0';
+
+ kcdata_memcpy(&signal_reason->osr_kcd_descriptor, data_addr, truncated_procname,
+ (uint32_t)strlen((char *) &truncated_procname));
+ } else if (*sender_proc->p_name) {
+ kcdata_memcpy(&signal_reason->osr_kcd_descriptor, data_addr, &sender_proc->p_name,
+ sizeof(sender_proc->p_name));
+ } else {
+ kcdata_memcpy(&signal_reason->osr_kcd_descriptor, data_addr, &default_sender_procname,
+ (uint32_t)strlen(default_sender_procname) + 1);
+ }
+ } else {
+ printf("build_signal_reason: exceeded space in signal reason buf, unable to log procname\n");
+ }
+
+ return signal_reason;
+}
+
+/*
+ * Send the signal to the process. If the signal has an action, the action
+ * is usually performed by the target process rather than the caller; we add
+ * the signal to the set of pending signals for the process.
+ *
+ * Always drops a reference on a signal_reason if one is provided, whether via
+ * passing it to a thread or deallocating directly.
+ *
+ * Exceptions:
+ * o When a stop signal is sent to a sleeping process that takes the
+ * default action, the process is stopped without awakening it.
+ * o SIGCONT restarts stopped processes (or puts them back to sleep)
+ * regardless of the signal action (eg, blocked or ignored).
+ *
+ * Other ignored signals are discarded immediately.
+ */
+static void
+psignal_internal(proc_t p, task_t task, thread_t thread, int flavor, int signum, os_reason_t signal_reason)
+{
+ int prop;
+ user_addr_t action = USER_ADDR_NULL;
+ proc_t sig_proc;
+ thread_t sig_thread;
+ task_t sig_task;
+ int mask;
+ struct uthread *uth;
+ kern_return_t kret;
+ uid_t r_uid;
+ proc_t pp;
+ kauth_cred_t my_cred;
+ char *launchd_exit_reason_desc = NULL;
+ boolean_t update_thread_policy = FALSE;
+
+ if ((u_int)signum >= NSIG || signum == 0) {
+ panic("psignal: bad signal number %d", signum);
+ }