19454b2d8SWarner Losh /*- 251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 351369649SPedro F. Giffuni * 4df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1989, 1991, 1993 5df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 6df8bae1dSRodney W. Grimes * (c) UNIX System Laboratories, Inc. 7df8bae1dSRodney W. Grimes * All or some portions of this file are derived from material licensed 8df8bae1dSRodney W. Grimes * to the University of California by American Telephone and Telegraph 9df8bae1dSRodney W. Grimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 10df8bae1dSRodney W. Grimes * the permission of UNIX System Laboratories, Inc. 11df8bae1dSRodney W. Grimes * 12df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 13df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 14df8bae1dSRodney W. Grimes * are met: 15df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 16df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 17df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 18df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 19df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 2069a28758SEd Maste * 3. Neither the name of the University nor the names of its contributors 21df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 22df8bae1dSRodney W. Grimes * without specific prior written permission. 23df8bae1dSRodney W. Grimes * 24df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34df8bae1dSRodney W. Grimes * SUCH DAMAGE. 35df8bae1dSRodney W. Grimes * 36df8bae1dSRodney W. Grimes * @(#)kern_sig.c 8.7 (Berkeley) 4/18/94 37df8bae1dSRodney W. Grimes */ 38df8bae1dSRodney W. Grimes 39677b542eSDavid E. O'Brien #include <sys/cdefs.h> 40677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 41677b542eSDavid E. O'Brien 42db6a20e2SGarrett Wollman #include "opt_ktrace.h" 43db6a20e2SGarrett Wollman 44df8bae1dSRodney W. Grimes #include <sys/param.h> 45eb6368d4SRui Paulo #include <sys/ctype.h> 4636240ea5SDoug Rabson #include <sys/systm.h> 47df8bae1dSRodney W. Grimes #include <sys/signalvar.h> 48df8bae1dSRodney W. Grimes #include <sys/vnode.h> 49df8bae1dSRodney W. Grimes #include <sys/acct.h> 504a144410SRobert Watson #include <sys/capsicum.h> 5178f57a9cSMark Johnston #include <sys/compressor.h> 52238510fcSJason Evans #include <sys/condvar.h> 53773e541eSWarner Losh #include <sys/devctl.h> 54854dc8c2SJohn Baldwin #include <sys/event.h> 55854dc8c2SJohn Baldwin #include <sys/fcntl.h> 56e7228204SAlfred Perlstein #include <sys/imgact.h> 57854dc8c2SJohn Baldwin #include <sys/kernel.h> 580384fff8SJason Evans #include <sys/ktr.h> 59df8bae1dSRodney W. Grimes #include <sys/ktrace.h> 6091898857SMark Johnston #include <sys/limits.h> 61854dc8c2SJohn Baldwin #include <sys/lock.h> 62854dc8c2SJohn Baldwin #include <sys/malloc.h> 63854dc8c2SJohn Baldwin #include <sys/mutex.h> 64c959c237SMateusz Guzik #include <sys/refcount.h> 65854dc8c2SJohn Baldwin #include <sys/namei.h> 66854dc8c2SJohn Baldwin #include <sys/proc.h> 67cfb5f768SJonathan Anderson #include <sys/procdesc.h> 68ef401a85SKonstantin Belousov #include <sys/ptrace.h> 696aeb05d7STom Rhodes #include <sys/posix4.h> 70b8fdb0d9SEdward Tomasz Napierala #include <sys/racct.h> 71c31146a1SJohn Baldwin #include <sys/resourcevar.h> 725d217f17SJohn Birrell #include <sys/sdt.h> 7336b208e0SRobert Watson #include <sys/sbuf.h> 7444f3b092SJohn Baldwin #include <sys/sleepqueue.h> 756caa8a15SJohn Baldwin #include <sys/smp.h> 76df8bae1dSRodney W. Grimes #include <sys/stat.h> 771005a129SJohn Baldwin #include <sys/sx.h> 788f19eb88SIan Dowse #include <sys/syscallsubr.h> 79c87e2930SDavid Greenman #include <sys/sysctl.h> 80854dc8c2SJohn Baldwin #include <sys/sysent.h> 81854dc8c2SJohn Baldwin #include <sys/syslog.h> 82854dc8c2SJohn Baldwin #include <sys/sysproto.h> 8356c06c4bSDavid Xu #include <sys/timers.h> 8406ae1e91SMatthew Dillon #include <sys/unistd.h> 85854dc8c2SJohn Baldwin #include <sys/wait.h> 869104847fSDavid Xu #include <vm/vm.h> 879104847fSDavid Xu #include <vm/vm_extern.h> 889104847fSDavid Xu #include <vm/uma.h> 89df8bae1dSRodney W. Grimes 90e7228204SAlfred Perlstein #include <sys/jail.h> 91e7228204SAlfred Perlstein 92df8bae1dSRodney W. Grimes #include <machine/cpu.h> 93df8bae1dSRodney W. Grimes 94bfd7575aSWayne Salamon #include <security/audit/audit.h> 95bfd7575aSWayne Salamon 966f841fb7SMarcel Moolenaar #define ONSIG 32 /* NSIG for osig* syscalls. XXX. */ 976f841fb7SMarcel Moolenaar 985d217f17SJohn Birrell SDT_PROVIDER_DECLARE(proc); 9936160958SMark Johnston SDT_PROBE_DEFINE3(proc, , , signal__send, 10036160958SMark Johnston "struct thread *", "struct proc *", "int"); 10136160958SMark Johnston SDT_PROBE_DEFINE2(proc, , , signal__clear, 10236160958SMark Johnston "int", "ksiginfo_t *"); 10336160958SMark Johnston SDT_PROBE_DEFINE3(proc, , , signal__discard, 1047b77e1feSMark Johnston "struct thread *", "struct proc *", "int"); 1055d217f17SJohn Birrell 1064d77a549SAlfred Perlstein static int coredump(struct thread *); 107a3de221dSKonstantin Belousov static int killpg1(struct thread *td, int sig, int pgid, int all, 108a3de221dSKonstantin Belousov ksiginfo_t *ksi); 1093cf3b9f0SJohn Baldwin static int issignal(struct thread *td); 1100bc52b0bSKonstantin Belousov static void reschedule_signals(struct proc *p, sigset_t block, int flags); 1114d77a549SAlfred Perlstein static int sigprop(int sig); 11294f0972bSDavid Xu static void tdsigwakeup(struct thread *, int, sig_t, int); 1136f56cb8dSKonstantin Belousov static int sig_suspend_threads(struct thread *, struct proc *, int); 114cb679c38SJonathan Lemon static int filt_sigattach(struct knote *kn); 115cb679c38SJonathan Lemon static void filt_sigdetach(struct knote *kn); 116cb679c38SJonathan Lemon static int filt_signal(struct knote *kn, long hint); 117146fc63fSKonstantin Belousov static struct thread *sigtd(struct proc *p, int sig, bool fast_sigblock); 1189104847fSDavid Xu static void sigqueue_start(void); 1194fced864SKonstantin Belousov static void sigfastblock_setpend(struct thread *td, bool resched); 120cb679c38SJonathan Lemon 1219104847fSDavid Xu static uma_zone_t ksiginfo_zone = NULL; 122e76d823bSRobert Watson struct filterops sig_filtops = { 123e76d823bSRobert Watson .f_isfd = 0, 124e76d823bSRobert Watson .f_attach = filt_sigattach, 125e76d823bSRobert Watson .f_detach = filt_sigdetach, 126e76d823bSRobert Watson .f_event = filt_signal, 127e76d823bSRobert Watson }; 128cb679c38SJonathan Lemon 129fc8cca02SJohn Baldwin static int kern_logsigexit = 1; 1303d177f46SBill Fumerola SYSCTL_INT(_kern, KERN_LOGSIGEXIT, logsigexit, CTLFLAG_RW, 1313d177f46SBill Fumerola &kern_logsigexit, 0, 1323d177f46SBill Fumerola "Log processes quitting on abnormal signals to syslog(3)"); 13357308494SJoerg Wunsch 134f71a882fSDavid Xu static int kern_forcesigexit = 1; 135f71a882fSDavid Xu SYSCTL_INT(_kern, OID_AUTO, forcesigexit, CTLFLAG_RW, 136f71a882fSDavid Xu &kern_forcesigexit, 0, "Force trap signal to be handled"); 137f71a882fSDavid Xu 1387029da5cSPawel Biernacki static SYSCTL_NODE(_kern, OID_AUTO, sigqueue, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 1396472ac3dSEd Schouten "POSIX real time signal"); 1409104847fSDavid Xu 1419104847fSDavid Xu static int max_pending_per_proc = 128; 1429104847fSDavid Xu SYSCTL_INT(_kern_sigqueue, OID_AUTO, max_pending_per_proc, CTLFLAG_RW, 1439104847fSDavid Xu &max_pending_per_proc, 0, "Max pending signals per proc"); 1449104847fSDavid Xu 1459104847fSDavid Xu static int preallocate_siginfo = 1024; 146af3b2549SHans Petter Selasky SYSCTL_INT(_kern_sigqueue, OID_AUTO, preallocate, CTLFLAG_RDTUN, 1479104847fSDavid Xu &preallocate_siginfo, 0, "Preallocated signal memory size"); 1489104847fSDavid Xu 1499104847fSDavid Xu static int signal_overflow = 0; 150761a4d94SDavid Xu SYSCTL_INT(_kern_sigqueue, OID_AUTO, overflow, CTLFLAG_RD, 1519104847fSDavid Xu &signal_overflow, 0, "Number of signals overflew"); 1529104847fSDavid Xu 1539104847fSDavid Xu static int signal_alloc_fail = 0; 154761a4d94SDavid Xu SYSCTL_INT(_kern_sigqueue, OID_AUTO, alloc_fail, CTLFLAG_RD, 1559104847fSDavid Xu &signal_alloc_fail, 0, "signals failed to be allocated"); 1569104847fSDavid Xu 157f5a077c3SKonstantin Belousov static int kern_lognosys = 0; 158f5a077c3SKonstantin Belousov SYSCTL_INT(_kern, OID_AUTO, lognosys, CTLFLAG_RWTUN, &kern_lognosys, 0, 159f5a077c3SKonstantin Belousov "Log invalid syscalls"); 160f5a077c3SKonstantin Belousov 161a113b17fSKonstantin Belousov __read_frequently bool sigfastblock_fetch_always = false; 162a113b17fSKonstantin Belousov SYSCTL_BOOL(_kern, OID_AUTO, sigfastblock_fetch_always, CTLFLAG_RWTUN, 163a113b17fSKonstantin Belousov &sigfastblock_fetch_always, 0, 164a113b17fSKonstantin Belousov "Fetch sigfastblock word on each syscall entry for proper " 165a113b17fSKonstantin Belousov "blocking semantic"); 166a113b17fSKonstantin Belousov 167bc387624SKonstantin Belousov static bool kern_sig_discard_ign = true; 168bc387624SKonstantin Belousov SYSCTL_BOOL(_kern, OID_AUTO, sig_discard_ign, CTLFLAG_RWTUN, 169bc387624SKonstantin Belousov &kern_sig_discard_ign, 0, 170bc387624SKonstantin Belousov "Discard ignored signals on delivery, otherwise queue them to " 171bc387624SKonstantin Belousov "the target queue"); 172bc387624SKonstantin Belousov 1739104847fSDavid Xu SYSINIT(signal, SI_SUB_P1003_1B, SI_ORDER_FIRST+3, sigqueue_start, NULL); 1749104847fSDavid Xu 1752b87b6d4SRobert Watson /* 1762b87b6d4SRobert Watson * Policy -- Can ucred cr1 send SIGIO to process cr2? 1772b87b6d4SRobert Watson * Should use cr_cansignal() once cr_cansignal() allows SIGIO and SIGURG 1782b87b6d4SRobert Watson * in the right situations. 1792b87b6d4SRobert Watson */ 1802b87b6d4SRobert Watson #define CANSIGIO(cr1, cr2) \ 1812b87b6d4SRobert Watson ((cr1)->cr_uid == 0 || \ 1822b87b6d4SRobert Watson (cr1)->cr_ruid == (cr2)->cr_ruid || \ 1832b87b6d4SRobert Watson (cr1)->cr_uid == (cr2)->cr_ruid || \ 1842b87b6d4SRobert Watson (cr1)->cr_ruid == (cr2)->cr_uid || \ 1852b87b6d4SRobert Watson (cr1)->cr_uid == (cr2)->cr_uid) 1862b87b6d4SRobert Watson 187fc8cca02SJohn Baldwin static int sugid_coredump; 188af3b2549SHans Petter Selasky SYSCTL_INT(_kern, OID_AUTO, sugid_coredump, CTLFLAG_RWTUN, 1898b5adf9dSJoseph Koshy &sugid_coredump, 0, "Allow setuid and setgid processes to dump core"); 190c87e2930SDavid Greenman 191b0c9d4d7SPawel Jakub Dawidek static int capmode_coredump; 192af3b2549SHans Petter Selasky SYSCTL_INT(_kern, OID_AUTO, capmode_coredump, CTLFLAG_RWTUN, 193b0c9d4d7SPawel Jakub Dawidek &capmode_coredump, 0, "Allow processes in capability mode to dump core"); 194b0c9d4d7SPawel Jakub Dawidek 195e5a28db9SPaul Saab static int do_coredump = 1; 196e5a28db9SPaul Saab SYSCTL_INT(_kern, OID_AUTO, coredump, CTLFLAG_RW, 197e5a28db9SPaul Saab &do_coredump, 0, "Enable/Disable coredumps"); 198e5a28db9SPaul Saab 1996141e04aSJohn-Mark Gurney static int set_core_nodump_flag = 0; 2006141e04aSJohn-Mark Gurney SYSCTL_INT(_kern, OID_AUTO, nodump_coredump, CTLFLAG_RW, &set_core_nodump_flag, 2016141e04aSJohn-Mark Gurney 0, "Enable setting the NODUMP flag on coredump files"); 2026141e04aSJohn-Mark Gurney 2030da9e11bSRui Paulo static int coredump_devctl = 0; 204eb6368d4SRui Paulo SYSCTL_INT(_kern, OID_AUTO, coredump_devctl, CTLFLAG_RW, &coredump_devctl, 205eb6368d4SRui Paulo 0, "Generate a devctl notification when processes coredump"); 206eb6368d4SRui Paulo 2072c42a146SMarcel Moolenaar /* 2082c42a146SMarcel Moolenaar * Signal properties and actions. 2092c42a146SMarcel Moolenaar * The array below categorizes the signals and their default actions 2102c42a146SMarcel Moolenaar * according to the following properties: 2112c42a146SMarcel Moolenaar */ 212fd50a707SBrooks Davis #define SIGPROP_KILL 0x01 /* terminates process by default */ 213fd50a707SBrooks Davis #define SIGPROP_CORE 0x02 /* ditto and coredumps */ 214fd50a707SBrooks Davis #define SIGPROP_STOP 0x04 /* suspend process */ 215fd50a707SBrooks Davis #define SIGPROP_TTYSTOP 0x08 /* ditto, from tty */ 216fd50a707SBrooks Davis #define SIGPROP_IGNORE 0x10 /* ignore by default */ 217fd50a707SBrooks Davis #define SIGPROP_CONT 0x20 /* continue if suspended */ 218df8bae1dSRodney W. Grimes 2192c42a146SMarcel Moolenaar static int sigproptbl[NSIG] = { 220ed6d876bSBrooks Davis [SIGHUP] = SIGPROP_KILL, 221ed6d876bSBrooks Davis [SIGINT] = SIGPROP_KILL, 222ed6d876bSBrooks Davis [SIGQUIT] = SIGPROP_KILL | SIGPROP_CORE, 223ed6d876bSBrooks Davis [SIGILL] = SIGPROP_KILL | SIGPROP_CORE, 224ed6d876bSBrooks Davis [SIGTRAP] = SIGPROP_KILL | SIGPROP_CORE, 225ed6d876bSBrooks Davis [SIGABRT] = SIGPROP_KILL | SIGPROP_CORE, 226ed6d876bSBrooks Davis [SIGEMT] = SIGPROP_KILL | SIGPROP_CORE, 227ed6d876bSBrooks Davis [SIGFPE] = SIGPROP_KILL | SIGPROP_CORE, 228ed6d876bSBrooks Davis [SIGKILL] = SIGPROP_KILL, 229ed6d876bSBrooks Davis [SIGBUS] = SIGPROP_KILL | SIGPROP_CORE, 230ed6d876bSBrooks Davis [SIGSEGV] = SIGPROP_KILL | SIGPROP_CORE, 231ed6d876bSBrooks Davis [SIGSYS] = SIGPROP_KILL | SIGPROP_CORE, 232ed6d876bSBrooks Davis [SIGPIPE] = SIGPROP_KILL, 233ed6d876bSBrooks Davis [SIGALRM] = SIGPROP_KILL, 234ed6d876bSBrooks Davis [SIGTERM] = SIGPROP_KILL, 235ed6d876bSBrooks Davis [SIGURG] = SIGPROP_IGNORE, 236ed6d876bSBrooks Davis [SIGSTOP] = SIGPROP_STOP, 237ed6d876bSBrooks Davis [SIGTSTP] = SIGPROP_STOP | SIGPROP_TTYSTOP, 238ed6d876bSBrooks Davis [SIGCONT] = SIGPROP_IGNORE | SIGPROP_CONT, 239ed6d876bSBrooks Davis [SIGCHLD] = SIGPROP_IGNORE, 240ed6d876bSBrooks Davis [SIGTTIN] = SIGPROP_STOP | SIGPROP_TTYSTOP, 241ed6d876bSBrooks Davis [SIGTTOU] = SIGPROP_STOP | SIGPROP_TTYSTOP, 242ed6d876bSBrooks Davis [SIGIO] = SIGPROP_IGNORE, 243ed6d876bSBrooks Davis [SIGXCPU] = SIGPROP_KILL, 244ed6d876bSBrooks Davis [SIGXFSZ] = SIGPROP_KILL, 245ed6d876bSBrooks Davis [SIGVTALRM] = SIGPROP_KILL, 246ed6d876bSBrooks Davis [SIGPROF] = SIGPROP_KILL, 247ed6d876bSBrooks Davis [SIGWINCH] = SIGPROP_IGNORE, 248ed6d876bSBrooks Davis [SIGINFO] = SIGPROP_IGNORE, 249ed6d876bSBrooks Davis [SIGUSR1] = SIGPROP_KILL, 250ed6d876bSBrooks Davis [SIGUSR2] = SIGPROP_KILL, 2512c42a146SMarcel Moolenaar }; 2522c42a146SMarcel Moolenaar 25381f2e906SMark Johnston #define _SIG_FOREACH_ADVANCE(i, set) ({ \ 25481f2e906SMark Johnston int __found; \ 25581f2e906SMark Johnston for (;;) { \ 25681f2e906SMark Johnston if (__bits != 0) { \ 25781f2e906SMark Johnston int __sig = ffs(__bits); \ 25881f2e906SMark Johnston __bits &= ~(1u << (__sig - 1)); \ 25981f2e906SMark Johnston sig = __i * sizeof((set)->__bits[0]) * NBBY + __sig; \ 26081f2e906SMark Johnston __found = 1; \ 26181f2e906SMark Johnston break; \ 26281f2e906SMark Johnston } \ 26381f2e906SMark Johnston if (++__i == _SIG_WORDS) { \ 26481f2e906SMark Johnston __found = 0; \ 26581f2e906SMark Johnston break; \ 26681f2e906SMark Johnston } \ 26781f2e906SMark Johnston __bits = (set)->__bits[__i]; \ 26881f2e906SMark Johnston } \ 26981f2e906SMark Johnston __found != 0; \ 27081f2e906SMark Johnston }) 27181f2e906SMark Johnston 27281f2e906SMark Johnston #define SIG_FOREACH(i, set) \ 27381f2e906SMark Johnston for (int32_t __i = -1, __bits = 0; \ 27481f2e906SMark Johnston _SIG_FOREACH_ADVANCE(i, set); ) \ 27581f2e906SMark Johnston 2764fced864SKonstantin Belousov static sigset_t fastblock_mask; 2776b286ee8SKonstantin Belousov 2789104847fSDavid Xu static void 279c6d31b83SKonstantin Belousov ast_sig(struct thread *td, int tda) 280c6d31b83SKonstantin Belousov { 281c6d31b83SKonstantin Belousov struct proc *p; 282c6d31b83SKonstantin Belousov int sig; 283c6d31b83SKonstantin Belousov bool resched_sigs; 284c6d31b83SKonstantin Belousov 285c6d31b83SKonstantin Belousov p = td->td_proc; 286c6d31b83SKonstantin Belousov 287c6d31b83SKonstantin Belousov #ifdef DIAGNOSTIC 288c6d31b83SKonstantin Belousov if (p->p_numthreads == 1 && (tda & (TDAI(TDA_SIG) | 289c6d31b83SKonstantin Belousov TDAI(TDA_AST))) == 0) { 290c6d31b83SKonstantin Belousov PROC_LOCK(p); 291c6d31b83SKonstantin Belousov thread_lock(td); 292c6d31b83SKonstantin Belousov /* 293c6d31b83SKonstantin Belousov * Note that TDA_SIG should be re-read from 294c6d31b83SKonstantin Belousov * td_ast, since signal might have been delivered 295c6d31b83SKonstantin Belousov * after we cleared td_flags above. This is one of 296c6d31b83SKonstantin Belousov * the reason for looping check for AST condition. 297c6d31b83SKonstantin Belousov * See comment in userret() about P_PPWAIT. 298c6d31b83SKonstantin Belousov */ 299c6d31b83SKonstantin Belousov if ((p->p_flag & P_PPWAIT) == 0 && 300c6d31b83SKonstantin Belousov (td->td_pflags & TDP_SIGFASTBLOCK) == 0) { 301c6d31b83SKonstantin Belousov if (SIGPENDING(td) && ((tda | td->td_ast) & 302c6d31b83SKonstantin Belousov (TDAI(TDA_SIG) | TDAI(TDA_AST))) == 0) { 303c6d31b83SKonstantin Belousov thread_unlock(td); /* fix dumps */ 304c6d31b83SKonstantin Belousov panic( 305c6d31b83SKonstantin Belousov "failed2 to set signal flags for ast p %p " 306c6d31b83SKonstantin Belousov "td %p tda %#x td_ast %#x fl %#x", 307c6d31b83SKonstantin Belousov p, td, tda, td->td_ast, td->td_flags); 308c6d31b83SKonstantin Belousov } 309c6d31b83SKonstantin Belousov } 310c6d31b83SKonstantin Belousov thread_unlock(td); 311c6d31b83SKonstantin Belousov PROC_UNLOCK(p); 312c6d31b83SKonstantin Belousov } 313c6d31b83SKonstantin Belousov #endif 314c6d31b83SKonstantin Belousov 315c6d31b83SKonstantin Belousov /* 316c6d31b83SKonstantin Belousov * Check for signals. Unlocked reads of p_pendingcnt or 317c6d31b83SKonstantin Belousov * p_siglist might cause process-directed signal to be handled 318c6d31b83SKonstantin Belousov * later. 319c6d31b83SKonstantin Belousov */ 320*f2fd7d8bSKonstantin Belousov if ((tda & TDAI(TDA_SIG)) != 0 || p->p_pendingcnt > 0 || 321c6d31b83SKonstantin Belousov !SIGISEMPTY(p->p_siglist)) { 322c6d31b83SKonstantin Belousov sigfastblock_fetch(td); 323c6d31b83SKonstantin Belousov PROC_LOCK(p); 324c6d31b83SKonstantin Belousov mtx_lock(&p->p_sigacts->ps_mtx); 325c6d31b83SKonstantin Belousov while ((sig = cursig(td)) != 0) { 326c6d31b83SKonstantin Belousov KASSERT(sig >= 0, ("sig %d", sig)); 327c6d31b83SKonstantin Belousov postsig(sig); 328c6d31b83SKonstantin Belousov } 329c6d31b83SKonstantin Belousov mtx_unlock(&p->p_sigacts->ps_mtx); 330c6d31b83SKonstantin Belousov PROC_UNLOCK(p); 331c6d31b83SKonstantin Belousov resched_sigs = true; 332c6d31b83SKonstantin Belousov } else { 333c6d31b83SKonstantin Belousov resched_sigs = false; 334c6d31b83SKonstantin Belousov } 335c6d31b83SKonstantin Belousov 336c6d31b83SKonstantin Belousov /* 337c6d31b83SKonstantin Belousov * Handle deferred update of the fast sigblock value, after 338c6d31b83SKonstantin Belousov * the postsig() loop was performed. 339c6d31b83SKonstantin Belousov */ 340c6d31b83SKonstantin Belousov sigfastblock_setpend(td, resched_sigs); 341c6d31b83SKonstantin Belousov } 342c6d31b83SKonstantin Belousov 343c6d31b83SKonstantin Belousov static void 344c6d31b83SKonstantin Belousov ast_sigsuspend(struct thread *td, int tda __unused) 345c6d31b83SKonstantin Belousov { 346c6d31b83SKonstantin Belousov MPASS((td->td_pflags & TDP_OLDMASK) != 0); 347c6d31b83SKonstantin Belousov td->td_pflags &= ~TDP_OLDMASK; 348c6d31b83SKonstantin Belousov kern_sigprocmask(td, SIG_SETMASK, &td->td_oldsigmask, NULL, 0); 349c6d31b83SKonstantin Belousov } 350c6d31b83SKonstantin Belousov 351c6d31b83SKonstantin Belousov static void 3529104847fSDavid Xu sigqueue_start(void) 3539104847fSDavid Xu { 3549104847fSDavid Xu ksiginfo_zone = uma_zcreate("ksiginfo", sizeof(ksiginfo_t), 3559104847fSDavid Xu NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 3569104847fSDavid Xu uma_prealloc(ksiginfo_zone, preallocate_siginfo); 357b51d237aSDavid Xu p31b_setcfg(CTL_P1003_1B_REALTIME_SIGNALS, _POSIX_REALTIME_SIGNALS); 358b51d237aSDavid Xu p31b_setcfg(CTL_P1003_1B_RTSIG_MAX, SIGRTMAX - SIGRTMIN + 1); 359b51d237aSDavid Xu p31b_setcfg(CTL_P1003_1B_SIGQUEUE_MAX, max_pending_per_proc); 360146fc63fSKonstantin Belousov SIGFILLSET(fastblock_mask); 361146fc63fSKonstantin Belousov SIG_CANTMASK(fastblock_mask); 362c6d31b83SKonstantin Belousov ast_register(TDA_SIG, ASTR_UNCOND, 0, ast_sig); 363c6d31b83SKonstantin Belousov ast_register(TDA_SIGSUSPEND, ASTR_ASTF_REQUIRED | ASTR_TDP, 364c6d31b83SKonstantin Belousov TDP_OLDMASK, ast_sigsuspend); 3659104847fSDavid Xu } 3669104847fSDavid Xu 3675da49fcbSDavid Xu ksiginfo_t * 368ebceaf6dSDavid Xu ksiginfo_alloc(int wait) 3699104847fSDavid Xu { 370ebceaf6dSDavid Xu int flags; 371ebceaf6dSDavid Xu 372863070bbSEric van Gyzen flags = M_ZERO | (wait ? M_WAITOK : M_NOWAIT); 3739104847fSDavid Xu if (ksiginfo_zone != NULL) 374ebceaf6dSDavid Xu return ((ksiginfo_t *)uma_zalloc(ksiginfo_zone, flags)); 3759104847fSDavid Xu return (NULL); 3769104847fSDavid Xu } 3779104847fSDavid Xu 3785da49fcbSDavid Xu void 3799104847fSDavid Xu ksiginfo_free(ksiginfo_t *ksi) 3809104847fSDavid Xu { 3819104847fSDavid Xu uma_zfree(ksiginfo_zone, ksi); 3829104847fSDavid Xu } 3839104847fSDavid Xu 3845da49fcbSDavid Xu static __inline int 3855da49fcbSDavid Xu ksiginfo_tryfree(ksiginfo_t *ksi) 3865da49fcbSDavid Xu { 3875da49fcbSDavid Xu if (!(ksi->ksi_flags & KSI_EXT)) { 3885da49fcbSDavid Xu uma_zfree(ksiginfo_zone, ksi); 3895da49fcbSDavid Xu return (1); 3905da49fcbSDavid Xu } 3915da49fcbSDavid Xu return (0); 3925da49fcbSDavid Xu } 3935da49fcbSDavid Xu 3949104847fSDavid Xu void 3959104847fSDavid Xu sigqueue_init(sigqueue_t *list, struct proc *p) 3969104847fSDavid Xu { 3979104847fSDavid Xu SIGEMPTYSET(list->sq_signals); 3983dfcaad6SDavid Xu SIGEMPTYSET(list->sq_kill); 39982a4538fSEric Badger SIGEMPTYSET(list->sq_ptrace); 4009104847fSDavid Xu TAILQ_INIT(&list->sq_list); 4019104847fSDavid Xu list->sq_proc = p; 4029104847fSDavid Xu list->sq_flags = SQ_INIT; 4039104847fSDavid Xu } 4049104847fSDavid Xu 4059104847fSDavid Xu /* 4069104847fSDavid Xu * Get a signal's ksiginfo. 4079104847fSDavid Xu * Return: 4089104847fSDavid Xu * 0 - signal not found 4099104847fSDavid Xu * others - signal number 4109104847fSDavid Xu */ 411a5799a4fSKonstantin Belousov static int 4129104847fSDavid Xu sigqueue_get(sigqueue_t *sq, int signo, ksiginfo_t *si) 4139104847fSDavid Xu { 4149104847fSDavid Xu struct proc *p = sq->sq_proc; 4159104847fSDavid Xu struct ksiginfo *ksi, *next; 4169104847fSDavid Xu int count = 0; 4179104847fSDavid Xu 4189104847fSDavid Xu KASSERT(sq->sq_flags & SQ_INIT, ("sigqueue not inited")); 4199104847fSDavid Xu 4209104847fSDavid Xu if (!SIGISMEMBER(sq->sq_signals, signo)) 4219104847fSDavid Xu return (0); 4229104847fSDavid Xu 42382a4538fSEric Badger if (SIGISMEMBER(sq->sq_ptrace, signo)) { 42482a4538fSEric Badger count++; 42582a4538fSEric Badger SIGDELSET(sq->sq_ptrace, signo); 42682a4538fSEric Badger si->ksi_flags |= KSI_PTRACE; 42782a4538fSEric Badger } 4283dfcaad6SDavid Xu if (SIGISMEMBER(sq->sq_kill, signo)) { 4293dfcaad6SDavid Xu count++; 43082a4538fSEric Badger if (count == 1) 4313dfcaad6SDavid Xu SIGDELSET(sq->sq_kill, signo); 4323dfcaad6SDavid Xu } 4333dfcaad6SDavid Xu 4345c28a8d4SDavid Xu TAILQ_FOREACH_SAFE(ksi, &sq->sq_list, ksi_link, next) { 4359104847fSDavid Xu if (ksi->ksi_signo == signo) { 4369104847fSDavid Xu if (count == 0) { 4379104847fSDavid Xu TAILQ_REMOVE(&sq->sq_list, ksi, ksi_link); 4385da49fcbSDavid Xu ksi->ksi_sigq = NULL; 4399104847fSDavid Xu ksiginfo_copy(ksi, si); 4405da49fcbSDavid Xu if (ksiginfo_tryfree(ksi) && p != NULL) 4419104847fSDavid Xu p->p_pendingcnt--; 4429104847fSDavid Xu } 443016fa302SDavid Xu if (++count > 1) 444016fa302SDavid Xu break; 4459104847fSDavid Xu } 4469104847fSDavid Xu } 4479104847fSDavid Xu 4489104847fSDavid Xu if (count <= 1) 4499104847fSDavid Xu SIGDELSET(sq->sq_signals, signo); 4509104847fSDavid Xu si->ksi_signo = signo; 4519104847fSDavid Xu return (signo); 4529104847fSDavid Xu } 4539104847fSDavid Xu 4545da49fcbSDavid Xu void 4555da49fcbSDavid Xu sigqueue_take(ksiginfo_t *ksi) 4565da49fcbSDavid Xu { 4575da49fcbSDavid Xu struct ksiginfo *kp; 4585da49fcbSDavid Xu struct proc *p; 4595da49fcbSDavid Xu sigqueue_t *sq; 4605da49fcbSDavid Xu 461ebceaf6dSDavid Xu if (ksi == NULL || (sq = ksi->ksi_sigq) == NULL) 4625da49fcbSDavid Xu return; 4635da49fcbSDavid Xu 4645da49fcbSDavid Xu p = sq->sq_proc; 4655da49fcbSDavid Xu TAILQ_REMOVE(&sq->sq_list, ksi, ksi_link); 4665da49fcbSDavid Xu ksi->ksi_sigq = NULL; 4675da49fcbSDavid Xu if (!(ksi->ksi_flags & KSI_EXT) && p != NULL) 4685da49fcbSDavid Xu p->p_pendingcnt--; 4695da49fcbSDavid Xu 4705da49fcbSDavid Xu for (kp = TAILQ_FIRST(&sq->sq_list); kp != NULL; 4715da49fcbSDavid Xu kp = TAILQ_NEXT(kp, ksi_link)) { 4725da49fcbSDavid Xu if (kp->ksi_signo == ksi->ksi_signo) 4735da49fcbSDavid Xu break; 4745da49fcbSDavid Xu } 47582a4538fSEric Badger if (kp == NULL && !SIGISMEMBER(sq->sq_kill, ksi->ksi_signo) && 47682a4538fSEric Badger !SIGISMEMBER(sq->sq_ptrace, ksi->ksi_signo)) 4775da49fcbSDavid Xu SIGDELSET(sq->sq_signals, ksi->ksi_signo); 4785da49fcbSDavid Xu } 4795da49fcbSDavid Xu 480a5799a4fSKonstantin Belousov static int 4819104847fSDavid Xu sigqueue_add(sigqueue_t *sq, int signo, ksiginfo_t *si) 4829104847fSDavid Xu { 4839104847fSDavid Xu struct proc *p = sq->sq_proc; 4849104847fSDavid Xu struct ksiginfo *ksi; 4859104847fSDavid Xu int ret = 0; 4869104847fSDavid Xu 4879104847fSDavid Xu KASSERT(sq->sq_flags & SQ_INIT, ("sigqueue not inited")); 4889104847fSDavid Xu 48982a4538fSEric Badger /* 49082a4538fSEric Badger * SIGKILL/SIGSTOP cannot be caught or masked, so take the fast path 49182a4538fSEric Badger * for these signals. 49282a4538fSEric Badger */ 4933dfcaad6SDavid Xu if (signo == SIGKILL || signo == SIGSTOP || si == NULL) { 4943dfcaad6SDavid Xu SIGADDSET(sq->sq_kill, signo); 4959104847fSDavid Xu goto out_set_bit; 4963dfcaad6SDavid Xu } 4979104847fSDavid Xu 4985da49fcbSDavid Xu /* directly insert the ksi, don't copy it */ 4995da49fcbSDavid Xu if (si->ksi_flags & KSI_INS) { 5006a671a6bSKonstantin Belousov if (si->ksi_flags & KSI_HEAD) 5016a671a6bSKonstantin Belousov TAILQ_INSERT_HEAD(&sq->sq_list, si, ksi_link); 5026a671a6bSKonstantin Belousov else 5035da49fcbSDavid Xu TAILQ_INSERT_TAIL(&sq->sq_list, si, ksi_link); 5045da49fcbSDavid Xu si->ksi_sigq = sq; 5055da49fcbSDavid Xu goto out_set_bit; 5065da49fcbSDavid Xu } 5075da49fcbSDavid Xu 5083dfcaad6SDavid Xu if (__predict_false(ksiginfo_zone == NULL)) { 5093dfcaad6SDavid Xu SIGADDSET(sq->sq_kill, signo); 5109104847fSDavid Xu goto out_set_bit; 5113dfcaad6SDavid Xu } 5129104847fSDavid Xu 513ebceaf6dSDavid Xu if (p != NULL && p->p_pendingcnt >= max_pending_per_proc) { 5149104847fSDavid Xu signal_overflow++; 5159104847fSDavid Xu ret = EAGAIN; 516ebceaf6dSDavid Xu } else if ((ksi = ksiginfo_alloc(0)) == NULL) { 5179104847fSDavid Xu signal_alloc_fail++; 5189104847fSDavid Xu ret = EAGAIN; 5199104847fSDavid Xu } else { 5209104847fSDavid Xu if (p != NULL) 5219104847fSDavid Xu p->p_pendingcnt++; 5229104847fSDavid Xu ksiginfo_copy(si, ksi); 5239104847fSDavid Xu ksi->ksi_signo = signo; 5246a671a6bSKonstantin Belousov if (si->ksi_flags & KSI_HEAD) 5256a671a6bSKonstantin Belousov TAILQ_INSERT_HEAD(&sq->sq_list, ksi, ksi_link); 5266a671a6bSKonstantin Belousov else 5279104847fSDavid Xu TAILQ_INSERT_TAIL(&sq->sq_list, ksi, ksi_link); 5285da49fcbSDavid Xu ksi->ksi_sigq = sq; 5299104847fSDavid Xu } 5309104847fSDavid Xu 53182a4538fSEric Badger if (ret != 0) { 53282a4538fSEric Badger if ((si->ksi_flags & KSI_PTRACE) != 0) { 53382a4538fSEric Badger SIGADDSET(sq->sq_ptrace, signo); 53482a4538fSEric Badger ret = 0; 53582a4538fSEric Badger goto out_set_bit; 53682a4538fSEric Badger } else if ((si->ksi_flags & KSI_TRAP) != 0 || 537a3de221dSKonstantin Belousov (si->ksi_flags & KSI_SIGQ) == 0) { 5383dfcaad6SDavid Xu SIGADDSET(sq->sq_kill, signo); 5399104847fSDavid Xu ret = 0; 5409104847fSDavid Xu goto out_set_bit; 5419104847fSDavid Xu } 5429104847fSDavid Xu return (ret); 54382a4538fSEric Badger } 5449104847fSDavid Xu 5459104847fSDavid Xu out_set_bit: 5469104847fSDavid Xu SIGADDSET(sq->sq_signals, signo); 5479104847fSDavid Xu return (ret); 5489104847fSDavid Xu } 5499104847fSDavid Xu 5509104847fSDavid Xu void 5519104847fSDavid Xu sigqueue_flush(sigqueue_t *sq) 5529104847fSDavid Xu { 5539104847fSDavid Xu struct proc *p = sq->sq_proc; 5549104847fSDavid Xu ksiginfo_t *ksi; 5559104847fSDavid Xu 5569104847fSDavid Xu KASSERT(sq->sq_flags & SQ_INIT, ("sigqueue not inited")); 5579104847fSDavid Xu 5585da49fcbSDavid Xu if (p != NULL) 5595da49fcbSDavid Xu PROC_LOCK_ASSERT(p, MA_OWNED); 5605da49fcbSDavid Xu 5619104847fSDavid Xu while ((ksi = TAILQ_FIRST(&sq->sq_list)) != NULL) { 5629104847fSDavid Xu TAILQ_REMOVE(&sq->sq_list, ksi, ksi_link); 5635da49fcbSDavid Xu ksi->ksi_sigq = NULL; 5645da49fcbSDavid Xu if (ksiginfo_tryfree(ksi) && p != NULL) 5659104847fSDavid Xu p->p_pendingcnt--; 5669104847fSDavid Xu } 5679104847fSDavid Xu 5689104847fSDavid Xu SIGEMPTYSET(sq->sq_signals); 5693dfcaad6SDavid Xu SIGEMPTYSET(sq->sq_kill); 57082a4538fSEric Badger SIGEMPTYSET(sq->sq_ptrace); 5719104847fSDavid Xu } 5729104847fSDavid Xu 573a5799a4fSKonstantin Belousov static void 574fc4ecc1dSDavid Xu sigqueue_move_set(sigqueue_t *src, sigqueue_t *dst, const sigset_t *set) 5759104847fSDavid Xu { 576fc4ecc1dSDavid Xu sigset_t tmp; 5779104847fSDavid Xu struct proc *p1, *p2; 5789104847fSDavid Xu ksiginfo_t *ksi, *next; 5799104847fSDavid Xu 5809104847fSDavid Xu KASSERT(src->sq_flags & SQ_INIT, ("src sigqueue not inited")); 5819104847fSDavid Xu KASSERT(dst->sq_flags & SQ_INIT, ("dst sigqueue not inited")); 5829104847fSDavid Xu p1 = src->sq_proc; 5839104847fSDavid Xu p2 = dst->sq_proc; 5849104847fSDavid Xu /* Move siginfo to target list */ 5855c28a8d4SDavid Xu TAILQ_FOREACH_SAFE(ksi, &src->sq_list, ksi_link, next) { 586fc4ecc1dSDavid Xu if (SIGISMEMBER(*set, ksi->ksi_signo)) { 5879104847fSDavid Xu TAILQ_REMOVE(&src->sq_list, ksi, ksi_link); 5889104847fSDavid Xu if (p1 != NULL) 5899104847fSDavid Xu p1->p_pendingcnt--; 5909104847fSDavid Xu TAILQ_INSERT_TAIL(&dst->sq_list, ksi, ksi_link); 5915da49fcbSDavid Xu ksi->ksi_sigq = dst; 5929104847fSDavid Xu if (p2 != NULL) 5939104847fSDavid Xu p2->p_pendingcnt++; 5949104847fSDavid Xu } 5959104847fSDavid Xu } 5969104847fSDavid Xu 5979104847fSDavid Xu /* Move pending bits to target list */ 5983dfcaad6SDavid Xu tmp = src->sq_kill; 599fc4ecc1dSDavid Xu SIGSETAND(tmp, *set); 6003dfcaad6SDavid Xu SIGSETOR(dst->sq_kill, tmp); 6013dfcaad6SDavid Xu SIGSETNAND(src->sq_kill, tmp); 6023dfcaad6SDavid Xu 60382a4538fSEric Badger tmp = src->sq_ptrace; 60482a4538fSEric Badger SIGSETAND(tmp, *set); 60582a4538fSEric Badger SIGSETOR(dst->sq_ptrace, tmp); 60682a4538fSEric Badger SIGSETNAND(src->sq_ptrace, tmp); 60782a4538fSEric Badger 6089104847fSDavid Xu tmp = src->sq_signals; 609fc4ecc1dSDavid Xu SIGSETAND(tmp, *set); 6109104847fSDavid Xu SIGSETOR(dst->sq_signals, tmp); 6119104847fSDavid Xu SIGSETNAND(src->sq_signals, tmp); 6129104847fSDavid Xu } 6139104847fSDavid Xu 614407af02bSDavid Xu #if 0 615a5799a4fSKonstantin Belousov static void 6169104847fSDavid Xu sigqueue_move(sigqueue_t *src, sigqueue_t *dst, int signo) 6179104847fSDavid Xu { 6189104847fSDavid Xu sigset_t set; 6199104847fSDavid Xu 6209104847fSDavid Xu SIGEMPTYSET(set); 6219104847fSDavid Xu SIGADDSET(set, signo); 6229104847fSDavid Xu sigqueue_move_set(src, dst, &set); 6239104847fSDavid Xu } 624407af02bSDavid Xu #endif 6259104847fSDavid Xu 626a5799a4fSKonstantin Belousov static void 627fc4ecc1dSDavid Xu sigqueue_delete_set(sigqueue_t *sq, const sigset_t *set) 6289104847fSDavid Xu { 6299104847fSDavid Xu struct proc *p = sq->sq_proc; 6309104847fSDavid Xu ksiginfo_t *ksi, *next; 6319104847fSDavid Xu 6329104847fSDavid Xu KASSERT(sq->sq_flags & SQ_INIT, ("src sigqueue not inited")); 6339104847fSDavid Xu 6349104847fSDavid Xu /* Remove siginfo queue */ 6355c28a8d4SDavid Xu TAILQ_FOREACH_SAFE(ksi, &sq->sq_list, ksi_link, next) { 6369104847fSDavid Xu if (SIGISMEMBER(*set, ksi->ksi_signo)) { 6379104847fSDavid Xu TAILQ_REMOVE(&sq->sq_list, ksi, ksi_link); 6385da49fcbSDavid Xu ksi->ksi_sigq = NULL; 6395da49fcbSDavid Xu if (ksiginfo_tryfree(ksi) && p != NULL) 6409104847fSDavid Xu p->p_pendingcnt--; 6419104847fSDavid Xu } 6429104847fSDavid Xu } 6433dfcaad6SDavid Xu SIGSETNAND(sq->sq_kill, *set); 64482a4538fSEric Badger SIGSETNAND(sq->sq_ptrace, *set); 6459104847fSDavid Xu SIGSETNAND(sq->sq_signals, *set); 6469104847fSDavid Xu } 6479104847fSDavid Xu 6489104847fSDavid Xu void 6499104847fSDavid Xu sigqueue_delete(sigqueue_t *sq, int signo) 6509104847fSDavid Xu { 6519104847fSDavid Xu sigset_t set; 6529104847fSDavid Xu 6539104847fSDavid Xu SIGEMPTYSET(set); 6549104847fSDavid Xu SIGADDSET(set, signo); 6559104847fSDavid Xu sigqueue_delete_set(sq, &set); 6569104847fSDavid Xu } 6579104847fSDavid Xu 6589104847fSDavid Xu /* Remove a set of signals for a process */ 659a5799a4fSKonstantin Belousov static void 660fc4ecc1dSDavid Xu sigqueue_delete_set_proc(struct proc *p, const sigset_t *set) 6619104847fSDavid Xu { 6629104847fSDavid Xu sigqueue_t worklist; 6639104847fSDavid Xu struct thread *td0; 6649104847fSDavid Xu 6659104847fSDavid Xu PROC_LOCK_ASSERT(p, MA_OWNED); 6669104847fSDavid Xu 6679104847fSDavid Xu sigqueue_init(&worklist, NULL); 6689104847fSDavid Xu sigqueue_move_set(&p->p_sigqueue, &worklist, set); 6699104847fSDavid Xu 6709104847fSDavid Xu FOREACH_THREAD_IN_PROC(p, td0) 6719104847fSDavid Xu sigqueue_move_set(&td0->td_sigqueue, &worklist, set); 6729104847fSDavid Xu 6739104847fSDavid Xu sigqueue_flush(&worklist); 6749104847fSDavid Xu } 6759104847fSDavid Xu 6769104847fSDavid Xu void 6779104847fSDavid Xu sigqueue_delete_proc(struct proc *p, int signo) 6789104847fSDavid Xu { 6799104847fSDavid Xu sigset_t set; 6809104847fSDavid Xu 6819104847fSDavid Xu SIGEMPTYSET(set); 6829104847fSDavid Xu SIGADDSET(set, signo); 6839104847fSDavid Xu sigqueue_delete_set_proc(p, &set); 6849104847fSDavid Xu } 6859104847fSDavid Xu 686a5799a4fSKonstantin Belousov static void 6879104847fSDavid Xu sigqueue_delete_stopmask_proc(struct proc *p) 6889104847fSDavid Xu { 6899104847fSDavid Xu sigset_t set; 6909104847fSDavid Xu 6919104847fSDavid Xu SIGEMPTYSET(set); 6929104847fSDavid Xu SIGADDSET(set, SIGSTOP); 6939104847fSDavid Xu SIGADDSET(set, SIGTSTP); 6949104847fSDavid Xu SIGADDSET(set, SIGTTIN); 6959104847fSDavid Xu SIGADDSET(set, SIGTTOU); 6969104847fSDavid Xu sigqueue_delete_set_proc(p, &set); 6979104847fSDavid Xu } 6989104847fSDavid Xu 699fbbeeb6cSBruce Evans /* 7001968f37bSJohn Baldwin * Determine signal that should be delivered to thread td, the current 7011968f37bSJohn Baldwin * thread, 0 if none. If there is a pending stop signal with default 702fbbeeb6cSBruce Evans * action, the process stops in issignal(). 703fbbeeb6cSBruce Evans */ 704fbbeeb6cSBruce Evans int 7053cf3b9f0SJohn Baldwin cursig(struct thread *td) 706fbbeeb6cSBruce Evans { 707c9dfa2e0SJeff Roberson PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); 70890af4afaSJohn Baldwin mtx_assert(&td->td_proc->p_sigacts->ps_mtx, MA_OWNED); 709a54e85fdSJeff Roberson THREAD_LOCK_ASSERT(td, MA_NOTOWNED); 7103cf3b9f0SJohn Baldwin return (SIGPENDING(td) ? issignal(td) : 0); 711fbbeeb6cSBruce Evans } 712fbbeeb6cSBruce Evans 71379065dbaSBruce Evans /* 71479065dbaSBruce Evans * Arrange for ast() to handle unmasked pending signals on return to user 7159104847fSDavid Xu * mode. This must be called whenever a signal is added to td_sigqueue or 7164093529dSJeff Roberson * unmasked in td_sigmask. 71779065dbaSBruce Evans */ 71879065dbaSBruce Evans void 7194093529dSJeff Roberson signotify(struct thread *td) 72079065dbaSBruce Evans { 7214093529dSJeff Roberson 722ddd4d15eSMatt Macy PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); 7234093529dSJeff Roberson 724c6d31b83SKonstantin Belousov if (SIGPENDING(td)) 725c6d31b83SKonstantin Belousov ast_sched(td, TDA_SIG); 7268b94a061SJohn Baldwin } 7278b94a061SJohn Baldwin 728affd9185SKonstantin Belousov /* 729affd9185SKonstantin Belousov * Returns 1 (true) if altstack is configured for the thread, and the 730affd9185SKonstantin Belousov * passed stack bottom address falls into the altstack range. Handles 731affd9185SKonstantin Belousov * the 43 compat special case where the alt stack size is zero. 732affd9185SKonstantin Belousov */ 7338b94a061SJohn Baldwin int 7348b94a061SJohn Baldwin sigonstack(size_t sp) 7358b94a061SJohn Baldwin { 736affd9185SKonstantin Belousov struct thread *td; 7378b94a061SJohn Baldwin 738affd9185SKonstantin Belousov td = curthread; 739affd9185SKonstantin Belousov if ((td->td_pflags & TDP_ALTSTACK) == 0) 740affd9185SKonstantin Belousov return (0); 7411930e303SPoul-Henning Kamp #if defined(COMPAT_43) 7427e097daaSKonstantin Belousov if (SV_PROC_FLAG(td->td_proc, SV_AOUT) && td->td_sigstk.ss_size == 0) 743affd9185SKonstantin Belousov return ((td->td_sigstk.ss_flags & SS_ONSTACK) != 0); 7448b94a061SJohn Baldwin #endif 745affd9185SKonstantin Belousov return (sp >= (size_t)td->td_sigstk.ss_sp && 746affd9185SKonstantin Belousov sp < td->td_sigstk.ss_size + (size_t)td->td_sigstk.ss_sp); 7478b94a061SJohn Baldwin } 74879065dbaSBruce Evans 7496f841fb7SMarcel Moolenaar static __inline int 7506f841fb7SMarcel Moolenaar sigprop(int sig) 7512c42a146SMarcel Moolenaar { 7526f841fb7SMarcel Moolenaar 753ed6d876bSBrooks Davis if (sig > 0 && sig < nitems(sigproptbl)) 754ed6d876bSBrooks Davis return (sigproptbl[sig]); 7552c42a146SMarcel Moolenaar return (0); 756df8bae1dSRodney W. Grimes } 7572c42a146SMarcel Moolenaar 758350ae563SKonstantin Belousov static bool 759ea566832SEd Schouten sigact_flag_test(const struct sigaction *act, int flag) 760350ae563SKonstantin Belousov { 761350ae563SKonstantin Belousov 762c83655f3SKonstantin Belousov /* 763c83655f3SKonstantin Belousov * SA_SIGINFO is reset when signal disposition is set to 764c83655f3SKonstantin Belousov * ignore or default. Other flags are kept according to user 765c83655f3SKonstantin Belousov * settings. 766c83655f3SKonstantin Belousov */ 767c83655f3SKonstantin Belousov return ((act->sa_flags & flag) != 0 && (flag != SA_SIGINFO || 768c83655f3SKonstantin Belousov ((__sighandler_t *)act->sa_sigaction != SIG_IGN && 769c83655f3SKonstantin Belousov (__sighandler_t *)act->sa_sigaction != SIG_DFL))); 770350ae563SKonstantin Belousov } 771350ae563SKonstantin Belousov 7722c42a146SMarcel Moolenaar /* 7738f19eb88SIan Dowse * kern_sigaction 7742c42a146SMarcel Moolenaar * sigaction 77523eeeff7SPeter Wemm * freebsd4_sigaction 7762c42a146SMarcel Moolenaar * osigaction 7772c42a146SMarcel Moolenaar */ 7788f19eb88SIan Dowse int 779ea566832SEd Schouten kern_sigaction(struct thread *td, int sig, const struct sigaction *act, 780ea566832SEd Schouten struct sigaction *oact, int flags) 781df8bae1dSRodney W. Grimes { 78290af4afaSJohn Baldwin struct sigacts *ps; 7838f19eb88SIan Dowse struct proc *p = td->td_proc; 784df8bae1dSRodney W. Grimes 7852899d606SDag-Erling Smørgrav if (!_SIG_VALID(sig)) 7862c42a146SMarcel Moolenaar return (EINVAL); 787271ab240SKonstantin Belousov if (act != NULL && act->sa_handler != SIG_DFL && 788271ab240SKonstantin Belousov act->sa_handler != SIG_IGN && (act->sa_flags & ~(SA_ONSTACK | 789271ab240SKonstantin Belousov SA_RESTART | SA_RESETHAND | SA_NOCLDSTOP | SA_NODEFER | 790271ab240SKonstantin Belousov SA_NOCLDWAIT | SA_SIGINFO)) != 0) 7912d864174SKonstantin Belousov return (EINVAL); 7922c42a146SMarcel Moolenaar 793628d2653SJohn Baldwin PROC_LOCK(p); 794628d2653SJohn Baldwin ps = p->p_sigacts; 79590af4afaSJohn Baldwin mtx_lock(&ps->ps_mtx); 7962c42a146SMarcel Moolenaar if (oact) { 797fb441a88SKonstantin Belousov memset(oact, 0, sizeof(*oact)); 7982c42a146SMarcel Moolenaar oact->sa_mask = ps->ps_catchmask[_SIG_IDX(sig)]; 7992c42a146SMarcel Moolenaar if (SIGISMEMBER(ps->ps_sigonstack, sig)) 8002c42a146SMarcel Moolenaar oact->sa_flags |= SA_ONSTACK; 8012c42a146SMarcel Moolenaar if (!SIGISMEMBER(ps->ps_sigintr, sig)) 8022c42a146SMarcel Moolenaar oact->sa_flags |= SA_RESTART; 8032c42a146SMarcel Moolenaar if (SIGISMEMBER(ps->ps_sigreset, sig)) 8042c42a146SMarcel Moolenaar oact->sa_flags |= SA_RESETHAND; 8052c42a146SMarcel Moolenaar if (SIGISMEMBER(ps->ps_signodefer, sig)) 8062c42a146SMarcel Moolenaar oact->sa_flags |= SA_NODEFER; 80710c2b8e1SDavid E. O'Brien if (SIGISMEMBER(ps->ps_siginfo, sig)) { 8082c42a146SMarcel Moolenaar oact->sa_flags |= SA_SIGINFO; 80910c2b8e1SDavid E. O'Brien oact->sa_sigaction = 81010c2b8e1SDavid E. O'Brien (__siginfohandler_t *)ps->ps_sigact[_SIG_IDX(sig)]; 81110c2b8e1SDavid E. O'Brien } else 81210c2b8e1SDavid E. O'Brien oact->sa_handler = ps->ps_sigact[_SIG_IDX(sig)]; 81390af4afaSJohn Baldwin if (sig == SIGCHLD && ps->ps_flag & PS_NOCLDSTOP) 8142c42a146SMarcel Moolenaar oact->sa_flags |= SA_NOCLDSTOP; 81590af4afaSJohn Baldwin if (sig == SIGCHLD && ps->ps_flag & PS_NOCLDWAIT) 8162c42a146SMarcel Moolenaar oact->sa_flags |= SA_NOCLDWAIT; 8172c42a146SMarcel Moolenaar } 8182c42a146SMarcel Moolenaar if (act) { 8192c42a146SMarcel Moolenaar if ((sig == SIGKILL || sig == SIGSTOP) && 820628d2653SJohn Baldwin act->sa_handler != SIG_DFL) { 82190af4afaSJohn Baldwin mtx_unlock(&ps->ps_mtx); 822628d2653SJohn Baldwin PROC_UNLOCK(p); 8232c42a146SMarcel Moolenaar return (EINVAL); 824628d2653SJohn Baldwin } 8252c42a146SMarcel Moolenaar 826df8bae1dSRodney W. Grimes /* 827df8bae1dSRodney W. Grimes * Change setting atomically. 828df8bae1dSRodney W. Grimes */ 8292c42a146SMarcel Moolenaar 8302c42a146SMarcel Moolenaar ps->ps_catchmask[_SIG_IDX(sig)] = act->sa_mask; 8312c42a146SMarcel Moolenaar SIG_CANTMASK(ps->ps_catchmask[_SIG_IDX(sig)]); 832350ae563SKonstantin Belousov if (sigact_flag_test(act, SA_SIGINFO)) { 833aa7a4daeSPeter Wemm ps->ps_sigact[_SIG_IDX(sig)] = 834aa7a4daeSPeter Wemm (__sighandler_t *)act->sa_sigaction; 83580f42b55SIan Dowse SIGADDSET(ps->ps_siginfo, sig); 83680f42b55SIan Dowse } else { 83780f42b55SIan Dowse ps->ps_sigact[_SIG_IDX(sig)] = act->sa_handler; 8382c42a146SMarcel Moolenaar SIGDELSET(ps->ps_siginfo, sig); 8392c42a146SMarcel Moolenaar } 840350ae563SKonstantin Belousov if (!sigact_flag_test(act, SA_RESTART)) 8412c42a146SMarcel Moolenaar SIGADDSET(ps->ps_sigintr, sig); 842df8bae1dSRodney W. Grimes else 8432c42a146SMarcel Moolenaar SIGDELSET(ps->ps_sigintr, sig); 844350ae563SKonstantin Belousov if (sigact_flag_test(act, SA_ONSTACK)) 8452c42a146SMarcel Moolenaar SIGADDSET(ps->ps_sigonstack, sig); 846df8bae1dSRodney W. Grimes else 8472c42a146SMarcel Moolenaar SIGDELSET(ps->ps_sigonstack, sig); 848350ae563SKonstantin Belousov if (sigact_flag_test(act, SA_RESETHAND)) 8492c42a146SMarcel Moolenaar SIGADDSET(ps->ps_sigreset, sig); 8501e41c1b5SSteven Wallace else 8512c42a146SMarcel Moolenaar SIGDELSET(ps->ps_sigreset, sig); 852350ae563SKonstantin Belousov if (sigact_flag_test(act, SA_NODEFER)) 8532c42a146SMarcel Moolenaar SIGADDSET(ps->ps_signodefer, sig); 854289ccde0SPeter Wemm else 8552c42a146SMarcel Moolenaar SIGDELSET(ps->ps_signodefer, sig); 8562c42a146SMarcel Moolenaar if (sig == SIGCHLD) { 8572c42a146SMarcel Moolenaar if (act->sa_flags & SA_NOCLDSTOP) 85890af4afaSJohn Baldwin ps->ps_flag |= PS_NOCLDSTOP; 8596626c604SJulian Elischer else 86090af4afaSJohn Baldwin ps->ps_flag &= ~PS_NOCLDSTOP; 861ba1551caSIan Dowse if (act->sa_flags & SA_NOCLDWAIT) { 862245f17d4SJoerg Wunsch /* 8632c42a146SMarcel Moolenaar * Paranoia: since SA_NOCLDWAIT is implemented 8642c42a146SMarcel Moolenaar * by reparenting the dying child to PID 1 (and 8652c42a146SMarcel Moolenaar * trust it to reap the zombie), PID 1 itself 8662c42a146SMarcel Moolenaar * is forbidden to set SA_NOCLDWAIT. 867245f17d4SJoerg Wunsch */ 868245f17d4SJoerg Wunsch if (p->p_pid == 1) 86990af4afaSJohn Baldwin ps->ps_flag &= ~PS_NOCLDWAIT; 8706626c604SJulian Elischer else 87190af4afaSJohn Baldwin ps->ps_flag |= PS_NOCLDWAIT; 872245f17d4SJoerg Wunsch } else 87390af4afaSJohn Baldwin ps->ps_flag &= ~PS_NOCLDWAIT; 874ba1551caSIan Dowse if (ps->ps_sigact[_SIG_IDX(SIGCHLD)] == SIG_IGN) 87590af4afaSJohn Baldwin ps->ps_flag |= PS_CLDSIGIGN; 876ba1551caSIan Dowse else 87790af4afaSJohn Baldwin ps->ps_flag &= ~PS_CLDSIGIGN; 878df8bae1dSRodney W. Grimes } 879df8bae1dSRodney W. Grimes /* 88090af4afaSJohn Baldwin * Set bit in ps_sigignore for signals that are set to SIG_IGN, 8812c42a146SMarcel Moolenaar * and for signals set to SIG_DFL where the default is to 88290af4afaSJohn Baldwin * ignore. However, don't put SIGCONT in ps_sigignore, as we 8832c42a146SMarcel Moolenaar * have to restart the process. 884df8bae1dSRodney W. Grimes */ 8852c42a146SMarcel Moolenaar if (ps->ps_sigact[_SIG_IDX(sig)] == SIG_IGN || 886fd50a707SBrooks Davis (sigprop(sig) & SIGPROP_IGNORE && 8872c42a146SMarcel Moolenaar ps->ps_sigact[_SIG_IDX(sig)] == SIG_DFL)) { 8882c42a146SMarcel Moolenaar /* never to be seen again */ 8899104847fSDavid Xu sigqueue_delete_proc(p, sig); 8902c42a146SMarcel Moolenaar if (sig != SIGCONT) 8912c42a146SMarcel Moolenaar /* easier in psignal */ 89290af4afaSJohn Baldwin SIGADDSET(ps->ps_sigignore, sig); 89390af4afaSJohn Baldwin SIGDELSET(ps->ps_sigcatch, sig); 894645682fdSLuoqi Chen } else { 89590af4afaSJohn Baldwin SIGDELSET(ps->ps_sigignore, sig); 8962c42a146SMarcel Moolenaar if (ps->ps_sigact[_SIG_IDX(sig)] == SIG_DFL) 89790af4afaSJohn Baldwin SIGDELSET(ps->ps_sigcatch, sig); 8982c42a146SMarcel Moolenaar else 89990af4afaSJohn Baldwin SIGADDSET(ps->ps_sigcatch, sig); 9002c42a146SMarcel Moolenaar } 90123eeeff7SPeter Wemm #ifdef COMPAT_FREEBSD4 90223eeeff7SPeter Wemm if (ps->ps_sigact[_SIG_IDX(sig)] == SIG_IGN || 90323eeeff7SPeter Wemm ps->ps_sigact[_SIG_IDX(sig)] == SIG_DFL || 90423eeeff7SPeter Wemm (flags & KSA_FREEBSD4) == 0) 90523eeeff7SPeter Wemm SIGDELSET(ps->ps_freebsd4, sig); 90623eeeff7SPeter Wemm else 90723eeeff7SPeter Wemm SIGADDSET(ps->ps_freebsd4, sig); 90823eeeff7SPeter Wemm #endif 909e8ebc08fSPeter Wemm #ifdef COMPAT_43 910645682fdSLuoqi Chen if (ps->ps_sigact[_SIG_IDX(sig)] == SIG_IGN || 91123eeeff7SPeter Wemm ps->ps_sigact[_SIG_IDX(sig)] == SIG_DFL || 91223eeeff7SPeter Wemm (flags & KSA_OSIGSET) == 0) 913645682fdSLuoqi Chen SIGDELSET(ps->ps_osigset, sig); 914645682fdSLuoqi Chen else 915645682fdSLuoqi Chen SIGADDSET(ps->ps_osigset, sig); 916e8ebc08fSPeter Wemm #endif 917df8bae1dSRodney W. Grimes } 91890af4afaSJohn Baldwin mtx_unlock(&ps->ps_mtx); 919628d2653SJohn Baldwin PROC_UNLOCK(p); 9202c42a146SMarcel Moolenaar return (0); 9212c42a146SMarcel Moolenaar } 9222c42a146SMarcel Moolenaar 9232c42a146SMarcel Moolenaar #ifndef _SYS_SYSPROTO_H_ 9242c42a146SMarcel Moolenaar struct sigaction_args { 9252c42a146SMarcel Moolenaar int sig; 9262c42a146SMarcel Moolenaar struct sigaction *act; 9272c42a146SMarcel Moolenaar struct sigaction *oact; 9282c42a146SMarcel Moolenaar }; 9292c42a146SMarcel Moolenaar #endif 9302c42a146SMarcel Moolenaar int 931e052a8b9SEd Maste sys_sigaction(struct thread *td, struct sigaction_args *uap) 9322c42a146SMarcel Moolenaar { 9332c42a146SMarcel Moolenaar struct sigaction act, oact; 934e052a8b9SEd Maste struct sigaction *actp, *oactp; 9352c42a146SMarcel Moolenaar int error; 9362c42a146SMarcel Moolenaar 9376f841fb7SMarcel Moolenaar actp = (uap->act != NULL) ? &act : NULL; 9386f841fb7SMarcel Moolenaar oactp = (uap->oact != NULL) ? &oact : NULL; 9392c42a146SMarcel Moolenaar if (actp) { 9406f841fb7SMarcel Moolenaar error = copyin(uap->act, actp, sizeof(act)); 9412c42a146SMarcel Moolenaar if (error) 94244443757STim J. Robbins return (error); 9432c42a146SMarcel Moolenaar } 9448f19eb88SIan Dowse error = kern_sigaction(td, uap->sig, actp, oactp, 0); 94525d6dc06SJohn Baldwin if (oactp && !error) 9466f841fb7SMarcel Moolenaar error = copyout(oactp, uap->oact, sizeof(oact)); 9472c42a146SMarcel Moolenaar return (error); 9482c42a146SMarcel Moolenaar } 9492c42a146SMarcel Moolenaar 95023eeeff7SPeter Wemm #ifdef COMPAT_FREEBSD4 95123eeeff7SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 95223eeeff7SPeter Wemm struct freebsd4_sigaction_args { 95323eeeff7SPeter Wemm int sig; 95423eeeff7SPeter Wemm struct sigaction *act; 95523eeeff7SPeter Wemm struct sigaction *oact; 95623eeeff7SPeter Wemm }; 95723eeeff7SPeter Wemm #endif 95823eeeff7SPeter Wemm int 959e052a8b9SEd Maste freebsd4_sigaction(struct thread *td, struct freebsd4_sigaction_args *uap) 96023eeeff7SPeter Wemm { 96123eeeff7SPeter Wemm struct sigaction act, oact; 962e052a8b9SEd Maste struct sigaction *actp, *oactp; 96323eeeff7SPeter Wemm int error; 96423eeeff7SPeter Wemm 96523eeeff7SPeter Wemm actp = (uap->act != NULL) ? &act : NULL; 96623eeeff7SPeter Wemm oactp = (uap->oact != NULL) ? &oact : NULL; 96723eeeff7SPeter Wemm if (actp) { 96823eeeff7SPeter Wemm error = copyin(uap->act, actp, sizeof(act)); 96923eeeff7SPeter Wemm if (error) 97044443757STim J. Robbins return (error); 97123eeeff7SPeter Wemm } 97223eeeff7SPeter Wemm error = kern_sigaction(td, uap->sig, actp, oactp, KSA_FREEBSD4); 973a14e1189SJohn Baldwin if (oactp && !error) 97423eeeff7SPeter Wemm error = copyout(oactp, uap->oact, sizeof(oact)); 97523eeeff7SPeter Wemm return (error); 97623eeeff7SPeter Wemm } 97723eeeff7SPeter Wemm #endif /* COMAPT_FREEBSD4 */ 97823eeeff7SPeter Wemm 97931c8f3f0SMarcel Moolenaar #ifdef COMPAT_43 /* XXX - COMPAT_FBSD3 */ 9802c42a146SMarcel Moolenaar #ifndef _SYS_SYSPROTO_H_ 9812c42a146SMarcel Moolenaar struct osigaction_args { 9822c42a146SMarcel Moolenaar int signum; 9832c42a146SMarcel Moolenaar struct osigaction *nsa; 9842c42a146SMarcel Moolenaar struct osigaction *osa; 9852c42a146SMarcel Moolenaar }; 9862c42a146SMarcel Moolenaar #endif 9872c42a146SMarcel Moolenaar int 988e052a8b9SEd Maste osigaction(struct thread *td, struct osigaction_args *uap) 9892c42a146SMarcel Moolenaar { 9902c42a146SMarcel Moolenaar struct osigaction sa; 9912c42a146SMarcel Moolenaar struct sigaction nsa, osa; 992e052a8b9SEd Maste struct sigaction *nsap, *osap; 9932c42a146SMarcel Moolenaar int error; 9942c42a146SMarcel Moolenaar 9956f841fb7SMarcel Moolenaar if (uap->signum <= 0 || uap->signum >= ONSIG) 9966f841fb7SMarcel Moolenaar return (EINVAL); 997fb99ab88SMatthew Dillon 9986f841fb7SMarcel Moolenaar nsap = (uap->nsa != NULL) ? &nsa : NULL; 9996f841fb7SMarcel Moolenaar osap = (uap->osa != NULL) ? &osa : NULL; 1000fb99ab88SMatthew Dillon 10012c42a146SMarcel Moolenaar if (nsap) { 10026f841fb7SMarcel Moolenaar error = copyin(uap->nsa, &sa, sizeof(sa)); 10032c42a146SMarcel Moolenaar if (error) 100444443757STim J. Robbins return (error); 10052c42a146SMarcel Moolenaar nsap->sa_handler = sa.sa_handler; 10062c42a146SMarcel Moolenaar nsap->sa_flags = sa.sa_flags; 10072c42a146SMarcel Moolenaar OSIG2SIG(sa.sa_mask, nsap->sa_mask); 10082c42a146SMarcel Moolenaar } 100923eeeff7SPeter Wemm error = kern_sigaction(td, uap->signum, nsap, osap, KSA_OSIGSET); 10102c42a146SMarcel Moolenaar if (osap && !error) { 10112c42a146SMarcel Moolenaar sa.sa_handler = osap->sa_handler; 10122c42a146SMarcel Moolenaar sa.sa_flags = osap->sa_flags; 10132c42a146SMarcel Moolenaar SIG2OSIG(osap->sa_mask, sa.sa_mask); 10146f841fb7SMarcel Moolenaar error = copyout(&sa, uap->osa, sizeof(sa)); 10152c42a146SMarcel Moolenaar } 10162c42a146SMarcel Moolenaar return (error); 10172c42a146SMarcel Moolenaar } 101823eeeff7SPeter Wemm 101973dbd3daSJohn Baldwin #if !defined(__i386__) 102023eeeff7SPeter Wemm /* Avoid replicating the same stub everywhere */ 102123eeeff7SPeter Wemm int 1022e052a8b9SEd Maste osigreturn(struct thread *td, struct osigreturn_args *uap) 102323eeeff7SPeter Wemm { 102423eeeff7SPeter Wemm 102523eeeff7SPeter Wemm return (nosys(td, (struct nosys_args *)uap)); 102623eeeff7SPeter Wemm } 102723eeeff7SPeter Wemm #endif 102831c8f3f0SMarcel Moolenaar #endif /* COMPAT_43 */ 1029df8bae1dSRodney W. Grimes 1030df8bae1dSRodney W. Grimes /* 1031df8bae1dSRodney W. Grimes * Initialize signal state for process 0; 1032df8bae1dSRodney W. Grimes * set to ignore signals that are ignored by default. 1033df8bae1dSRodney W. Grimes */ 1034df8bae1dSRodney W. Grimes void 1035e052a8b9SEd Maste siginit(struct proc *p) 1036df8bae1dSRodney W. Grimes { 10373e85b721SEd Maste int i; 103890af4afaSJohn Baldwin struct sigacts *ps; 1039df8bae1dSRodney W. Grimes 1040628d2653SJohn Baldwin PROC_LOCK(p); 104190af4afaSJohn Baldwin ps = p->p_sigacts; 104290af4afaSJohn Baldwin mtx_lock(&ps->ps_mtx); 1043350ae563SKonstantin Belousov for (i = 1; i <= NSIG; i++) { 1044fd50a707SBrooks Davis if (sigprop(i) & SIGPROP_IGNORE && i != SIGCONT) { 104590af4afaSJohn Baldwin SIGADDSET(ps->ps_sigignore, i); 1046350ae563SKonstantin Belousov } 1047350ae563SKonstantin Belousov } 104890af4afaSJohn Baldwin mtx_unlock(&ps->ps_mtx); 1049628d2653SJohn Baldwin PROC_UNLOCK(p); 1050df8bae1dSRodney W. Grimes } 1051df8bae1dSRodney W. Grimes 1052df8bae1dSRodney W. Grimes /* 1053350ae563SKonstantin Belousov * Reset specified signal to the default disposition. 1054350ae563SKonstantin Belousov */ 1055350ae563SKonstantin Belousov static void 1056350ae563SKonstantin Belousov sigdflt(struct sigacts *ps, int sig) 1057350ae563SKonstantin Belousov { 1058350ae563SKonstantin Belousov 1059350ae563SKonstantin Belousov mtx_assert(&ps->ps_mtx, MA_OWNED); 1060350ae563SKonstantin Belousov SIGDELSET(ps->ps_sigcatch, sig); 1061fd50a707SBrooks Davis if ((sigprop(sig) & SIGPROP_IGNORE) != 0 && sig != SIGCONT) 1062350ae563SKonstantin Belousov SIGADDSET(ps->ps_sigignore, sig); 1063350ae563SKonstantin Belousov ps->ps_sigact[_SIG_IDX(sig)] = SIG_DFL; 1064350ae563SKonstantin Belousov SIGDELSET(ps->ps_siginfo, sig); 1065350ae563SKonstantin Belousov } 1066350ae563SKonstantin Belousov 1067350ae563SKonstantin Belousov /* 1068df8bae1dSRodney W. Grimes * Reset signals for an exec of the specified process. 1069df8bae1dSRodney W. Grimes */ 1070df8bae1dSRodney W. Grimes void 1071a30ec4b9SDavid Xu execsigs(struct proc *p) 1072df8bae1dSRodney W. Grimes { 1073a30ec4b9SDavid Xu struct sigacts *ps; 1074a30ec4b9SDavid Xu struct thread *td; 1075df8bae1dSRodney W. Grimes 1076df8bae1dSRodney W. Grimes /* 1077df8bae1dSRodney W. Grimes * Reset caught signals. Held signals remain held 10784093529dSJeff Roberson * through td_sigmask (unless they were caught, 1079df8bae1dSRodney W. Grimes * and are now ignored by default). 1080df8bae1dSRodney W. Grimes */ 10819b3b1c5fSJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 1082628d2653SJohn Baldwin ps = p->p_sigacts; 108390af4afaSJohn Baldwin mtx_lock(&ps->ps_mtx); 1084079c5b9eSKyle Evans sig_drop_caught(p); 1085f3fe76ecSEd Schouten 1086f3fe76ecSEd Schouten /* 1087df8bae1dSRodney W. Grimes * Reset stack state to the user stack. 1088df8bae1dSRodney W. Grimes * Clear set of signals caught on the signal stack. 1089df8bae1dSRodney W. Grimes */ 1090469ec1ebSKonstantin Belousov td = curthread; 1091469ec1ebSKonstantin Belousov MPASS(td->td_proc == p); 1092a30ec4b9SDavid Xu td->td_sigstk.ss_flags = SS_DISABLE; 1093a30ec4b9SDavid Xu td->td_sigstk.ss_size = 0; 1094a30ec4b9SDavid Xu td->td_sigstk.ss_sp = 0; 1095a30ec4b9SDavid Xu td->td_pflags &= ~TDP_ALTSTACK; 109680e907a1SPeter Wemm /* 109780e907a1SPeter Wemm * Reset no zombies if child dies flag as Solaris does. 109880e907a1SPeter Wemm */ 109990af4afaSJohn Baldwin ps->ps_flag &= ~(PS_NOCLDWAIT | PS_CLDSIGIGN); 1100c7fd62daSDavid Malone if (ps->ps_sigact[_SIG_IDX(SIGCHLD)] == SIG_IGN) 1101c7fd62daSDavid Malone ps->ps_sigact[_SIG_IDX(SIGCHLD)] = SIG_DFL; 110290af4afaSJohn Baldwin mtx_unlock(&ps->ps_mtx); 1103df8bae1dSRodney W. Grimes } 1104df8bae1dSRodney W. Grimes 1105df8bae1dSRodney W. Grimes /* 1106e77daab1SJohn Baldwin * kern_sigprocmask() 11077c8fdcbdSMatthew Dillon * 1108628d2653SJohn Baldwin * Manipulate signal mask. 1109df8bae1dSRodney W. Grimes */ 1110e77daab1SJohn Baldwin int 11116b286ee8SKonstantin Belousov kern_sigprocmask(struct thread *td, int how, sigset_t *set, sigset_t *oset, 111284440afbSKonstantin Belousov int flags) 11132c42a146SMarcel Moolenaar { 11146b286ee8SKonstantin Belousov sigset_t new_block, oset1; 11156b286ee8SKonstantin Belousov struct proc *p; 11162c42a146SMarcel Moolenaar int error; 11172c42a146SMarcel Moolenaar 11186b286ee8SKonstantin Belousov p = td->td_proc; 111970778bbaSKonstantin Belousov if ((flags & SIGPROCMASK_PROC_LOCKED) != 0) 112070778bbaSKonstantin Belousov PROC_LOCK_ASSERT(p, MA_OWNED); 112170778bbaSKonstantin Belousov else 11226b286ee8SKonstantin Belousov PROC_LOCK(p); 112370778bbaSKonstantin Belousov mtx_assert(&p->p_sigacts->ps_mtx, (flags & SIGPROCMASK_PS_LOCKED) != 0 112470778bbaSKonstantin Belousov ? MA_OWNED : MA_NOTOWNED); 11252c42a146SMarcel Moolenaar if (oset != NULL) 11264093529dSJeff Roberson *oset = td->td_sigmask; 11272c42a146SMarcel Moolenaar 11282c42a146SMarcel Moolenaar error = 0; 11292c42a146SMarcel Moolenaar if (set != NULL) { 11302c42a146SMarcel Moolenaar switch (how) { 11312c42a146SMarcel Moolenaar case SIG_BLOCK: 1132645682fdSLuoqi Chen SIG_CANTMASK(*set); 11336b286ee8SKonstantin Belousov oset1 = td->td_sigmask; 11344093529dSJeff Roberson SIGSETOR(td->td_sigmask, *set); 11356b286ee8SKonstantin Belousov new_block = td->td_sigmask; 11366b286ee8SKonstantin Belousov SIGSETNAND(new_block, oset1); 11372c42a146SMarcel Moolenaar break; 11382c42a146SMarcel Moolenaar case SIG_UNBLOCK: 11394093529dSJeff Roberson SIGSETNAND(td->td_sigmask, *set); 11404093529dSJeff Roberson signotify(td); 1141407af02bSDavid Xu goto out; 11422c42a146SMarcel Moolenaar case SIG_SETMASK: 1143645682fdSLuoqi Chen SIG_CANTMASK(*set); 11446b286ee8SKonstantin Belousov oset1 = td->td_sigmask; 114584440afbSKonstantin Belousov if (flags & SIGPROCMASK_OLD) 11464093529dSJeff Roberson SIGSETLO(td->td_sigmask, *set); 1147645682fdSLuoqi Chen else 11484093529dSJeff Roberson td->td_sigmask = *set; 11496b286ee8SKonstantin Belousov new_block = td->td_sigmask; 11506b286ee8SKonstantin Belousov SIGSETNAND(new_block, oset1); 11514093529dSJeff Roberson signotify(td); 11522c42a146SMarcel Moolenaar break; 11532c42a146SMarcel Moolenaar default: 11542c42a146SMarcel Moolenaar error = EINVAL; 1155407af02bSDavid Xu goto out; 11562c42a146SMarcel Moolenaar } 11576b286ee8SKonstantin Belousov 11586b286ee8SKonstantin Belousov /* 11597df8f6abSKonstantin Belousov * The new_block set contains signals that were not previously 11606b286ee8SKonstantin Belousov * blocked, but are blocked now. 11616b286ee8SKonstantin Belousov * 11626b286ee8SKonstantin Belousov * In case we block any signal that was not previously blocked 11636b286ee8SKonstantin Belousov * for td, and process has the signal pending, try to schedule 1164407af02bSDavid Xu * signal delivery to some thread that does not block the 1165407af02bSDavid Xu * signal, possibly waking it up. 11666b286ee8SKonstantin Belousov */ 11676b286ee8SKonstantin Belousov if (p->p_numthreads != 1) 116880a8b0f3SKonstantin Belousov reschedule_signals(p, new_block, flags); 1169407af02bSDavid Xu } 11706b286ee8SKonstantin Belousov 1171407af02bSDavid Xu out: 117284440afbSKonstantin Belousov if (!(flags & SIGPROCMASK_PROC_LOCKED)) 11736b286ee8SKonstantin Belousov PROC_UNLOCK(p); 11742c42a146SMarcel Moolenaar return (error); 11752c42a146SMarcel Moolenaar } 11762c42a146SMarcel Moolenaar 1177d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1178df8bae1dSRodney W. Grimes struct sigprocmask_args { 1179df8bae1dSRodney W. Grimes int how; 11802c42a146SMarcel Moolenaar const sigset_t *set; 11812c42a146SMarcel Moolenaar sigset_t *oset; 1182df8bae1dSRodney W. Grimes }; 1183d2d3e875SBruce Evans #endif 118426f9a767SRodney W. Grimes int 1185e052a8b9SEd Maste sys_sigprocmask(struct thread *td, struct sigprocmask_args *uap) 1186df8bae1dSRodney W. Grimes { 11872c42a146SMarcel Moolenaar sigset_t set, oset; 11882c42a146SMarcel Moolenaar sigset_t *setp, *osetp; 11892c42a146SMarcel Moolenaar int error; 1190df8bae1dSRodney W. Grimes 11916f841fb7SMarcel Moolenaar setp = (uap->set != NULL) ? &set : NULL; 11926f841fb7SMarcel Moolenaar osetp = (uap->oset != NULL) ? &oset : NULL; 11932c42a146SMarcel Moolenaar if (setp) { 11946f841fb7SMarcel Moolenaar error = copyin(uap->set, setp, sizeof(set)); 11952c42a146SMarcel Moolenaar if (error) 11962c42a146SMarcel Moolenaar return (error); 1197df8bae1dSRodney W. Grimes } 1198e77daab1SJohn Baldwin error = kern_sigprocmask(td, uap->how, setp, osetp, 0); 11992c42a146SMarcel Moolenaar if (osetp && !error) { 12006f841fb7SMarcel Moolenaar error = copyout(osetp, uap->oset, sizeof(oset)); 12012c42a146SMarcel Moolenaar } 12022c42a146SMarcel Moolenaar return (error); 12032c42a146SMarcel Moolenaar } 12042c42a146SMarcel Moolenaar 120531c8f3f0SMarcel Moolenaar #ifdef COMPAT_43 /* XXX - COMPAT_FBSD3 */ 12062c42a146SMarcel Moolenaar #ifndef _SYS_SYSPROTO_H_ 12072c42a146SMarcel Moolenaar struct osigprocmask_args { 12082c42a146SMarcel Moolenaar int how; 12092c42a146SMarcel Moolenaar osigset_t mask; 12102c42a146SMarcel Moolenaar }; 12112c42a146SMarcel Moolenaar #endif 12122c42a146SMarcel Moolenaar int 1213e052a8b9SEd Maste osigprocmask(struct thread *td, struct osigprocmask_args *uap) 12142c42a146SMarcel Moolenaar { 12152c42a146SMarcel Moolenaar sigset_t set, oset; 12162c42a146SMarcel Moolenaar int error; 12172c42a146SMarcel Moolenaar 12182c42a146SMarcel Moolenaar OSIG2SIG(uap->mask, set); 1219e77daab1SJohn Baldwin error = kern_sigprocmask(td, uap->how, &set, &oset, 1); 1220b40ce416SJulian Elischer SIG2OSIG(oset, td->td_retval[0]); 1221df8bae1dSRodney W. Grimes return (error); 1222df8bae1dSRodney W. Grimes } 122331c8f3f0SMarcel Moolenaar #endif /* COMPAT_43 */ 1224df8bae1dSRodney W. Grimes 122526f9a767SRodney W. Grimes int 12268451d0ddSKip Macy sys_sigwait(struct thread *td, struct sigwait_args *uap) 1227a447cd8bSJeff Roberson { 12289104847fSDavid Xu ksiginfo_t ksi; 1229a447cd8bSJeff Roberson sigset_t set; 1230a447cd8bSJeff Roberson int error; 1231a447cd8bSJeff Roberson 1232a447cd8bSJeff Roberson error = copyin(uap->set, &set, sizeof(set)); 123336939a0aSDavid Xu if (error) { 123436939a0aSDavid Xu td->td_retval[0] = error; 123536939a0aSDavid Xu return (0); 123636939a0aSDavid Xu } 1237a447cd8bSJeff Roberson 12389104847fSDavid Xu error = kern_sigtimedwait(td, set, &ksi, NULL); 123936939a0aSDavid Xu if (error) { 1240acced8b0SKonstantin Belousov /* 1241acced8b0SKonstantin Belousov * sigwait() function shall not return EINTR, but 1242acced8b0SKonstantin Belousov * the syscall does. Non-ancient libc provides the 1243acced8b0SKonstantin Belousov * wrapper which hides EINTR. Otherwise, EINTR return 1244acced8b0SKonstantin Belousov * is used by libthr to handle required cancellation 1245acced8b0SKonstantin Belousov * point in the sigwait(). 1246acced8b0SKonstantin Belousov */ 12478e9a54eeSKonstantin Belousov if (error == EINTR && td->td_proc->p_osrel < P_OSREL_SIGWAIT) 1248afb36e28SKonstantin Belousov return (ERESTART); 124936939a0aSDavid Xu td->td_retval[0] = error; 125036939a0aSDavid Xu return (0); 125136939a0aSDavid Xu } 1252a447cd8bSJeff Roberson 12539104847fSDavid Xu error = copyout(&ksi.ksi_signo, uap->sig, sizeof(ksi.ksi_signo)); 125436939a0aSDavid Xu td->td_retval[0] = error; 125536939a0aSDavid Xu return (0); 1256a447cd8bSJeff Roberson } 12570c14ff0eSRobert Watson 1258a447cd8bSJeff Roberson int 12598451d0ddSKip Macy sys_sigtimedwait(struct thread *td, struct sigtimedwait_args *uap) 1260a447cd8bSJeff Roberson { 1261a447cd8bSJeff Roberson struct timespec ts; 1262a447cd8bSJeff Roberson struct timespec *timeout; 1263a447cd8bSJeff Roberson sigset_t set; 12649104847fSDavid Xu ksiginfo_t ksi; 1265a447cd8bSJeff Roberson int error; 1266a447cd8bSJeff Roberson 1267a447cd8bSJeff Roberson if (uap->timeout) { 1268a447cd8bSJeff Roberson error = copyin(uap->timeout, &ts, sizeof(ts)); 1269a447cd8bSJeff Roberson if (error) 1270a447cd8bSJeff Roberson return (error); 1271a447cd8bSJeff Roberson 1272a447cd8bSJeff Roberson timeout = &ts; 1273a447cd8bSJeff Roberson } else 1274a447cd8bSJeff Roberson timeout = NULL; 1275a447cd8bSJeff Roberson 1276a447cd8bSJeff Roberson error = copyin(uap->set, &set, sizeof(set)); 1277a447cd8bSJeff Roberson if (error) 1278a447cd8bSJeff Roberson return (error); 1279a447cd8bSJeff Roberson 12809104847fSDavid Xu error = kern_sigtimedwait(td, set, &ksi, timeout); 1281a447cd8bSJeff Roberson if (error) 1282a447cd8bSJeff Roberson return (error); 12839dde3bc9SDavid Xu 1284418228dfSDavid Xu if (uap->info) 12859104847fSDavid Xu error = copyout(&ksi.ksi_info, uap->info, sizeof(siginfo_t)); 12869104847fSDavid Xu 12879104847fSDavid Xu if (error == 0) 12889104847fSDavid Xu td->td_retval[0] = ksi.ksi_signo; 1289a447cd8bSJeff Roberson return (error); 1290a447cd8bSJeff Roberson } 1291a447cd8bSJeff Roberson 1292a447cd8bSJeff Roberson int 12938451d0ddSKip Macy sys_sigwaitinfo(struct thread *td, struct sigwaitinfo_args *uap) 1294a447cd8bSJeff Roberson { 12959104847fSDavid Xu ksiginfo_t ksi; 1296a447cd8bSJeff Roberson sigset_t set; 1297a447cd8bSJeff Roberson int error; 1298a447cd8bSJeff Roberson 1299a447cd8bSJeff Roberson error = copyin(uap->set, &set, sizeof(set)); 1300a447cd8bSJeff Roberson if (error) 1301a447cd8bSJeff Roberson return (error); 1302a447cd8bSJeff Roberson 13039104847fSDavid Xu error = kern_sigtimedwait(td, set, &ksi, NULL); 1304a447cd8bSJeff Roberson if (error) 1305a447cd8bSJeff Roberson return (error); 1306a447cd8bSJeff Roberson 1307418228dfSDavid Xu if (uap->info) 13089104847fSDavid Xu error = copyout(&ksi.ksi_info, uap->info, sizeof(siginfo_t)); 13099104847fSDavid Xu 13109104847fSDavid Xu if (error == 0) 13119104847fSDavid Xu td->td_retval[0] = ksi.ksi_signo; 1312a447cd8bSJeff Roberson return (error); 1313a447cd8bSJeff Roberson } 1314a447cd8bSJeff Roberson 131586be94fcSTycho Nightingale static void 131686be94fcSTycho Nightingale proc_td_siginfo_capture(struct thread *td, siginfo_t *si) 131786be94fcSTycho Nightingale { 131886be94fcSTycho Nightingale struct thread *thr; 131986be94fcSTycho Nightingale 132086be94fcSTycho Nightingale FOREACH_THREAD_IN_PROC(td->td_proc, thr) { 132186be94fcSTycho Nightingale if (thr == td) 132286be94fcSTycho Nightingale thr->td_si = *si; 132386be94fcSTycho Nightingale else 132486be94fcSTycho Nightingale thr->td_si.si_signo = 0; 132586be94fcSTycho Nightingale } 132686be94fcSTycho Nightingale } 132786be94fcSTycho Nightingale 1328c6511aeaSDavid Xu int 13299104847fSDavid Xu kern_sigtimedwait(struct thread *td, sigset_t waitset, ksiginfo_t *ksi, 1330a447cd8bSJeff Roberson struct timespec *timeout) 1331a447cd8bSJeff Roberson { 13323074d1b4SDavid Xu struct sigacts *ps; 1333407af02bSDavid Xu sigset_t saved_mask, new_block; 1334a447cd8bSJeff Roberson struct proc *p; 13354a700f3cSDmitry Chagin int error, sig, timevalid = 0; 13364a700f3cSDmitry Chagin sbintime_t sbt, precision, tsbt; 13374a700f3cSDmitry Chagin struct timespec ts; 1338ef401a85SKonstantin Belousov bool traced; 1339a447cd8bSJeff Roberson 1340a447cd8bSJeff Roberson p = td->td_proc; 1341a447cd8bSJeff Roberson error = 0; 1342ef401a85SKonstantin Belousov traced = false; 1343a447cd8bSJeff Roberson 1344dbec10e0SJonathan T. Looney /* Ensure the sigfastblock value is up to date. */ 1345dbec10e0SJonathan T. Looney sigfastblock_fetch(td); 1346dbec10e0SJonathan T. Looney 1347407af02bSDavid Xu if (timeout != NULL) { 13481089f031SDavid Xu if (timeout->tv_nsec >= 0 && timeout->tv_nsec < 1000000000) { 13491089f031SDavid Xu timevalid = 1; 13504a700f3cSDmitry Chagin ts = *timeout; 13514a700f3cSDmitry Chagin if (ts.tv_sec < INT32_MAX / 2) { 13524a700f3cSDmitry Chagin tsbt = tstosbt(ts); 13534a700f3cSDmitry Chagin precision = tsbt; 13544a700f3cSDmitry Chagin precision >>= tc_precexp; 13554a700f3cSDmitry Chagin if (TIMESEL(&sbt, tsbt)) 13564a700f3cSDmitry Chagin sbt += tc_tick_sbt; 13574a700f3cSDmitry Chagin sbt += tsbt; 13584a700f3cSDmitry Chagin } else 13594a700f3cSDmitry Chagin precision = sbt = 0; 13601089f031SDavid Xu } 13614a700f3cSDmitry Chagin } else 13624a700f3cSDmitry Chagin precision = sbt = 0; 1363407af02bSDavid Xu ksiginfo_init(ksi); 1364407af02bSDavid Xu /* Some signals can not be waited for. */ 1365407af02bSDavid Xu SIG_CANTMASK(waitset); 1366407af02bSDavid Xu ps = p->p_sigacts; 1367407af02bSDavid Xu PROC_LOCK(p); 1368407af02bSDavid Xu saved_mask = td->td_sigmask; 1369407af02bSDavid Xu SIGSETNAND(td->td_sigmask, waitset); 1370bc387624SKonstantin Belousov if ((p->p_sysent->sv_flags & SV_SIG_DISCIGN) != 0 || 1371b599982bSKonstantin Belousov !kern_sig_discard_ign) { 1372b599982bSKonstantin Belousov thread_lock(td); 1373b599982bSKonstantin Belousov td->td_flags |= TDF_SIGWAIT; 1374b599982bSKonstantin Belousov thread_unlock(td); 1375b599982bSKonstantin Belousov } 1376407af02bSDavid Xu for (;;) { 13773074d1b4SDavid Xu mtx_lock(&ps->ps_mtx); 13783cf3b9f0SJohn Baldwin sig = cursig(td); 13793074d1b4SDavid Xu mtx_unlock(&ps->ps_mtx); 138046e47c4fSKonstantin Belousov KASSERT(sig >= 0, ("sig %d", sig)); 1381407af02bSDavid Xu if (sig != 0 && SIGISMEMBER(waitset, sig)) { 1382407af02bSDavid Xu if (sigqueue_get(&td->td_sigqueue, sig, ksi) != 0 || 1383407af02bSDavid Xu sigqueue_get(&p->p_sigqueue, sig, ksi) != 0) { 1384407af02bSDavid Xu error = 0; 1385407af02bSDavid Xu break; 13863074d1b4SDavid Xu } 13877e0221a2SDavid Xu } 13887e0221a2SDavid Xu 1389407af02bSDavid Xu if (error != 0) 1390407af02bSDavid Xu break; 13913074d1b4SDavid Xu 1392a447cd8bSJeff Roberson /* 1393a447cd8bSJeff Roberson * POSIX says this must be checked after looking for pending 1394a447cd8bSJeff Roberson * signals. 1395a447cd8bSJeff Roberson */ 13964a700f3cSDmitry Chagin if (timeout != NULL && !timevalid) { 1397a447cd8bSJeff Roberson error = EINVAL; 1398407af02bSDavid Xu break; 1399a447cd8bSJeff Roberson } 1400a447cd8bSJeff Roberson 1401ef401a85SKonstantin Belousov if (traced) { 1402ef401a85SKonstantin Belousov error = EINTR; 1403ef401a85SKonstantin Belousov break; 1404ef401a85SKonstantin Belousov } 1405ef401a85SKonstantin Belousov 14064a700f3cSDmitry Chagin error = msleep_sbt(&p->p_sigacts, &p->p_mtx, PPAUSE | PCATCH, 14074a700f3cSDmitry Chagin "sigwait", sbt, precision, C_ABSOLUTE); 1408407af02bSDavid Xu 1409afb36e28SKonstantin Belousov /* The syscalls can not be restarted. */ 1410afb36e28SKonstantin Belousov if (error == ERESTART) 14113074d1b4SDavid Xu error = EINTR; 1412afb36e28SKonstantin Belousov 1413ef401a85SKonstantin Belousov /* 1414ef401a85SKonstantin Belousov * If PTRACE_SCE or PTRACE_SCX were set after 1415ef401a85SKonstantin Belousov * userspace entered the syscall, return spurious 1416ef401a85SKonstantin Belousov * EINTR after wait was done. Only do this as last 1417ef401a85SKonstantin Belousov * resort after rechecking for possible queued signals 1418ef401a85SKonstantin Belousov * and expired timeouts. 1419ef401a85SKonstantin Belousov */ 1420ef401a85SKonstantin Belousov if (error == 0 && (p->p_ptevents & PTRACE_SYSCALL) != 0) 1421ef401a85SKonstantin Belousov traced = true; 1422407af02bSDavid Xu } 1423b599982bSKonstantin Belousov thread_lock(td); 1424b599982bSKonstantin Belousov td->td_flags &= ~TDF_SIGWAIT; 1425b599982bSKonstantin Belousov thread_unlock(td); 14269dde3bc9SDavid Xu 1427407af02bSDavid Xu new_block = saved_mask; 1428407af02bSDavid Xu SIGSETNAND(new_block, td->td_sigmask); 1429407af02bSDavid Xu td->td_sigmask = saved_mask; 1430407af02bSDavid Xu /* 1431407af02bSDavid Xu * Fewer signals can be delivered to us, reschedule signal 1432407af02bSDavid Xu * notification. 1433407af02bSDavid Xu */ 1434407af02bSDavid Xu if (p->p_numthreads != 1) 1435407af02bSDavid Xu reschedule_signals(p, new_block, 0); 14365d217f17SJohn Birrell 1437407af02bSDavid Xu if (error == 0) { 143836160958SMark Johnston SDT_PROBE2(proc, , , signal__clear, sig, ksi); 14395d217f17SJohn Birrell 144056c06c4bSDavid Xu if (ksi->ksi_code == SI_TIMER) 144156c06c4bSDavid Xu itimer_accept(p, ksi->ksi_timerid, ksi); 14427e0221a2SDavid Xu 14437e0221a2SDavid Xu #ifdef KTRACE 14447e0221a2SDavid Xu if (KTRPOINT(td, KTR_PSIG)) { 14457e0221a2SDavid Xu sig_t action; 14467e0221a2SDavid Xu 14473074d1b4SDavid Xu mtx_lock(&ps->ps_mtx); 1448a447cd8bSJeff Roberson action = ps->ps_sigact[_SIG_IDX(sig)]; 144990af4afaSJohn Baldwin mtx_unlock(&ps->ps_mtx); 145061009552SJilles Tjoelker ktrpsig(sig, action, &td->td_sigmask, ksi->ksi_code); 14517e0221a2SDavid Xu } 1452a447cd8bSJeff Roberson #endif 145386be94fcSTycho Nightingale if (sig == SIGKILL) { 145486be94fcSTycho Nightingale proc_td_siginfo_capture(td, &ksi->ksi_info); 14557e0221a2SDavid Xu sigexit(td, sig); 14563074d1b4SDavid Xu } 145786be94fcSTycho Nightingale } 1458a447cd8bSJeff Roberson PROC_UNLOCK(p); 1459a447cd8bSJeff Roberson return (error); 1460a447cd8bSJeff Roberson } 1461a447cd8bSJeff Roberson 14629104847fSDavid Xu #ifndef _SYS_SYSPROTO_H_ 14639104847fSDavid Xu struct sigpending_args { 14649104847fSDavid Xu sigset_t *set; 14659104847fSDavid Xu }; 14669104847fSDavid Xu #endif 1467a447cd8bSJeff Roberson int 1468e052a8b9SEd Maste sys_sigpending(struct thread *td, struct sigpending_args *uap) 1469df8bae1dSRodney W. Grimes { 1470b40ce416SJulian Elischer struct proc *p = td->td_proc; 14719104847fSDavid Xu sigset_t pending; 1472df8bae1dSRodney W. Grimes 1473628d2653SJohn Baldwin PROC_LOCK(p); 14749104847fSDavid Xu pending = p->p_sigqueue.sq_signals; 14759104847fSDavid Xu SIGSETOR(pending, td->td_sigqueue.sq_signals); 1476628d2653SJohn Baldwin PROC_UNLOCK(p); 14779104847fSDavid Xu return (copyout(&pending, uap->set, sizeof(sigset_t))); 14782c42a146SMarcel Moolenaar } 14792c42a146SMarcel Moolenaar 148031c8f3f0SMarcel Moolenaar #ifdef COMPAT_43 /* XXX - COMPAT_FBSD3 */ 14812c42a146SMarcel Moolenaar #ifndef _SYS_SYSPROTO_H_ 14822c42a146SMarcel Moolenaar struct osigpending_args { 14832c42a146SMarcel Moolenaar int dummy; 14842c42a146SMarcel Moolenaar }; 14852c42a146SMarcel Moolenaar #endif 14862c42a146SMarcel Moolenaar int 1487e052a8b9SEd Maste osigpending(struct thread *td, struct osigpending_args *uap) 14882c42a146SMarcel Moolenaar { 1489b40ce416SJulian Elischer struct proc *p = td->td_proc; 14909104847fSDavid Xu sigset_t pending; 1491b40ce416SJulian Elischer 1492628d2653SJohn Baldwin PROC_LOCK(p); 14939104847fSDavid Xu pending = p->p_sigqueue.sq_signals; 14949104847fSDavid Xu SIGSETOR(pending, td->td_sigqueue.sq_signals); 1495628d2653SJohn Baldwin PROC_UNLOCK(p); 14969104847fSDavid Xu SIG2OSIG(pending, td->td_retval[0]); 1497df8bae1dSRodney W. Grimes return (0); 1498df8bae1dSRodney W. Grimes } 149931c8f3f0SMarcel Moolenaar #endif /* COMPAT_43 */ 1500df8bae1dSRodney W. Grimes 15011930e303SPoul-Henning Kamp #if defined(COMPAT_43) 1502df8bae1dSRodney W. Grimes /* 1503df8bae1dSRodney W. Grimes * Generalized interface signal handler, 4.3-compatible. 1504df8bae1dSRodney W. Grimes */ 1505d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1506df8bae1dSRodney W. Grimes struct osigvec_args { 1507df8bae1dSRodney W. Grimes int signum; 1508df8bae1dSRodney W. Grimes struct sigvec *nsv; 1509df8bae1dSRodney W. Grimes struct sigvec *osv; 1510df8bae1dSRodney W. Grimes }; 1511d2d3e875SBruce Evans #endif 1512df8bae1dSRodney W. Grimes /* ARGSUSED */ 151326f9a767SRodney W. Grimes int 1514e052a8b9SEd Maste osigvec(struct thread *td, struct osigvec_args *uap) 1515df8bae1dSRodney W. Grimes { 1516df8bae1dSRodney W. Grimes struct sigvec vec; 15172c42a146SMarcel Moolenaar struct sigaction nsa, osa; 1518e052a8b9SEd Maste struct sigaction *nsap, *osap; 15192c42a146SMarcel Moolenaar int error; 1520df8bae1dSRodney W. Grimes 15216f841fb7SMarcel Moolenaar if (uap->signum <= 0 || uap->signum >= ONSIG) 15226f841fb7SMarcel Moolenaar return (EINVAL); 15236f841fb7SMarcel Moolenaar nsap = (uap->nsv != NULL) ? &nsa : NULL; 15246f841fb7SMarcel Moolenaar osap = (uap->osv != NULL) ? &osa : NULL; 15252c42a146SMarcel Moolenaar if (nsap) { 15266f841fb7SMarcel Moolenaar error = copyin(uap->nsv, &vec, sizeof(vec)); 15272c42a146SMarcel Moolenaar if (error) 1528df8bae1dSRodney W. Grimes return (error); 15292c42a146SMarcel Moolenaar nsap->sa_handler = vec.sv_handler; 15302c42a146SMarcel Moolenaar OSIG2SIG(vec.sv_mask, nsap->sa_mask); 15312c42a146SMarcel Moolenaar nsap->sa_flags = vec.sv_flags; 15322c42a146SMarcel Moolenaar nsap->sa_flags ^= SA_RESTART; /* opposite of SV_INTERRUPT */ 1533df8bae1dSRodney W. Grimes } 15345edadff9SJohn Baldwin error = kern_sigaction(td, uap->signum, nsap, osap, KSA_OSIGSET); 15352c42a146SMarcel Moolenaar if (osap && !error) { 15362c42a146SMarcel Moolenaar vec.sv_handler = osap->sa_handler; 15372c42a146SMarcel Moolenaar SIG2OSIG(osap->sa_mask, vec.sv_mask); 15382c42a146SMarcel Moolenaar vec.sv_flags = osap->sa_flags; 15392c42a146SMarcel Moolenaar vec.sv_flags &= ~SA_NOCLDWAIT; 15402c42a146SMarcel Moolenaar vec.sv_flags ^= SA_RESTART; 15416f841fb7SMarcel Moolenaar error = copyout(&vec, uap->osv, sizeof(vec)); 15422c42a146SMarcel Moolenaar } 15432c42a146SMarcel Moolenaar return (error); 1544df8bae1dSRodney W. Grimes } 1545df8bae1dSRodney W. Grimes 1546d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1547df8bae1dSRodney W. Grimes struct osigblock_args { 1548df8bae1dSRodney W. Grimes int mask; 1549df8bae1dSRodney W. Grimes }; 1550d2d3e875SBruce Evans #endif 155126f9a767SRodney W. Grimes int 1552e052a8b9SEd Maste osigblock(struct thread *td, struct osigblock_args *uap) 1553df8bae1dSRodney W. Grimes { 1554d6e029adSKonstantin Belousov sigset_t set, oset; 1555df8bae1dSRodney W. Grimes 15562c42a146SMarcel Moolenaar OSIG2SIG(uap->mask, set); 1557d6e029adSKonstantin Belousov kern_sigprocmask(td, SIG_BLOCK, &set, &oset, 0); 1558d6e029adSKonstantin Belousov SIG2OSIG(oset, td->td_retval[0]); 1559df8bae1dSRodney W. Grimes return (0); 1560df8bae1dSRodney W. Grimes } 1561df8bae1dSRodney W. Grimes 1562d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1563df8bae1dSRodney W. Grimes struct osigsetmask_args { 1564df8bae1dSRodney W. Grimes int mask; 1565df8bae1dSRodney W. Grimes }; 1566d2d3e875SBruce Evans #endif 156726f9a767SRodney W. Grimes int 1568e052a8b9SEd Maste osigsetmask(struct thread *td, struct osigsetmask_args *uap) 1569df8bae1dSRodney W. Grimes { 1570d6e029adSKonstantin Belousov sigset_t set, oset; 1571df8bae1dSRodney W. Grimes 15722c42a146SMarcel Moolenaar OSIG2SIG(uap->mask, set); 1573d6e029adSKonstantin Belousov kern_sigprocmask(td, SIG_SETMASK, &set, &oset, 0); 1574d6e029adSKonstantin Belousov SIG2OSIG(oset, td->td_retval[0]); 1575df8bae1dSRodney W. Grimes return (0); 1576df8bae1dSRodney W. Grimes } 15771930e303SPoul-Henning Kamp #endif /* COMPAT_43 */ 1578df8bae1dSRodney W. Grimes 1579df8bae1dSRodney W. Grimes /* 1580873fbcd7SRobert Watson * Suspend calling thread until signal, providing mask to be set in the 1581873fbcd7SRobert Watson * meantime. 1582df8bae1dSRodney W. Grimes */ 1583d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1584df8bae1dSRodney W. Grimes struct sigsuspend_args { 15852c42a146SMarcel Moolenaar const sigset_t *sigmask; 1586df8bae1dSRodney W. Grimes }; 1587d2d3e875SBruce Evans #endif 1588df8bae1dSRodney W. Grimes /* ARGSUSED */ 158926f9a767SRodney W. Grimes int 1590e052a8b9SEd Maste sys_sigsuspend(struct thread *td, struct sigsuspend_args *uap) 1591df8bae1dSRodney W. Grimes { 15922c42a146SMarcel Moolenaar sigset_t mask; 15932c42a146SMarcel Moolenaar int error; 15942c42a146SMarcel Moolenaar 15956f841fb7SMarcel Moolenaar error = copyin(uap->sigmask, &mask, sizeof(mask)); 15962c42a146SMarcel Moolenaar if (error) 15972c42a146SMarcel Moolenaar return (error); 15988f19eb88SIan Dowse return (kern_sigsuspend(td, mask)); 15998f19eb88SIan Dowse } 16008f19eb88SIan Dowse 16018f19eb88SIan Dowse int 16028f19eb88SIan Dowse kern_sigsuspend(struct thread *td, sigset_t mask) 16038f19eb88SIan Dowse { 16048f19eb88SIan Dowse struct proc *p = td->td_proc; 160584440afbSKonstantin Belousov int has_sig, sig; 1606df8bae1dSRodney W. Grimes 1607dbec10e0SJonathan T. Looney /* Ensure the sigfastblock value is up to date. */ 1608dbec10e0SJonathan T. Looney sigfastblock_fetch(td); 1609dbec10e0SJonathan T. Looney 1610df8bae1dSRodney W. Grimes /* 1611645682fdSLuoqi Chen * When returning from sigsuspend, we want 1612df8bae1dSRodney W. Grimes * the old mask to be restored after the 1613df8bae1dSRodney W. Grimes * signal handler has finished. Thus, we 1614df8bae1dSRodney W. Grimes * save it here and mark the sigacts structure 1615df8bae1dSRodney W. Grimes * to indicate this. 1616df8bae1dSRodney W. Grimes */ 1617628d2653SJohn Baldwin PROC_LOCK(p); 161884440afbSKonstantin Belousov kern_sigprocmask(td, SIG_SETMASK, &mask, &td->td_oldsigmask, 161984440afbSKonstantin Belousov SIGPROCMASK_PROC_LOCKED); 16205e26dcb5SJohn Baldwin td->td_pflags |= TDP_OLDMASK; 1621c6d31b83SKonstantin Belousov ast_sched(td, TDA_SIGSUSPEND); 162284440afbSKonstantin Belousov 162384440afbSKonstantin Belousov /* 162484440afbSKonstantin Belousov * Process signals now. Otherwise, we can get spurious wakeup 162584440afbSKonstantin Belousov * due to signal entered process queue, but delivered to other 162684440afbSKonstantin Belousov * thread. But sigsuspend should return only on signal 162784440afbSKonstantin Belousov * delivery. 162884440afbSKonstantin Belousov */ 1629afe1a688SKonstantin Belousov (p->p_sysent->sv_set_syscall_retval)(td, EINTR); 163084440afbSKonstantin Belousov for (has_sig = 0; !has_sig;) { 163184440afbSKonstantin Belousov while (msleep(&p->p_sigacts, &p->p_mtx, PPAUSE|PCATCH, "pause", 163284440afbSKonstantin Belousov 0) == 0) 16332c42a146SMarcel Moolenaar /* void */; 163484440afbSKonstantin Belousov thread_suspend_check(0); 163584440afbSKonstantin Belousov mtx_lock(&p->p_sigacts->ps_mtx); 163646e47c4fSKonstantin Belousov while ((sig = cursig(td)) != 0) { 163746e47c4fSKonstantin Belousov KASSERT(sig >= 0, ("sig %d", sig)); 163875c586a4SKonstantin Belousov has_sig += postsig(sig); 163946e47c4fSKonstantin Belousov } 164084440afbSKonstantin Belousov mtx_unlock(&p->p_sigacts->ps_mtx); 1641ef401a85SKonstantin Belousov 1642ef401a85SKonstantin Belousov /* 1643ef401a85SKonstantin Belousov * If PTRACE_SCE or PTRACE_SCX were set after 1644ef401a85SKonstantin Belousov * userspace entered the syscall, return spurious 1645ef401a85SKonstantin Belousov * EINTR. 1646ef401a85SKonstantin Belousov */ 1647ef401a85SKonstantin Belousov if ((p->p_ptevents & PTRACE_SYSCALL) != 0) 1648ef401a85SKonstantin Belousov has_sig += 1; 164984440afbSKonstantin Belousov } 1650628d2653SJohn Baldwin PROC_UNLOCK(p); 16512dd9ea6fSKonstantin Belousov td->td_errno = EINTR; 16522dd9ea6fSKonstantin Belousov td->td_pflags |= TDP_NERRNO; 165375c586a4SKonstantin Belousov return (EJUSTRETURN); 16542c42a146SMarcel Moolenaar } 16552c42a146SMarcel Moolenaar 165631c8f3f0SMarcel Moolenaar #ifdef COMPAT_43 /* XXX - COMPAT_FBSD3 */ 165797563428SAlexander Kabaev /* 165897563428SAlexander Kabaev * Compatibility sigsuspend call for old binaries. Note nonstandard calling 165997563428SAlexander Kabaev * convention: libc stub passes mask, not pointer, to save a copyin. 166097563428SAlexander Kabaev */ 16612c42a146SMarcel Moolenaar #ifndef _SYS_SYSPROTO_H_ 16622c42a146SMarcel Moolenaar struct osigsuspend_args { 16632c42a146SMarcel Moolenaar osigset_t mask; 16642c42a146SMarcel Moolenaar }; 16652c42a146SMarcel Moolenaar #endif 16662c42a146SMarcel Moolenaar /* ARGSUSED */ 16672c42a146SMarcel Moolenaar int 1668e052a8b9SEd Maste osigsuspend(struct thread *td, struct osigsuspend_args *uap) 16692c42a146SMarcel Moolenaar { 1670645682fdSLuoqi Chen sigset_t mask; 16712c42a146SMarcel Moolenaar 1672645682fdSLuoqi Chen OSIG2SIG(uap->mask, mask); 167384440afbSKonstantin Belousov return (kern_sigsuspend(td, mask)); 1674df8bae1dSRodney W. Grimes } 167531c8f3f0SMarcel Moolenaar #endif /* COMPAT_43 */ 1676df8bae1dSRodney W. Grimes 16771930e303SPoul-Henning Kamp #if defined(COMPAT_43) 1678d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1679df8bae1dSRodney W. Grimes struct osigstack_args { 1680df8bae1dSRodney W. Grimes struct sigstack *nss; 1681df8bae1dSRodney W. Grimes struct sigstack *oss; 1682df8bae1dSRodney W. Grimes }; 1683d2d3e875SBruce Evans #endif 1684df8bae1dSRodney W. Grimes /* ARGSUSED */ 168526f9a767SRodney W. Grimes int 1686e052a8b9SEd Maste osigstack(struct thread *td, struct osigstack_args *uap) 1687df8bae1dSRodney W. Grimes { 16885afe0c99SJohn Baldwin struct sigstack nss, oss; 1689fb99ab88SMatthew Dillon int error = 0; 1690fb99ab88SMatthew Dillon 1691d034d459SMarcel Moolenaar if (uap->nss != NULL) { 16925afe0c99SJohn Baldwin error = copyin(uap->nss, &nss, sizeof(nss)); 16935afe0c99SJohn Baldwin if (error) 16945afe0c99SJohn Baldwin return (error); 1695df8bae1dSRodney W. Grimes } 1696a30ec4b9SDavid Xu oss.ss_sp = td->td_sigstk.ss_sp; 16975afe0c99SJohn Baldwin oss.ss_onstack = sigonstack(cpu_getstack(td)); 16985afe0c99SJohn Baldwin if (uap->nss != NULL) { 1699a30ec4b9SDavid Xu td->td_sigstk.ss_sp = nss.ss_sp; 1700a30ec4b9SDavid Xu td->td_sigstk.ss_size = 0; 1701a30ec4b9SDavid Xu td->td_sigstk.ss_flags |= nss.ss_onstack & SS_ONSTACK; 1702a30ec4b9SDavid Xu td->td_pflags |= TDP_ALTSTACK; 17035afe0c99SJohn Baldwin } 17045afe0c99SJohn Baldwin if (uap->oss != NULL) 17055afe0c99SJohn Baldwin error = copyout(&oss, uap->oss, sizeof(oss)); 17065afe0c99SJohn Baldwin 1707fb99ab88SMatthew Dillon return (error); 1708df8bae1dSRodney W. Grimes } 17091930e303SPoul-Henning Kamp #endif /* COMPAT_43 */ 1710df8bae1dSRodney W. Grimes 1711d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1712df8bae1dSRodney W. Grimes struct sigaltstack_args { 17132c42a146SMarcel Moolenaar stack_t *ss; 17142c42a146SMarcel Moolenaar stack_t *oss; 1715df8bae1dSRodney W. Grimes }; 1716d2d3e875SBruce Evans #endif 1717df8bae1dSRodney W. Grimes /* ARGSUSED */ 171826f9a767SRodney W. Grimes int 1719e052a8b9SEd Maste sys_sigaltstack(struct thread *td, struct sigaltstack_args *uap) 1720df8bae1dSRodney W. Grimes { 17218f19eb88SIan Dowse stack_t ss, oss; 17228f19eb88SIan Dowse int error; 17238f19eb88SIan Dowse 17248f19eb88SIan Dowse if (uap->ss != NULL) { 17258f19eb88SIan Dowse error = copyin(uap->ss, &ss, sizeof(ss)); 17268f19eb88SIan Dowse if (error) 17278f19eb88SIan Dowse return (error); 17288f19eb88SIan Dowse } 17298f19eb88SIan Dowse error = kern_sigaltstack(td, (uap->ss != NULL) ? &ss : NULL, 17308f19eb88SIan Dowse (uap->oss != NULL) ? &oss : NULL); 17318f19eb88SIan Dowse if (error) 17328f19eb88SIan Dowse return (error); 17338f19eb88SIan Dowse if (uap->oss != NULL) 17348f19eb88SIan Dowse error = copyout(&oss, uap->oss, sizeof(stack_t)); 17358f19eb88SIan Dowse return (error); 17368f19eb88SIan Dowse } 17378f19eb88SIan Dowse 17388f19eb88SIan Dowse int 17398f19eb88SIan Dowse kern_sigaltstack(struct thread *td, stack_t *ss, stack_t *oss) 17408f19eb88SIan Dowse { 1741b40ce416SJulian Elischer struct proc *p = td->td_proc; 1742fb99ab88SMatthew Dillon int oonstack; 1743fb99ab88SMatthew Dillon 1744b40ce416SJulian Elischer oonstack = sigonstack(cpu_getstack(td)); 1745d034d459SMarcel Moolenaar 17468f19eb88SIan Dowse if (oss != NULL) { 1747a30ec4b9SDavid Xu *oss = td->td_sigstk; 1748a30ec4b9SDavid Xu oss->ss_flags = (td->td_pflags & TDP_ALTSTACK) 1749d034d459SMarcel Moolenaar ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE; 1750df8bae1dSRodney W. Grimes } 1751d034d459SMarcel Moolenaar 17528f19eb88SIan Dowse if (ss != NULL) { 1753a30ec4b9SDavid Xu if (oonstack) 1754cf60731bSJohn Baldwin return (EPERM); 1755a30ec4b9SDavid Xu if ((ss->ss_flags & ~SS_DISABLE) != 0) 1756cf60731bSJohn Baldwin return (EINVAL); 17578f19eb88SIan Dowse if (!(ss->ss_flags & SS_DISABLE)) { 17589104847fSDavid Xu if (ss->ss_size < p->p_sysent->sv_minsigstksz) 1759cf60731bSJohn Baldwin return (ENOMEM); 17609104847fSDavid Xu 1761a30ec4b9SDavid Xu td->td_sigstk = *ss; 1762a30ec4b9SDavid Xu td->td_pflags |= TDP_ALTSTACK; 1763628d2653SJohn Baldwin } else { 1764a30ec4b9SDavid Xu td->td_pflags &= ~TDP_ALTSTACK; 1765628d2653SJohn Baldwin } 1766d034d459SMarcel Moolenaar } 1767cf60731bSJohn Baldwin return (0); 1768df8bae1dSRodney W. Grimes } 1769df8bae1dSRodney W. Grimes 17700cc9fb75SKonstantin Belousov struct killpg1_ctx { 17710cc9fb75SKonstantin Belousov struct thread *td; 17720cc9fb75SKonstantin Belousov ksiginfo_t *ksi; 17730cc9fb75SKonstantin Belousov int sig; 17740cc9fb75SKonstantin Belousov bool sent; 17750cc9fb75SKonstantin Belousov bool found; 17760cc9fb75SKonstantin Belousov int ret; 17770cc9fb75SKonstantin Belousov }; 17780cc9fb75SKonstantin Belousov 17790cc9fb75SKonstantin Belousov static void 17800cc9fb75SKonstantin Belousov killpg1_sendsig(struct proc *p, bool notself, struct killpg1_ctx *arg) 17810cc9fb75SKonstantin Belousov { 17820cc9fb75SKonstantin Belousov int err; 17830cc9fb75SKonstantin Belousov 17840cc9fb75SKonstantin Belousov if (p->p_pid <= 1 || (p->p_flag & P_SYSTEM) != 0 || 17850cc9fb75SKonstantin Belousov (notself && p == arg->td->td_proc) || p->p_state == PRS_NEW) 17860cc9fb75SKonstantin Belousov return; 17870cc9fb75SKonstantin Belousov PROC_LOCK(p); 17880cc9fb75SKonstantin Belousov err = p_cansignal(arg->td, p, arg->sig); 17890cc9fb75SKonstantin Belousov if (err == 0 && arg->sig != 0) 17900cc9fb75SKonstantin Belousov pksignal(p, arg->sig, arg->ksi); 17910cc9fb75SKonstantin Belousov PROC_UNLOCK(p); 17920cc9fb75SKonstantin Belousov if (err != ESRCH) 17930cc9fb75SKonstantin Belousov arg->found = true; 17940cc9fb75SKonstantin Belousov if (err == 0) 17950cc9fb75SKonstantin Belousov arg->sent = true; 17960cc9fb75SKonstantin Belousov else if (arg->ret == 0 && err != ESRCH && err != EPERM) 17970cc9fb75SKonstantin Belousov arg->ret = err; 17980cc9fb75SKonstantin Belousov } 17990cc9fb75SKonstantin Belousov 1800d93f860cSPoul-Henning Kamp /* 1801d93f860cSPoul-Henning Kamp * Common code for kill process group/broadcast kill. 1802d93f860cSPoul-Henning Kamp * cp is calling process. 1803d93f860cSPoul-Henning Kamp */ 180437c84183SPoul-Henning Kamp static int 1805a3de221dSKonstantin Belousov killpg1(struct thread *td, int sig, int pgid, int all, ksiginfo_t *ksi) 1806d93f860cSPoul-Henning Kamp { 1807a3de221dSKonstantin Belousov struct proc *p; 1808d93f860cSPoul-Henning Kamp struct pgrp *pgrp; 18090cc9fb75SKonstantin Belousov struct killpg1_ctx arg; 1810d93f860cSPoul-Henning Kamp 18110cc9fb75SKonstantin Belousov arg.td = td; 18120cc9fb75SKonstantin Belousov arg.ksi = ksi; 18130cc9fb75SKonstantin Belousov arg.sig = sig; 18140cc9fb75SKonstantin Belousov arg.sent = false; 18150cc9fb75SKonstantin Belousov arg.found = false; 18160cc9fb75SKonstantin Belousov arg.ret = 0; 1817553629ebSJake Burkholder if (all) { 1818d93f860cSPoul-Henning Kamp /* 1819d93f860cSPoul-Henning Kamp * broadcast 1820d93f860cSPoul-Henning Kamp */ 18211005a129SJohn Baldwin sx_slock(&allproc_lock); 18224f506694SXin LI FOREACH_PROC_IN_SYSTEM(p) { 18230cc9fb75SKonstantin Belousov killpg1_sendsig(p, true, &arg); 1824d93f860cSPoul-Henning Kamp } 18251005a129SJohn Baldwin sx_sunlock(&allproc_lock); 1826553629ebSJake Burkholder } else { 1827ba626c1dSJohn Baldwin sx_slock(&proctree_lock); 1828f591779bSSeigo Tanimura if (pgid == 0) { 1829d93f860cSPoul-Henning Kamp /* 1830d93f860cSPoul-Henning Kamp * zero pgid means send to my process group. 1831d93f860cSPoul-Henning Kamp */ 18329c1ab3e0SJohn Baldwin pgrp = td->td_proc->p_pgrp; 1833f591779bSSeigo Tanimura PGRP_LOCK(pgrp); 1834f591779bSSeigo Tanimura } else { 1835d93f860cSPoul-Henning Kamp pgrp = pgfind(pgid); 1836f591779bSSeigo Tanimura if (pgrp == NULL) { 1837ba626c1dSJohn Baldwin sx_sunlock(&proctree_lock); 1838d93f860cSPoul-Henning Kamp return (ESRCH); 1839d93f860cSPoul-Henning Kamp } 1840f591779bSSeigo Tanimura } 1841ba626c1dSJohn Baldwin sx_sunlock(&proctree_lock); 18422e3c8fcbSPoul-Henning Kamp LIST_FOREACH(p, &pgrp->pg_members, p_pglist) { 18430cc9fb75SKonstantin Belousov killpg1_sendsig(p, false, &arg); 1844d93f860cSPoul-Henning Kamp } 1845f591779bSSeigo Tanimura PGRP_UNLOCK(pgrp); 1846d93f860cSPoul-Henning Kamp } 18470cc9fb75SKonstantin Belousov MPASS(arg.ret != 0 || arg.found || !arg.sent); 18480cc9fb75SKonstantin Belousov if (arg.ret == 0 && !arg.sent) 18490cc9fb75SKonstantin Belousov arg.ret = arg.found ? EPERM : ESRCH; 18500cc9fb75SKonstantin Belousov return (arg.ret); 1851d93f860cSPoul-Henning Kamp } 1852d93f860cSPoul-Henning Kamp 1853d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1854df8bae1dSRodney W. Grimes struct kill_args { 1855df8bae1dSRodney W. Grimes int pid; 1856df8bae1dSRodney W. Grimes int signum; 1857df8bae1dSRodney W. Grimes }; 1858d2d3e875SBruce Evans #endif 1859df8bae1dSRodney W. Grimes /* ARGSUSED */ 186026f9a767SRodney W. Grimes int 18618451d0ddSKip Macy sys_kill(struct thread *td, struct kill_args *uap) 1862df8bae1dSRodney W. Grimes { 186334ad5ac2SEdward Tomasz Napierala 186434ad5ac2SEdward Tomasz Napierala return (kern_kill(td, uap->pid, uap->signum)); 186534ad5ac2SEdward Tomasz Napierala } 186634ad5ac2SEdward Tomasz Napierala 186734ad5ac2SEdward Tomasz Napierala int 186834ad5ac2SEdward Tomasz Napierala kern_kill(struct thread *td, pid_t pid, int signum) 186934ad5ac2SEdward Tomasz Napierala { 1870a3de221dSKonstantin Belousov ksiginfo_t ksi; 1871a3de221dSKonstantin Belousov struct proc *p; 187290af4afaSJohn Baldwin int error; 1873df8bae1dSRodney W. Grimes 18748890f5d0SPawel Jakub Dawidek /* 18758890f5d0SPawel Jakub Dawidek * A process in capability mode can send signals only to himself. 18768890f5d0SPawel Jakub Dawidek * The main rationale behind this is that abort(3) is implemented as 18778890f5d0SPawel Jakub Dawidek * kill(getpid(), SIGABRT). 18788890f5d0SPawel Jakub Dawidek */ 187934ad5ac2SEdward Tomasz Napierala if (IN_CAPABILITY_MODE(td) && pid != td->td_proc->p_pid) 18808890f5d0SPawel Jakub Dawidek return (ECAPMODE); 18818890f5d0SPawel Jakub Dawidek 188234ad5ac2SEdward Tomasz Napierala AUDIT_ARG_SIGNUM(signum); 188334ad5ac2SEdward Tomasz Napierala AUDIT_ARG_PID(pid); 188434ad5ac2SEdward Tomasz Napierala if ((u_int)signum > _SIG_MAXSIG) 1885df8bae1dSRodney W. Grimes return (EINVAL); 1886fb99ab88SMatthew Dillon 1887a3de221dSKonstantin Belousov ksiginfo_init(&ksi); 188834ad5ac2SEdward Tomasz Napierala ksi.ksi_signo = signum; 1889a3de221dSKonstantin Belousov ksi.ksi_code = SI_USER; 1890a3de221dSKonstantin Belousov ksi.ksi_pid = td->td_proc->p_pid; 1891a3de221dSKonstantin Belousov ksi.ksi_uid = td->td_ucred->cr_ruid; 1892a3de221dSKonstantin Belousov 189334ad5ac2SEdward Tomasz Napierala if (pid > 0) { 1894df8bae1dSRodney W. Grimes /* kill single process */ 189534ad5ac2SEdward Tomasz Napierala if ((p = pfind_any(pid)) == NULL) 189690af4afaSJohn Baldwin return (ESRCH); 189714961ba7SRobert Watson AUDIT_ARG_PROCESS(p); 189834ad5ac2SEdward Tomasz Napierala error = p_cansignal(td, p, signum); 189934ad5ac2SEdward Tomasz Napierala if (error == 0 && signum) 190034ad5ac2SEdward Tomasz Napierala pksignal(p, signum, &ksi); 1901628d2653SJohn Baldwin PROC_UNLOCK(p); 190290af4afaSJohn Baldwin return (error); 1903df8bae1dSRodney W. Grimes } 190434ad5ac2SEdward Tomasz Napierala switch (pid) { 1905df8bae1dSRodney W. Grimes case -1: /* broadcast signal */ 190634ad5ac2SEdward Tomasz Napierala return (killpg1(td, signum, 0, 1, &ksi)); 1907df8bae1dSRodney W. Grimes case 0: /* signal own process group */ 190834ad5ac2SEdward Tomasz Napierala return (killpg1(td, signum, 0, 0, &ksi)); 1909df8bae1dSRodney W. Grimes default: /* negative explicit process group */ 191034ad5ac2SEdward Tomasz Napierala return (killpg1(td, signum, -pid, 0, &ksi)); 1911df8bae1dSRodney W. Grimes } 191290af4afaSJohn Baldwin /* NOTREACHED */ 1913df8bae1dSRodney W. Grimes } 1914df8bae1dSRodney W. Grimes 1915cfb5f768SJonathan Anderson int 1916e052a8b9SEd Maste sys_pdkill(struct thread *td, struct pdkill_args *uap) 1917cfb5f768SJonathan Anderson { 1918cfb5f768SJonathan Anderson struct proc *p; 1919cfb5f768SJonathan Anderson int error; 1920cfb5f768SJonathan Anderson 1921cfb5f768SJonathan Anderson AUDIT_ARG_SIGNUM(uap->signum); 1922cfb5f768SJonathan Anderson AUDIT_ARG_FD(uap->fd); 1923cfb5f768SJonathan Anderson if ((u_int)uap->signum > _SIG_MAXSIG) 1924cfb5f768SJonathan Anderson return (EINVAL); 1925cfb5f768SJonathan Anderson 1926cbd92ce6SMatt Macy error = procdesc_find(td, uap->fd, &cap_pdkill_rights, &p); 1927cfb5f768SJonathan Anderson if (error) 1928cfb5f768SJonathan Anderson return (error); 1929cfb5f768SJonathan Anderson AUDIT_ARG_PROCESS(p); 1930cfb5f768SJonathan Anderson error = p_cansignal(td, p, uap->signum); 1931cfb5f768SJonathan Anderson if (error == 0 && uap->signum) 19328451d0ddSKip Macy kern_psignal(p, uap->signum); 1933cfb5f768SJonathan Anderson PROC_UNLOCK(p); 1934cfb5f768SJonathan Anderson return (error); 1935cfb5f768SJonathan Anderson } 1936cfb5f768SJonathan Anderson 19371930e303SPoul-Henning Kamp #if defined(COMPAT_43) 1938d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1939df8bae1dSRodney W. Grimes struct okillpg_args { 1940df8bae1dSRodney W. Grimes int pgid; 1941df8bae1dSRodney W. Grimes int signum; 1942df8bae1dSRodney W. Grimes }; 1943d2d3e875SBruce Evans #endif 1944df8bae1dSRodney W. Grimes /* ARGSUSED */ 194526f9a767SRodney W. Grimes int 1946a3de221dSKonstantin Belousov okillpg(struct thread *td, struct okillpg_args *uap) 1947df8bae1dSRodney W. Grimes { 1948a3de221dSKonstantin Belousov ksiginfo_t ksi; 1949df8bae1dSRodney W. Grimes 195014961ba7SRobert Watson AUDIT_ARG_SIGNUM(uap->signum); 195114961ba7SRobert Watson AUDIT_ARG_PID(uap->pgid); 19526c1534a7SPeter Wemm if ((u_int)uap->signum > _SIG_MAXSIG) 1953df8bae1dSRodney W. Grimes return (EINVAL); 19549104847fSDavid Xu 1955a3de221dSKonstantin Belousov ksiginfo_init(&ksi); 1956a3de221dSKonstantin Belousov ksi.ksi_signo = uap->signum; 1957a3de221dSKonstantin Belousov ksi.ksi_code = SI_USER; 1958a3de221dSKonstantin Belousov ksi.ksi_pid = td->td_proc->p_pid; 1959a3de221dSKonstantin Belousov ksi.ksi_uid = td->td_ucred->cr_ruid; 1960a3de221dSKonstantin Belousov return (killpg1(td, uap->signum, uap->pgid, 0, &ksi)); 1961df8bae1dSRodney W. Grimes } 19621930e303SPoul-Henning Kamp #endif /* COMPAT_43 */ 1963df8bae1dSRodney W. Grimes 19649104847fSDavid Xu #ifndef _SYS_SYSPROTO_H_ 19659104847fSDavid Xu struct sigqueue_args { 19669104847fSDavid Xu pid_t pid; 19679104847fSDavid Xu int signum; 19689104847fSDavid Xu /* union sigval */ void *value; 19699104847fSDavid Xu }; 19709104847fSDavid Xu #endif 19719104847fSDavid Xu int 19728451d0ddSKip Macy sys_sigqueue(struct thread *td, struct sigqueue_args *uap) 19739104847fSDavid Xu { 1974f19351aaSBrooks Davis union sigval sv; 1975f19351aaSBrooks Davis 1976f19351aaSBrooks Davis sv.sival_ptr = uap->value; 1977f19351aaSBrooks Davis 1978f19351aaSBrooks Davis return (kern_sigqueue(td, uap->pid, uap->signum, &sv)); 1979f19351aaSBrooks Davis } 1980f19351aaSBrooks Davis 1981f19351aaSBrooks Davis int 1982f19351aaSBrooks Davis kern_sigqueue(struct thread *td, pid_t pid, int signum, union sigval *value) 1983f19351aaSBrooks Davis { 19849104847fSDavid Xu ksiginfo_t ksi; 19859104847fSDavid Xu struct proc *p; 19869104847fSDavid Xu int error; 19879104847fSDavid Xu 1988f19351aaSBrooks Davis if ((u_int)signum > _SIG_MAXSIG) 19899104847fSDavid Xu return (EINVAL); 19909104847fSDavid Xu 19919104847fSDavid Xu /* 19929104847fSDavid Xu * Specification says sigqueue can only send signal to 19939104847fSDavid Xu * single process. 19949104847fSDavid Xu */ 1995f19351aaSBrooks Davis if (pid <= 0) 19969104847fSDavid Xu return (EINVAL); 19979104847fSDavid Xu 1998537d0fb1SMateusz Guzik if ((p = pfind_any(pid)) == NULL) 19999104847fSDavid Xu return (ESRCH); 2000f19351aaSBrooks Davis error = p_cansignal(td, p, signum); 2001f19351aaSBrooks Davis if (error == 0 && signum != 0) { 20029104847fSDavid Xu ksiginfo_init(&ksi); 2003a3de221dSKonstantin Belousov ksi.ksi_flags = KSI_SIGQ; 2004f19351aaSBrooks Davis ksi.ksi_signo = signum; 20059104847fSDavid Xu ksi.ksi_code = SI_QUEUE; 20069104847fSDavid Xu ksi.ksi_pid = td->td_proc->p_pid; 20079104847fSDavid Xu ksi.ksi_uid = td->td_ucred->cr_ruid; 2008f19351aaSBrooks Davis ksi.ksi_value = *value; 2009ad6eec7bSJohn Baldwin error = pksignal(p, ksi.ksi_signo, &ksi); 20109104847fSDavid Xu } 20119104847fSDavid Xu PROC_UNLOCK(p); 20129104847fSDavid Xu return (error); 20139104847fSDavid Xu } 20149104847fSDavid Xu 2015df8bae1dSRodney W. Grimes /* 2016df8bae1dSRodney W. Grimes * Send a signal to a process group. 2017df8bae1dSRodney W. Grimes */ 2018df8bae1dSRodney W. Grimes void 2019a3de221dSKonstantin Belousov gsignal(int pgid, int sig, ksiginfo_t *ksi) 2020df8bae1dSRodney W. Grimes { 2021df8bae1dSRodney W. Grimes struct pgrp *pgrp; 2022df8bae1dSRodney W. Grimes 2023f591779bSSeigo Tanimura if (pgid != 0) { 2024ba626c1dSJohn Baldwin sx_slock(&proctree_lock); 2025f591779bSSeigo Tanimura pgrp = pgfind(pgid); 2026ba626c1dSJohn Baldwin sx_sunlock(&proctree_lock); 2027f591779bSSeigo Tanimura if (pgrp != NULL) { 2028a3de221dSKonstantin Belousov pgsignal(pgrp, sig, 0, ksi); 2029f591779bSSeigo Tanimura PGRP_UNLOCK(pgrp); 2030f591779bSSeigo Tanimura } 2031f591779bSSeigo Tanimura } 2032df8bae1dSRodney W. Grimes } 2033df8bae1dSRodney W. Grimes 2034df8bae1dSRodney W. Grimes /* 2035df8bae1dSRodney W. Grimes * Send a signal to a process group. If checktty is 1, 2036df8bae1dSRodney W. Grimes * limit to members which have a controlling terminal. 2037df8bae1dSRodney W. Grimes */ 2038df8bae1dSRodney W. Grimes void 2039a3de221dSKonstantin Belousov pgsignal(struct pgrp *pgrp, int sig, int checkctty, ksiginfo_t *ksi) 2040df8bae1dSRodney W. Grimes { 2041a3de221dSKonstantin Belousov struct proc *p; 2042df8bae1dSRodney W. Grimes 2043628d2653SJohn Baldwin if (pgrp) { 2044f591779bSSeigo Tanimura PGRP_LOCK_ASSERT(pgrp, MA_OWNED); 2045628d2653SJohn Baldwin LIST_FOREACH(p, &pgrp->pg_members, p_pglist) { 2046628d2653SJohn Baldwin PROC_LOCK(p); 2047e806d352SJohn Baldwin if (p->p_state == PRS_NORMAL && 2048e806d352SJohn Baldwin (checkctty == 0 || p->p_flag & P_CONTROLT)) 2049a3de221dSKonstantin Belousov pksignal(p, sig, ksi); 2050628d2653SJohn Baldwin PROC_UNLOCK(p); 2051628d2653SJohn Baldwin } 2052628d2653SJohn Baldwin } 2053df8bae1dSRodney W. Grimes } 2054df8bae1dSRodney W. Grimes 2055e442f29fSKonstantin Belousov /* 2056e442f29fSKonstantin Belousov * Recalculate the signal mask and reset the signal disposition after 2057e442f29fSKonstantin Belousov * usermode frame for delivery is formed. Should be called after 2058e442f29fSKonstantin Belousov * mach-specific routine, because sysent->sv_sendsig() needs correct 2059e442f29fSKonstantin Belousov * ps_siginfo and signal mask. 2060e442f29fSKonstantin Belousov */ 2061e442f29fSKonstantin Belousov static void 2062e442f29fSKonstantin Belousov postsig_done(int sig, struct thread *td, struct sigacts *ps) 2063e442f29fSKonstantin Belousov { 2064e442f29fSKonstantin Belousov sigset_t mask; 2065e442f29fSKonstantin Belousov 2066e442f29fSKonstantin Belousov mtx_assert(&ps->ps_mtx, MA_OWNED); 2067e442f29fSKonstantin Belousov td->td_ru.ru_nsignals++; 2068e442f29fSKonstantin Belousov mask = ps->ps_catchmask[_SIG_IDX(sig)]; 2069e442f29fSKonstantin Belousov if (!SIGISMEMBER(ps->ps_signodefer, sig)) 2070e442f29fSKonstantin Belousov SIGADDSET(mask, sig); 2071e442f29fSKonstantin Belousov kern_sigprocmask(td, SIG_BLOCK, &mask, NULL, 2072e442f29fSKonstantin Belousov SIGPROCMASK_PROC_LOCKED | SIGPROCMASK_PS_LOCKED); 2073e442f29fSKonstantin Belousov if (SIGISMEMBER(ps->ps_sigreset, sig)) 2074e442f29fSKonstantin Belousov sigdflt(ps, sig); 2075e442f29fSKonstantin Belousov } 2076e442f29fSKonstantin Belousov 2077df8bae1dSRodney W. Grimes /* 20780c14ff0eSRobert Watson * Send a signal caused by a trap to the current thread. If it will be 20790c14ff0eSRobert Watson * caught immediately, deliver it with correct code. Otherwise, post it 20800c14ff0eSRobert Watson * normally. 2081df8bae1dSRodney W. Grimes */ 2082df8bae1dSRodney W. Grimes void 20839104847fSDavid Xu trapsignal(struct thread *td, ksiginfo_t *ksi) 2084df8bae1dSRodney W. Grimes { 20851bf4700bSJeff Roberson struct sigacts *ps; 20861bf4700bSJeff Roberson struct proc *p; 2087146fc63fSKonstantin Belousov sigset_t sigmask; 2088c5c981d4SMateusz Guzik int sig; 20891bf4700bSJeff Roberson 20901bf4700bSJeff Roberson p = td->td_proc; 20919104847fSDavid Xu sig = ksi->ksi_signo; 20929104847fSDavid Xu KASSERT(_SIG_VALID(sig), ("invalid signal")); 20939104847fSDavid Xu 2094a113b17fSKonstantin Belousov sigfastblock_fetch(td); 2095628d2653SJohn Baldwin PROC_LOCK(p); 2096ef3dab76STim J. Robbins ps = p->p_sigacts; 209790af4afaSJohn Baldwin mtx_lock(&ps->ps_mtx); 2098146fc63fSKonstantin Belousov sigmask = td->td_sigmask; 2099146fc63fSKonstantin Belousov if (td->td_sigblock_val != 0) 2100146fc63fSKonstantin Belousov SIGSETOR(sigmask, fastblock_mask); 210190af4afaSJohn Baldwin if ((p->p_flag & P_TRACED) == 0 && SIGISMEMBER(ps->ps_sigcatch, sig) && 2102146fc63fSKonstantin Belousov !SIGISMEMBER(sigmask, sig)) { 2103df8bae1dSRodney W. Grimes #ifdef KTRACE 2104374a15aaSJohn Baldwin if (KTRPOINT(curthread, KTR_PSIG)) 2105374a15aaSJohn Baldwin ktrpsig(sig, ps->ps_sigact[_SIG_IDX(sig)], 2106c5c981d4SMateusz Guzik &td->td_sigmask, ksi->ksi_code); 2107df8bae1dSRodney W. Grimes #endif 21089104847fSDavid Xu (*p->p_sysent->sv_sendsig)(ps->ps_sigact[_SIG_IDX(sig)], 21099104847fSDavid Xu ksi, &td->td_sigmask); 2110e442f29fSKonstantin Belousov postsig_done(sig, td, ps); 211190af4afaSJohn Baldwin mtx_unlock(&ps->ps_mtx); 21126f841fb7SMarcel Moolenaar } else { 2113f71a882fSDavid Xu /* 2114f71a882fSDavid Xu * Avoid a possible infinite loop if the thread 2115f71a882fSDavid Xu * masking the signal or process is ignoring the 2116f71a882fSDavid Xu * signal. 2117f71a882fSDavid Xu */ 2118146fc63fSKonstantin Belousov if (kern_forcesigexit && (SIGISMEMBER(sigmask, sig) || 2119f71a882fSDavid Xu ps->ps_sigact[_SIG_IDX(sig)] == SIG_IGN)) { 2120f71a882fSDavid Xu SIGDELSET(td->td_sigmask, sig); 2121f71a882fSDavid Xu SIGDELSET(ps->ps_sigcatch, sig); 2122f71a882fSDavid Xu SIGDELSET(ps->ps_sigignore, sig); 2123f71a882fSDavid Xu ps->ps_sigact[_SIG_IDX(sig)] = SIG_DFL; 2124146fc63fSKonstantin Belousov td->td_pflags &= ~TDP_SIGFASTBLOCK; 2125146fc63fSKonstantin Belousov td->td_sigblock_val = 0; 2126f71a882fSDavid Xu } 212790af4afaSJohn Baldwin mtx_unlock(&ps->ps_mtx); 21282c42a146SMarcel Moolenaar p->p_sig = sig; /* XXX to verify code */ 2129ad6eec7bSJohn Baldwin tdsendsignal(p, td, sig, ksi); 2130df8bae1dSRodney W. Grimes } 2131628d2653SJohn Baldwin PROC_UNLOCK(p); 2132df8bae1dSRodney W. Grimes } 2133df8bae1dSRodney W. Grimes 21344093529dSJeff Roberson static struct thread * 2135146fc63fSKonstantin Belousov sigtd(struct proc *p, int sig, bool fast_sigblock) 21364093529dSJeff Roberson { 21373074d1b4SDavid Xu struct thread *td, *signal_td; 21384093529dSJeff Roberson 21394093529dSJeff Roberson PROC_LOCK_ASSERT(p, MA_OWNED); 2140146fc63fSKonstantin Belousov MPASS(!fast_sigblock || p == curproc); 21414093529dSJeff Roberson 21424093529dSJeff Roberson /* 2143627451c1SDavid Xu * Check if current thread can handle the signal without 214415b7a831SKonstantin Belousov * switching context to another thread. 21454093529dSJeff Roberson */ 2146146fc63fSKonstantin Belousov if (curproc == p && !SIGISMEMBER(curthread->td_sigmask, sig) && 2147146fc63fSKonstantin Belousov (!fast_sigblock || curthread->td_sigblock_val == 0)) 2148627451c1SDavid Xu return (curthread); 21493074d1b4SDavid Xu signal_td = NULL; 21503074d1b4SDavid Xu FOREACH_THREAD_IN_PROC(p, td) { 2151146fc63fSKonstantin Belousov if (!SIGISMEMBER(td->td_sigmask, sig) && (!fast_sigblock || 2152146fc63fSKonstantin Belousov td != curthread || td->td_sigblock_val == 0)) { 21533074d1b4SDavid Xu signal_td = td; 2154627451c1SDavid Xu break; 21553074d1b4SDavid Xu } 21563074d1b4SDavid Xu } 21573074d1b4SDavid Xu if (signal_td == NULL) 21583074d1b4SDavid Xu signal_td = FIRST_THREAD_IN_PROC(p); 21593074d1b4SDavid Xu return (signal_td); 21604093529dSJeff Roberson } 21614093529dSJeff Roberson 2162df8bae1dSRodney W. Grimes /* 2163df8bae1dSRodney W. Grimes * Send the signal to the process. If the signal has an action, the action 2164df8bae1dSRodney W. Grimes * is usually performed by the target process rather than the caller; we add 2165df8bae1dSRodney W. Grimes * the signal to the set of pending signals for the process. 2166df8bae1dSRodney W. Grimes * 2167df8bae1dSRodney W. Grimes * Exceptions: 2168df8bae1dSRodney W. Grimes * o When a stop signal is sent to a sleeping process that takes the 2169df8bae1dSRodney W. Grimes * default action, the process is stopped without awakening it. 2170df8bae1dSRodney W. Grimes * o SIGCONT restarts stopped processes (or puts them back to sleep) 2171df8bae1dSRodney W. Grimes * regardless of the signal action (eg, blocked or ignored). 2172df8bae1dSRodney W. Grimes * 2173df8bae1dSRodney W. Grimes * Other ignored signals are discarded immediately. 21744dec0e67SRobert Watson * 21754dec0e67SRobert Watson * NB: This function may be entered from the debugger via the "kill" DDB 21764dec0e67SRobert Watson * command. There is little that can be done to mitigate the possibly messy 21774dec0e67SRobert Watson * side effects of this unwise possibility. 2178df8bae1dSRodney W. Grimes */ 2179df8bae1dSRodney W. Grimes void 21808451d0ddSKip Macy kern_psignal(struct proc *p, int sig) 2181df8bae1dSRodney W. Grimes { 2182a3de221dSKonstantin Belousov ksiginfo_t ksi; 2183a3de221dSKonstantin Belousov 2184a3de221dSKonstantin Belousov ksiginfo_init(&ksi); 2185a3de221dSKonstantin Belousov ksi.ksi_signo = sig; 2186a3de221dSKonstantin Belousov ksi.ksi_code = SI_KERNEL; 2187ad6eec7bSJohn Baldwin (void) tdsendsignal(p, NULL, sig, &ksi); 2188a3de221dSKonstantin Belousov } 2189a3de221dSKonstantin Belousov 2190ad6eec7bSJohn Baldwin int 2191a3de221dSKonstantin Belousov pksignal(struct proc *p, int sig, ksiginfo_t *ksi) 2192a3de221dSKonstantin Belousov { 2193a3de221dSKonstantin Belousov 2194ad6eec7bSJohn Baldwin return (tdsendsignal(p, NULL, sig, ksi)); 21959104847fSDavid Xu } 21969104847fSDavid Xu 2197cf7d9a8cSDavid Xu /* Utility function for finding a thread to send signal event to. */ 21989104847fSDavid Xu int 2199cf7d9a8cSDavid Xu sigev_findtd(struct proc *p, struct sigevent *sigev, struct thread **ttd) 22009104847fSDavid Xu { 2201cf7d9a8cSDavid Xu struct thread *td; 220241b3077aSJacques Vidrine 22036d7b314bSDavid Xu if (sigev->sigev_notify == SIGEV_THREAD_ID) { 2204cf7d9a8cSDavid Xu td = tdfind(sigev->sigev_notify_thread_id, p->p_pid); 22056d7b314bSDavid Xu if (td == NULL) 22066d7b314bSDavid Xu return (ESRCH); 2207cf7d9a8cSDavid Xu *ttd = td; 2208cf7d9a8cSDavid Xu } else { 2209cf7d9a8cSDavid Xu *ttd = NULL; 2210cf7d9a8cSDavid Xu PROC_LOCK(p); 22116d7b314bSDavid Xu } 2212cf7d9a8cSDavid Xu return (0); 22134093529dSJeff Roberson } 22144093529dSJeff Roberson 2215ad6eec7bSJohn Baldwin void 2216ad6eec7bSJohn Baldwin tdsignal(struct thread *td, int sig) 2217ad6eec7bSJohn Baldwin { 2218ad6eec7bSJohn Baldwin ksiginfo_t ksi; 2219ad6eec7bSJohn Baldwin 2220ad6eec7bSJohn Baldwin ksiginfo_init(&ksi); 2221ad6eec7bSJohn Baldwin ksi.ksi_signo = sig; 2222ad6eec7bSJohn Baldwin ksi.ksi_code = SI_KERNEL; 2223ad6eec7bSJohn Baldwin (void) tdsendsignal(td->td_proc, td, sig, &ksi); 2224ad6eec7bSJohn Baldwin } 2225ad6eec7bSJohn Baldwin 2226ad6eec7bSJohn Baldwin void 2227ad6eec7bSJohn Baldwin tdksignal(struct thread *td, int sig, ksiginfo_t *ksi) 2228ad6eec7bSJohn Baldwin { 2229ad6eec7bSJohn Baldwin 2230ad6eec7bSJohn Baldwin (void) tdsendsignal(td->td_proc, td, sig, ksi); 2231ad6eec7bSJohn Baldwin } 2232ad6eec7bSJohn Baldwin 22339b86d3e5SKonstantin Belousov static int 22349b86d3e5SKonstantin Belousov sig_sleepq_abort(struct thread *td, int intrval) 22359b86d3e5SKonstantin Belousov { 22369b86d3e5SKonstantin Belousov THREAD_LOCK_ASSERT(td, MA_OWNED); 22379b86d3e5SKonstantin Belousov 22389b86d3e5SKonstantin Belousov if (intrval == 0 && (td->td_flags & TDF_SIGWAIT) == 0) { 22399b86d3e5SKonstantin Belousov thread_unlock(td); 22409b86d3e5SKonstantin Belousov return (0); 22419b86d3e5SKonstantin Belousov } 22429b86d3e5SKonstantin Belousov return (sleepq_abort(td, intrval)); 22439b86d3e5SKonstantin Belousov } 22449b86d3e5SKonstantin Belousov 2245cf7d9a8cSDavid Xu int 2246ad6eec7bSJohn Baldwin tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi) 22474093529dSJeff Roberson { 22489104847fSDavid Xu sig_t action; 22499104847fSDavid Xu sigqueue_t *sigqueue; 22509104847fSDavid Xu int prop; 225190af4afaSJohn Baldwin struct sigacts *ps; 225294f0972bSDavid Xu int intrval; 22539104847fSDavid Xu int ret = 0; 2254da7bbd2cSJohn Baldwin int wakeup_swapper; 2255df8bae1dSRodney W. Grimes 2256cf7d9a8cSDavid Xu MPASS(td == NULL || p == td->td_proc); 22576d7b314bSDavid Xu PROC_LOCK_ASSERT(p, MA_OWNED); 22586d7b314bSDavid Xu 225941b3077aSJacques Vidrine if (!_SIG_VALID(sig)) 2260212bc4b3SDavid Xu panic("%s(): invalid signal %d", __func__, sig); 22614093529dSJeff Roberson 2262212bc4b3SDavid Xu KASSERT(ksi == NULL || !KSI_ONQ(ksi), ("%s: ksi on queue", __func__)); 22636d7b314bSDavid Xu 22646d7b314bSDavid Xu /* 22656d7b314bSDavid Xu * IEEE Std 1003.1-2001: return success when killing a zombie. 22666d7b314bSDavid Xu */ 22676d7b314bSDavid Xu if (p->p_state == PRS_ZOMBIE) { 22686d7b314bSDavid Xu if (ksi && (ksi->ksi_flags & KSI_INS)) 22696d7b314bSDavid Xu ksiginfo_tryfree(ksi); 22706d7b314bSDavid Xu return (ret); 22716d7b314bSDavid Xu } 22726d7b314bSDavid Xu 227390af4afaSJohn Baldwin ps = p->p_sigacts; 22749e590ff0SKonstantin Belousov KNOTE_LOCKED(p->p_klist, NOTE_SIGNAL | sig); 22752c42a146SMarcel Moolenaar prop = sigprop(sig); 22764093529dSJeff Roberson 22776d7b314bSDavid Xu if (td == NULL) { 2278146fc63fSKonstantin Belousov td = sigtd(p, sig, false); 22796d7b314bSDavid Xu sigqueue = &p->p_sigqueue; 2280462314b3SMateusz Guzik } else 22819104847fSDavid Xu sigqueue = &td->td_sigqueue; 22824093529dSJeff Roberson 228336160958SMark Johnston SDT_PROBE3(proc, , , signal__send, td, p, sig); 22845d217f17SJohn Birrell 2285df8bae1dSRodney W. Grimes /* 2286bc387624SKonstantin Belousov * If the signal is being ignored, then we forget about it 2287bc387624SKonstantin Belousov * immediately, except when the target process executes 2288bc387624SKonstantin Belousov * sigwait(). (Note: we don't set SIGCONT in ps_sigignore, 2289bc387624SKonstantin Belousov * and if it is set to SIG_IGN, action will be SIG_DFL here.) 2290df8bae1dSRodney W. Grimes */ 229190af4afaSJohn Baldwin mtx_lock(&ps->ps_mtx); 22920fc32899SJohn Baldwin if (SIGISMEMBER(ps->ps_sigignore, sig)) { 2293bc387624SKonstantin Belousov if (kern_sig_discard_ign && 2294bc387624SKonstantin Belousov (p->p_sysent->sv_flags & SV_SIG_DISCIGN) == 0) { 229536160958SMark Johnston SDT_PROBE3(proc, , , signal__discard, td, p, sig); 22965d217f17SJohn Birrell 229790af4afaSJohn Baldwin mtx_unlock(&ps->ps_mtx); 22986d7b314bSDavid Xu if (ksi && (ksi->ksi_flags & KSI_INS)) 22996d7b314bSDavid Xu ksiginfo_tryfree(ksi); 23009104847fSDavid Xu return (ret); 2301bc387624SKonstantin Belousov } else { 2302bc387624SKonstantin Belousov action = SIG_CATCH; 2303f17eb93dSKonstantin Belousov intrval = 0; 230490af4afaSJohn Baldwin } 2305f17eb93dSKonstantin Belousov } else { 2306f17eb93dSKonstantin Belousov if (SIGISMEMBER(td->td_sigmask, sig)) 2307df8bae1dSRodney W. Grimes action = SIG_HOLD; 230890af4afaSJohn Baldwin else if (SIGISMEMBER(ps->ps_sigcatch, sig)) 2309df8bae1dSRodney W. Grimes action = SIG_CATCH; 2310df8bae1dSRodney W. Grimes else 2311df8bae1dSRodney W. Grimes action = SIG_DFL; 231294f0972bSDavid Xu if (SIGISMEMBER(ps->ps_sigintr, sig)) 231394f0972bSDavid Xu intrval = EINTR; 231494f0972bSDavid Xu else 231594f0972bSDavid Xu intrval = ERESTART; 2316f17eb93dSKonstantin Belousov } 231790af4afaSJohn Baldwin mtx_unlock(&ps->ps_mtx); 2318df8bae1dSRodney W. Grimes 2319fd50a707SBrooks Davis if (prop & SIGPROP_CONT) 23209104847fSDavid Xu sigqueue_delete_stopmask_proc(p); 2321fd50a707SBrooks Davis else if (prop & SIGPROP_STOP) { 2322df8bae1dSRodney W. Grimes /* 2323df8bae1dSRodney W. Grimes * If sending a tty stop signal to a member of an orphaned 2324df8bae1dSRodney W. Grimes * process group, discard the signal here if the action 2325df8bae1dSRodney W. Grimes * is default; don't stop the process below if sleeping, 2326df8bae1dSRodney W. Grimes * and don't clear any pending SIGCONT. 2327df8bae1dSRodney W. Grimes */ 2328993a1699SKonstantin Belousov if ((prop & SIGPROP_TTYSTOP) != 0 && 23295844bd05SKonstantin Belousov (p->p_pgrp->pg_flags & PGRP_ORPHANED) != 0 && 2330993a1699SKonstantin Belousov action == SIG_DFL) { 23316d7b314bSDavid Xu if (ksi && (ksi->ksi_flags & KSI_INS)) 23326d7b314bSDavid Xu ksiginfo_tryfree(ksi); 23339104847fSDavid Xu return (ret); 23346d7b314bSDavid Xu } 23359104847fSDavid Xu sigqueue_delete_proc(p, SIGCONT); 2336ebceaf6dSDavid Xu if (p->p_flag & P_CONTINUED) { 23376933e3c1SJulian Elischer p->p_flag &= ~P_CONTINUED; 2338ebceaf6dSDavid Xu PROC_LOCK(p->p_pptr); 2339ebceaf6dSDavid Xu sigqueue_take(p->p_ksi); 2340ebceaf6dSDavid Xu PROC_UNLOCK(p->p_pptr); 2341ebceaf6dSDavid Xu } 2342df8bae1dSRodney W. Grimes } 23433074d1b4SDavid Xu 23449104847fSDavid Xu ret = sigqueue_add(sigqueue, sig, ksi); 23459104847fSDavid Xu if (ret != 0) 23469104847fSDavid Xu return (ret); 23476d7b314bSDavid Xu signotify(td); 23485312b1c7SDavid Xu /* 23495312b1c7SDavid Xu * Defer further processing for signals which are held, 23505312b1c7SDavid Xu * except that stopped processes must be continued by SIGCONT. 23515312b1c7SDavid Xu */ 23525312b1c7SDavid Xu if (action == SIG_HOLD && 2353fd50a707SBrooks Davis !((prop & SIGPROP_CONT) && (p->p_flag & P_STOPPED_SIG))) 23549104847fSDavid Xu return (ret); 2355b4d33259SEric Badger 235661a74c5cSJeff Roberson wakeup_swapper = 0; 235761a74c5cSJeff Roberson 235890d75f78SAlfred Perlstein /* 2359e602ba25SJulian Elischer * Some signals have a process-wide effect and a per-thread 2360e602ba25SJulian Elischer * component. Most processing occurs when the process next 2361e602ba25SJulian Elischer * tries to cross the user boundary, however there are some 23621968f37bSJohn Baldwin * times when processing needs to be done immediately, such as 2363e602ba25SJulian Elischer * waking up threads so that they can cross the user boundary. 23641968f37bSJohn Baldwin * We try to do the per-process part here. 2365df8bae1dSRodney W. Grimes */ 2366e602ba25SJulian Elischer if (P_SHOULDSTOP(p)) { 23670f14f15bSJohn Baldwin KASSERT(!(p->p_flag & P_WEXIT), 23680f14f15bSJohn Baldwin ("signal to stopped but exiting process")); 2369e602ba25SJulian Elischer if (sig == SIGKILL) { 2370137cf33dSDavid Xu /* 2371137cf33dSDavid Xu * If traced process is already stopped, 2372137cf33dSDavid Xu * then no further action is necessary. 2373137cf33dSDavid Xu */ 237483b718ebSDavid Xu if (p->p_flag & P_TRACED) 237583b718ebSDavid Xu goto out; 2376df8bae1dSRodney W. Grimes /* 2377e602ba25SJulian Elischer * SIGKILL sets process running. 2378e602ba25SJulian Elischer * It will die elsewhere. 2379e602ba25SJulian Elischer * All threads must be restarted. 2380df8bae1dSRodney W. Grimes */ 2381482d099cSDavid Xu p->p_flag &= ~P_STOPPED_SIG; 2382e602ba25SJulian Elischer goto runfast; 2383e602ba25SJulian Elischer } 2384e602ba25SJulian Elischer 2385fd50a707SBrooks Davis if (prop & SIGPROP_CONT) { 2386137cf33dSDavid Xu /* 2387137cf33dSDavid Xu * If traced process is already stopped, 2388137cf33dSDavid Xu * then no further action is necessary. 2389137cf33dSDavid Xu */ 239083b718ebSDavid Xu if (p->p_flag & P_TRACED) 239183b718ebSDavid Xu goto out; 2392e602ba25SJulian Elischer /* 2393e602ba25SJulian Elischer * If SIGCONT is default (or ignored), we continue the 23949104847fSDavid Xu * process but don't leave the signal in sigqueue as 23951d9c5696SJuli Mallett * it has no further action. If SIGCONT is held, we 2396e602ba25SJulian Elischer * continue the process and leave the signal in 23979104847fSDavid Xu * sigqueue. If the process catches SIGCONT, let it 2398e602ba25SJulian Elischer * handle the signal itself. If it isn't waiting on 2399e602ba25SJulian Elischer * an event, it goes back to run state. 2400e602ba25SJulian Elischer * Otherwise, process goes back to sleep state. 2401e602ba25SJulian Elischer */ 24021279572aSDavid Xu p->p_flag &= ~P_STOPPED_SIG; 24037b4a950aSDavid Xu PROC_SLOCK(p); 2404ebceaf6dSDavid Xu if (p->p_numthreads == p->p_suspcount) { 24057b4a950aSDavid Xu PROC_SUNLOCK(p); 24066933e3c1SJulian Elischer p->p_flag |= P_CONTINUED; 2407b4490c6eSKonstantin Belousov p->p_xsig = SIGCONT; 24087f96995eSDavid Xu PROC_LOCK(p->p_pptr); 2409ebceaf6dSDavid Xu childproc_continued(p); 24107f96995eSDavid Xu PROC_UNLOCK(p->p_pptr); 24117b4a950aSDavid Xu PROC_SLOCK(p); 2412ebceaf6dSDavid Xu } 2413e602ba25SJulian Elischer if (action == SIG_DFL) { 2414a54e85fdSJeff Roberson thread_unsuspend(p); 24157b4a950aSDavid Xu PROC_SUNLOCK(p); 24169104847fSDavid Xu sigqueue_delete(sigqueue, sig); 2417dc47fdf1SKonstantin Belousov goto out_cont; 2418a54e85fdSJeff Roberson } 2419a54e85fdSJeff Roberson if (action == SIG_CATCH) { 24208460a577SJohn Birrell /* 24218460a577SJohn Birrell * The process wants to catch it so it needs 24228460a577SJohn Birrell * to run at least one thread, but which one? 24238460a577SJohn Birrell */ 24247b4a950aSDavid Xu PROC_SUNLOCK(p); 2425e602ba25SJulian Elischer goto runfast; 2426e602ba25SJulian Elischer } 2427e602ba25SJulian Elischer /* 2428e602ba25SJulian Elischer * The signal is not ignored or caught. 2429e602ba25SJulian Elischer */ 243004774f23SJulian Elischer thread_unsuspend(p); 24317b4a950aSDavid Xu PROC_SUNLOCK(p); 2432dc47fdf1SKonstantin Belousov goto out_cont; 2433e602ba25SJulian Elischer } 2434e602ba25SJulian Elischer 2435fd50a707SBrooks Davis if (prop & SIGPROP_STOP) { 2436137cf33dSDavid Xu /* 2437137cf33dSDavid Xu * If traced process is already stopped, 2438137cf33dSDavid Xu * then no further action is necessary. 2439137cf33dSDavid Xu */ 244083b718ebSDavid Xu if (p->p_flag & P_TRACED) 244183b718ebSDavid Xu goto out; 2442e602ba25SJulian Elischer /* 2443e602ba25SJulian Elischer * Already stopped, don't need to stop again 2444e602ba25SJulian Elischer * (If we did the shell could get confused). 244504774f23SJulian Elischer * Just make sure the signal STOP bit set. 2446e602ba25SJulian Elischer */ 24471279572aSDavid Xu p->p_flag |= P_STOPPED_SIG; 24489104847fSDavid Xu sigqueue_delete(sigqueue, sig); 2449e602ba25SJulian Elischer goto out; 2450e602ba25SJulian Elischer } 2451e602ba25SJulian Elischer 2452e602ba25SJulian Elischer /* 2453e602ba25SJulian Elischer * All other kinds of signals: 2454e602ba25SJulian Elischer * If a thread is sleeping interruptibly, simulate a 2455e602ba25SJulian Elischer * wakeup so that when it is continued it will be made 2456e602ba25SJulian Elischer * runnable and can look at the signal. However, don't make 245704774f23SJulian Elischer * the PROCESS runnable, leave it stopped. 2458e602ba25SJulian Elischer * It may run a bit until it hits a thread_suspend_check(). 2459e602ba25SJulian Elischer */ 24607b4a950aSDavid Xu PROC_SLOCK(p); 2461a54e85fdSJeff Roberson thread_lock(td); 246261a74c5cSJeff Roberson if (TD_CAN_ABORT(td)) 24639b86d3e5SKonstantin Belousov wakeup_swapper = sig_sleepq_abort(td, intrval); 246461a74c5cSJeff Roberson else 2465a54e85fdSJeff Roberson thread_unlock(td); 24667b4a950aSDavid Xu PROC_SUNLOCK(p); 2467df8bae1dSRodney W. Grimes goto out; 2468df8bae1dSRodney W. Grimes /* 24699a6a4cb5SPeter Wemm * Mutexes are short lived. Threads waiting on them will 24709a6a4cb5SPeter Wemm * hit thread_suspend_check() soon. 2471df8bae1dSRodney W. Grimes */ 2472e602ba25SJulian Elischer } else if (p->p_state == PRS_NORMAL) { 2473ec8297bdSDavid Xu if (p->p_flag & P_TRACED || action == SIG_CATCH) { 247494f0972bSDavid Xu tdsigwakeup(td, sig, action, intrval); 2475df8bae1dSRodney W. Grimes goto out; 247604774f23SJulian Elischer } 2477ec8297bdSDavid Xu 2478ec8297bdSDavid Xu MPASS(action == SIG_DFL); 2479ec8297bdSDavid Xu 2480fd50a707SBrooks Davis if (prop & SIGPROP_STOP) { 24810f14f15bSJohn Baldwin if (p->p_flag & (P_PPWAIT|P_WEXIT)) 248235c32a76SDavid Xu goto out; 2483e574e444SDavid Xu p->p_flag |= P_STOPPED_SIG; 2484b4490c6eSKonstantin Belousov p->p_xsig = sig; 24857b4a950aSDavid Xu PROC_SLOCK(p); 24866f56cb8dSKonstantin Belousov wakeup_swapper = sig_suspend_threads(td, p, 1); 24874093529dSJeff Roberson if (p->p_numthreads == p->p_suspcount) { 2488ebceaf6dSDavid Xu /* 2489ebceaf6dSDavid Xu * only thread sending signal to another 2490ebceaf6dSDavid Xu * process can reach here, if thread is sending 2491ebceaf6dSDavid Xu * signal to its process, because thread does 2492ebceaf6dSDavid Xu * not suspend itself here, p_numthreads 2493ebceaf6dSDavid Xu * should never be equal to p_suspcount. 2494ebceaf6dSDavid Xu */ 2495ebceaf6dSDavid Xu thread_stopped(p); 24967b4a950aSDavid Xu PROC_SUNLOCK(p); 2497b4490c6eSKonstantin Belousov sigqueue_delete_proc(p, p->p_xsig); 24987b4a950aSDavid Xu } else 24997b4a950aSDavid Xu PROC_SUNLOCK(p); 250035c32a76SDavid Xu goto out; 250135c32a76SDavid Xu } 2502e602ba25SJulian Elischer } else { 2503e602ba25SJulian Elischer /* Not in "NORMAL" state. discard the signal. */ 25049104847fSDavid Xu sigqueue_delete(sigqueue, sig); 2505e602ba25SJulian Elischer goto out; 2506e602ba25SJulian Elischer } 2507e602ba25SJulian Elischer 2508b40ce416SJulian Elischer /* 2509e602ba25SJulian Elischer * The process is not stopped so we need to apply the signal to all the 2510e602ba25SJulian Elischer * running threads. 2511b40ce416SJulian Elischer */ 2512e602ba25SJulian Elischer runfast: 251394f0972bSDavid Xu tdsigwakeup(td, sig, action, intrval); 25147b4a950aSDavid Xu PROC_SLOCK(p); 2515e602ba25SJulian Elischer thread_unsuspend(p); 25167b4a950aSDavid Xu PROC_SUNLOCK(p); 2517dc47fdf1SKonstantin Belousov out_cont: 2518dc47fdf1SKonstantin Belousov itimer_proc_continue(p); 25192fd1ffefSKonstantin Belousov kqtimer_proc_continue(p); 2520e602ba25SJulian Elischer out: 25217b4a950aSDavid Xu /* If we jump here, proc slock should not be owned. */ 25227b4a950aSDavid Xu PROC_SLOCK_ASSERT(p, MA_NOTOWNED); 252361a74c5cSJeff Roberson if (wakeup_swapper) 252461a74c5cSJeff Roberson kick_proc0(); 252561a74c5cSJeff Roberson 25269104847fSDavid Xu return (ret); 2527e602ba25SJulian Elischer } 2528e602ba25SJulian Elischer 2529e602ba25SJulian Elischer /* 2530e602ba25SJulian Elischer * The force of a signal has been directed against a single 2531e602ba25SJulian Elischer * thread. We need to see what we can do about knocking it 2532e602ba25SJulian Elischer * out of any sleep it may be in etc. 2533e602ba25SJulian Elischer */ 2534e602ba25SJulian Elischer static void 253594f0972bSDavid Xu tdsigwakeup(struct thread *td, int sig, sig_t action, int intrval) 2536e602ba25SJulian Elischer { 2537e602ba25SJulian Elischer struct proc *p = td->td_proc; 253861a74c5cSJeff Roberson int prop, wakeup_swapper; 2539e602ba25SJulian Elischer 25408b94a061SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 2541e602ba25SJulian Elischer prop = sigprop(sig); 2542a4c2da15SBruce Evans 25437b4a950aSDavid Xu PROC_SLOCK(p); 2544374ae2a3SJeff Roberson thread_lock(td); 2545e602ba25SJulian Elischer /* 2546aa0fa334SJulian Elischer * Bring the priority of a thread up if we want it to get 2547aef68c96SKonstantin Belousov * killed in this lifetime. Be careful to avoid bumping the 2548aef68c96SKonstantin Belousov * priority of the idle thread, since we still allow to signal 2549aef68c96SKonstantin Belousov * kernel processes. 2550e602ba25SJulian Elischer */ 2551fd50a707SBrooks Davis if (action == SIG_DFL && (prop & SIGPROP_KILL) != 0 && 2552aef68c96SKonstantin Belousov td->td_priority > PUSER && !TD_IS_IDLETHREAD(td)) 2553b3a4fb14SDavid Xu sched_prio(td, PUSER); 255480c4433cSJohn Baldwin if (TD_ON_SLEEPQ(td)) { 2555e602ba25SJulian Elischer /* 2556e602ba25SJulian Elischer * If thread is sleeping uninterruptibly 2557e602ba25SJulian Elischer * we can't interrupt the sleep... the signal will 2558e602ba25SJulian Elischer * be noticed when the process returns through 2559e602ba25SJulian Elischer * trap() or syscall(). 2560e602ba25SJulian Elischer */ 256144f3b092SJohn Baldwin if ((td->td_flags & TDF_SINTR) == 0) 2562374ae2a3SJeff Roberson goto out; 2563e602ba25SJulian Elischer /* 2564e602ba25SJulian Elischer * If SIGCONT is default (or ignored) and process is 2565e602ba25SJulian Elischer * asleep, we are finished; the process should not 2566e602ba25SJulian Elischer * be awakened. 2567df8bae1dSRodney W. Grimes */ 2568fd50a707SBrooks Davis if ((prop & SIGPROP_CONT) && action == SIG_DFL) { 2569a54e85fdSJeff Roberson thread_unlock(td); 25707b4a950aSDavid Xu PROC_SUNLOCK(p); 25719104847fSDavid Xu sigqueue_delete(&p->p_sigqueue, sig); 25724093529dSJeff Roberson /* 25734093529dSJeff Roberson * It may be on either list in this state. 25744093529dSJeff Roberson * Remove from both for now. 25754093529dSJeff Roberson */ 25769104847fSDavid Xu sigqueue_delete(&td->td_sigqueue, sig); 2577aa0fa334SJulian Elischer return; 2578df8bae1dSRodney W. Grimes } 2579df8bae1dSRodney W. Grimes 2580aa0fa334SJulian Elischer /* 2581a120a7a3SJohn Baldwin * Don't awaken a sleeping thread for SIGSTOP if the 2582a120a7a3SJohn Baldwin * STOP signal is deferred. 2583a120a7a3SJohn Baldwin */ 2584fd50a707SBrooks Davis if ((prop & SIGPROP_STOP) != 0 && (td->td_flags & (TDF_SBDRY | 25856f56cb8dSKonstantin Belousov TDF_SERESTART | TDF_SEINTR)) == TDF_SBDRY) 2586a120a7a3SJohn Baldwin goto out; 2587a120a7a3SJohn Baldwin 2588a120a7a3SJohn Baldwin /* 2589a4c2da15SBruce Evans * Give low priority threads a better chance to run. 2590aa0fa334SJulian Elischer */ 2591aef68c96SKonstantin Belousov if (td->td_priority > PUSER && !TD_IS_IDLETHREAD(td)) 2592b3a4fb14SDavid Xu sched_prio(td, PUSER); 2593ec8297bdSDavid Xu 25949b86d3e5SKonstantin Belousov wakeup_swapper = sig_sleepq_abort(td, intrval); 259561a74c5cSJeff Roberson PROC_SUNLOCK(p); 259661a74c5cSJeff Roberson if (wakeup_swapper) 259761a74c5cSJeff Roberson kick_proc0(); 259861a74c5cSJeff Roberson return; 259961a74c5cSJeff Roberson } 260061a74c5cSJeff Roberson 2601df8bae1dSRodney W. Grimes /* 2602a4c2da15SBruce Evans * Other states do nothing with the signal immediately, 2603df8bae1dSRodney W. Grimes * other than kicking ourselves if we are running. 2604df8bae1dSRodney W. Grimes * It will either never be noticed, or noticed very soon. 2605df8bae1dSRodney W. Grimes */ 2606a4c2da15SBruce Evans #ifdef SMP 260744f3b092SJohn Baldwin if (TD_IS_RUNNING(td) && td != curthread) 2608e602ba25SJulian Elischer forward_signal(td); 26093163861cSTor Egge #endif 261061a74c5cSJeff Roberson 2611374ae2a3SJeff Roberson out: 26127b4a950aSDavid Xu PROC_SUNLOCK(p); 2613374ae2a3SJeff Roberson thread_unlock(td); 2614a4c2da15SBruce Evans } 2615df8bae1dSRodney W. Grimes 261687a64872SKonstantin Belousov static void 261787a64872SKonstantin Belousov ptrace_coredump(struct thread *td) 261887a64872SKonstantin Belousov { 261987a64872SKonstantin Belousov struct proc *p; 262087a64872SKonstantin Belousov struct thr_coredump_req *tcq; 262187a64872SKonstantin Belousov void *rl_cookie; 262287a64872SKonstantin Belousov 262387a64872SKonstantin Belousov MPASS(td == curthread); 262487a64872SKonstantin Belousov p = td->td_proc; 262587a64872SKonstantin Belousov PROC_LOCK_ASSERT(p, MA_OWNED); 262687a64872SKonstantin Belousov if ((td->td_dbgflags & TDB_COREDUMPRQ) == 0) 262787a64872SKonstantin Belousov return; 262887a64872SKonstantin Belousov KASSERT((p->p_flag & P_STOPPED_TRACE) != 0, ("not stopped")); 262987a64872SKonstantin Belousov 263087a64872SKonstantin Belousov tcq = td->td_coredump; 263187a64872SKonstantin Belousov KASSERT(tcq != NULL, ("td_coredump is NULL")); 263287a64872SKonstantin Belousov 263387a64872SKonstantin Belousov if (p->p_sysent->sv_coredump == NULL) { 263487a64872SKonstantin Belousov tcq->tc_error = ENOSYS; 263587a64872SKonstantin Belousov goto wake; 263687a64872SKonstantin Belousov } 263787a64872SKonstantin Belousov 263887a64872SKonstantin Belousov PROC_UNLOCK(p); 263987a64872SKonstantin Belousov rl_cookie = vn_rangelock_wlock(tcq->tc_vp, 0, OFF_MAX); 264087a64872SKonstantin Belousov 264187a64872SKonstantin Belousov tcq->tc_error = p->p_sysent->sv_coredump(td, tcq->tc_vp, 264287a64872SKonstantin Belousov tcq->tc_limit, tcq->tc_flags); 264387a64872SKonstantin Belousov 264487a64872SKonstantin Belousov vn_rangelock_unlock(tcq->tc_vp, rl_cookie); 264587a64872SKonstantin Belousov PROC_LOCK(p); 264687a64872SKonstantin Belousov wake: 264787a64872SKonstantin Belousov td->td_dbgflags &= ~TDB_COREDUMPRQ; 264887a64872SKonstantin Belousov td->td_coredump = NULL; 264987a64872SKonstantin Belousov wakeup(p); 265087a64872SKonstantin Belousov } 265187a64872SKonstantin Belousov 26526f56cb8dSKonstantin Belousov static int 2653d8267df7SDavid Xu sig_suspend_threads(struct thread *td, struct proc *p, int sending) 2654d8267df7SDavid Xu { 2655d8267df7SDavid Xu struct thread *td2; 26566f56cb8dSKonstantin Belousov int wakeup_swapper; 2657d8267df7SDavid Xu 2658d8267df7SDavid Xu PROC_LOCK_ASSERT(p, MA_OWNED); 26597b4a950aSDavid Xu PROC_SLOCK_ASSERT(p, MA_OWNED); 26600c46712cSMark Johnston MPASS(sending || td == curthread); 2661d8267df7SDavid Xu 26626f56cb8dSKonstantin Belousov wakeup_swapper = 0; 2663d8267df7SDavid Xu FOREACH_THREAD_IN_PROC(p, td2) { 2664a54e85fdSJeff Roberson thread_lock(td2); 2665c6d31b83SKonstantin Belousov ast_sched_locked(td2, TDA_SUSPEND); 2666d8267df7SDavid Xu if ((TD_IS_SLEEPING(td2) || TD_IS_SWAPPED(td2)) && 2667f33a947bSKonstantin Belousov (td2->td_flags & TDF_SINTR)) { 2668f33a947bSKonstantin Belousov if (td2->td_flags & TDF_SBDRY) { 2669a120a7a3SJohn Baldwin /* 2670a120a7a3SJohn Baldwin * Once a thread is asleep with 26716f56cb8dSKonstantin Belousov * TDF_SBDRY and without TDF_SERESTART 26726f56cb8dSKonstantin Belousov * or TDF_SEINTR set, it should never 2673a120a7a3SJohn Baldwin * become suspended due to this check. 2674a120a7a3SJohn Baldwin */ 2675a120a7a3SJohn Baldwin KASSERT(!TD_IS_SUSPENDED(td2), 2676a120a7a3SJohn Baldwin ("thread with deferred stops suspended")); 267761a74c5cSJeff Roberson if (TD_SBDRY_INTR(td2)) { 267846e47c4fSKonstantin Belousov wakeup_swapper |= sleepq_abort(td2, 267946e47c4fSKonstantin Belousov TD_SBDRY_ERRNO(td2)); 268061a74c5cSJeff Roberson continue; 2681f33a947bSKonstantin Belousov } 268261a74c5cSJeff Roberson } else if (!TD_IS_SUSPENDED(td2)) 268361a74c5cSJeff Roberson thread_suspend_one(td2); 2684f33a947bSKonstantin Belousov } else if (!TD_IS_SUSPENDED(td2)) { 2685d8267df7SDavid Xu if (sending || td != td2) 2686c6d31b83SKonstantin Belousov ast_sched_locked(td2, TDA_AST); 2687d8267df7SDavid Xu #ifdef SMP 2688d8267df7SDavid Xu if (TD_IS_RUNNING(td2) && td2 != td) 2689d8267df7SDavid Xu forward_signal(td2); 2690d8267df7SDavid Xu #endif 2691d8267df7SDavid Xu } 2692a54e85fdSJeff Roberson thread_unlock(td2); 2693d8267df7SDavid Xu } 26946f56cb8dSKonstantin Belousov return (wakeup_swapper); 2695d8267df7SDavid Xu } 2696d8267df7SDavid Xu 269782a4538fSEric Badger /* 269882a4538fSEric Badger * Stop the process for an event deemed interesting to the debugger. If si is 269982a4538fSEric Badger * non-NULL, this is a signal exchange; the new signal requested by the 270082a4538fSEric Badger * debugger will be returned for handling. If si is NULL, this is some other 270182a4538fSEric Badger * type of interesting event. The debugger may request a signal be delivered in 270282a4538fSEric Badger * that case as well, however it will be deferred until it can be handled. 270382a4538fSEric Badger */ 2704cbf4e354SDavid Xu int 270582a4538fSEric Badger ptracestop(struct thread *td, int sig, ksiginfo_t *si) 27064cc9f52fSRobert Drehmel { 27074cc9f52fSRobert Drehmel struct proc *p = td->td_proc; 270882a4538fSEric Badger struct thread *td2; 270982a4538fSEric Badger ksiginfo_t ksi; 27104cc9f52fSRobert Drehmel 271130a9f26dSRobert Watson PROC_LOCK_ASSERT(p, MA_OWNED); 27120f14f15bSJohn Baldwin KASSERT(!(p->p_flag & P_WEXIT), ("Stopping exiting process")); 27134cc9f52fSRobert Drehmel WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, 2714aa89d8cdSJohn Baldwin &p->p_mtx.lock_object, "Stopping for traced signal"); 27154cc9f52fSRobert Drehmel 2716cbf4e354SDavid Xu td->td_xsig = sig; 271782a4538fSEric Badger 271882a4538fSEric Badger if (si == NULL || (si->ksi_flags & KSI_PTRACE) == 0) { 271982a4538fSEric Badger td->td_dbgflags |= TDB_XSIG; 2720515b7a0bSJohn Baldwin CTR4(KTR_PTRACE, "ptracestop: tid %d (pid %d) flags %#x sig %d", 2721515b7a0bSJohn Baldwin td->td_tid, p->p_pid, td->td_dbgflags, sig); 27227b4a950aSDavid Xu PROC_SLOCK(p); 2723904c5ec4SDavid Xu while ((p->p_flag & P_TRACED) && (td->td_dbgflags & TDB_XSIG)) { 272482a4538fSEric Badger if (P_KILLED(p)) { 272582a4538fSEric Badger /* 272682a4538fSEric Badger * Ensure that, if we've been PT_KILLed, the 272782a4538fSEric Badger * exit status reflects that. Another thread 272882a4538fSEric Badger * may also be in ptracestop(), having just 272982a4538fSEric Badger * received the SIGKILL, but this thread was 273082a4538fSEric Badger * unsuspended first. 273182a4538fSEric Badger */ 273282a4538fSEric Badger td->td_dbgflags &= ~TDB_XSIG; 273382a4538fSEric Badger td->td_xsig = SIGKILL; 273482a4538fSEric Badger p->p_ptevents = 0; 273582a4538fSEric Badger break; 273682a4538fSEric Badger } 27375fcfab6eSJohn Baldwin if (p->p_flag & P_SINGLE_EXIT && 27385fcfab6eSJohn Baldwin !(td->td_dbgflags & TDB_EXIT)) { 27395fcfab6eSJohn Baldwin /* 27405fcfab6eSJohn Baldwin * Ignore ptrace stops except for thread exit 27415fcfab6eSJohn Baldwin * events when the process exits. 27425fcfab6eSJohn Baldwin */ 2743904c5ec4SDavid Xu td->td_dbgflags &= ~TDB_XSIG; 27447b4a950aSDavid Xu PROC_SUNLOCK(p); 274582a4538fSEric Badger return (0); 2746cbf4e354SDavid Xu } 2747b7a25e63SKonstantin Belousov 2748cbf4e354SDavid Xu /* 2749b7a25e63SKonstantin Belousov * Make wait(2) work. Ensure that right after the 2750b7a25e63SKonstantin Belousov * attach, the thread which was decided to become the 2751b7a25e63SKonstantin Belousov * leader of attach gets reported to the waiter. 2752b7a25e63SKonstantin Belousov * Otherwise, just avoid overwriting another thread's 2753b7a25e63SKonstantin Belousov * assignment to p_xthread. If another thread has 2754b7a25e63SKonstantin Belousov * already set p_xthread, the current thread will get 2755b7a25e63SKonstantin Belousov * a chance to report itself upon the next iteration. 2756cbf4e354SDavid Xu */ 2757b7a25e63SKonstantin Belousov if ((td->td_dbgflags & TDB_FSTP) != 0 || 27587f649ddaSMark Johnston ((p->p_flag2 & P2_PTRACE_FSTP) == 0 && 2759b7a25e63SKonstantin Belousov p->p_xthread == NULL)) { 2760b4490c6eSKonstantin Belousov p->p_xsig = sig; 2761cbf4e354SDavid Xu p->p_xthread = td; 2762ab74c843SKonstantin Belousov 2763ab74c843SKonstantin Belousov /* 2764ab74c843SKonstantin Belousov * If we are on sleepqueue already, 2765ab74c843SKonstantin Belousov * let sleepqueue code decide if it 2766ab74c843SKonstantin Belousov * needs to go sleep after attach. 2767ab74c843SKonstantin Belousov */ 2768ab74c843SKonstantin Belousov if (td->td_wchan == NULL) 2769b7a25e63SKonstantin Belousov td->td_dbgflags &= ~TDB_FSTP; 2770ab74c843SKonstantin Belousov 2771b7a25e63SKonstantin Belousov p->p_flag2 &= ~P2_PTRACE_FSTP; 2772b7a25e63SKonstantin Belousov p->p_flag |= P_STOPPED_SIG | P_STOPPED_TRACE; 2773d8267df7SDavid Xu sig_suspend_threads(td, p, 0); 2774b7a25e63SKonstantin Belousov } 27756fa39a73SKonstantin Belousov if ((td->td_dbgflags & TDB_STOPATFORK) != 0) { 27766fa39a73SKonstantin Belousov td->td_dbgflags &= ~TDB_STOPATFORK; 27776fa39a73SKonstantin Belousov } 2778cbf4e354SDavid Xu stopme: 277968d311b6SKonstantin Belousov td->td_dbgflags |= TDB_SSWITCH; 27806ddcc233SKonstantin Belousov thread_suspend_switch(td, p); 278168d311b6SKonstantin Belousov td->td_dbgflags &= ~TDB_SSWITCH; 278287a64872SKonstantin Belousov if ((td->td_dbgflags & TDB_COREDUMPRQ) != 0) { 278387a64872SKonstantin Belousov PROC_SUNLOCK(p); 278487a64872SKonstantin Belousov ptrace_coredump(td); 278587a64872SKonstantin Belousov PROC_SLOCK(p); 278687a64872SKonstantin Belousov goto stopme; 278787a64872SKonstantin Belousov } 27887ce60f60SDavid Xu if (p->p_xthread == td) 27897ce60f60SDavid Xu p->p_xthread = NULL; 27907ce60f60SDavid Xu if (!(p->p_flag & P_TRACED)) 2791cbf4e354SDavid Xu break; 2792904c5ec4SDavid Xu if (td->td_dbgflags & TDB_SUSPEND) { 2793cbf4e354SDavid Xu if (p->p_flag & P_SINGLE_EXIT) 2794cbf4e354SDavid Xu break; 2795cbf4e354SDavid Xu goto stopme; 2796cbf4e354SDavid Xu } 2797cbf4e354SDavid Xu } 27987b4a950aSDavid Xu PROC_SUNLOCK(p); 279982a4538fSEric Badger } 280082a4538fSEric Badger 280182a4538fSEric Badger if (si != NULL && sig == td->td_xsig) { 280282a4538fSEric Badger /* Parent wants us to take the original signal unchanged. */ 280382a4538fSEric Badger si->ksi_flags |= KSI_HEAD; 280482a4538fSEric Badger if (sigqueue_add(&td->td_sigqueue, sig, si) != 0) 280582a4538fSEric Badger si->ksi_signo = 0; 280682a4538fSEric Badger } else if (td->td_xsig != 0) { 280782a4538fSEric Badger /* 280882a4538fSEric Badger * If parent wants us to take a new signal, then it will leave 280982a4538fSEric Badger * it in td->td_xsig; otherwise we just look for signals again. 281082a4538fSEric Badger */ 281182a4538fSEric Badger ksiginfo_init(&ksi); 281282a4538fSEric Badger ksi.ksi_signo = td->td_xsig; 281382a4538fSEric Badger ksi.ksi_flags |= KSI_PTRACE; 2814146fc63fSKonstantin Belousov td2 = sigtd(p, td->td_xsig, false); 281582a4538fSEric Badger tdsendsignal(p, td2, td->td_xsig, &ksi); 281682a4538fSEric Badger if (td != td2) 281782a4538fSEric Badger return (0); 281882a4538fSEric Badger } 281982a4538fSEric Badger 2820cbf4e354SDavid Xu return (td->td_xsig); 28214cc9f52fSRobert Drehmel } 28224cc9f52fSRobert Drehmel 28230bc52b0bSKonstantin Belousov static void 282480a8b0f3SKonstantin Belousov reschedule_signals(struct proc *p, sigset_t block, int flags) 28256b286ee8SKonstantin Belousov { 28266b286ee8SKonstantin Belousov struct sigacts *ps; 28276b286ee8SKonstantin Belousov struct thread *td; 2828407af02bSDavid Xu int sig; 2829146fc63fSKonstantin Belousov bool fastblk, pslocked; 28306b286ee8SKonstantin Belousov 28316b286ee8SKonstantin Belousov PROC_LOCK_ASSERT(p, MA_OWNED); 283270778bbaSKonstantin Belousov ps = p->p_sigacts; 2833146fc63fSKonstantin Belousov pslocked = (flags & SIGPROCMASK_PS_LOCKED) != 0; 2834146fc63fSKonstantin Belousov mtx_assert(&ps->ps_mtx, pslocked ? MA_OWNED : MA_NOTOWNED); 2835407af02bSDavid Xu if (SIGISEMPTY(p->p_siglist)) 2836407af02bSDavid Xu return; 2837407af02bSDavid Xu SIGSETAND(block, p->p_siglist); 2838146fc63fSKonstantin Belousov fastblk = (flags & SIGPROCMASK_FASTBLK) != 0; 283981f2e906SMark Johnston SIG_FOREACH(sig, &block) { 2840146fc63fSKonstantin Belousov td = sigtd(p, sig, fastblk); 2841146fc63fSKonstantin Belousov 2842146fc63fSKonstantin Belousov /* 2843146fc63fSKonstantin Belousov * If sigtd() selected us despite sigfastblock is 2844146fc63fSKonstantin Belousov * blocking, do not activate AST or wake us, to avoid 2845146fc63fSKonstantin Belousov * loop in AST handler. 2846146fc63fSKonstantin Belousov */ 2847146fc63fSKonstantin Belousov if (fastblk && td == curthread) 2848146fc63fSKonstantin Belousov continue; 2849146fc63fSKonstantin Belousov 28506b286ee8SKonstantin Belousov signotify(td); 2851146fc63fSKonstantin Belousov if (!pslocked) 28526b286ee8SKonstantin Belousov mtx_lock(&ps->ps_mtx); 2853396a0d44SKonstantin Belousov if (p->p_flag & P_TRACED || 2854396a0d44SKonstantin Belousov (SIGISMEMBER(ps->ps_sigcatch, sig) && 2855146fc63fSKonstantin Belousov !SIGISMEMBER(td->td_sigmask, sig))) { 2856407af02bSDavid Xu tdsigwakeup(td, sig, SIG_CATCH, 2857407af02bSDavid Xu (SIGISMEMBER(ps->ps_sigintr, sig) ? EINTR : 28586b286ee8SKonstantin Belousov ERESTART)); 2859146fc63fSKonstantin Belousov } 2860146fc63fSKonstantin Belousov if (!pslocked) 28616b286ee8SKonstantin Belousov mtx_unlock(&ps->ps_mtx); 28626b286ee8SKonstantin Belousov } 28636b286ee8SKonstantin Belousov } 28646b286ee8SKonstantin Belousov 28656b286ee8SKonstantin Belousov void 28666b286ee8SKonstantin Belousov tdsigcleanup(struct thread *td) 28676b286ee8SKonstantin Belousov { 28686b286ee8SKonstantin Belousov struct proc *p; 28696b286ee8SKonstantin Belousov sigset_t unblocked; 28706b286ee8SKonstantin Belousov 28716b286ee8SKonstantin Belousov p = td->td_proc; 28726b286ee8SKonstantin Belousov PROC_LOCK_ASSERT(p, MA_OWNED); 28736b286ee8SKonstantin Belousov 28746b286ee8SKonstantin Belousov sigqueue_flush(&td->td_sigqueue); 28756b286ee8SKonstantin Belousov if (p->p_numthreads == 1) 28766b286ee8SKonstantin Belousov return; 28776b286ee8SKonstantin Belousov 28786b286ee8SKonstantin Belousov /* 28796b286ee8SKonstantin Belousov * Since we cannot handle signals, notify signal post code 28806b286ee8SKonstantin Belousov * about this by filling the sigmask. 28816b286ee8SKonstantin Belousov * 28826b286ee8SKonstantin Belousov * Also, if needed, wake up thread(s) that do not block the 28836b286ee8SKonstantin Belousov * same signals as the exiting thread, since the thread might 28846b286ee8SKonstantin Belousov * have been selected for delivery and woken up. 28856b286ee8SKonstantin Belousov */ 28866b286ee8SKonstantin Belousov SIGFILLSET(unblocked); 28876b286ee8SKonstantin Belousov SIGSETNAND(unblocked, td->td_sigmask); 28886b286ee8SKonstantin Belousov SIGFILLSET(td->td_sigmask); 288980a8b0f3SKonstantin Belousov reschedule_signals(p, unblocked, 0); 28906b286ee8SKonstantin Belousov 28916b286ee8SKonstantin Belousov } 28926b286ee8SKonstantin Belousov 28933a1e5dd8SKonstantin Belousov static int 28943a1e5dd8SKonstantin Belousov sigdeferstop_curr_flags(int cflags) 2895a120a7a3SJohn Baldwin { 2896a120a7a3SJohn Baldwin 28973a1e5dd8SKonstantin Belousov MPASS((cflags & (TDF_SEINTR | TDF_SERESTART)) == 0 || 28983a1e5dd8SKonstantin Belousov (cflags & TDF_SBDRY) != 0); 28993a1e5dd8SKonstantin Belousov return (cflags & (TDF_SBDRY | TDF_SEINTR | TDF_SERESTART)); 2900a120a7a3SJohn Baldwin } 2901a120a7a3SJohn Baldwin 2902a120a7a3SJohn Baldwin /* 29033a1e5dd8SKonstantin Belousov * Defer the delivery of SIGSTOP for the current thread, according to 29043a1e5dd8SKonstantin Belousov * the requested mode. Returns previous flags, which must be restored 29053a1e5dd8SKonstantin Belousov * by sigallowstop(). 29063a1e5dd8SKonstantin Belousov * 29073a1e5dd8SKonstantin Belousov * TDF_SBDRY, TDF_SEINTR, and TDF_SERESTART flags are only set and 29083a1e5dd8SKonstantin Belousov * cleared by the current thread, which allow the lock-less read-only 29093a1e5dd8SKonstantin Belousov * accesses below. 2910a120a7a3SJohn Baldwin */ 2911e3612a4cSKonstantin Belousov int 291246e47c4fSKonstantin Belousov sigdeferstop_impl(int mode) 2913a120a7a3SJohn Baldwin { 2914593efaf9SJohn Baldwin struct thread *td; 29153a1e5dd8SKonstantin Belousov int cflags, nflags; 2916a120a7a3SJohn Baldwin 2917593efaf9SJohn Baldwin td = curthread; 29183a1e5dd8SKonstantin Belousov cflags = sigdeferstop_curr_flags(td->td_flags); 29193a1e5dd8SKonstantin Belousov switch (mode) { 29203a1e5dd8SKonstantin Belousov case SIGDEFERSTOP_NOP: 29213a1e5dd8SKonstantin Belousov nflags = cflags; 29223a1e5dd8SKonstantin Belousov break; 29233a1e5dd8SKonstantin Belousov case SIGDEFERSTOP_OFF: 29243a1e5dd8SKonstantin Belousov nflags = 0; 29253a1e5dd8SKonstantin Belousov break; 29263a1e5dd8SKonstantin Belousov case SIGDEFERSTOP_SILENT: 29273a1e5dd8SKonstantin Belousov nflags = (cflags | TDF_SBDRY) & ~(TDF_SEINTR | TDF_SERESTART); 29283a1e5dd8SKonstantin Belousov break; 29293a1e5dd8SKonstantin Belousov case SIGDEFERSTOP_EINTR: 29303a1e5dd8SKonstantin Belousov nflags = (cflags | TDF_SBDRY | TDF_SEINTR) & ~TDF_SERESTART; 29313a1e5dd8SKonstantin Belousov break; 29323a1e5dd8SKonstantin Belousov case SIGDEFERSTOP_ERESTART: 29333a1e5dd8SKonstantin Belousov nflags = (cflags | TDF_SBDRY | TDF_SERESTART) & ~TDF_SEINTR; 29343a1e5dd8SKonstantin Belousov break; 29353a1e5dd8SKonstantin Belousov default: 29363a1e5dd8SKonstantin Belousov panic("sigdeferstop: invalid mode %x", mode); 29373a1e5dd8SKonstantin Belousov break; 29383a1e5dd8SKonstantin Belousov } 293946e47c4fSKonstantin Belousov if (cflags == nflags) 294046e47c4fSKonstantin Belousov return (SIGDEFERSTOP_VAL_NCHG); 2941a120a7a3SJohn Baldwin thread_lock(td); 29423a1e5dd8SKonstantin Belousov td->td_flags = (td->td_flags & ~cflags) | nflags; 2943a120a7a3SJohn Baldwin thread_unlock(td); 29443a1e5dd8SKonstantin Belousov return (cflags); 29453a1e5dd8SKonstantin Belousov } 29463a1e5dd8SKonstantin Belousov 29473a1e5dd8SKonstantin Belousov /* 29483a1e5dd8SKonstantin Belousov * Restores the STOP handling mode, typically permitting the delivery 29493a1e5dd8SKonstantin Belousov * of SIGSTOP for the current thread. This does not immediately 29503a1e5dd8SKonstantin Belousov * suspend if a stop was posted. Instead, the thread will suspend 29513a1e5dd8SKonstantin Belousov * either via ast() or a subsequent interruptible sleep. 29523a1e5dd8SKonstantin Belousov */ 29533a1e5dd8SKonstantin Belousov void 295446e47c4fSKonstantin Belousov sigallowstop_impl(int prev) 29553a1e5dd8SKonstantin Belousov { 29563a1e5dd8SKonstantin Belousov struct thread *td; 29573a1e5dd8SKonstantin Belousov int cflags; 29583a1e5dd8SKonstantin Belousov 295946e47c4fSKonstantin Belousov KASSERT(prev != SIGDEFERSTOP_VAL_NCHG, ("failed sigallowstop")); 29603a1e5dd8SKonstantin Belousov KASSERT((prev & ~(TDF_SBDRY | TDF_SEINTR | TDF_SERESTART)) == 0, 29613a1e5dd8SKonstantin Belousov ("sigallowstop: incorrect previous mode %x", prev)); 29623a1e5dd8SKonstantin Belousov td = curthread; 29633a1e5dd8SKonstantin Belousov cflags = sigdeferstop_curr_flags(td->td_flags); 29643a1e5dd8SKonstantin Belousov if (cflags != prev) { 29653a1e5dd8SKonstantin Belousov thread_lock(td); 29663a1e5dd8SKonstantin Belousov td->td_flags = (td->td_flags & ~cflags) | prev; 29673a1e5dd8SKonstantin Belousov thread_unlock(td); 29683a1e5dd8SKonstantin Belousov } 2969a120a7a3SJohn Baldwin } 2970a120a7a3SJohn Baldwin 297181f2e906SMark Johnston enum sigstatus { 297281f2e906SMark Johnston SIGSTATUS_HANDLE, 297381f2e906SMark Johnston SIGSTATUS_HANDLED, 297481f2e906SMark Johnston SIGSTATUS_IGNORE, 297581f2e906SMark Johnston SIGSTATUS_SBDRY_STOP, 297681f2e906SMark Johnston }; 297781f2e906SMark Johnston 297881f2e906SMark Johnston /* 297981f2e906SMark Johnston * The thread has signal "sig" pending. Figure out what to do with it: 298081f2e906SMark Johnston * 298181f2e906SMark Johnston * _HANDLE -> the caller should handle the signal 298281f2e906SMark Johnston * _HANDLED -> handled internally, reload pending signal set 298381f2e906SMark Johnston * _IGNORE -> ignored, remove from the set of pending signals and try the 298481f2e906SMark Johnston * next pending signal 298581f2e906SMark Johnston * _SBDRY_STOP -> the signal should stop the thread but this is not 298681f2e906SMark Johnston * permitted in the current context 298781f2e906SMark Johnston */ 298881f2e906SMark Johnston static enum sigstatus 298981f2e906SMark Johnston sigprocess(struct thread *td, int sig) 299081f2e906SMark Johnston { 299181f2e906SMark Johnston struct proc *p; 299281f2e906SMark Johnston struct sigacts *ps; 299381f2e906SMark Johnston struct sigqueue *queue; 299481f2e906SMark Johnston ksiginfo_t ksi; 299581f2e906SMark Johnston int prop; 299681f2e906SMark Johnston 299781f2e906SMark Johnston KASSERT(_SIG_VALID(sig), ("%s: invalid signal %d", __func__, sig)); 299881f2e906SMark Johnston 299981f2e906SMark Johnston p = td->td_proc; 300081f2e906SMark Johnston ps = p->p_sigacts; 300181f2e906SMark Johnston mtx_assert(&ps->ps_mtx, MA_OWNED); 300281f2e906SMark Johnston PROC_LOCK_ASSERT(p, MA_OWNED); 300381f2e906SMark Johnston 300481f2e906SMark Johnston /* 300581f2e906SMark Johnston * We should allow pending but ignored signals below 300602a2aacbSKonstantin Belousov * if there is sigwait() active, or P_TRACED was 300781f2e906SMark Johnston * on when they were posted. 300881f2e906SMark Johnston */ 300981f2e906SMark Johnston if (SIGISMEMBER(ps->ps_sigignore, sig) && 301081f2e906SMark Johnston (p->p_flag & P_TRACED) == 0 && 301181f2e906SMark Johnston (td->td_flags & TDF_SIGWAIT) == 0) { 301281f2e906SMark Johnston return (SIGSTATUS_IGNORE); 301381f2e906SMark Johnston } 301481f2e906SMark Johnston 301502a2aacbSKonstantin Belousov /* 301602a2aacbSKonstantin Belousov * If the process is going to single-thread mode to prepare 301702a2aacbSKonstantin Belousov * for exit, there is no sense in delivering any signal 301802a2aacbSKonstantin Belousov * to usermode. Another important consequence is that 301902a2aacbSKonstantin Belousov * msleep(..., PCATCH, ...) now is only interruptible by a 302002a2aacbSKonstantin Belousov * suspend request. 302102a2aacbSKonstantin Belousov */ 302202a2aacbSKonstantin Belousov if ((p->p_flag2 & P2_WEXIT) != 0) 302302a2aacbSKonstantin Belousov return (SIGSTATUS_IGNORE); 302402a2aacbSKonstantin Belousov 302581f2e906SMark Johnston if ((p->p_flag & (P_TRACED | P_PPTRACE)) == P_TRACED) { 302681f2e906SMark Johnston /* 302781f2e906SMark Johnston * If traced, always stop. 302881f2e906SMark Johnston * Remove old signal from queue before the stop. 302981f2e906SMark Johnston * XXX shrug off debugger, it causes siginfo to 303081f2e906SMark Johnston * be thrown away. 303181f2e906SMark Johnston */ 303281f2e906SMark Johnston queue = &td->td_sigqueue; 303381f2e906SMark Johnston ksiginfo_init(&ksi); 303481f2e906SMark Johnston if (sigqueue_get(queue, sig, &ksi) == 0) { 303581f2e906SMark Johnston queue = &p->p_sigqueue; 303681f2e906SMark Johnston sigqueue_get(queue, sig, &ksi); 303781f2e906SMark Johnston } 303881f2e906SMark Johnston td->td_si = ksi.ksi_info; 303981f2e906SMark Johnston 304081f2e906SMark Johnston mtx_unlock(&ps->ps_mtx); 304181f2e906SMark Johnston sig = ptracestop(td, sig, &ksi); 304281f2e906SMark Johnston mtx_lock(&ps->ps_mtx); 304381f2e906SMark Johnston 304481f2e906SMark Johnston td->td_si.si_signo = 0; 304581f2e906SMark Johnston 304681f2e906SMark Johnston /* 304781f2e906SMark Johnston * Keep looking if the debugger discarded or 304881f2e906SMark Johnston * replaced the signal. 304981f2e906SMark Johnston */ 305081f2e906SMark Johnston if (sig == 0) 305181f2e906SMark Johnston return (SIGSTATUS_HANDLED); 305281f2e906SMark Johnston 305381f2e906SMark Johnston /* 305481f2e906SMark Johnston * If the signal became masked, re-queue it. 305581f2e906SMark Johnston */ 305681f2e906SMark Johnston if (SIGISMEMBER(td->td_sigmask, sig)) { 305781f2e906SMark Johnston ksi.ksi_flags |= KSI_HEAD; 305881f2e906SMark Johnston sigqueue_add(&p->p_sigqueue, sig, &ksi); 305981f2e906SMark Johnston return (SIGSTATUS_HANDLED); 306081f2e906SMark Johnston } 306181f2e906SMark Johnston 306281f2e906SMark Johnston /* 306381f2e906SMark Johnston * If the traced bit got turned off, requeue the signal and 306481f2e906SMark Johnston * reload the set of pending signals. This ensures that p_sig* 306581f2e906SMark Johnston * and p_sigact are consistent. 306681f2e906SMark Johnston */ 306781f2e906SMark Johnston if ((p->p_flag & P_TRACED) == 0) { 3068a24afbb4SKonstantin Belousov if ((ksi.ksi_flags & KSI_PTRACE) == 0) { 306981f2e906SMark Johnston ksi.ksi_flags |= KSI_HEAD; 307081f2e906SMark Johnston sigqueue_add(queue, sig, &ksi); 3071a24afbb4SKonstantin Belousov } 307281f2e906SMark Johnston return (SIGSTATUS_HANDLED); 307381f2e906SMark Johnston } 307481f2e906SMark Johnston } 307581f2e906SMark Johnston 307681f2e906SMark Johnston /* 307781f2e906SMark Johnston * Decide whether the signal should be returned. 307881f2e906SMark Johnston * Return the signal's number, or fall through 307981f2e906SMark Johnston * to clear it from the pending mask. 308081f2e906SMark Johnston */ 308181f2e906SMark Johnston switch ((intptr_t)p->p_sigacts->ps_sigact[_SIG_IDX(sig)]) { 308281f2e906SMark Johnston case (intptr_t)SIG_DFL: 308381f2e906SMark Johnston /* 308481f2e906SMark Johnston * Don't take default actions on system processes. 308581f2e906SMark Johnston */ 308681f2e906SMark Johnston if (p->p_pid <= 1) { 308781f2e906SMark Johnston #ifdef DIAGNOSTIC 308881f2e906SMark Johnston /* 308981f2e906SMark Johnston * Are you sure you want to ignore SIGSEGV 309081f2e906SMark Johnston * in init? XXX 309181f2e906SMark Johnston */ 309281f2e906SMark Johnston printf("Process (pid %lu) got signal %d\n", 309381f2e906SMark Johnston (u_long)p->p_pid, sig); 309481f2e906SMark Johnston #endif 309581f2e906SMark Johnston return (SIGSTATUS_IGNORE); 309681f2e906SMark Johnston } 309781f2e906SMark Johnston 309881f2e906SMark Johnston /* 309981f2e906SMark Johnston * If there is a pending stop signal to process with 310081f2e906SMark Johnston * default action, stop here, then clear the signal. 310181f2e906SMark Johnston * Traced or exiting processes should ignore stops. 310281f2e906SMark Johnston * Additionally, a member of an orphaned process group 310381f2e906SMark Johnston * should ignore tty stops. 310481f2e906SMark Johnston */ 310581f2e906SMark Johnston prop = sigprop(sig); 310681f2e906SMark Johnston if (prop & SIGPROP_STOP) { 310781f2e906SMark Johnston mtx_unlock(&ps->ps_mtx); 310881f2e906SMark Johnston if ((p->p_flag & (P_TRACED | P_WEXIT | 310981f2e906SMark Johnston P_SINGLE_EXIT)) != 0 || ((p->p_pgrp-> 311081f2e906SMark Johnston pg_flags & PGRP_ORPHANED) != 0 && 311181f2e906SMark Johnston (prop & SIGPROP_TTYSTOP) != 0)) { 311281f2e906SMark Johnston mtx_lock(&ps->ps_mtx); 311381f2e906SMark Johnston return (SIGSTATUS_IGNORE); 311481f2e906SMark Johnston } 311581f2e906SMark Johnston if (TD_SBDRY_INTR(td)) { 311681f2e906SMark Johnston KASSERT((td->td_flags & TDF_SBDRY) != 0, 311781f2e906SMark Johnston ("lost TDF_SBDRY")); 311881f2e906SMark Johnston mtx_lock(&ps->ps_mtx); 311981f2e906SMark Johnston return (SIGSTATUS_SBDRY_STOP); 312081f2e906SMark Johnston } 312181f2e906SMark Johnston WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, 312281f2e906SMark Johnston &p->p_mtx.lock_object, "Catching SIGSTOP"); 312381f2e906SMark Johnston sigqueue_delete(&td->td_sigqueue, sig); 312481f2e906SMark Johnston sigqueue_delete(&p->p_sigqueue, sig); 312581f2e906SMark Johnston p->p_flag |= P_STOPPED_SIG; 312681f2e906SMark Johnston p->p_xsig = sig; 312781f2e906SMark Johnston PROC_SLOCK(p); 312881f2e906SMark Johnston sig_suspend_threads(td, p, 0); 312981f2e906SMark Johnston thread_suspend_switch(td, p); 313081f2e906SMark Johnston PROC_SUNLOCK(p); 313181f2e906SMark Johnston mtx_lock(&ps->ps_mtx); 313281f2e906SMark Johnston return (SIGSTATUS_HANDLED); 313381f2e906SMark Johnston } else if ((prop & SIGPROP_IGNORE) != 0 && 313481f2e906SMark Johnston (td->td_flags & TDF_SIGWAIT) == 0) { 313581f2e906SMark Johnston /* 313681f2e906SMark Johnston * Default action is to ignore; drop it if 313781f2e906SMark Johnston * not in kern_sigtimedwait(). 313881f2e906SMark Johnston */ 313981f2e906SMark Johnston return (SIGSTATUS_IGNORE); 314081f2e906SMark Johnston } else { 314181f2e906SMark Johnston return (SIGSTATUS_HANDLE); 314281f2e906SMark Johnston } 314381f2e906SMark Johnston 314481f2e906SMark Johnston case (intptr_t)SIG_IGN: 314581f2e906SMark Johnston if ((td->td_flags & TDF_SIGWAIT) == 0) 314681f2e906SMark Johnston return (SIGSTATUS_IGNORE); 314781f2e906SMark Johnston else 314881f2e906SMark Johnston return (SIGSTATUS_HANDLE); 314981f2e906SMark Johnston 315081f2e906SMark Johnston default: 315181f2e906SMark Johnston /* 315281f2e906SMark Johnston * This signal has an action, let postsig() process it. 315381f2e906SMark Johnston */ 315481f2e906SMark Johnston return (SIGSTATUS_HANDLE); 315581f2e906SMark Johnston } 315681f2e906SMark Johnston } 315781f2e906SMark Johnston 3158df8bae1dSRodney W. Grimes /* 3159df8bae1dSRodney W. Grimes * If the current process has received a signal (should be caught or cause 3160df8bae1dSRodney W. Grimes * termination, should interrupt current syscall), return the signal number. 3161df8bae1dSRodney W. Grimes * Stop signals with default action are processed immediately, then cleared; 3162df8bae1dSRodney W. Grimes * they aren't returned. This is checked after each entry to the system for 316381f2e906SMark Johnston * a syscall or trap (though this can usually be done without calling 316481f2e906SMark Johnston * issignal by checking the pending signal masks in cursig.) The normal call 3165df8bae1dSRodney W. Grimes * sequence is 3166df8bae1dSRodney W. Grimes * 3167e602ba25SJulian Elischer * while (sig = cursig(curthread)) 31682c42a146SMarcel Moolenaar * postsig(sig); 3169df8bae1dSRodney W. Grimes */ 31706711f10fSJohn Baldwin static int 31713cf3b9f0SJohn Baldwin issignal(struct thread *td) 3172df8bae1dSRodney W. Grimes { 3173e602ba25SJulian Elischer struct proc *p; 31744093529dSJeff Roberson sigset_t sigpending; 317581f2e906SMark Johnston int sig; 3176df8bae1dSRodney W. Grimes 3177e602ba25SJulian Elischer p = td->td_proc; 3178628d2653SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 317981f2e906SMark Johnston 3180df8bae1dSRodney W. Grimes for (;;) { 31819104847fSDavid Xu sigpending = td->td_sigqueue.sq_signals; 31826b286ee8SKonstantin Belousov SIGSETOR(sigpending, p->p_sigqueue.sq_signals); 31834093529dSJeff Roberson SIGSETNAND(sigpending, td->td_sigmask); 31844093529dSJeff Roberson 31856f56cb8dSKonstantin Belousov if ((p->p_flag & P_PPWAIT) != 0 || (td->td_flags & 31866f56cb8dSKonstantin Belousov (TDF_SBDRY | TDF_SERESTART | TDF_SEINTR)) == TDF_SBDRY) 31874093529dSJeff Roberson SIG_STOPSIGMASK(sigpending); 31884093529dSJeff Roberson if (SIGISEMPTY(sigpending)) /* no signal to send */ 3189df8bae1dSRodney W. Grimes return (0); 3190146fc63fSKonstantin Belousov 3191146fc63fSKonstantin Belousov /* 3192146fc63fSKonstantin Belousov * Do fast sigblock if requested by usermode. Since 3193146fc63fSKonstantin Belousov * we do know that there was a signal pending at this 3194146fc63fSKonstantin Belousov * point, set the FAST_SIGBLOCK_PEND as indicator for 3195146fc63fSKonstantin Belousov * usermode to perform a dummy call to 3196146fc63fSKonstantin Belousov * FAST_SIGBLOCK_UNBLOCK, which causes immediate 3197146fc63fSKonstantin Belousov * delivery of postponed pending signal. 3198146fc63fSKonstantin Belousov */ 3199146fc63fSKonstantin Belousov if ((td->td_pflags & TDP_SIGFASTBLOCK) != 0) { 3200146fc63fSKonstantin Belousov if (td->td_sigblock_val != 0) 3201146fc63fSKonstantin Belousov SIGSETNAND(sigpending, fastblock_mask); 3202146fc63fSKonstantin Belousov if (SIGISEMPTY(sigpending)) { 3203146fc63fSKonstantin Belousov td->td_pflags |= TDP_SIGFASTPENDING; 3204146fc63fSKonstantin Belousov return (0); 3205146fc63fSKonstantin Belousov } 3206146fc63fSKonstantin Belousov } 3207146fc63fSKonstantin Belousov 3208b7a25e63SKonstantin Belousov if ((p->p_flag & (P_TRACED | P_PPTRACE)) == P_TRACED && 3209b7a25e63SKonstantin Belousov (p->p_flag2 & P2_PTRACE_FSTP) != 0 && 3210b7a25e63SKonstantin Belousov SIGISMEMBER(sigpending, SIGSTOP)) { 3211b7a25e63SKonstantin Belousov /* 3212b7a25e63SKonstantin Belousov * If debugger just attached, always consume 3213b7a25e63SKonstantin Belousov * SIGSTOP from ptrace(PT_ATTACH) first, to 3214b7a25e63SKonstantin Belousov * execute the debugger attach ritual in 3215b7a25e63SKonstantin Belousov * order. 3216b7a25e63SKonstantin Belousov */ 3217b7a25e63SKonstantin Belousov td->td_dbgflags |= TDB_FSTP; 321881f2e906SMark Johnston SIGEMPTYSET(sigpending); 321981f2e906SMark Johnston SIGADDSET(sigpending, SIGSTOP); 3220b7a25e63SKonstantin Belousov } 32212a024a2bSSean Eric Fagan 322281f2e906SMark Johnston SIG_FOREACH(sig, &sigpending) { 322381f2e906SMark Johnston switch (sigprocess(td, sig)) { 322481f2e906SMark Johnston case SIGSTATUS_HANDLE: 322581f2e906SMark Johnston return (sig); 322681f2e906SMark Johnston case SIGSTATUS_HANDLED: 322781f2e906SMark Johnston goto next; 322881f2e906SMark Johnston case SIGSTATUS_IGNORE: 32299104847fSDavid Xu sigqueue_delete(&td->td_sigqueue, sig); 32306b286ee8SKonstantin Belousov sigqueue_delete(&p->p_sigqueue, sig); 323181f2e906SMark Johnston break; 323281f2e906SMark Johnston case SIGSTATUS_SBDRY_STOP: 323346e47c4fSKonstantin Belousov return (-1); 323446e47c4fSKonstantin Belousov } 3235df8bae1dSRodney W. Grimes } 3236b7a25e63SKonstantin Belousov next:; 3237df8bae1dSRodney W. Grimes } 3238df8bae1dSRodney W. Grimes } 3239df8bae1dSRodney W. Grimes 3240e574e444SDavid Xu void 3241e574e444SDavid Xu thread_stopped(struct proc *p) 3242e574e444SDavid Xu { 3243e574e444SDavid Xu int n; 3244e574e444SDavid Xu 3245e574e444SDavid Xu PROC_LOCK_ASSERT(p, MA_OWNED); 32467b4a950aSDavid Xu PROC_SLOCK_ASSERT(p, MA_OWNED); 3247e574e444SDavid Xu n = p->p_suspcount; 32487c9a98f1SDavid Xu if (p == curproc) 3249e574e444SDavid Xu n++; 3250e574e444SDavid Xu if ((p->p_flag & P_STOPPED_SIG) && (n == p->p_numthreads)) { 32517b4a950aSDavid Xu PROC_SUNLOCK(p); 3252407948a5SDavid Xu p->p_flag &= ~P_WAITED; 3253e574e444SDavid Xu PROC_LOCK(p->p_pptr); 32547f96995eSDavid Xu childproc_stopped(p, (p->p_flag & P_TRACED) ? 3255ebceaf6dSDavid Xu CLD_TRAPPED : CLD_STOPPED); 3256e574e444SDavid Xu PROC_UNLOCK(p->p_pptr); 32577b4a950aSDavid Xu PROC_SLOCK(p); 3258e574e444SDavid Xu } 3259e574e444SDavid Xu } 3260e574e444SDavid Xu 3261df8bae1dSRodney W. Grimes /* 3262df8bae1dSRodney W. Grimes * Take the action for the specified signal 3263df8bae1dSRodney W. Grimes * from the current set of pending signals. 3264df8bae1dSRodney W. Grimes */ 326575c586a4SKonstantin Belousov int 32660167b33bSKonstantin Belousov postsig(int sig) 3267df8bae1dSRodney W. Grimes { 32680167b33bSKonstantin Belousov struct thread *td; 32690167b33bSKonstantin Belousov struct proc *p; 3270628d2653SJohn Baldwin struct sigacts *ps; 32712c42a146SMarcel Moolenaar sig_t action; 32729104847fSDavid Xu ksiginfo_t ksi; 3273e442f29fSKonstantin Belousov sigset_t returnmask; 3274df8bae1dSRodney W. Grimes 32752c42a146SMarcel Moolenaar KASSERT(sig != 0, ("postsig")); 32765526d2d9SEivind Eklund 32770167b33bSKonstantin Belousov td = curthread; 32780167b33bSKonstantin Belousov p = td->td_proc; 32792ad7d304SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 3280628d2653SJohn Baldwin ps = p->p_sigacts; 328190af4afaSJohn Baldwin mtx_assert(&ps->ps_mtx, MA_OWNED); 32825da49fcbSDavid Xu ksiginfo_init(&ksi); 32836b286ee8SKonstantin Belousov if (sigqueue_get(&td->td_sigqueue, sig, &ksi) == 0 && 32846b286ee8SKonstantin Belousov sigqueue_get(&p->p_sigqueue, sig, &ksi) == 0) 328575c586a4SKonstantin Belousov return (0); 32869104847fSDavid Xu ksi.ksi_signo = sig; 328756c06c4bSDavid Xu if (ksi.ksi_code == SI_TIMER) 328856c06c4bSDavid Xu itimer_accept(p, ksi.ksi_timerid, &ksi); 32892c42a146SMarcel Moolenaar action = ps->ps_sigact[_SIG_IDX(sig)]; 3290df8bae1dSRodney W. Grimes #ifdef KTRACE 3291374a15aaSJohn Baldwin if (KTRPOINT(td, KTR_PSIG)) 32925e26dcb5SJohn Baldwin ktrpsig(sig, action, td->td_pflags & TDP_OLDMASK ? 329361009552SJilles Tjoelker &td->td_oldsigmask : &td->td_sigmask, ksi.ksi_code); 3294df8bae1dSRodney W. Grimes #endif 32952a024a2bSSean Eric Fagan 32968460a577SJohn Birrell if (action == SIG_DFL) { 3297df8bae1dSRodney W. Grimes /* 3298df8bae1dSRodney W. Grimes * Default action, where the default is to kill 3299df8bae1dSRodney W. Grimes * the process. (Other cases were ignored above.) 3300df8bae1dSRodney W. Grimes */ 330190af4afaSJohn Baldwin mtx_unlock(&ps->ps_mtx); 330286be94fcSTycho Nightingale proc_td_siginfo_capture(td, &ksi.ksi_info); 3303b40ce416SJulian Elischer sigexit(td, sig); 3304df8bae1dSRodney W. Grimes /* NOTREACHED */ 3305df8bae1dSRodney W. Grimes } else { 3306df8bae1dSRodney W. Grimes /* 3307df8bae1dSRodney W. Grimes * If we get here, the signal must be caught. 3308df8bae1dSRodney W. Grimes */ 3309cd735d8fSKonstantin Belousov KASSERT(action != SIG_IGN, ("postsig action %p", action)); 3310cd735d8fSKonstantin Belousov KASSERT(!SIGISMEMBER(td->td_sigmask, sig), 3311cd735d8fSKonstantin Belousov ("postsig action: blocked sig %d", sig)); 3312cd735d8fSKonstantin Belousov 3313df8bae1dSRodney W. Grimes /* 3314df8bae1dSRodney W. Grimes * Set the new mask value and also defer further 3315645682fdSLuoqi Chen * occurrences of this signal. 3316df8bae1dSRodney W. Grimes * 3317645682fdSLuoqi Chen * Special case: user has done a sigsuspend. Here the 3318df8bae1dSRodney W. Grimes * current mask is not of interest, but rather the 3319645682fdSLuoqi Chen * mask from before the sigsuspend is what we want 3320df8bae1dSRodney W. Grimes * restored after the signal processing is completed. 3321df8bae1dSRodney W. Grimes */ 33225e26dcb5SJohn Baldwin if (td->td_pflags & TDP_OLDMASK) { 33234093529dSJeff Roberson returnmask = td->td_oldsigmask; 33245e26dcb5SJohn Baldwin td->td_pflags &= ~TDP_OLDMASK; 3325df8bae1dSRodney W. Grimes } else 33264093529dSJeff Roberson returnmask = td->td_sigmask; 33272c42a146SMarcel Moolenaar 3328c90c9021SEd Schouten if (p->p_sig == sig) { 33296626c604SJulian Elischer p->p_sig = 0; 3330df8bae1dSRodney W. Grimes } 33319104847fSDavid Xu (*p->p_sysent->sv_sendsig)(action, &ksi, &returnmask); 3332e442f29fSKonstantin Belousov postsig_done(sig, td, ps); 3333df8bae1dSRodney W. Grimes } 333475c586a4SKonstantin Belousov return (1); 3335df8bae1dSRodney W. Grimes } 3336df8bae1dSRodney W. Grimes 33370c82fb26SKonstantin Belousov int 33380c82fb26SKonstantin Belousov sig_ast_checksusp(struct thread *td) 33390c82fb26SKonstantin Belousov { 33403d277851SKonstantin Belousov struct proc *p __diagused; 33410c82fb26SKonstantin Belousov int ret; 33420c82fb26SKonstantin Belousov 33430c82fb26SKonstantin Belousov p = td->td_proc; 33440c82fb26SKonstantin Belousov PROC_LOCK_ASSERT(p, MA_OWNED); 33450c82fb26SKonstantin Belousov 3346c6d31b83SKonstantin Belousov if (!td_ast_pending(td, TDA_SUSPEND)) 33470c82fb26SKonstantin Belousov return (0); 33480c82fb26SKonstantin Belousov 33490c82fb26SKonstantin Belousov ret = thread_suspend_check(1); 33500c82fb26SKonstantin Belousov MPASS(ret == 0 || ret == EINTR || ret == ERESTART); 33510c82fb26SKonstantin Belousov return (ret); 33520c82fb26SKonstantin Belousov } 33530c82fb26SKonstantin Belousov 33540c82fb26SKonstantin Belousov int 33550c82fb26SKonstantin Belousov sig_ast_needsigchk(struct thread *td) 33560c82fb26SKonstantin Belousov { 33570c82fb26SKonstantin Belousov struct proc *p; 33580c82fb26SKonstantin Belousov struct sigacts *ps; 33590c82fb26SKonstantin Belousov int ret, sig; 33600c82fb26SKonstantin Belousov 33610c82fb26SKonstantin Belousov p = td->td_proc; 33620c82fb26SKonstantin Belousov PROC_LOCK_ASSERT(p, MA_OWNED); 33630c82fb26SKonstantin Belousov 3364c6d31b83SKonstantin Belousov if (!td_ast_pending(td, TDA_SIG)) 33650c82fb26SKonstantin Belousov return (0); 33660c82fb26SKonstantin Belousov 33670c82fb26SKonstantin Belousov ps = p->p_sigacts; 33680c82fb26SKonstantin Belousov mtx_lock(&ps->ps_mtx); 33690c82fb26SKonstantin Belousov sig = cursig(td); 33700c82fb26SKonstantin Belousov if (sig == -1) { 33710c82fb26SKonstantin Belousov mtx_unlock(&ps->ps_mtx); 33720c82fb26SKonstantin Belousov KASSERT((td->td_flags & TDF_SBDRY) != 0, ("lost TDF_SBDRY")); 33730c82fb26SKonstantin Belousov KASSERT(TD_SBDRY_INTR(td), 33740c82fb26SKonstantin Belousov ("lost TDF_SERESTART of TDF_SEINTR")); 33750c82fb26SKonstantin Belousov KASSERT((td->td_flags & (TDF_SEINTR | TDF_SERESTART)) != 33760c82fb26SKonstantin Belousov (TDF_SEINTR | TDF_SERESTART), 33770c82fb26SKonstantin Belousov ("both TDF_SEINTR and TDF_SERESTART")); 33780c82fb26SKonstantin Belousov ret = TD_SBDRY_ERRNO(td); 33790c82fb26SKonstantin Belousov } else if (sig != 0) { 33800c82fb26SKonstantin Belousov ret = SIGISMEMBER(ps->ps_sigintr, sig) ? EINTR : ERESTART; 33810c82fb26SKonstantin Belousov mtx_unlock(&ps->ps_mtx); 33820c82fb26SKonstantin Belousov } else { 33830c82fb26SKonstantin Belousov mtx_unlock(&ps->ps_mtx); 33840c82fb26SKonstantin Belousov ret = 0; 33850c82fb26SKonstantin Belousov } 33860c82fb26SKonstantin Belousov 33870c82fb26SKonstantin Belousov /* 33880c82fb26SKonstantin Belousov * Do not go into sleep if this thread was the ptrace(2) 33890c82fb26SKonstantin Belousov * attach leader. cursig() consumed SIGSTOP from PT_ATTACH, 33900c82fb26SKonstantin Belousov * but we usually act on the signal by interrupting sleep, and 33910c82fb26SKonstantin Belousov * should do that here as well. 33920c82fb26SKonstantin Belousov */ 33930c82fb26SKonstantin Belousov if ((td->td_dbgflags & TDB_FSTP) != 0) { 33940c82fb26SKonstantin Belousov if (ret == 0) 33950c82fb26SKonstantin Belousov ret = EINTR; 33960c82fb26SKonstantin Belousov td->td_dbgflags &= ~TDB_FSTP; 33970c82fb26SKonstantin Belousov } 33980c82fb26SKonstantin Belousov 33990c82fb26SKonstantin Belousov return (ret); 34000c82fb26SKonstantin Belousov } 34010c82fb26SKonstantin Belousov 34020400be45SKonstantin Belousov int 34030400be45SKonstantin Belousov sig_intr(void) 34040400be45SKonstantin Belousov { 34050400be45SKonstantin Belousov struct thread *td; 34060400be45SKonstantin Belousov struct proc *p; 34070400be45SKonstantin Belousov int ret; 34080400be45SKonstantin Belousov 34090400be45SKonstantin Belousov td = curthread; 3410c6d31b83SKonstantin Belousov if (!td_ast_pending(td, TDA_SIG) && !td_ast_pending(td, TDA_SUSPEND)) 3411203dda8aSKonstantin Belousov return (0); 3412203dda8aSKonstantin Belousov 34130400be45SKonstantin Belousov p = td->td_proc; 34140400be45SKonstantin Belousov 34150400be45SKonstantin Belousov PROC_LOCK(p); 34160400be45SKonstantin Belousov ret = sig_ast_checksusp(td); 34170400be45SKonstantin Belousov if (ret == 0) 34180400be45SKonstantin Belousov ret = sig_ast_needsigchk(td); 34190400be45SKonstantin Belousov PROC_UNLOCK(p); 34200400be45SKonstantin Belousov return (ret); 34210400be45SKonstantin Belousov } 34220400be45SKonstantin Belousov 3423244ab566SKonstantin Belousov bool 3424244ab566SKonstantin Belousov curproc_sigkilled(void) 3425244ab566SKonstantin Belousov { 3426244ab566SKonstantin Belousov struct thread *td; 3427244ab566SKonstantin Belousov struct proc *p; 3428244ab566SKonstantin Belousov struct sigacts *ps; 3429244ab566SKonstantin Belousov bool res; 3430244ab566SKonstantin Belousov 3431244ab566SKonstantin Belousov td = curthread; 3432c6d31b83SKonstantin Belousov if (!td_ast_pending(td, TDA_SIG)) 3433244ab566SKonstantin Belousov return (false); 3434244ab566SKonstantin Belousov 3435244ab566SKonstantin Belousov p = td->td_proc; 3436244ab566SKonstantin Belousov PROC_LOCK(p); 3437244ab566SKonstantin Belousov ps = p->p_sigacts; 3438244ab566SKonstantin Belousov mtx_lock(&ps->ps_mtx); 3439244ab566SKonstantin Belousov res = SIGISMEMBER(td->td_sigqueue.sq_signals, SIGKILL) || 3440244ab566SKonstantin Belousov SIGISMEMBER(p->p_sigqueue.sq_signals, SIGKILL); 3441244ab566SKonstantin Belousov mtx_unlock(&ps->ps_mtx); 3442244ab566SKonstantin Belousov PROC_UNLOCK(p); 3443244ab566SKonstantin Belousov return (res); 3444244ab566SKonstantin Belousov } 3445244ab566SKonstantin Belousov 3446a70e9a13SKonstantin Belousov void 3447a70e9a13SKonstantin Belousov proc_wkilled(struct proc *p) 3448a70e9a13SKonstantin Belousov { 3449a70e9a13SKonstantin Belousov 3450a70e9a13SKonstantin Belousov PROC_LOCK_ASSERT(p, MA_OWNED); 3451a70e9a13SKonstantin Belousov if ((p->p_flag & P_WKILLED) == 0) { 3452a70e9a13SKonstantin Belousov p->p_flag |= P_WKILLED; 3453a70e9a13SKonstantin Belousov /* 3454a70e9a13SKonstantin Belousov * Notify swapper that there is a process to swap in. 3455a70e9a13SKonstantin Belousov * The notification is racy, at worst it would take 10 3456a70e9a13SKonstantin Belousov * seconds for the swapper process to notice. 3457a70e9a13SKonstantin Belousov */ 3458a70e9a13SKonstantin Belousov if ((p->p_flag & (P_INMEM | P_SWAPPINGIN)) == 0) 3459a70e9a13SKonstantin Belousov wakeup(&proc0); 3460a70e9a13SKonstantin Belousov } 3461a70e9a13SKonstantin Belousov } 3462a70e9a13SKonstantin Belousov 3463df8bae1dSRodney W. Grimes /* 3464df8bae1dSRodney W. Grimes * Kill the current process for stated reason. 3465df8bae1dSRodney W. Grimes */ 346626f9a767SRodney W. Grimes void 3467fe20aaecSRyan Libby killproc(struct proc *p, const char *why) 3468df8bae1dSRodney W. Grimes { 34699081e5e8SJohn Baldwin 34709081e5e8SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 3471c3209846SPawel Jakub Dawidek CTR3(KTR_PROC, "killproc: proc %p (pid %d, %s)", p, p->p_pid, 3472c3209846SPawel Jakub Dawidek p->p_comm); 3473af8beccaSKristof Provost log(LOG_ERR, "pid %d (%s), jid %d, uid %d, was killed: %s\n", 34744ae4822dSKristof Provost p->p_pid, p->p_comm, p->p_ucred->cr_prison->pr_id, 3475de2d0d29SKristof Provost p->p_ucred->cr_uid, why); 3476a70e9a13SKonstantin Belousov proc_wkilled(p); 34778451d0ddSKip Macy kern_psignal(p, SIGKILL); 3478df8bae1dSRodney W. Grimes } 3479df8bae1dSRodney W. Grimes 3480df8bae1dSRodney W. Grimes /* 3481df8bae1dSRodney W. Grimes * Force the current process to exit with the specified signal, dumping core 3482df8bae1dSRodney W. Grimes * if appropriate. We bypass the normal tests for masked and caught signals, 3483df8bae1dSRodney W. Grimes * allowing unrecoverable failures to terminate the process without changing 3484df8bae1dSRodney W. Grimes * signal state. Mark the accounting record with the signal termination. 3485df8bae1dSRodney W. Grimes * If dumping core, save the signal number for the debugger. Calls exit and 3486df8bae1dSRodney W. Grimes * does not return. 3487df8bae1dSRodney W. Grimes */ 348826f9a767SRodney W. Grimes void 3489e052a8b9SEd Maste sigexit(struct thread *td, int sig) 3490df8bae1dSRodney W. Grimes { 3491b40ce416SJulian Elischer struct proc *p = td->td_proc; 3492df8bae1dSRodney W. Grimes 3493628d2653SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 34944493a13eSKonstantin Belousov proc_set_p2_wexit(p); 34954493a13eSKonstantin Belousov 3496df8bae1dSRodney W. Grimes p->p_acflag |= AXSIG; 3497f97c3df1SDavid Schultz /* 3498f97c3df1SDavid Schultz * We must be single-threading to generate a core dump. This 3499f97c3df1SDavid Schultz * ensures that the registers in the core file are up-to-date. 3500f97c3df1SDavid Schultz * Also, the ELF dump handler assumes that the thread list doesn't 3501f97c3df1SDavid Schultz * change out from under it. 3502f97c3df1SDavid Schultz * 3503f97c3df1SDavid Schultz * XXX If another thread attempts to single-thread before us 3504f97c3df1SDavid Schultz * (e.g. via fork()), we won't get a dump at all. 3505f97c3df1SDavid Schultz */ 3506fd50a707SBrooks Davis if ((sigprop(sig) & SIGPROP_CORE) && 3507fd50a707SBrooks Davis thread_single(p, SINGLE_NO_EXIT) == 0) { 35082c42a146SMarcel Moolenaar p->p_sig = sig; 3509c364e17eSAndrey A. Chernov /* 3510c364e17eSAndrey A. Chernov * Log signals which would cause core dumps 3511c364e17eSAndrey A. Chernov * (Log as LOG_INFO to appease those who don't want 3512c364e17eSAndrey A. Chernov * these messages.) 3513c364e17eSAndrey A. Chernov * XXX : Todo, as well as euid, write out ruid too 35144ae89b95SJohn Baldwin * Note that coredump() drops proc lock. 3515c364e17eSAndrey A. Chernov */ 3516b40ce416SJulian Elischer if (coredump(td) == 0) 35172c42a146SMarcel Moolenaar sig |= WCOREFLAG; 351857308494SJoerg Wunsch if (kern_logsigexit) 351957308494SJoerg Wunsch log(LOG_INFO, 3520af8beccaSKristof Provost "pid %d (%s), jid %d, uid %d: exited on " 35214ae4822dSKristof Provost "signal %d%s\n", p->p_pid, p->p_comm, 35224ae4822dSKristof Provost p->p_ucred->cr_prison->pr_id, 3523de2d0d29SKristof Provost td->td_ucred->cr_uid, 35242c42a146SMarcel Moolenaar sig &~ WCOREFLAG, 35252c42a146SMarcel Moolenaar sig & WCOREFLAG ? " (core dumped)" : ""); 35264ae89b95SJohn Baldwin } else 3527628d2653SJohn Baldwin PROC_UNLOCK(p); 3528b4490c6eSKonstantin Belousov exit1(td, 0, sig); 3529df8bae1dSRodney W. Grimes /* NOTREACHED */ 3530df8bae1dSRodney W. Grimes } 3531df8bae1dSRodney W. Grimes 3532ebceaf6dSDavid Xu /* 35337f96995eSDavid Xu * Send queued SIGCHLD to parent when child process's state 35347f96995eSDavid Xu * is changed. 3535ebceaf6dSDavid Xu */ 35367f96995eSDavid Xu static void 35377f96995eSDavid Xu sigparent(struct proc *p, int reason, int status) 3538ebceaf6dSDavid Xu { 3539ebceaf6dSDavid Xu PROC_LOCK_ASSERT(p, MA_OWNED); 3540ebceaf6dSDavid Xu PROC_LOCK_ASSERT(p->p_pptr, MA_OWNED); 3541ebceaf6dSDavid Xu 3542ebceaf6dSDavid Xu if (p->p_ksi != NULL) { 3543ebceaf6dSDavid Xu p->p_ksi->ksi_signo = SIGCHLD; 3544ebceaf6dSDavid Xu p->p_ksi->ksi_code = reason; 35457f96995eSDavid Xu p->p_ksi->ksi_status = status; 3546ebceaf6dSDavid Xu p->p_ksi->ksi_pid = p->p_pid; 3547ebceaf6dSDavid Xu p->p_ksi->ksi_uid = p->p_ucred->cr_ruid; 3548ebceaf6dSDavid Xu if (KSI_ONQ(p->p_ksi)) 3549ebceaf6dSDavid Xu return; 3550ebceaf6dSDavid Xu } 3551ad6eec7bSJohn Baldwin pksignal(p->p_pptr, SIGCHLD, p->p_ksi); 3552ebceaf6dSDavid Xu } 3553ebceaf6dSDavid Xu 35547f96995eSDavid Xu static void 3555b20a9aa9SJilles Tjoelker childproc_jobstate(struct proc *p, int reason, int sig) 35567f96995eSDavid Xu { 35577f96995eSDavid Xu struct sigacts *ps; 35587f96995eSDavid Xu 35597f96995eSDavid Xu PROC_LOCK_ASSERT(p, MA_OWNED); 35607f96995eSDavid Xu PROC_LOCK_ASSERT(p->p_pptr, MA_OWNED); 35617f96995eSDavid Xu 35627f96995eSDavid Xu /* 35637f96995eSDavid Xu * Wake up parent sleeping in kern_wait(), also send 35647f96995eSDavid Xu * SIGCHLD to parent, but SIGCHLD does not guarantee 35657f96995eSDavid Xu * that parent will awake, because parent may masked 35667f96995eSDavid Xu * the signal. 35677f96995eSDavid Xu */ 35687f96995eSDavid Xu p->p_pptr->p_flag |= P_STATCHILD; 35697f96995eSDavid Xu wakeup(p->p_pptr); 35707f96995eSDavid Xu 35717f96995eSDavid Xu ps = p->p_pptr->p_sigacts; 35727f96995eSDavid Xu mtx_lock(&ps->ps_mtx); 35737f96995eSDavid Xu if ((ps->ps_flag & PS_NOCLDSTOP) == 0) { 35747f96995eSDavid Xu mtx_unlock(&ps->ps_mtx); 3575b20a9aa9SJilles Tjoelker sigparent(p, reason, sig); 35767f96995eSDavid Xu } else 35777f96995eSDavid Xu mtx_unlock(&ps->ps_mtx); 35787f96995eSDavid Xu } 35797f96995eSDavid Xu 35807f96995eSDavid Xu void 35817f96995eSDavid Xu childproc_stopped(struct proc *p, int reason) 35827f96995eSDavid Xu { 3583b4490c6eSKonstantin Belousov 3584b4490c6eSKonstantin Belousov childproc_jobstate(p, reason, p->p_xsig); 35857f96995eSDavid Xu } 35867f96995eSDavid Xu 3587ebceaf6dSDavid Xu void 3588ebceaf6dSDavid Xu childproc_continued(struct proc *p) 3589ebceaf6dSDavid Xu { 35907f96995eSDavid Xu childproc_jobstate(p, CLD_CONTINUED, SIGCONT); 3591ebceaf6dSDavid Xu } 3592ebceaf6dSDavid Xu 3593ebceaf6dSDavid Xu void 3594ebceaf6dSDavid Xu childproc_exited(struct proc *p) 3595ebceaf6dSDavid Xu { 3596b4490c6eSKonstantin Belousov int reason, status; 3597ebceaf6dSDavid Xu 3598b4490c6eSKonstantin Belousov if (WCOREDUMP(p->p_xsig)) { 3599b4490c6eSKonstantin Belousov reason = CLD_DUMPED; 3600b4490c6eSKonstantin Belousov status = WTERMSIG(p->p_xsig); 3601b4490c6eSKonstantin Belousov } else if (WIFSIGNALED(p->p_xsig)) { 3602b4490c6eSKonstantin Belousov reason = CLD_KILLED; 3603b4490c6eSKonstantin Belousov status = WTERMSIG(p->p_xsig); 3604b4490c6eSKonstantin Belousov } else { 3605b4490c6eSKonstantin Belousov reason = CLD_EXITED; 3606b4490c6eSKonstantin Belousov status = p->p_xexit; 3607b4490c6eSKonstantin Belousov } 36087f96995eSDavid Xu /* 36097f96995eSDavid Xu * XXX avoid calling wakeup(p->p_pptr), the work is 36107f96995eSDavid Xu * done in exit1(). 36117f96995eSDavid Xu */ 36127f96995eSDavid Xu sigparent(p, reason, status); 3613ebceaf6dSDavid Xu } 3614ebceaf6dSDavid Xu 3615f1fe1e02SMariusz Zaborski #define MAX_NUM_CORE_FILES 100000 3616cc37baeaSStephen J. Kiernan #ifndef NUM_CORE_FILES 3617cc37baeaSStephen J. Kiernan #define NUM_CORE_FILES 5 3618cc37baeaSStephen J. Kiernan #endif 3619cc37baeaSStephen J. Kiernan CTASSERT(NUM_CORE_FILES >= 0 && NUM_CORE_FILES <= MAX_NUM_CORE_FILES); 3620cc37baeaSStephen J. Kiernan static int num_cores = NUM_CORE_FILES; 3621e7228204SAlfred Perlstein 3622e7228204SAlfred Perlstein static int 3623e7228204SAlfred Perlstein sysctl_debug_num_cores_check (SYSCTL_HANDLER_ARGS) 3624e7228204SAlfred Perlstein { 3625e7228204SAlfred Perlstein int error; 3626e7228204SAlfred Perlstein int new_val; 3627e7228204SAlfred Perlstein 3628c5105012SKonstantin Belousov new_val = num_cores; 3629e7228204SAlfred Perlstein error = sysctl_handle_int(oidp, &new_val, 0, req); 3630e7228204SAlfred Perlstein if (error != 0 || req->newptr == NULL) 3631e7228204SAlfred Perlstein return (error); 3632cc37baeaSStephen J. Kiernan if (new_val > MAX_NUM_CORE_FILES) 3633cc37baeaSStephen J. Kiernan new_val = MAX_NUM_CORE_FILES; 3634e7228204SAlfred Perlstein if (new_val < 0) 3635e7228204SAlfred Perlstein new_val = 0; 3636e7228204SAlfred Perlstein num_cores = new_val; 3637e7228204SAlfred Perlstein return (0); 3638e7228204SAlfred Perlstein } 36397029da5cSPawel Biernacki SYSCTL_PROC(_debug, OID_AUTO, ncores, 3640fe27f1dbSAlexander Motin CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 0, sizeof(int), 36417029da5cSPawel Biernacki sysctl_debug_num_cores_check, "I", 36426cad1a5dSMariusz Zaborski "Maximum number of generated process corefiles while using index format"); 3643e7228204SAlfred Perlstein 36446026dcd7SMark Johnston #define GZIP_SUFFIX ".gz" 36456026dcd7SMark Johnston #define ZSTD_SUFFIX ".zst" 3646aa14e9b7SMark Johnston 364778f57a9cSMark Johnston int compress_user_cores = 0; 3648e7228204SAlfred Perlstein 364978f57a9cSMark Johnston static int 365078f57a9cSMark Johnston sysctl_compress_user_cores(SYSCTL_HANDLER_ARGS) 365178f57a9cSMark Johnston { 365278f57a9cSMark Johnston int error, val; 365378f57a9cSMark Johnston 365478f57a9cSMark Johnston val = compress_user_cores; 365578f57a9cSMark Johnston error = sysctl_handle_int(oidp, &val, 0, req); 365678f57a9cSMark Johnston if (error != 0 || req->newptr == NULL) 365778f57a9cSMark Johnston return (error); 365878f57a9cSMark Johnston if (val != 0 && !compressor_avail(val)) 365978f57a9cSMark Johnston return (EINVAL); 366078f57a9cSMark Johnston compress_user_cores = val; 366178f57a9cSMark Johnston return (error); 366278f57a9cSMark Johnston } 36637029da5cSPawel Biernacki SYSCTL_PROC(_kern, OID_AUTO, compress_user_cores, 36647029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, 0, sizeof(int), 36657029da5cSPawel Biernacki sysctl_compress_user_cores, "I", 36666026dcd7SMark Johnston "Enable compression of user corefiles (" 36676026dcd7SMark Johnston __XSTRING(COMPRESS_GZIP) " = gzip, " 36686026dcd7SMark Johnston __XSTRING(COMPRESS_ZSTD) " = zstd)"); 366978f57a9cSMark Johnston 367078f57a9cSMark Johnston int compress_user_cores_level = 6; 367178f57a9cSMark Johnston SYSCTL_INT(_kern, OID_AUTO, compress_user_cores_level, CTLFLAG_RWTUN, 367278f57a9cSMark Johnston &compress_user_cores_level, 0, 367378f57a9cSMark Johnston "Corefile compression level"); 3674e7228204SAlfred Perlstein 36755bc0ff88SMateusz Guzik /* 36765bc0ff88SMateusz Guzik * Protect the access to corefilename[] by allproc_lock. 36775bc0ff88SMateusz Guzik */ 36785bc0ff88SMateusz Guzik #define corefilename_lock allproc_lock 36795bc0ff88SMateusz Guzik 36806d1ab6edSWarner Losh static char corefilename[MAXPATHLEN] = {"%N.core"}; 3681fb4cdc96SMariusz Zaborski TUNABLE_STR("kern.corefile", corefilename, sizeof(corefilename)); 36825bc0ff88SMateusz Guzik 36835bc0ff88SMateusz Guzik static int 36845bc0ff88SMateusz Guzik sysctl_kern_corefile(SYSCTL_HANDLER_ARGS) 36855bc0ff88SMateusz Guzik { 36865bc0ff88SMateusz Guzik int error; 36875bc0ff88SMateusz Guzik 36885bc0ff88SMateusz Guzik sx_xlock(&corefilename_lock); 36895bc0ff88SMateusz Guzik error = sysctl_handle_string(oidp, corefilename, sizeof(corefilename), 36905bc0ff88SMateusz Guzik req); 36915bc0ff88SMateusz Guzik sx_xunlock(&corefilename_lock); 36925bc0ff88SMateusz Guzik 36935bc0ff88SMateusz Guzik return (error); 36945bc0ff88SMateusz Guzik } 3695fb4cdc96SMariusz Zaborski SYSCTL_PROC(_kern, OID_AUTO, corefile, CTLTYPE_STRING | CTLFLAG_RW | 36965bc0ff88SMateusz Guzik CTLFLAG_MPSAFE, 0, 0, sysctl_kern_corefile, "A", 36975bc0ff88SMateusz Guzik "Process corefile name format string"); 3698c5edb423SSean Eric Fagan 36990dea6e3cSMariusz Zaborski static void 37000dea6e3cSMariusz Zaborski vnode_close_locked(struct thread *td, struct vnode *vp) 37010dea6e3cSMariusz Zaborski { 37020dea6e3cSMariusz Zaborski 3703b249ce48SMateusz Guzik VOP_UNLOCK(vp); 37040dea6e3cSMariusz Zaborski vn_close(vp, FWRITE, td->td_ucred, td); 37050dea6e3cSMariusz Zaborski } 37060dea6e3cSMariusz Zaborski 37070dea6e3cSMariusz Zaborski /* 37080dea6e3cSMariusz Zaborski * If the core format has a %I in it, then we need to check 37090dea6e3cSMariusz Zaborski * for existing corefiles before defining a name. 3710f1fe1e02SMariusz Zaborski * To do this we iterate over 0..ncores to find a 37110dea6e3cSMariusz Zaborski * non-existing core file name to use. If all core files are 37120dea6e3cSMariusz Zaborski * already used we choose the oldest one. 37130dea6e3cSMariusz Zaborski */ 37140dea6e3cSMariusz Zaborski static int 37150dea6e3cSMariusz Zaborski corefile_open_last(struct thread *td, char *name, int indexpos, 3716f1fe1e02SMariusz Zaborski int indexlen, int ncores, struct vnode **vpp) 37170dea6e3cSMariusz Zaborski { 37180dea6e3cSMariusz Zaborski struct vnode *oldvp, *nextvp, *vp; 37190dea6e3cSMariusz Zaborski struct vattr vattr; 37200dea6e3cSMariusz Zaborski struct nameidata nd; 37210dea6e3cSMariusz Zaborski int error, i, flags, oflags, cmode; 3722f1fe1e02SMariusz Zaborski char ch; 37230dea6e3cSMariusz Zaborski struct timespec lasttime; 37240dea6e3cSMariusz Zaborski 37250dea6e3cSMariusz Zaborski nextvp = oldvp = NULL; 37260dea6e3cSMariusz Zaborski cmode = S_IRUSR | S_IWUSR; 37270dea6e3cSMariusz Zaborski oflags = VN_OPEN_NOAUDIT | VN_OPEN_NAMECACHE | 37280dea6e3cSMariusz Zaborski (capmode_coredump ? VN_OPEN_NOCAPCHECK : 0); 37290dea6e3cSMariusz Zaborski 3730f1fe1e02SMariusz Zaborski for (i = 0; i < ncores; i++) { 37310dea6e3cSMariusz Zaborski flags = O_CREAT | FWRITE | O_NOFOLLOW; 3732f1fe1e02SMariusz Zaborski 3733f1fe1e02SMariusz Zaborski ch = name[indexpos + indexlen]; 3734f1fe1e02SMariusz Zaborski (void)snprintf(name + indexpos, indexlen + 1, "%.*u", indexlen, 3735f1fe1e02SMariusz Zaborski i); 3736f1fe1e02SMariusz Zaborski name[indexpos + indexlen] = ch; 37370dea6e3cSMariusz Zaborski 37387e1d3eefSMateusz Guzik NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, name); 37390dea6e3cSMariusz Zaborski error = vn_open_cred(&nd, &flags, cmode, oflags, td->td_ucred, 37400dea6e3cSMariusz Zaborski NULL); 37410dea6e3cSMariusz Zaborski if (error != 0) 37420dea6e3cSMariusz Zaborski break; 37430dea6e3cSMariusz Zaborski 37440dea6e3cSMariusz Zaborski vp = nd.ni_vp; 3745bb92cd7bSMateusz Guzik NDFREE_PNBUF(&nd); 37460dea6e3cSMariusz Zaborski if ((flags & O_CREAT) == O_CREAT) { 37470dea6e3cSMariusz Zaborski nextvp = vp; 37480dea6e3cSMariusz Zaborski break; 37490dea6e3cSMariusz Zaborski } 37500dea6e3cSMariusz Zaborski 37510dea6e3cSMariusz Zaborski error = VOP_GETATTR(vp, &vattr, td->td_ucred); 37520dea6e3cSMariusz Zaborski if (error != 0) { 37530dea6e3cSMariusz Zaborski vnode_close_locked(td, vp); 37540dea6e3cSMariusz Zaborski break; 37550dea6e3cSMariusz Zaborski } 37560dea6e3cSMariusz Zaborski 37570dea6e3cSMariusz Zaborski if (oldvp == NULL || 37580dea6e3cSMariusz Zaborski lasttime.tv_sec > vattr.va_mtime.tv_sec || 37590dea6e3cSMariusz Zaborski (lasttime.tv_sec == vattr.va_mtime.tv_sec && 37600dea6e3cSMariusz Zaborski lasttime.tv_nsec >= vattr.va_mtime.tv_nsec)) { 37610dea6e3cSMariusz Zaborski if (oldvp != NULL) 3762e298466eSAndriy Gapon vn_close(oldvp, FWRITE, td->td_ucred, td); 37630dea6e3cSMariusz Zaborski oldvp = vp; 3764e298466eSAndriy Gapon VOP_UNLOCK(oldvp); 37650dea6e3cSMariusz Zaborski lasttime = vattr.va_mtime; 37660dea6e3cSMariusz Zaborski } else { 37670dea6e3cSMariusz Zaborski vnode_close_locked(td, vp); 37680dea6e3cSMariusz Zaborski } 37690dea6e3cSMariusz Zaborski } 37700dea6e3cSMariusz Zaborski 37710dea6e3cSMariusz Zaborski if (oldvp != NULL) { 377289f2ab06SKonstantin Belousov if (nextvp == NULL) { 377389f2ab06SKonstantin Belousov if ((td->td_proc->p_flag & P_SUGID) != 0) { 377489f2ab06SKonstantin Belousov error = EFAULT; 3775e298466eSAndriy Gapon vn_close(oldvp, FWRITE, td->td_ucred, td); 377689f2ab06SKonstantin Belousov } else { 377789f2ab06SKonstantin Belousov nextvp = oldvp; 3778e298466eSAndriy Gapon error = vn_lock(nextvp, LK_EXCLUSIVE); 3779e298466eSAndriy Gapon if (error != 0) { 3780e298466eSAndriy Gapon vn_close(nextvp, FWRITE, td->td_ucred, 3781e298466eSAndriy Gapon td); 3782e298466eSAndriy Gapon nextvp = NULL; 3783e298466eSAndriy Gapon } 378489f2ab06SKonstantin Belousov } 378589f2ab06SKonstantin Belousov } else { 3786e298466eSAndriy Gapon vn_close(oldvp, FWRITE, td->td_ucred, td); 378789f2ab06SKonstantin Belousov } 37880dea6e3cSMariusz Zaborski } 37890dea6e3cSMariusz Zaborski if (error != 0) { 37900dea6e3cSMariusz Zaborski if (nextvp != NULL) 37910dea6e3cSMariusz Zaborski vnode_close_locked(td, oldvp); 37920dea6e3cSMariusz Zaborski } else { 37930dea6e3cSMariusz Zaborski *vpp = nextvp; 37940dea6e3cSMariusz Zaborski } 37950dea6e3cSMariusz Zaborski 37960dea6e3cSMariusz Zaborski return (error); 37970dea6e3cSMariusz Zaborski } 37980dea6e3cSMariusz Zaborski 3799c5edb423SSean Eric Fagan /* 3800c345faeaSPawel Jakub Dawidek * corefile_open(comm, uid, pid, td, compress, vpp, namep) 3801c345faeaSPawel Jakub Dawidek * Expand the name described in corefilename, using name, uid, and pid 3802c345faeaSPawel Jakub Dawidek * and open/create core file. 3803c5edb423SSean Eric Fagan * corefilename is a printf-like string, with three format specifiers: 3804c5edb423SSean Eric Fagan * %N name of process ("name") 3805c5edb423SSean Eric Fagan * %P process id (pid) 3806c5edb423SSean Eric Fagan * %U user id (uid) 3807c5edb423SSean Eric Fagan * For example, "%N.core" is the default; they can be disabled completely 3808c5edb423SSean Eric Fagan * by using "/dev/null", or all core files can be stored in "/cores/%U/%N-%P". 3809c5edb423SSean Eric Fagan * This is controlled by the sysctl variable kern.corefile (see above). 3810c5edb423SSean Eric Fagan */ 3811c345faeaSPawel Jakub Dawidek static int 3812c345faeaSPawel Jakub Dawidek corefile_open(const char *comm, uid_t uid, pid_t pid, struct thread *td, 38139d3ecb7eSEric van Gyzen int compress, int signum, struct vnode **vpp, char **namep) 38148b43b535SAlfred Perlstein { 381536b208e0SRobert Watson struct sbuf sb; 38160dea6e3cSMariusz Zaborski struct nameidata nd; 381736b208e0SRobert Watson const char *format; 3818c345faeaSPawel Jakub Dawidek char *hostname, *name; 3819f1fe1e02SMariusz Zaborski int cmode, error, flags, i, indexpos, indexlen, oflags, ncores; 3820c5edb423SSean Eric Fagan 3821b7402d82SAlfred Perlstein hostname = NULL; 38228b43b535SAlfred Perlstein format = corefilename; 3823086053a3SPawel Jakub Dawidek name = malloc(MAXPATHLEN, M_TEMP, M_WAITOK | M_ZERO); 3824f1fe1e02SMariusz Zaborski indexlen = 0; 3825e7228204SAlfred Perlstein indexpos = -1; 3826f1fe1e02SMariusz Zaborski ncores = num_cores; 3827c52ff611SPawel Jakub Dawidek (void)sbuf_new(&sb, name, MAXPATHLEN, SBUF_FIXEDLEN); 38285bc0ff88SMateusz Guzik sx_slock(&corefilename_lock); 382929146f1aSPawel Jakub Dawidek for (i = 0; format[i] != '\0'; i++) { 3830c5edb423SSean Eric Fagan switch (format[i]) { 3831c5edb423SSean Eric Fagan case '%': /* Format character */ 3832c5edb423SSean Eric Fagan i++; 3833c5edb423SSean Eric Fagan switch (format[i]) { 3834c5edb423SSean Eric Fagan case '%': 383536b208e0SRobert Watson sbuf_putc(&sb, '%'); 3836c5edb423SSean Eric Fagan break; 3837e7228204SAlfred Perlstein case 'H': /* hostname */ 3838b7402d82SAlfred Perlstein if (hostname == NULL) { 3839b7402d82SAlfred Perlstein hostname = malloc(MAXHOSTNAMELEN, 3840086053a3SPawel Jakub Dawidek M_TEMP, M_WAITOK); 3841b7402d82SAlfred Perlstein } 3842e7228204SAlfred Perlstein getcredhostname(td->td_ucred, hostname, 3843b7402d82SAlfred Perlstein MAXHOSTNAMELEN); 3844e7228204SAlfred Perlstein sbuf_printf(&sb, "%s", hostname); 3845e7228204SAlfred Perlstein break; 3846e7228204SAlfred Perlstein case 'I': /* autoincrementing index */ 3847f1fe1e02SMariusz Zaborski if (indexpos != -1) { 3848f1fe1e02SMariusz Zaborski sbuf_printf(&sb, "%%I"); 3849f1fe1e02SMariusz Zaborski break; 3850f1fe1e02SMariusz Zaborski } 3851f1fe1e02SMariusz Zaborski 3852f1fe1e02SMariusz Zaborski indexpos = sbuf_len(&sb); 3853f1fe1e02SMariusz Zaborski sbuf_printf(&sb, "%u", ncores - 1); 3854f1fe1e02SMariusz Zaborski indexlen = sbuf_len(&sb) - indexpos; 3855e7228204SAlfred Perlstein break; 3856c5edb423SSean Eric Fagan case 'N': /* process name */ 3857c52ff611SPawel Jakub Dawidek sbuf_printf(&sb, "%s", comm); 3858c5edb423SSean Eric Fagan break; 3859c5edb423SSean Eric Fagan case 'P': /* process id */ 386036b208e0SRobert Watson sbuf_printf(&sb, "%u", pid); 3861c5edb423SSean Eric Fagan break; 38629d3ecb7eSEric van Gyzen case 'S': /* signal number */ 38639d3ecb7eSEric van Gyzen sbuf_printf(&sb, "%i", signum); 38649d3ecb7eSEric van Gyzen break; 3865c5edb423SSean Eric Fagan case 'U': /* user id */ 386636b208e0SRobert Watson sbuf_printf(&sb, "%u", uid); 3867c5edb423SSean Eric Fagan break; 3868c5edb423SSean Eric Fagan default: 38698b43b535SAlfred Perlstein log(LOG_ERR, 387036b208e0SRobert Watson "Unknown format character %c in " 387136b208e0SRobert Watson "corename `%s'\n", format[i], format); 387229146f1aSPawel Jakub Dawidek break; 3873c5edb423SSean Eric Fagan } 3874c5edb423SSean Eric Fagan break; 3875c5edb423SSean Eric Fagan default: 387636b208e0SRobert Watson sbuf_putc(&sb, format[i]); 38776c08be2bSPawel Jakub Dawidek break; 3878c5edb423SSean Eric Fagan } 3879c5edb423SSean Eric Fagan } 38805bc0ff88SMateusz Guzik sx_sunlock(&corefilename_lock); 3881b7402d82SAlfred Perlstein free(hostname, M_TEMP); 388278f57a9cSMark Johnston if (compress == COMPRESS_GZIP) 38836026dcd7SMark Johnston sbuf_printf(&sb, GZIP_SUFFIX); 38846026dcd7SMark Johnston else if (compress == COMPRESS_ZSTD) 38856026dcd7SMark Johnston sbuf_printf(&sb, ZSTD_SUFFIX); 38864d369413SMatthew D Fleming if (sbuf_error(&sb) != 0) { 388736b208e0SRobert Watson log(LOG_ERR, "pid %ld (%s), uid (%lu): corename is too " 3888c52ff611SPawel Jakub Dawidek "long\n", (long)pid, comm, (u_long)uid); 3889b7402d82SAlfred Perlstein sbuf_delete(&sb); 3890c52ff611SPawel Jakub Dawidek free(name, M_TEMP); 3891c345faeaSPawel Jakub Dawidek return (ENOMEM); 3892c5edb423SSean Eric Fagan } 389336b208e0SRobert Watson sbuf_finish(&sb); 389436b208e0SRobert Watson sbuf_delete(&sb); 3895e7228204SAlfred Perlstein 3896e7228204SAlfred Perlstein if (indexpos != -1) { 3897f1fe1e02SMariusz Zaborski error = corefile_open_last(td, name, indexpos, indexlen, ncores, 3898f1fe1e02SMariusz Zaborski vpp); 38990dea6e3cSMariusz Zaborski if (error != 0) { 3900e7228204SAlfred Perlstein log(LOG_ERR, 3901e7228204SAlfred Perlstein "pid %d (%s), uid (%u): Path `%s' failed " 3902e7228204SAlfred Perlstein "on initial open test, error = %d\n", 3903c52ff611SPawel Jakub Dawidek pid, comm, uid, name, error); 3904c345faeaSPawel Jakub Dawidek } 39050dea6e3cSMariusz Zaborski } else { 39060dea6e3cSMariusz Zaborski cmode = S_IRUSR | S_IWUSR; 39070dea6e3cSMariusz Zaborski oflags = VN_OPEN_NOAUDIT | VN_OPEN_NAMECACHE | 39080dea6e3cSMariusz Zaborski (capmode_coredump ? VN_OPEN_NOCAPCHECK : 0); 39090dea6e3cSMariusz Zaborski flags = O_CREAT | FWRITE | O_NOFOLLOW; 391089f2ab06SKonstantin Belousov if ((td->td_proc->p_flag & P_SUGID) != 0) 391189f2ab06SKonstantin Belousov flags |= O_EXCL; 39120dea6e3cSMariusz Zaborski 39137e1d3eefSMateusz Guzik NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, name); 39140dea6e3cSMariusz Zaborski error = vn_open_cred(&nd, &flags, cmode, oflags, td->td_ucred, 39150dea6e3cSMariusz Zaborski NULL); 39160dea6e3cSMariusz Zaborski if (error == 0) { 39170dea6e3cSMariusz Zaborski *vpp = nd.ni_vp; 3918bb92cd7bSMateusz Guzik NDFREE_PNBUF(&nd); 3919c345faeaSPawel Jakub Dawidek } 3920c345faeaSPawel Jakub Dawidek } 3921c345faeaSPawel Jakub Dawidek 39220dea6e3cSMariusz Zaborski if (error != 0) { 3923c345faeaSPawel Jakub Dawidek #ifdef AUDIT 3924c345faeaSPawel Jakub Dawidek audit_proc_coredump(td, name, error); 3925c345faeaSPawel Jakub Dawidek #endif 3926c52ff611SPawel Jakub Dawidek free(name, M_TEMP); 3927c345faeaSPawel Jakub Dawidek return (error); 3928e7228204SAlfred Perlstein } 3929c345faeaSPawel Jakub Dawidek *namep = name; 3930c345faeaSPawel Jakub Dawidek return (0); 393136b208e0SRobert Watson } 3932c5edb423SSean Eric Fagan 3933df8bae1dSRodney W. Grimes /* 3934fca666a1SJulian Elischer * Dump a process' core. The main routine does some 3935fca666a1SJulian Elischer * policy checking, and creates the name of the coredump; 3936fca666a1SJulian Elischer * then it passes on a vnode and a size limit to the process-specific 3937fca666a1SJulian Elischer * coredump routine if there is one; if there _is not_ one, it returns 3938fca666a1SJulian Elischer * ENOSYS; otherwise it returns the error from the process-specific routine. 3939fca666a1SJulian Elischer */ 3940fca666a1SJulian Elischer 3941fca666a1SJulian Elischer static int 3942b40ce416SJulian Elischer coredump(struct thread *td) 3943fca666a1SJulian Elischer { 3944b40ce416SJulian Elischer struct proc *p = td->td_proc; 3945f06f465dSPawel Jakub Dawidek struct ucred *cred = td->td_ucred; 3946f06f465dSPawel Jakub Dawidek struct vnode *vp; 394706ae1e91SMatthew Dillon struct flock lf; 3948fca666a1SJulian Elischer struct vattr vattr; 39497739d927SMateusz Guzik size_t fullpathsize; 3950c345faeaSPawel Jakub Dawidek int error, error1, locked; 3951fca666a1SJulian Elischer char *name; /* name of corefile */ 3952539c9eefSKonstantin Belousov void *rl_cookie; 3953fca666a1SJulian Elischer off_t limit; 3954842ab62bSRui Paulo char *fullpath, *freepath = NULL; 3955349fcda4SWarner Losh struct sbuf *sb; 3956fca666a1SJulian Elischer 39574ae89b95SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 3958f97c3df1SDavid Schultz MPASS((p->p_flag & P_HADTHREADS) == 0 || p->p_singlethread == td); 3959fca666a1SJulian Elischer 3960677258f7SKonstantin Belousov if (!do_coredump || (!sugid_coredump && (p->p_flag & P_SUGID) != 0) || 3961677258f7SKonstantin Belousov (p->p_flag2 & P2_NOTRACE) != 0) { 3962628d2653SJohn Baldwin PROC_UNLOCK(p); 3963fca666a1SJulian Elischer return (EFAULT); 3964628d2653SJohn Baldwin } 3965fca666a1SJulian Elischer 3966fca666a1SJulian Elischer /* 396735a2598fSSean Eric Fagan * Note that the bulk of limit checking is done after 396835a2598fSSean Eric Fagan * the corefile is created. The exception is if the limit 396935a2598fSSean Eric Fagan * for corefiles is 0, in which case we don't bother 397035a2598fSSean Eric Fagan * creating the corefile at all. This layout means that 397135a2598fSSean Eric Fagan * a corefile is truncated instead of not being created, 397235a2598fSSean Eric Fagan * if it is larger than the limit. 3973fca666a1SJulian Elischer */ 3974f6f6d240SMateusz Guzik limit = (off_t)lim_cur(td, RLIMIT_CORE); 3975b8fdb0d9SEdward Tomasz Napierala if (limit == 0 || racct_get_available(p, RACCT_CORE) == 0) { 3976628d2653SJohn Baldwin PROC_UNLOCK(p); 397791d5354aSJohn Baldwin return (EFBIG); 397857274c51SChristian S.J. Peron } 3979b8fdb0d9SEdward Tomasz Napierala PROC_UNLOCK(p); 398035a2598fSSean Eric Fagan 3981aa14e9b7SMark Johnston error = corefile_open(p->p_comm, cred->cr_uid, p->p_pid, td, 39829d3ecb7eSEric van Gyzen compress_user_cores, p->p_sig, &vp, &name); 3983c345faeaSPawel Jakub Dawidek if (error != 0) 3984fca666a1SJulian Elischer return (error); 398506ae1e91SMatthew Dillon 3986539c9eefSKonstantin Belousov /* 3987539c9eefSKonstantin Belousov * Don't dump to non-regular files or files with links. 398889f2ab06SKonstantin Belousov * Do not dump into system files. Effective user must own the corefile. 3989539c9eefSKonstantin Belousov */ 3990f06f465dSPawel Jakub Dawidek if (vp->v_type != VREG || VOP_GETATTR(vp, &vattr, cred) != 0 || 39917a29e0bfSKonstantin Belousov vattr.va_nlink != 1 || (vp->v_vflag & VV_SYSTEM) != 0 || 399289f2ab06SKonstantin Belousov vattr.va_uid != cred->cr_uid) { 3993b249ce48SMateusz Guzik VOP_UNLOCK(vp); 3994832dafadSDon Lewis error = EFAULT; 3995dacbc9dbSKonstantin Belousov goto out; 3996832dafadSDon Lewis } 3997832dafadSDon Lewis 3998b249ce48SMateusz Guzik VOP_UNLOCK(vp); 3999539c9eefSKonstantin Belousov 4000539c9eefSKonstantin Belousov /* Postpone other writers, including core dumps of other processes. */ 4001539c9eefSKonstantin Belousov rl_cookie = vn_rangelock_wlock(vp, 0, OFF_MAX); 4002539c9eefSKonstantin Belousov 400306ae1e91SMatthew Dillon lf.l_whence = SEEK_SET; 400406ae1e91SMatthew Dillon lf.l_start = 0; 400506ae1e91SMatthew Dillon lf.l_len = 0; 400606ae1e91SMatthew Dillon lf.l_type = F_WRLCK; 4007c447f5b2SRobert Watson locked = (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &lf, F_FLOCK) == 0); 400806ae1e91SMatthew Dillon 4009fca666a1SJulian Elischer VATTR_NULL(&vattr); 4010fca666a1SJulian Elischer vattr.va_size = 0; 40116141e04aSJohn-Mark Gurney if (set_core_nodump_flag) 40126141e04aSJohn-Mark Gurney vattr.va_flags = UF_NODUMP; 4013cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 40140359a12eSAttilio Rao VOP_SETATTR(vp, &vattr, cred); 4015b249ce48SMateusz Guzik VOP_UNLOCK(vp); 4016628d2653SJohn Baldwin PROC_LOCK(p); 4017fca666a1SJulian Elischer p->p_acflag |= ACORE; 4018628d2653SJohn Baldwin PROC_UNLOCK(p); 4019fca666a1SJulian Elischer 402023c6445aSPawel Jakub Dawidek if (p->p_sysent->sv_coredump != NULL) { 402178f57a9cSMark Johnston error = p->p_sysent->sv_coredump(td, vp, limit, 0); 402223c6445aSPawel Jakub Dawidek } else { 402323c6445aSPawel Jakub Dawidek error = ENOSYS; 402423c6445aSPawel Jakub Dawidek } 4025fca666a1SJulian Elischer 4026c447f5b2SRobert Watson if (locked) { 402706ae1e91SMatthew Dillon lf.l_type = F_UNLCK; 402806ae1e91SMatthew Dillon VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_FLOCK); 4029c447f5b2SRobert Watson } 4030539c9eefSKonstantin Belousov vn_rangelock_unlock(vp, rl_cookie); 4031dacbc9dbSKonstantin Belousov 4032842ab62bSRui Paulo /* 4033842ab62bSRui Paulo * Notify the userland helper that a process triggered a core dump. 4034842ab62bSRui Paulo * This allows the helper to run an automated debugging session. 4035842ab62bSRui Paulo */ 4036dacbc9dbSKonstantin Belousov if (error != 0 || coredump_devctl == 0) 4037842ab62bSRui Paulo goto out; 4038349fcda4SWarner Losh sb = sbuf_new_auto(); 4039feabaaf9SMateusz Guzik if (vn_fullpath_global(p->p_textvp, &fullpath, &freepath) != 0) 4040349fcda4SWarner Losh goto out2; 4041349fcda4SWarner Losh sbuf_printf(sb, "comm=\""); 4042349fcda4SWarner Losh devctl_safe_quote_sb(sb, fullpath); 4043842ab62bSRui Paulo free(freepath, M_TEMP); 4044349fcda4SWarner Losh sbuf_printf(sb, "\" core=\""); 4045349fcda4SWarner Losh 4046349fcda4SWarner Losh /* 4047349fcda4SWarner Losh * We can't lookup core file vp directly. When we're replacing a core, and 4048349fcda4SWarner Losh * other random times, we flush the name cache, so it will fail. Instead, 4049349fcda4SWarner Losh * if the path of the core is relative, add the current dir in front if it. 4050349fcda4SWarner Losh */ 4051349fcda4SWarner Losh if (name[0] != '/') { 40527739d927SMateusz Guzik fullpathsize = MAXPATHLEN; 40537739d927SMateusz Guzik freepath = malloc(fullpathsize, M_TEMP, M_WAITOK); 4054feabaaf9SMateusz Guzik if (vn_getcwd(freepath, &fullpath, &fullpathsize) != 0) { 40557739d927SMateusz Guzik free(freepath, M_TEMP); 4056349fcda4SWarner Losh goto out2; 4057349fcda4SWarner Losh } 4058349fcda4SWarner Losh devctl_safe_quote_sb(sb, fullpath); 40597739d927SMateusz Guzik free(freepath, M_TEMP); 4060349fcda4SWarner Losh sbuf_putc(sb, '/'); 4061349fcda4SWarner Losh } 4062349fcda4SWarner Losh devctl_safe_quote_sb(sb, name); 4063349fcda4SWarner Losh sbuf_printf(sb, "\""); 4064349fcda4SWarner Losh if (sbuf_finish(sb) == 0) 4065349fcda4SWarner Losh devctl_notify("kernel", "signal", "coredump", sbuf_data(sb)); 4066349fcda4SWarner Losh out2: 4067349fcda4SWarner Losh sbuf_delete(sb); 4068842ab62bSRui Paulo out: 4069dacbc9dbSKonstantin Belousov error1 = vn_close(vp, FWRITE, cred, td); 4070dacbc9dbSKonstantin Belousov if (error == 0) 4071dacbc9dbSKonstantin Belousov error = error1; 407257274c51SChristian S.J. Peron #ifdef AUDIT 407357274c51SChristian S.J. Peron audit_proc_coredump(td, name, error); 407457274c51SChristian S.J. Peron #endif 407557274c51SChristian S.J. Peron free(name, M_TEMP); 4076fca666a1SJulian Elischer return (error); 4077fca666a1SJulian Elischer } 4078fca666a1SJulian Elischer 4079fca666a1SJulian Elischer /* 40800c14ff0eSRobert Watson * Nonexistent system call-- signal process (may want to handle it). Flag 40810c14ff0eSRobert Watson * error in case process won't see signal immediately (blocked or ignored). 4082df8bae1dSRodney W. Grimes */ 4083d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 4084df8bae1dSRodney W. Grimes struct nosys_args { 4085df8bae1dSRodney W. Grimes int dummy; 4086df8bae1dSRodney W. Grimes }; 4087d2d3e875SBruce Evans #endif 4088df8bae1dSRodney W. Grimes /* ARGSUSED */ 408926f9a767SRodney W. Grimes int 4090e052a8b9SEd Maste nosys(struct thread *td, struct nosys_args *args) 4091df8bae1dSRodney W. Grimes { 4092f5a077c3SKonstantin Belousov struct proc *p; 4093f5a077c3SKonstantin Belousov 4094f5a077c3SKonstantin Belousov p = td->td_proc; 4095b40ce416SJulian Elischer 4096628d2653SJohn Baldwin PROC_LOCK(p); 4097888aefefSKonstantin Belousov tdsignal(td, SIGSYS); 4098628d2653SJohn Baldwin PROC_UNLOCK(p); 40997ceeb35bSKonstantin Belousov if (kern_lognosys == 1 || kern_lognosys == 3) { 4100f5a077c3SKonstantin Belousov uprintf("pid %d comm %s: nosys %d\n", p->p_pid, p->p_comm, 4101f5a077c3SKonstantin Belousov td->td_sa.code); 41027ceeb35bSKonstantin Belousov } 410318f917a9SBrooks Davis if (kern_lognosys == 2 || kern_lognosys == 3 || 410418f917a9SBrooks Davis (p->p_pid == 1 && (kern_lognosys & 3) == 0)) { 41057ceeb35bSKonstantin Belousov printf("pid %d comm %s: nosys %d\n", p->p_pid, p->p_comm, 41067ceeb35bSKonstantin Belousov td->td_sa.code); 41077ceeb35bSKonstantin Belousov } 4108f5216b9aSBruce Evans return (ENOSYS); 4109df8bae1dSRodney W. Grimes } 4110831d27a9SDon Lewis 4111831d27a9SDon Lewis /* 41120c14ff0eSRobert Watson * Send a SIGIO or SIGURG signal to a process or process group using stored 41130c14ff0eSRobert Watson * credentials rather than those of the current process. 4114831d27a9SDon Lewis */ 4115831d27a9SDon Lewis void 4116e052a8b9SEd Maste pgsigio(struct sigio **sigiop, int sig, int checkctty) 4117831d27a9SDon Lewis { 4118a3de221dSKonstantin Belousov ksiginfo_t ksi; 4119f1320723SAlfred Perlstein struct sigio *sigio; 4120831d27a9SDon Lewis 4121a3de221dSKonstantin Belousov ksiginfo_init(&ksi); 4122a3de221dSKonstantin Belousov ksi.ksi_signo = sig; 4123a3de221dSKonstantin Belousov ksi.ksi_code = SI_KERNEL; 4124a3de221dSKonstantin Belousov 4125f1320723SAlfred Perlstein SIGIO_LOCK(); 4126f1320723SAlfred Perlstein sigio = *sigiop; 4127f1320723SAlfred Perlstein if (sigio == NULL) { 4128f1320723SAlfred Perlstein SIGIO_UNLOCK(); 4129f1320723SAlfred Perlstein return; 4130f1320723SAlfred Perlstein } 4131831d27a9SDon Lewis if (sigio->sio_pgid > 0) { 4132628d2653SJohn Baldwin PROC_LOCK(sigio->sio_proc); 41332b87b6d4SRobert Watson if (CANSIGIO(sigio->sio_ucred, sigio->sio_proc->p_ucred)) 41348451d0ddSKip Macy kern_psignal(sigio->sio_proc, sig); 4135628d2653SJohn Baldwin PROC_UNLOCK(sigio->sio_proc); 4136831d27a9SDon Lewis } else if (sigio->sio_pgid < 0) { 4137831d27a9SDon Lewis struct proc *p; 4138831d27a9SDon Lewis 4139f591779bSSeigo Tanimura PGRP_LOCK(sigio->sio_pgrp); 4140628d2653SJohn Baldwin LIST_FOREACH(p, &sigio->sio_pgrp->pg_members, p_pglist) { 4141628d2653SJohn Baldwin PROC_LOCK(p); 4142e806d352SJohn Baldwin if (p->p_state == PRS_NORMAL && 4143e806d352SJohn Baldwin CANSIGIO(sigio->sio_ucred, p->p_ucred) && 4144831d27a9SDon Lewis (checkctty == 0 || (p->p_flag & P_CONTROLT))) 41458451d0ddSKip Macy kern_psignal(p, sig); 4146628d2653SJohn Baldwin PROC_UNLOCK(p); 4147628d2653SJohn Baldwin } 4148f591779bSSeigo Tanimura PGRP_UNLOCK(sigio->sio_pgrp); 4149831d27a9SDon Lewis } 4150f1320723SAlfred Perlstein SIGIO_UNLOCK(); 4151831d27a9SDon Lewis } 4152cb679c38SJonathan Lemon 4153cb679c38SJonathan Lemon static int 4154cb679c38SJonathan Lemon filt_sigattach(struct knote *kn) 4155cb679c38SJonathan Lemon { 4156cb679c38SJonathan Lemon struct proc *p = curproc; 4157cb679c38SJonathan Lemon 4158cb679c38SJonathan Lemon kn->kn_ptr.p_proc = p; 4159cb679c38SJonathan Lemon kn->kn_flags |= EV_CLEAR; /* automatically set */ 4160cb679c38SJonathan Lemon 41619e590ff0SKonstantin Belousov knlist_add(p->p_klist, kn, 0); 4162cb679c38SJonathan Lemon 4163cb679c38SJonathan Lemon return (0); 4164cb679c38SJonathan Lemon } 4165cb679c38SJonathan Lemon 4166cb679c38SJonathan Lemon static void 4167cb679c38SJonathan Lemon filt_sigdetach(struct knote *kn) 4168cb679c38SJonathan Lemon { 4169cb679c38SJonathan Lemon struct proc *p = kn->kn_ptr.p_proc; 4170cb679c38SJonathan Lemon 41719e590ff0SKonstantin Belousov knlist_remove(p->p_klist, kn, 0); 4172cb679c38SJonathan Lemon } 4173cb679c38SJonathan Lemon 4174cb679c38SJonathan Lemon /* 4175cb679c38SJonathan Lemon * signal knotes are shared with proc knotes, so we apply a mask to 4176cb679c38SJonathan Lemon * the hint in order to differentiate them from process hints. This 4177cb679c38SJonathan Lemon * could be avoided by using a signal-specific knote list, but probably 4178cb679c38SJonathan Lemon * isn't worth the trouble. 4179cb679c38SJonathan Lemon */ 4180cb679c38SJonathan Lemon static int 4181cb679c38SJonathan Lemon filt_signal(struct knote *kn, long hint) 4182cb679c38SJonathan Lemon { 4183cb679c38SJonathan Lemon 4184cb679c38SJonathan Lemon if (hint & NOTE_SIGNAL) { 4185cb679c38SJonathan Lemon hint &= ~NOTE_SIGNAL; 4186cb679c38SJonathan Lemon 4187cb679c38SJonathan Lemon if (kn->kn_id == hint) 4188cb679c38SJonathan Lemon kn->kn_data++; 4189cb679c38SJonathan Lemon } 4190cb679c38SJonathan Lemon return (kn->kn_data != 0); 4191cb679c38SJonathan Lemon } 419290af4afaSJohn Baldwin 419390af4afaSJohn Baldwin struct sigacts * 419490af4afaSJohn Baldwin sigacts_alloc(void) 419590af4afaSJohn Baldwin { 419690af4afaSJohn Baldwin struct sigacts *ps; 419790af4afaSJohn Baldwin 419890af4afaSJohn Baldwin ps = malloc(sizeof(struct sigacts), M_SUBPROC, M_WAITOK | M_ZERO); 4199ce8daaadSMateusz Guzik refcount_init(&ps->ps_refcnt, 1); 420090af4afaSJohn Baldwin mtx_init(&ps->ps_mtx, "sigacts", NULL, MTX_DEF); 420190af4afaSJohn Baldwin return (ps); 420290af4afaSJohn Baldwin } 420390af4afaSJohn Baldwin 420490af4afaSJohn Baldwin void 420590af4afaSJohn Baldwin sigacts_free(struct sigacts *ps) 420690af4afaSJohn Baldwin { 420790af4afaSJohn Baldwin 4208c959c237SMateusz Guzik if (refcount_release(&ps->ps_refcnt) == 0) 4209c959c237SMateusz Guzik return; 421090af4afaSJohn Baldwin mtx_destroy(&ps->ps_mtx); 421190af4afaSJohn Baldwin free(ps, M_SUBPROC); 421290af4afaSJohn Baldwin } 421390af4afaSJohn Baldwin 421490af4afaSJohn Baldwin struct sigacts * 421590af4afaSJohn Baldwin sigacts_hold(struct sigacts *ps) 421690af4afaSJohn Baldwin { 4217c959c237SMateusz Guzik 4218c959c237SMateusz Guzik refcount_acquire(&ps->ps_refcnt); 421990af4afaSJohn Baldwin return (ps); 422090af4afaSJohn Baldwin } 422190af4afaSJohn Baldwin 422290af4afaSJohn Baldwin void 422390af4afaSJohn Baldwin sigacts_copy(struct sigacts *dest, struct sigacts *src) 422490af4afaSJohn Baldwin { 422590af4afaSJohn Baldwin 422690af4afaSJohn Baldwin KASSERT(dest->ps_refcnt == 1, ("sigacts_copy to shared dest")); 422790af4afaSJohn Baldwin mtx_lock(&src->ps_mtx); 422890af4afaSJohn Baldwin bcopy(src, dest, offsetof(struct sigacts, ps_refcnt)); 422990af4afaSJohn Baldwin mtx_unlock(&src->ps_mtx); 423090af4afaSJohn Baldwin } 423190af4afaSJohn Baldwin 423290af4afaSJohn Baldwin int 423390af4afaSJohn Baldwin sigacts_shared(struct sigacts *ps) 423490af4afaSJohn Baldwin { 423590af4afaSJohn Baldwin 4236d00c8ea4SMateusz Guzik return (ps->ps_refcnt > 1); 423790af4afaSJohn Baldwin } 4238079c5b9eSKyle Evans 4239079c5b9eSKyle Evans void 4240079c5b9eSKyle Evans sig_drop_caught(struct proc *p) 4241079c5b9eSKyle Evans { 4242079c5b9eSKyle Evans int sig; 4243079c5b9eSKyle Evans struct sigacts *ps; 4244079c5b9eSKyle Evans 4245079c5b9eSKyle Evans ps = p->p_sigacts; 4246079c5b9eSKyle Evans PROC_LOCK_ASSERT(p, MA_OWNED); 4247079c5b9eSKyle Evans mtx_assert(&ps->ps_mtx, MA_OWNED); 424881f2e906SMark Johnston SIG_FOREACH(sig, &ps->ps_sigcatch) { 4249079c5b9eSKyle Evans sigdflt(ps, sig); 4250079c5b9eSKyle Evans if ((sigprop(sig) & SIGPROP_IGNORE) != 0) 4251079c5b9eSKyle Evans sigqueue_delete_proc(p, sig); 4252079c5b9eSKyle Evans } 4253079c5b9eSKyle Evans } 4254146fc63fSKonstantin Belousov 4255a113b17fSKonstantin Belousov static void 4256a113b17fSKonstantin Belousov sigfastblock_failed(struct thread *td, bool sendsig, bool write) 4257a113b17fSKonstantin Belousov { 4258a113b17fSKonstantin Belousov ksiginfo_t ksi; 4259a113b17fSKonstantin Belousov 4260a113b17fSKonstantin Belousov /* 4261a113b17fSKonstantin Belousov * Prevent further fetches and SIGSEGVs, allowing thread to 4262a113b17fSKonstantin Belousov * issue syscalls despite corruption. 4263a113b17fSKonstantin Belousov */ 4264a113b17fSKonstantin Belousov sigfastblock_clear(td); 4265a113b17fSKonstantin Belousov 4266a113b17fSKonstantin Belousov if (!sendsig) 4267a113b17fSKonstantin Belousov return; 4268a113b17fSKonstantin Belousov ksiginfo_init_trap(&ksi); 4269a113b17fSKonstantin Belousov ksi.ksi_signo = SIGSEGV; 4270a113b17fSKonstantin Belousov ksi.ksi_code = write ? SEGV_ACCERR : SEGV_MAPERR; 4271a113b17fSKonstantin Belousov ksi.ksi_addr = td->td_sigblock_ptr; 4272a113b17fSKonstantin Belousov trapsignal(td, &ksi); 4273a113b17fSKonstantin Belousov } 4274a113b17fSKonstantin Belousov 4275a113b17fSKonstantin Belousov static bool 4276a113b17fSKonstantin Belousov sigfastblock_fetch_sig(struct thread *td, bool sendsig, uint32_t *valp) 4277a113b17fSKonstantin Belousov { 4278a113b17fSKonstantin Belousov uint32_t res; 4279a113b17fSKonstantin Belousov 4280a113b17fSKonstantin Belousov if ((td->td_pflags & TDP_SIGFASTBLOCK) == 0) 4281a113b17fSKonstantin Belousov return (true); 4282a113b17fSKonstantin Belousov if (fueword32((void *)td->td_sigblock_ptr, &res) == -1) { 4283a113b17fSKonstantin Belousov sigfastblock_failed(td, sendsig, false); 4284a113b17fSKonstantin Belousov return (false); 4285a113b17fSKonstantin Belousov } 4286a113b17fSKonstantin Belousov *valp = res; 4287a113b17fSKonstantin Belousov td->td_sigblock_val = res & ~SIGFASTBLOCK_FLAGS; 4288a113b17fSKonstantin Belousov return (true); 4289a113b17fSKonstantin Belousov } 4290a113b17fSKonstantin Belousov 4291fb3c434bSKonstantin Belousov static void 4292fb3c434bSKonstantin Belousov sigfastblock_resched(struct thread *td, bool resched) 4293fb3c434bSKonstantin Belousov { 4294fb3c434bSKonstantin Belousov struct proc *p; 4295fb3c434bSKonstantin Belousov 4296fb3c434bSKonstantin Belousov if (resched) { 4297fb3c434bSKonstantin Belousov p = td->td_proc; 4298fb3c434bSKonstantin Belousov PROC_LOCK(p); 4299fb3c434bSKonstantin Belousov reschedule_signals(p, td->td_sigmask, 0); 4300fb3c434bSKonstantin Belousov PROC_UNLOCK(p); 4301fb3c434bSKonstantin Belousov } 4302c6d31b83SKonstantin Belousov ast_sched(td, TDA_SIG); 4303fb3c434bSKonstantin Belousov } 4304fb3c434bSKonstantin Belousov 4305146fc63fSKonstantin Belousov int 4306146fc63fSKonstantin Belousov sys_sigfastblock(struct thread *td, struct sigfastblock_args *uap) 4307146fc63fSKonstantin Belousov { 4308146fc63fSKonstantin Belousov struct proc *p; 4309146fc63fSKonstantin Belousov int error, res; 4310146fc63fSKonstantin Belousov uint32_t oldval; 4311146fc63fSKonstantin Belousov 4312146fc63fSKonstantin Belousov error = 0; 4313a113b17fSKonstantin Belousov p = td->td_proc; 4314146fc63fSKonstantin Belousov switch (uap->cmd) { 4315146fc63fSKonstantin Belousov case SIGFASTBLOCK_SETPTR: 4316146fc63fSKonstantin Belousov if ((td->td_pflags & TDP_SIGFASTBLOCK) != 0) { 4317146fc63fSKonstantin Belousov error = EBUSY; 4318146fc63fSKonstantin Belousov break; 4319146fc63fSKonstantin Belousov } 4320146fc63fSKonstantin Belousov if (((uintptr_t)(uap->ptr) & (sizeof(uint32_t) - 1)) != 0) { 4321146fc63fSKonstantin Belousov error = EINVAL; 4322146fc63fSKonstantin Belousov break; 4323146fc63fSKonstantin Belousov } 4324146fc63fSKonstantin Belousov td->td_pflags |= TDP_SIGFASTBLOCK; 4325146fc63fSKonstantin Belousov td->td_sigblock_ptr = uap->ptr; 4326146fc63fSKonstantin Belousov break; 4327146fc63fSKonstantin Belousov 4328146fc63fSKonstantin Belousov case SIGFASTBLOCK_UNBLOCK: 4329a113b17fSKonstantin Belousov if ((td->td_pflags & TDP_SIGFASTBLOCK) == 0) { 4330146fc63fSKonstantin Belousov error = EINVAL; 4331146fc63fSKonstantin Belousov break; 4332146fc63fSKonstantin Belousov } 4333a113b17fSKonstantin Belousov 4334a113b17fSKonstantin Belousov for (;;) { 4335a113b17fSKonstantin Belousov res = casueword32(td->td_sigblock_ptr, 4336a113b17fSKonstantin Belousov SIGFASTBLOCK_PEND, &oldval, 0); 4337146fc63fSKonstantin Belousov if (res == -1) { 4338146fc63fSKonstantin Belousov error = EFAULT; 4339a113b17fSKonstantin Belousov sigfastblock_failed(td, false, true); 4340146fc63fSKonstantin Belousov break; 4341146fc63fSKonstantin Belousov } 4342a113b17fSKonstantin Belousov if (res == 0) 4343a113b17fSKonstantin Belousov break; 4344a113b17fSKonstantin Belousov MPASS(res == 1); 4345146fc63fSKonstantin Belousov if (oldval != SIGFASTBLOCK_PEND) { 4346146fc63fSKonstantin Belousov error = EBUSY; 4347146fc63fSKonstantin Belousov break; 4348146fc63fSKonstantin Belousov } 4349146fc63fSKonstantin Belousov error = thread_check_susp(td, false); 4350146fc63fSKonstantin Belousov if (error != 0) 4351146fc63fSKonstantin Belousov break; 4352146fc63fSKonstantin Belousov } 4353a113b17fSKonstantin Belousov if (error != 0) 4354a113b17fSKonstantin Belousov break; 4355a113b17fSKonstantin Belousov 4356a113b17fSKonstantin Belousov /* 4357a113b17fSKonstantin Belousov * td_sigblock_val is cleared there, but not on a 4358a113b17fSKonstantin Belousov * syscall exit. The end effect is that a single 4359a113b17fSKonstantin Belousov * interruptible sleep, while user sigblock word is 4360a113b17fSKonstantin Belousov * set, might return EINTR or ERESTART to usermode 4361a113b17fSKonstantin Belousov * without delivering signal. All further sleeps, 4362a113b17fSKonstantin Belousov * until userspace clears the word and does 4363a113b17fSKonstantin Belousov * sigfastblock(UNBLOCK), observe current word and no 4364a113b17fSKonstantin Belousov * longer get interrupted. It is slight 4365a113b17fSKonstantin Belousov * non-conformance, with alternative to have read the 4366a113b17fSKonstantin Belousov * sigblock word on each syscall entry. 4367a113b17fSKonstantin Belousov */ 4368146fc63fSKonstantin Belousov td->td_sigblock_val = 0; 4369146fc63fSKonstantin Belousov 4370146fc63fSKonstantin Belousov /* 4371146fc63fSKonstantin Belousov * Rely on normal ast mechanism to deliver pending 4372146fc63fSKonstantin Belousov * signals to current thread. But notify others about 4373146fc63fSKonstantin Belousov * fake unblock. 4374146fc63fSKonstantin Belousov */ 4375fb3c434bSKonstantin Belousov sigfastblock_resched(td, error == 0 && p->p_numthreads != 1); 4376fb3c434bSKonstantin Belousov 4377146fc63fSKonstantin Belousov break; 4378146fc63fSKonstantin Belousov 4379146fc63fSKonstantin Belousov case SIGFASTBLOCK_UNSETPTR: 4380146fc63fSKonstantin Belousov if ((td->td_pflags & TDP_SIGFASTBLOCK) == 0) { 4381146fc63fSKonstantin Belousov error = EINVAL; 4382146fc63fSKonstantin Belousov break; 4383146fc63fSKonstantin Belousov } 4384a113b17fSKonstantin Belousov if (!sigfastblock_fetch_sig(td, false, &oldval)) { 4385146fc63fSKonstantin Belousov error = EFAULT; 4386146fc63fSKonstantin Belousov break; 4387146fc63fSKonstantin Belousov } 4388146fc63fSKonstantin Belousov if (oldval != 0 && oldval != SIGFASTBLOCK_PEND) { 4389146fc63fSKonstantin Belousov error = EBUSY; 4390146fc63fSKonstantin Belousov break; 4391146fc63fSKonstantin Belousov } 4392a113b17fSKonstantin Belousov sigfastblock_clear(td); 4393146fc63fSKonstantin Belousov break; 4394146fc63fSKonstantin Belousov 4395146fc63fSKonstantin Belousov default: 4396146fc63fSKonstantin Belousov error = EINVAL; 4397146fc63fSKonstantin Belousov break; 4398146fc63fSKonstantin Belousov } 4399146fc63fSKonstantin Belousov return (error); 4400146fc63fSKonstantin Belousov } 4401146fc63fSKonstantin Belousov 4402146fc63fSKonstantin Belousov void 4403a113b17fSKonstantin Belousov sigfastblock_clear(struct thread *td) 4404146fc63fSKonstantin Belousov { 4405a113b17fSKonstantin Belousov bool resched; 4406146fc63fSKonstantin Belousov 4407146fc63fSKonstantin Belousov if ((td->td_pflags & TDP_SIGFASTBLOCK) == 0) 4408146fc63fSKonstantin Belousov return; 4409a113b17fSKonstantin Belousov td->td_sigblock_val = 0; 441000ebd809SKonstantin Belousov resched = (td->td_pflags & TDP_SIGFASTPENDING) != 0 || 441100ebd809SKonstantin Belousov SIGPENDING(td); 4412a113b17fSKonstantin Belousov td->td_pflags &= ~(TDP_SIGFASTBLOCK | TDP_SIGFASTPENDING); 4413fb3c434bSKonstantin Belousov sigfastblock_resched(td, resched); 4414146fc63fSKonstantin Belousov } 4415146fc63fSKonstantin Belousov 4416146fc63fSKonstantin Belousov void 4417a113b17fSKonstantin Belousov sigfastblock_fetch(struct thread *td) 4418146fc63fSKonstantin Belousov { 4419a113b17fSKonstantin Belousov uint32_t val; 4420146fc63fSKonstantin Belousov 4421a113b17fSKonstantin Belousov (void)sigfastblock_fetch_sig(td, true, &val); 4422a113b17fSKonstantin Belousov } 4423146fc63fSKonstantin Belousov 44240bc52b0bSKonstantin Belousov static void 44250bc52b0bSKonstantin Belousov sigfastblock_setpend1(struct thread *td) 4426a113b17fSKonstantin Belousov { 4427a113b17fSKonstantin Belousov int res; 4428a113b17fSKonstantin Belousov uint32_t oldval; 4429a113b17fSKonstantin Belousov 4430513320c0SKonstantin Belousov if ((td->td_pflags & TDP_SIGFASTPENDING) == 0) 4431a113b17fSKonstantin Belousov return; 4432a113b17fSKonstantin Belousov res = fueword32((void *)td->td_sigblock_ptr, &oldval); 4433a113b17fSKonstantin Belousov if (res == -1) { 4434a113b17fSKonstantin Belousov sigfastblock_failed(td, true, false); 4435a113b17fSKonstantin Belousov return; 4436a113b17fSKonstantin Belousov } 4437a113b17fSKonstantin Belousov for (;;) { 4438a113b17fSKonstantin Belousov res = casueword32(td->td_sigblock_ptr, oldval, &oldval, 4439a113b17fSKonstantin Belousov oldval | SIGFASTBLOCK_PEND); 4440a113b17fSKonstantin Belousov if (res == -1) { 4441a113b17fSKonstantin Belousov sigfastblock_failed(td, true, true); 4442a113b17fSKonstantin Belousov return; 4443a113b17fSKonstantin Belousov } 4444a113b17fSKonstantin Belousov if (res == 0) { 4445a113b17fSKonstantin Belousov td->td_sigblock_val = oldval & ~SIGFASTBLOCK_FLAGS; 4446a113b17fSKonstantin Belousov td->td_pflags &= ~TDP_SIGFASTPENDING; 4447a113b17fSKonstantin Belousov break; 4448a113b17fSKonstantin Belousov } 4449a113b17fSKonstantin Belousov MPASS(res == 1); 4450a113b17fSKonstantin Belousov if (thread_check_susp(td, false) != 0) 4451a113b17fSKonstantin Belousov break; 4452a113b17fSKonstantin Belousov } 4453146fc63fSKonstantin Belousov } 44540bc52b0bSKonstantin Belousov 44554fced864SKonstantin Belousov static void 44560bc52b0bSKonstantin Belousov sigfastblock_setpend(struct thread *td, bool resched) 44570bc52b0bSKonstantin Belousov { 44580bc52b0bSKonstantin Belousov struct proc *p; 44590bc52b0bSKonstantin Belousov 44600bc52b0bSKonstantin Belousov sigfastblock_setpend1(td); 44610bc52b0bSKonstantin Belousov if (resched) { 44620bc52b0bSKonstantin Belousov p = td->td_proc; 44630bc52b0bSKonstantin Belousov PROC_LOCK(p); 44640bc52b0bSKonstantin Belousov reschedule_signals(p, fastblock_mask, SIGPROCMASK_FASTBLK); 44650bc52b0bSKonstantin Belousov PROC_UNLOCK(p); 44660bc52b0bSKonstantin Belousov } 44670bc52b0bSKonstantin Belousov } 4468