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 37140ceb5dSKonstantin Belousov #include "opt_capsicum.h" 38db6a20e2SGarrett Wollman #include "opt_ktrace.h" 39db6a20e2SGarrett Wollman 40df8bae1dSRodney W. Grimes #include <sys/param.h> 41140ceb5dSKonstantin Belousov #include <sys/capsicum.h> 42eb6368d4SRui Paulo #include <sys/ctype.h> 4336240ea5SDoug Rabson #include <sys/systm.h> 44df8bae1dSRodney W. Grimes #include <sys/signalvar.h> 45df8bae1dSRodney W. Grimes #include <sys/vnode.h> 46df8bae1dSRodney W. Grimes #include <sys/acct.h> 474a144410SRobert Watson #include <sys/capsicum.h> 4878f57a9cSMark Johnston #include <sys/compressor.h> 49238510fcSJason Evans #include <sys/condvar.h> 50773e541eSWarner Losh #include <sys/devctl.h> 51854dc8c2SJohn Baldwin #include <sys/event.h> 52854dc8c2SJohn Baldwin #include <sys/fcntl.h> 53e7228204SAlfred Perlstein #include <sys/imgact.h> 54437e1e37SBrooks Davis #include <sys/jail.h> 55854dc8c2SJohn Baldwin #include <sys/kernel.h> 560384fff8SJason Evans #include <sys/ktr.h> 57df8bae1dSRodney W. Grimes #include <sys/ktrace.h> 5891898857SMark Johnston #include <sys/limits.h> 59854dc8c2SJohn Baldwin #include <sys/lock.h> 60854dc8c2SJohn Baldwin #include <sys/malloc.h> 61854dc8c2SJohn Baldwin #include <sys/mutex.h> 62c959c237SMateusz Guzik #include <sys/refcount.h> 63854dc8c2SJohn Baldwin #include <sys/namei.h> 64854dc8c2SJohn Baldwin #include <sys/proc.h> 65cfb5f768SJonathan Anderson #include <sys/procdesc.h> 66ef401a85SKonstantin Belousov #include <sys/ptrace.h> 676aeb05d7STom Rhodes #include <sys/posix4.h> 68b8fdb0d9SEdward Tomasz Napierala #include <sys/racct.h> 69c31146a1SJohn Baldwin #include <sys/resourcevar.h> 705d217f17SJohn Birrell #include <sys/sdt.h> 7136b208e0SRobert Watson #include <sys/sbuf.h> 7244f3b092SJohn Baldwin #include <sys/sleepqueue.h> 736caa8a15SJohn Baldwin #include <sys/smp.h> 74df8bae1dSRodney W. Grimes #include <sys/stat.h> 751005a129SJohn Baldwin #include <sys/sx.h> 76140ceb5dSKonstantin Belousov #include <sys/syscall.h> 778f19eb88SIan Dowse #include <sys/syscallsubr.h> 78c87e2930SDavid Greenman #include <sys/sysctl.h> 79854dc8c2SJohn Baldwin #include <sys/sysent.h> 80854dc8c2SJohn Baldwin #include <sys/syslog.h> 81854dc8c2SJohn Baldwin #include <sys/sysproto.h> 8256c06c4bSDavid Xu #include <sys/timers.h> 8306ae1e91SMatthew Dillon #include <sys/unistd.h> 84140ceb5dSKonstantin Belousov #include <sys/vmmeter.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 90df8bae1dSRodney W. Grimes #include <machine/cpu.h> 91df8bae1dSRodney W. Grimes 92bfd7575aSWayne Salamon #include <security/audit/audit.h> 93bfd7575aSWayne Salamon 946f841fb7SMarcel Moolenaar #define ONSIG 32 /* NSIG for osig* syscalls. XXX. */ 956f841fb7SMarcel Moolenaar 965d217f17SJohn Birrell SDT_PROVIDER_DECLARE(proc); 9736160958SMark Johnston SDT_PROBE_DEFINE3(proc, , , signal__send, 9836160958SMark Johnston "struct thread *", "struct proc *", "int"); 9936160958SMark Johnston SDT_PROBE_DEFINE2(proc, , , signal__clear, 10036160958SMark Johnston "int", "ksiginfo_t *"); 10136160958SMark Johnston SDT_PROBE_DEFINE3(proc, , , signal__discard, 1027b77e1feSMark Johnston "struct thread *", "struct proc *", "int"); 1035d217f17SJohn Birrell 1044d77a549SAlfred Perlstein static int coredump(struct thread *); 105a3de221dSKonstantin Belousov static int killpg1(struct thread *td, int sig, int pgid, int all, 106a3de221dSKonstantin Belousov ksiginfo_t *ksi); 1073cf3b9f0SJohn Baldwin static int issignal(struct thread *td); 1080bc52b0bSKonstantin Belousov static void reschedule_signals(struct proc *p, sigset_t block, int flags); 1094d77a549SAlfred Perlstein static int sigprop(int sig); 11094f0972bSDavid Xu static void tdsigwakeup(struct thread *, int, sig_t, int); 111d4c4ca85SMark Johnston static void sig_suspend_threads(struct thread *, struct proc *); 112cb679c38SJonathan Lemon static int filt_sigattach(struct knote *kn); 113cb679c38SJonathan Lemon static void filt_sigdetach(struct knote *kn); 114cb679c38SJonathan Lemon static int filt_signal(struct knote *kn, long hint); 115146fc63fSKonstantin Belousov static struct thread *sigtd(struct proc *p, int sig, bool fast_sigblock); 1169104847fSDavid Xu static void sigqueue_start(void); 1174fced864SKonstantin Belousov static void sigfastblock_setpend(struct thread *td, bool resched); 118cb679c38SJonathan Lemon 1199104847fSDavid Xu static uma_zone_t ksiginfo_zone = NULL; 120*ef9ffb85SMark Johnston const struct filterops sig_filtops = { 121e76d823bSRobert Watson .f_isfd = 0, 122e76d823bSRobert Watson .f_attach = filt_sigattach, 123e76d823bSRobert Watson .f_detach = filt_sigdetach, 124e76d823bSRobert Watson .f_event = filt_signal, 125e76d823bSRobert Watson }; 126cb679c38SJonathan Lemon 127fc8cca02SJohn Baldwin static int kern_logsigexit = 1; 1283d177f46SBill Fumerola SYSCTL_INT(_kern, KERN_LOGSIGEXIT, logsigexit, CTLFLAG_RW, 1293d177f46SBill Fumerola &kern_logsigexit, 0, 1303d177f46SBill Fumerola "Log processes quitting on abnormal signals to syslog(3)"); 13157308494SJoerg Wunsch 132f71a882fSDavid Xu static int kern_forcesigexit = 1; 133f71a882fSDavid Xu SYSCTL_INT(_kern, OID_AUTO, forcesigexit, CTLFLAG_RW, 134f71a882fSDavid Xu &kern_forcesigexit, 0, "Force trap signal to be handled"); 135f71a882fSDavid Xu 1367029da5cSPawel Biernacki static SYSCTL_NODE(_kern, OID_AUTO, sigqueue, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 1376472ac3dSEd Schouten "POSIX real time signal"); 1389104847fSDavid Xu 1399104847fSDavid Xu static int max_pending_per_proc = 128; 1409104847fSDavid Xu SYSCTL_INT(_kern_sigqueue, OID_AUTO, max_pending_per_proc, CTLFLAG_RW, 1419104847fSDavid Xu &max_pending_per_proc, 0, "Max pending signals per proc"); 1429104847fSDavid Xu 1439104847fSDavid Xu static int preallocate_siginfo = 1024; 144af3b2549SHans Petter Selasky SYSCTL_INT(_kern_sigqueue, OID_AUTO, preallocate, CTLFLAG_RDTUN, 1459104847fSDavid Xu &preallocate_siginfo, 0, "Preallocated signal memory size"); 1469104847fSDavid Xu 1479104847fSDavid Xu static int signal_overflow = 0; 148761a4d94SDavid Xu SYSCTL_INT(_kern_sigqueue, OID_AUTO, overflow, CTLFLAG_RD, 1499104847fSDavid Xu &signal_overflow, 0, "Number of signals overflew"); 1509104847fSDavid Xu 1519104847fSDavid Xu static int signal_alloc_fail = 0; 152761a4d94SDavid Xu SYSCTL_INT(_kern_sigqueue, OID_AUTO, alloc_fail, CTLFLAG_RD, 1539104847fSDavid Xu &signal_alloc_fail, 0, "signals failed to be allocated"); 1549104847fSDavid Xu 155f5a077c3SKonstantin Belousov static int kern_lognosys = 0; 156f5a077c3SKonstantin Belousov SYSCTL_INT(_kern, OID_AUTO, lognosys, CTLFLAG_RWTUN, &kern_lognosys, 0, 157f5a077c3SKonstantin Belousov "Log invalid syscalls"); 158f5a077c3SKonstantin Belousov 1595804a162SKonstantin Belousov static int kern_signosys = 1; 1605804a162SKonstantin Belousov SYSCTL_INT(_kern, OID_AUTO, signosys, CTLFLAG_RWTUN, &kern_signosys, 0, 1615804a162SKonstantin Belousov "Send SIGSYS on return from invalid syscall"); 1625804a162SKonstantin Belousov 163a113b17fSKonstantin Belousov __read_frequently bool sigfastblock_fetch_always = false; 164a113b17fSKonstantin Belousov SYSCTL_BOOL(_kern, OID_AUTO, sigfastblock_fetch_always, CTLFLAG_RWTUN, 165a113b17fSKonstantin Belousov &sigfastblock_fetch_always, 0, 166a113b17fSKonstantin Belousov "Fetch sigfastblock word on each syscall entry for proper " 167a113b17fSKonstantin Belousov "blocking semantic"); 168a113b17fSKonstantin Belousov 169bc387624SKonstantin Belousov static bool kern_sig_discard_ign = true; 170bc387624SKonstantin Belousov SYSCTL_BOOL(_kern, OID_AUTO, sig_discard_ign, CTLFLAG_RWTUN, 171bc387624SKonstantin Belousov &kern_sig_discard_ign, 0, 172bc387624SKonstantin Belousov "Discard ignored signals on delivery, otherwise queue them to " 173bc387624SKonstantin Belousov "the target queue"); 174bc387624SKonstantin Belousov 1759104847fSDavid Xu SYSINIT(signal, SI_SUB_P1003_1B, SI_ORDER_FIRST+3, sigqueue_start, NULL); 1769104847fSDavid Xu 1772b87b6d4SRobert Watson /* 1782b87b6d4SRobert Watson * Policy -- Can ucred cr1 send SIGIO to process cr2? 1792b87b6d4SRobert Watson * Should use cr_cansignal() once cr_cansignal() allows SIGIO and SIGURG 1802b87b6d4SRobert Watson * in the right situations. 1812b87b6d4SRobert Watson */ 1822b87b6d4SRobert Watson #define CANSIGIO(cr1, cr2) \ 1832b87b6d4SRobert Watson ((cr1)->cr_uid == 0 || \ 1842b87b6d4SRobert Watson (cr1)->cr_ruid == (cr2)->cr_ruid || \ 1852b87b6d4SRobert Watson (cr1)->cr_uid == (cr2)->cr_ruid || \ 1862b87b6d4SRobert Watson (cr1)->cr_ruid == (cr2)->cr_uid || \ 1872b87b6d4SRobert Watson (cr1)->cr_uid == (cr2)->cr_uid) 1882b87b6d4SRobert Watson 189fc8cca02SJohn Baldwin static int sugid_coredump; 190af3b2549SHans Petter Selasky SYSCTL_INT(_kern, OID_AUTO, sugid_coredump, CTLFLAG_RWTUN, 1918b5adf9dSJoseph Koshy &sugid_coredump, 0, "Allow setuid and setgid processes to dump core"); 192c87e2930SDavid Greenman 193b0c9d4d7SPawel Jakub Dawidek static int capmode_coredump; 194af3b2549SHans Petter Selasky SYSCTL_INT(_kern, OID_AUTO, capmode_coredump, CTLFLAG_RWTUN, 195b0c9d4d7SPawel Jakub Dawidek &capmode_coredump, 0, "Allow processes in capability mode to dump core"); 196b0c9d4d7SPawel Jakub Dawidek 197e5a28db9SPaul Saab static int do_coredump = 1; 198e5a28db9SPaul Saab SYSCTL_INT(_kern, OID_AUTO, coredump, CTLFLAG_RW, 199e5a28db9SPaul Saab &do_coredump, 0, "Enable/Disable coredumps"); 200e5a28db9SPaul Saab 2016141e04aSJohn-Mark Gurney static int set_core_nodump_flag = 0; 2026141e04aSJohn-Mark Gurney SYSCTL_INT(_kern, OID_AUTO, nodump_coredump, CTLFLAG_RW, &set_core_nodump_flag, 2036141e04aSJohn-Mark Gurney 0, "Enable setting the NODUMP flag on coredump files"); 2046141e04aSJohn-Mark Gurney 2050da9e11bSRui Paulo static int coredump_devctl = 0; 206eb6368d4SRui Paulo SYSCTL_INT(_kern, OID_AUTO, coredump_devctl, CTLFLAG_RW, &coredump_devctl, 207eb6368d4SRui Paulo 0, "Generate a devctl notification when processes coredump"); 208eb6368d4SRui Paulo 2092c42a146SMarcel Moolenaar /* 2102c42a146SMarcel Moolenaar * Signal properties and actions. 2112c42a146SMarcel Moolenaar * The array below categorizes the signals and their default actions 2122c42a146SMarcel Moolenaar * according to the following properties: 2132c42a146SMarcel Moolenaar */ 214fd50a707SBrooks Davis #define SIGPROP_KILL 0x01 /* terminates process by default */ 215fd50a707SBrooks Davis #define SIGPROP_CORE 0x02 /* ditto and coredumps */ 216fd50a707SBrooks Davis #define SIGPROP_STOP 0x04 /* suspend process */ 217fd50a707SBrooks Davis #define SIGPROP_TTYSTOP 0x08 /* ditto, from tty */ 218fd50a707SBrooks Davis #define SIGPROP_IGNORE 0x10 /* ignore by default */ 219fd50a707SBrooks Davis #define SIGPROP_CONT 0x20 /* continue if suspended */ 220df8bae1dSRodney W. Grimes 2210d3f1b4fSMark Johnston static const int sigproptbl[NSIG] = { 222ed6d876bSBrooks Davis [SIGHUP] = SIGPROP_KILL, 223ed6d876bSBrooks Davis [SIGINT] = SIGPROP_KILL, 224ed6d876bSBrooks Davis [SIGQUIT] = SIGPROP_KILL | SIGPROP_CORE, 225ed6d876bSBrooks Davis [SIGILL] = SIGPROP_KILL | SIGPROP_CORE, 226ed6d876bSBrooks Davis [SIGTRAP] = SIGPROP_KILL | SIGPROP_CORE, 227ed6d876bSBrooks Davis [SIGABRT] = SIGPROP_KILL | SIGPROP_CORE, 228ed6d876bSBrooks Davis [SIGEMT] = SIGPROP_KILL | SIGPROP_CORE, 229ed6d876bSBrooks Davis [SIGFPE] = SIGPROP_KILL | SIGPROP_CORE, 230ed6d876bSBrooks Davis [SIGKILL] = SIGPROP_KILL, 231ed6d876bSBrooks Davis [SIGBUS] = SIGPROP_KILL | SIGPROP_CORE, 232ed6d876bSBrooks Davis [SIGSEGV] = SIGPROP_KILL | SIGPROP_CORE, 233ed6d876bSBrooks Davis [SIGSYS] = SIGPROP_KILL | SIGPROP_CORE, 234ed6d876bSBrooks Davis [SIGPIPE] = SIGPROP_KILL, 235ed6d876bSBrooks Davis [SIGALRM] = SIGPROP_KILL, 236ed6d876bSBrooks Davis [SIGTERM] = SIGPROP_KILL, 237ed6d876bSBrooks Davis [SIGURG] = SIGPROP_IGNORE, 238ed6d876bSBrooks Davis [SIGSTOP] = SIGPROP_STOP, 239ed6d876bSBrooks Davis [SIGTSTP] = SIGPROP_STOP | SIGPROP_TTYSTOP, 240ed6d876bSBrooks Davis [SIGCONT] = SIGPROP_IGNORE | SIGPROP_CONT, 241ed6d876bSBrooks Davis [SIGCHLD] = SIGPROP_IGNORE, 242ed6d876bSBrooks Davis [SIGTTIN] = SIGPROP_STOP | SIGPROP_TTYSTOP, 243ed6d876bSBrooks Davis [SIGTTOU] = SIGPROP_STOP | SIGPROP_TTYSTOP, 244ed6d876bSBrooks Davis [SIGIO] = SIGPROP_IGNORE, 245ed6d876bSBrooks Davis [SIGXCPU] = SIGPROP_KILL, 246ed6d876bSBrooks Davis [SIGXFSZ] = SIGPROP_KILL, 247ed6d876bSBrooks Davis [SIGVTALRM] = SIGPROP_KILL, 248ed6d876bSBrooks Davis [SIGPROF] = SIGPROP_KILL, 249ed6d876bSBrooks Davis [SIGWINCH] = SIGPROP_IGNORE, 250ed6d876bSBrooks Davis [SIGINFO] = SIGPROP_IGNORE, 251ed6d876bSBrooks Davis [SIGUSR1] = SIGPROP_KILL, 252ed6d876bSBrooks Davis [SIGUSR2] = SIGPROP_KILL, 2532c42a146SMarcel Moolenaar }; 2542c42a146SMarcel Moolenaar 25581f2e906SMark Johnston #define _SIG_FOREACH_ADVANCE(i, set) ({ \ 25681f2e906SMark Johnston int __found; \ 25781f2e906SMark Johnston for (;;) { \ 25881f2e906SMark Johnston if (__bits != 0) { \ 25981f2e906SMark Johnston int __sig = ffs(__bits); \ 26081f2e906SMark Johnston __bits &= ~(1u << (__sig - 1)); \ 26181f2e906SMark Johnston sig = __i * sizeof((set)->__bits[0]) * NBBY + __sig; \ 26281f2e906SMark Johnston __found = 1; \ 26381f2e906SMark Johnston break; \ 26481f2e906SMark Johnston } \ 26581f2e906SMark Johnston if (++__i == _SIG_WORDS) { \ 26681f2e906SMark Johnston __found = 0; \ 26781f2e906SMark Johnston break; \ 26881f2e906SMark Johnston } \ 26981f2e906SMark Johnston __bits = (set)->__bits[__i]; \ 27081f2e906SMark Johnston } \ 27181f2e906SMark Johnston __found != 0; \ 27281f2e906SMark Johnston }) 27381f2e906SMark Johnston 27481f2e906SMark Johnston #define SIG_FOREACH(i, set) \ 27581f2e906SMark Johnston for (int32_t __i = -1, __bits = 0; \ 27681f2e906SMark Johnston _SIG_FOREACH_ADVANCE(i, set); ) \ 27781f2e906SMark Johnston 2784fced864SKonstantin Belousov static sigset_t fastblock_mask; 2796b286ee8SKonstantin Belousov 2809104847fSDavid Xu static void 281c6d31b83SKonstantin Belousov ast_sig(struct thread *td, int tda) 282c6d31b83SKonstantin Belousov { 283c6d31b83SKonstantin Belousov struct proc *p; 284f0592b3cSKonstantin Belousov int old_boundary, sig; 285c6d31b83SKonstantin Belousov bool resched_sigs; 286c6d31b83SKonstantin Belousov 287c6d31b83SKonstantin Belousov p = td->td_proc; 288c6d31b83SKonstantin Belousov 289c6d31b83SKonstantin Belousov #ifdef DIAGNOSTIC 290c6d31b83SKonstantin Belousov if (p->p_numthreads == 1 && (tda & (TDAI(TDA_SIG) | 291c6d31b83SKonstantin Belousov TDAI(TDA_AST))) == 0) { 292c6d31b83SKonstantin Belousov PROC_LOCK(p); 293c6d31b83SKonstantin Belousov thread_lock(td); 294c6d31b83SKonstantin Belousov /* 295c6d31b83SKonstantin Belousov * Note that TDA_SIG should be re-read from 296c6d31b83SKonstantin Belousov * td_ast, since signal might have been delivered 297c6d31b83SKonstantin Belousov * after we cleared td_flags above. This is one of 298c6d31b83SKonstantin Belousov * the reason for looping check for AST condition. 299c6d31b83SKonstantin Belousov * See comment in userret() about P_PPWAIT. 300c6d31b83SKonstantin Belousov */ 301c6d31b83SKonstantin Belousov if ((p->p_flag & P_PPWAIT) == 0 && 302c6d31b83SKonstantin Belousov (td->td_pflags & TDP_SIGFASTBLOCK) == 0) { 303c6d31b83SKonstantin Belousov if (SIGPENDING(td) && ((tda | td->td_ast) & 304c6d31b83SKonstantin Belousov (TDAI(TDA_SIG) | TDAI(TDA_AST))) == 0) { 305c6d31b83SKonstantin Belousov thread_unlock(td); /* fix dumps */ 306c6d31b83SKonstantin Belousov panic( 307c6d31b83SKonstantin Belousov "failed2 to set signal flags for ast p %p " 308c6d31b83SKonstantin Belousov "td %p tda %#x td_ast %#x fl %#x", 309c6d31b83SKonstantin Belousov p, td, tda, td->td_ast, td->td_flags); 310c6d31b83SKonstantin Belousov } 311c6d31b83SKonstantin Belousov } 312c6d31b83SKonstantin Belousov thread_unlock(td); 313c6d31b83SKonstantin Belousov PROC_UNLOCK(p); 314c6d31b83SKonstantin Belousov } 315c6d31b83SKonstantin Belousov #endif 316c6d31b83SKonstantin Belousov 317c6d31b83SKonstantin Belousov /* 318c6d31b83SKonstantin Belousov * Check for signals. Unlocked reads of p_pendingcnt or 319c6d31b83SKonstantin Belousov * p_siglist might cause process-directed signal to be handled 320c6d31b83SKonstantin Belousov * later. 321c6d31b83SKonstantin Belousov */ 322f2fd7d8bSKonstantin Belousov if ((tda & TDAI(TDA_SIG)) != 0 || p->p_pendingcnt > 0 || 323c6d31b83SKonstantin Belousov !SIGISEMPTY(p->p_siglist)) { 324c6d31b83SKonstantin Belousov sigfastblock_fetch(td); 325c6d31b83SKonstantin Belousov PROC_LOCK(p); 326f0592b3cSKonstantin Belousov old_boundary = ~TDB_BOUNDARY | (td->td_dbgflags & TDB_BOUNDARY); 327f0592b3cSKonstantin Belousov td->td_dbgflags |= TDB_BOUNDARY; 328c6d31b83SKonstantin Belousov mtx_lock(&p->p_sigacts->ps_mtx); 329c6d31b83SKonstantin Belousov while ((sig = cursig(td)) != 0) { 330c6d31b83SKonstantin Belousov KASSERT(sig >= 0, ("sig %d", sig)); 331c6d31b83SKonstantin Belousov postsig(sig); 332c6d31b83SKonstantin Belousov } 333c6d31b83SKonstantin Belousov mtx_unlock(&p->p_sigacts->ps_mtx); 334f0592b3cSKonstantin Belousov td->td_dbgflags &= old_boundary; 335c6d31b83SKonstantin Belousov PROC_UNLOCK(p); 336c6d31b83SKonstantin Belousov resched_sigs = true; 337c6d31b83SKonstantin Belousov } else { 338c6d31b83SKonstantin Belousov resched_sigs = false; 339c6d31b83SKonstantin Belousov } 340c6d31b83SKonstantin Belousov 341c6d31b83SKonstantin Belousov /* 342c6d31b83SKonstantin Belousov * Handle deferred update of the fast sigblock value, after 343c6d31b83SKonstantin Belousov * the postsig() loop was performed. 344c6d31b83SKonstantin Belousov */ 345c6d31b83SKonstantin Belousov sigfastblock_setpend(td, resched_sigs); 346c6d31b83SKonstantin Belousov } 347c6d31b83SKonstantin Belousov 348c6d31b83SKonstantin Belousov static void 349c6d31b83SKonstantin Belousov ast_sigsuspend(struct thread *td, int tda __unused) 350c6d31b83SKonstantin Belousov { 351c6d31b83SKonstantin Belousov MPASS((td->td_pflags & TDP_OLDMASK) != 0); 352c6d31b83SKonstantin Belousov td->td_pflags &= ~TDP_OLDMASK; 353c6d31b83SKonstantin Belousov kern_sigprocmask(td, SIG_SETMASK, &td->td_oldsigmask, NULL, 0); 354c6d31b83SKonstantin Belousov } 355c6d31b83SKonstantin Belousov 356c6d31b83SKonstantin Belousov static void 3579104847fSDavid Xu sigqueue_start(void) 3589104847fSDavid Xu { 3599104847fSDavid Xu ksiginfo_zone = uma_zcreate("ksiginfo", sizeof(ksiginfo_t), 3609104847fSDavid Xu NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 3619104847fSDavid Xu uma_prealloc(ksiginfo_zone, preallocate_siginfo); 362b51d237aSDavid Xu p31b_setcfg(CTL_P1003_1B_REALTIME_SIGNALS, _POSIX_REALTIME_SIGNALS); 363b51d237aSDavid Xu p31b_setcfg(CTL_P1003_1B_RTSIG_MAX, SIGRTMAX - SIGRTMIN + 1); 364b51d237aSDavid Xu p31b_setcfg(CTL_P1003_1B_SIGQUEUE_MAX, max_pending_per_proc); 365146fc63fSKonstantin Belousov SIGFILLSET(fastblock_mask); 366146fc63fSKonstantin Belousov SIG_CANTMASK(fastblock_mask); 367c6d31b83SKonstantin Belousov ast_register(TDA_SIG, ASTR_UNCOND, 0, ast_sig); 368cab31f56SKyle Evans 369cab31f56SKyle Evans /* 370cab31f56SKyle Evans * TDA_PSELECT is for the case where the signal mask should be restored 371cab31f56SKyle Evans * before delivering any signals so that we do not deliver any that are 372cab31f56SKyle Evans * blocked by the normal thread mask. It is mutually exclusive with 373cab31f56SKyle Evans * TDA_SIGSUSPEND, which should be used if we *do* want to deliver 374cab31f56SKyle Evans * signals that are normally blocked, e.g., if it interrupted our sleep. 375cab31f56SKyle Evans */ 376cab31f56SKyle Evans ast_register(TDA_PSELECT, ASTR_ASTF_REQUIRED | ASTR_TDP, 377cab31f56SKyle Evans TDP_OLDMASK, ast_sigsuspend); 378c6d31b83SKonstantin Belousov ast_register(TDA_SIGSUSPEND, ASTR_ASTF_REQUIRED | ASTR_TDP, 379c6d31b83SKonstantin Belousov TDP_OLDMASK, ast_sigsuspend); 3809104847fSDavid Xu } 3819104847fSDavid Xu 3825da49fcbSDavid Xu ksiginfo_t * 383cc29f221SKonstantin Belousov ksiginfo_alloc(int mwait) 3849104847fSDavid Xu { 385cc29f221SKonstantin Belousov MPASS(mwait == M_WAITOK || mwait == M_NOWAIT); 386ebceaf6dSDavid Xu 387cc29f221SKonstantin Belousov if (ksiginfo_zone == NULL) 3889104847fSDavid Xu return (NULL); 389cc29f221SKonstantin Belousov return (uma_zalloc(ksiginfo_zone, mwait | M_ZERO)); 3909104847fSDavid Xu } 3919104847fSDavid Xu 3925da49fcbSDavid Xu void 3939104847fSDavid Xu ksiginfo_free(ksiginfo_t *ksi) 3949104847fSDavid Xu { 3959104847fSDavid Xu uma_zfree(ksiginfo_zone, ksi); 3969104847fSDavid Xu } 3979104847fSDavid Xu 398cdb58f9dSKonstantin Belousov static __inline bool 3995da49fcbSDavid Xu ksiginfo_tryfree(ksiginfo_t *ksi) 4005da49fcbSDavid Xu { 401cdb58f9dSKonstantin Belousov if ((ksi->ksi_flags & KSI_EXT) == 0) { 4025da49fcbSDavid Xu uma_zfree(ksiginfo_zone, ksi); 403cdb58f9dSKonstantin Belousov return (true); 4045da49fcbSDavid Xu } 405cdb58f9dSKonstantin Belousov return (false); 4065da49fcbSDavid Xu } 4075da49fcbSDavid Xu 4089104847fSDavid Xu void 4099104847fSDavid Xu sigqueue_init(sigqueue_t *list, struct proc *p) 4109104847fSDavid Xu { 4119104847fSDavid Xu SIGEMPTYSET(list->sq_signals); 4123dfcaad6SDavid Xu SIGEMPTYSET(list->sq_kill); 41382a4538fSEric Badger SIGEMPTYSET(list->sq_ptrace); 4149104847fSDavid Xu TAILQ_INIT(&list->sq_list); 4159104847fSDavid Xu list->sq_proc = p; 4169104847fSDavid Xu list->sq_flags = SQ_INIT; 4179104847fSDavid Xu } 4189104847fSDavid Xu 4199104847fSDavid Xu /* 4209104847fSDavid Xu * Get a signal's ksiginfo. 4219104847fSDavid Xu * Return: 4229104847fSDavid Xu * 0 - signal not found 4239104847fSDavid Xu * others - signal number 4249104847fSDavid Xu */ 425a5799a4fSKonstantin Belousov static int 4269104847fSDavid Xu sigqueue_get(sigqueue_t *sq, int signo, ksiginfo_t *si) 4279104847fSDavid Xu { 4289104847fSDavid Xu struct proc *p = sq->sq_proc; 4299104847fSDavid Xu struct ksiginfo *ksi, *next; 4309104847fSDavid Xu int count = 0; 4319104847fSDavid Xu 4329104847fSDavid Xu KASSERT(sq->sq_flags & SQ_INIT, ("sigqueue not inited")); 4339104847fSDavid Xu 4349104847fSDavid Xu if (!SIGISMEMBER(sq->sq_signals, signo)) 4359104847fSDavid Xu return (0); 4369104847fSDavid Xu 43782a4538fSEric Badger if (SIGISMEMBER(sq->sq_ptrace, signo)) { 43882a4538fSEric Badger count++; 43982a4538fSEric Badger SIGDELSET(sq->sq_ptrace, signo); 44082a4538fSEric Badger si->ksi_flags |= KSI_PTRACE; 44182a4538fSEric Badger } 4423dfcaad6SDavid Xu if (SIGISMEMBER(sq->sq_kill, signo)) { 4433dfcaad6SDavid Xu count++; 44482a4538fSEric Badger if (count == 1) 4453dfcaad6SDavid Xu SIGDELSET(sq->sq_kill, signo); 4463dfcaad6SDavid Xu } 4473dfcaad6SDavid Xu 4485c28a8d4SDavid Xu TAILQ_FOREACH_SAFE(ksi, &sq->sq_list, ksi_link, next) { 4499104847fSDavid Xu if (ksi->ksi_signo == signo) { 4509104847fSDavid Xu if (count == 0) { 4519104847fSDavid Xu TAILQ_REMOVE(&sq->sq_list, ksi, ksi_link); 4525da49fcbSDavid Xu ksi->ksi_sigq = NULL; 4539104847fSDavid Xu ksiginfo_copy(ksi, si); 4545da49fcbSDavid Xu if (ksiginfo_tryfree(ksi) && p != NULL) 4559104847fSDavid Xu p->p_pendingcnt--; 4569104847fSDavid Xu } 457016fa302SDavid Xu if (++count > 1) 458016fa302SDavid Xu break; 4599104847fSDavid Xu } 4609104847fSDavid Xu } 4619104847fSDavid Xu 4629104847fSDavid Xu if (count <= 1) 4639104847fSDavid Xu SIGDELSET(sq->sq_signals, signo); 4649104847fSDavid Xu si->ksi_signo = signo; 4659104847fSDavid Xu return (signo); 4669104847fSDavid Xu } 4679104847fSDavid Xu 4685da49fcbSDavid Xu void 4695da49fcbSDavid Xu sigqueue_take(ksiginfo_t *ksi) 4705da49fcbSDavid Xu { 4715da49fcbSDavid Xu struct ksiginfo *kp; 4725da49fcbSDavid Xu struct proc *p; 4735da49fcbSDavid Xu sigqueue_t *sq; 4745da49fcbSDavid Xu 475ebceaf6dSDavid Xu if (ksi == NULL || (sq = ksi->ksi_sigq) == NULL) 4765da49fcbSDavid Xu return; 4775da49fcbSDavid Xu 4785da49fcbSDavid Xu p = sq->sq_proc; 4795da49fcbSDavid Xu TAILQ_REMOVE(&sq->sq_list, ksi, ksi_link); 4805da49fcbSDavid Xu ksi->ksi_sigq = NULL; 4815da49fcbSDavid Xu if (!(ksi->ksi_flags & KSI_EXT) && p != NULL) 4825da49fcbSDavid Xu p->p_pendingcnt--; 4835da49fcbSDavid Xu 4845da49fcbSDavid Xu for (kp = TAILQ_FIRST(&sq->sq_list); kp != NULL; 4855da49fcbSDavid Xu kp = TAILQ_NEXT(kp, ksi_link)) { 4865da49fcbSDavid Xu if (kp->ksi_signo == ksi->ksi_signo) 4875da49fcbSDavid Xu break; 4885da49fcbSDavid Xu } 48982a4538fSEric Badger if (kp == NULL && !SIGISMEMBER(sq->sq_kill, ksi->ksi_signo) && 49082a4538fSEric Badger !SIGISMEMBER(sq->sq_ptrace, ksi->ksi_signo)) 4915da49fcbSDavid Xu SIGDELSET(sq->sq_signals, ksi->ksi_signo); 4925da49fcbSDavid Xu } 4935da49fcbSDavid Xu 494a5799a4fSKonstantin Belousov static int 4959104847fSDavid Xu sigqueue_add(sigqueue_t *sq, int signo, ksiginfo_t *si) 4969104847fSDavid Xu { 4979104847fSDavid Xu struct proc *p = sq->sq_proc; 4989104847fSDavid Xu struct ksiginfo *ksi; 4999104847fSDavid Xu int ret = 0; 5009104847fSDavid Xu 5019104847fSDavid Xu KASSERT(sq->sq_flags & SQ_INIT, ("sigqueue not inited")); 5029104847fSDavid Xu 50382a4538fSEric Badger /* 50482a4538fSEric Badger * SIGKILL/SIGSTOP cannot be caught or masked, so take the fast path 50582a4538fSEric Badger * for these signals. 50682a4538fSEric Badger */ 5073dfcaad6SDavid Xu if (signo == SIGKILL || signo == SIGSTOP || si == NULL) { 5083dfcaad6SDavid Xu SIGADDSET(sq->sq_kill, signo); 5099104847fSDavid Xu goto out_set_bit; 5103dfcaad6SDavid Xu } 5119104847fSDavid Xu 5125da49fcbSDavid Xu /* directly insert the ksi, don't copy it */ 5135da49fcbSDavid Xu if (si->ksi_flags & KSI_INS) { 5146a671a6bSKonstantin Belousov if (si->ksi_flags & KSI_HEAD) 5156a671a6bSKonstantin Belousov TAILQ_INSERT_HEAD(&sq->sq_list, si, ksi_link); 5166a671a6bSKonstantin Belousov else 5175da49fcbSDavid Xu TAILQ_INSERT_TAIL(&sq->sq_list, si, ksi_link); 5185da49fcbSDavid Xu si->ksi_sigq = sq; 5195da49fcbSDavid Xu goto out_set_bit; 5205da49fcbSDavid Xu } 5215da49fcbSDavid Xu 5223dfcaad6SDavid Xu if (__predict_false(ksiginfo_zone == NULL)) { 5233dfcaad6SDavid Xu SIGADDSET(sq->sq_kill, signo); 5249104847fSDavid Xu goto out_set_bit; 5253dfcaad6SDavid Xu } 5269104847fSDavid Xu 527ebceaf6dSDavid Xu if (p != NULL && p->p_pendingcnt >= max_pending_per_proc) { 5289104847fSDavid Xu signal_overflow++; 5299104847fSDavid Xu ret = EAGAIN; 530cc29f221SKonstantin Belousov } else if ((ksi = ksiginfo_alloc(M_NOWAIT)) == NULL) { 5319104847fSDavid Xu signal_alloc_fail++; 5329104847fSDavid Xu ret = EAGAIN; 5339104847fSDavid Xu } else { 5349104847fSDavid Xu if (p != NULL) 5359104847fSDavid Xu p->p_pendingcnt++; 5369104847fSDavid Xu ksiginfo_copy(si, ksi); 5379104847fSDavid Xu ksi->ksi_signo = signo; 5386a671a6bSKonstantin Belousov if (si->ksi_flags & KSI_HEAD) 5396a671a6bSKonstantin Belousov TAILQ_INSERT_HEAD(&sq->sq_list, ksi, ksi_link); 5406a671a6bSKonstantin Belousov else 5419104847fSDavid Xu TAILQ_INSERT_TAIL(&sq->sq_list, ksi, ksi_link); 5425da49fcbSDavid Xu ksi->ksi_sigq = sq; 5439104847fSDavid Xu } 5449104847fSDavid Xu 54582a4538fSEric Badger if (ret != 0) { 54682a4538fSEric Badger if ((si->ksi_flags & KSI_PTRACE) != 0) { 54782a4538fSEric Badger SIGADDSET(sq->sq_ptrace, signo); 54882a4538fSEric Badger ret = 0; 54982a4538fSEric Badger goto out_set_bit; 55082a4538fSEric Badger } else if ((si->ksi_flags & KSI_TRAP) != 0 || 551a3de221dSKonstantin Belousov (si->ksi_flags & KSI_SIGQ) == 0) { 5523dfcaad6SDavid Xu SIGADDSET(sq->sq_kill, signo); 5539104847fSDavid Xu ret = 0; 5549104847fSDavid Xu goto out_set_bit; 5559104847fSDavid Xu } 5569104847fSDavid Xu return (ret); 55782a4538fSEric Badger } 5589104847fSDavid Xu 5599104847fSDavid Xu out_set_bit: 5609104847fSDavid Xu SIGADDSET(sq->sq_signals, signo); 5619104847fSDavid Xu return (ret); 5629104847fSDavid Xu } 5639104847fSDavid Xu 5649104847fSDavid Xu void 5659104847fSDavid Xu sigqueue_flush(sigqueue_t *sq) 5669104847fSDavid Xu { 5679104847fSDavid Xu struct proc *p = sq->sq_proc; 5689104847fSDavid Xu ksiginfo_t *ksi; 5699104847fSDavid Xu 5709104847fSDavid Xu KASSERT(sq->sq_flags & SQ_INIT, ("sigqueue not inited")); 5719104847fSDavid Xu 5725da49fcbSDavid Xu if (p != NULL) 5735da49fcbSDavid Xu PROC_LOCK_ASSERT(p, MA_OWNED); 5745da49fcbSDavid Xu 5759104847fSDavid Xu while ((ksi = TAILQ_FIRST(&sq->sq_list)) != NULL) { 5769104847fSDavid Xu TAILQ_REMOVE(&sq->sq_list, ksi, ksi_link); 5775da49fcbSDavid Xu ksi->ksi_sigq = NULL; 5785da49fcbSDavid Xu if (ksiginfo_tryfree(ksi) && p != NULL) 5799104847fSDavid Xu p->p_pendingcnt--; 5809104847fSDavid Xu } 5819104847fSDavid Xu 5829104847fSDavid Xu SIGEMPTYSET(sq->sq_signals); 5833dfcaad6SDavid Xu SIGEMPTYSET(sq->sq_kill); 58482a4538fSEric Badger SIGEMPTYSET(sq->sq_ptrace); 5859104847fSDavid Xu } 5869104847fSDavid Xu 587a5799a4fSKonstantin Belousov static void 588fc4ecc1dSDavid Xu sigqueue_move_set(sigqueue_t *src, sigqueue_t *dst, const sigset_t *set) 5899104847fSDavid Xu { 590fc4ecc1dSDavid Xu sigset_t tmp; 5919104847fSDavid Xu struct proc *p1, *p2; 5929104847fSDavid Xu ksiginfo_t *ksi, *next; 5939104847fSDavid Xu 5949104847fSDavid Xu KASSERT(src->sq_flags & SQ_INIT, ("src sigqueue not inited")); 5959104847fSDavid Xu KASSERT(dst->sq_flags & SQ_INIT, ("dst sigqueue not inited")); 5969104847fSDavid Xu p1 = src->sq_proc; 5979104847fSDavid Xu p2 = dst->sq_proc; 5989104847fSDavid Xu /* Move siginfo to target list */ 5995c28a8d4SDavid Xu TAILQ_FOREACH_SAFE(ksi, &src->sq_list, ksi_link, next) { 600fc4ecc1dSDavid Xu if (SIGISMEMBER(*set, ksi->ksi_signo)) { 6019104847fSDavid Xu TAILQ_REMOVE(&src->sq_list, ksi, ksi_link); 6029104847fSDavid Xu if (p1 != NULL) 6039104847fSDavid Xu p1->p_pendingcnt--; 6049104847fSDavid Xu TAILQ_INSERT_TAIL(&dst->sq_list, ksi, ksi_link); 6055da49fcbSDavid Xu ksi->ksi_sigq = dst; 6069104847fSDavid Xu if (p2 != NULL) 6079104847fSDavid Xu p2->p_pendingcnt++; 6089104847fSDavid Xu } 6099104847fSDavid Xu } 6109104847fSDavid Xu 6119104847fSDavid Xu /* Move pending bits to target list */ 6123dfcaad6SDavid Xu tmp = src->sq_kill; 613fc4ecc1dSDavid Xu SIGSETAND(tmp, *set); 6143dfcaad6SDavid Xu SIGSETOR(dst->sq_kill, tmp); 6153dfcaad6SDavid Xu SIGSETNAND(src->sq_kill, tmp); 6163dfcaad6SDavid Xu 61782a4538fSEric Badger tmp = src->sq_ptrace; 61882a4538fSEric Badger SIGSETAND(tmp, *set); 61982a4538fSEric Badger SIGSETOR(dst->sq_ptrace, tmp); 62082a4538fSEric Badger SIGSETNAND(src->sq_ptrace, tmp); 62182a4538fSEric Badger 6229104847fSDavid Xu tmp = src->sq_signals; 623fc4ecc1dSDavid Xu SIGSETAND(tmp, *set); 6249104847fSDavid Xu SIGSETOR(dst->sq_signals, tmp); 6259104847fSDavid Xu SIGSETNAND(src->sq_signals, tmp); 6269104847fSDavid Xu } 6279104847fSDavid Xu 628407af02bSDavid Xu #if 0 629a5799a4fSKonstantin Belousov static void 6309104847fSDavid Xu sigqueue_move(sigqueue_t *src, sigqueue_t *dst, int signo) 6319104847fSDavid Xu { 6329104847fSDavid Xu sigset_t set; 6339104847fSDavid Xu 6349104847fSDavid Xu SIGEMPTYSET(set); 6359104847fSDavid Xu SIGADDSET(set, signo); 6369104847fSDavid Xu sigqueue_move_set(src, dst, &set); 6379104847fSDavid Xu } 638407af02bSDavid Xu #endif 6399104847fSDavid Xu 640a5799a4fSKonstantin Belousov static void 641fc4ecc1dSDavid Xu sigqueue_delete_set(sigqueue_t *sq, const sigset_t *set) 6429104847fSDavid Xu { 6439104847fSDavid Xu struct proc *p = sq->sq_proc; 6449104847fSDavid Xu ksiginfo_t *ksi, *next; 6459104847fSDavid Xu 6469104847fSDavid Xu KASSERT(sq->sq_flags & SQ_INIT, ("src sigqueue not inited")); 6479104847fSDavid Xu 6489104847fSDavid Xu /* Remove siginfo queue */ 6495c28a8d4SDavid Xu TAILQ_FOREACH_SAFE(ksi, &sq->sq_list, ksi_link, next) { 6509104847fSDavid Xu if (SIGISMEMBER(*set, ksi->ksi_signo)) { 6519104847fSDavid Xu TAILQ_REMOVE(&sq->sq_list, ksi, ksi_link); 6525da49fcbSDavid Xu ksi->ksi_sigq = NULL; 6535da49fcbSDavid Xu if (ksiginfo_tryfree(ksi) && p != NULL) 6549104847fSDavid Xu p->p_pendingcnt--; 6559104847fSDavid Xu } 6569104847fSDavid Xu } 6573dfcaad6SDavid Xu SIGSETNAND(sq->sq_kill, *set); 65882a4538fSEric Badger SIGSETNAND(sq->sq_ptrace, *set); 6599104847fSDavid Xu SIGSETNAND(sq->sq_signals, *set); 6609104847fSDavid Xu } 6619104847fSDavid Xu 6629104847fSDavid Xu void 6639104847fSDavid Xu sigqueue_delete(sigqueue_t *sq, int signo) 6649104847fSDavid Xu { 6659104847fSDavid Xu sigset_t set; 6669104847fSDavid Xu 6679104847fSDavid Xu SIGEMPTYSET(set); 6689104847fSDavid Xu SIGADDSET(set, signo); 6699104847fSDavid Xu sigqueue_delete_set(sq, &set); 6709104847fSDavid Xu } 6719104847fSDavid Xu 6729104847fSDavid Xu /* Remove a set of signals for a process */ 673a5799a4fSKonstantin Belousov static void 674fc4ecc1dSDavid Xu sigqueue_delete_set_proc(struct proc *p, const sigset_t *set) 6759104847fSDavid Xu { 6769104847fSDavid Xu sigqueue_t worklist; 6779104847fSDavid Xu struct thread *td0; 6789104847fSDavid Xu 6799104847fSDavid Xu PROC_LOCK_ASSERT(p, MA_OWNED); 6809104847fSDavid Xu 681aaa92413SKonstantin Belousov sigqueue_init(&worklist, NULL); 6829104847fSDavid Xu sigqueue_move_set(&p->p_sigqueue, &worklist, set); 6839104847fSDavid Xu 6849104847fSDavid Xu FOREACH_THREAD_IN_PROC(p, td0) 6859104847fSDavid Xu sigqueue_move_set(&td0->td_sigqueue, &worklist, set); 6869104847fSDavid Xu 6879104847fSDavid Xu sigqueue_flush(&worklist); 6889104847fSDavid Xu } 6899104847fSDavid Xu 6909104847fSDavid Xu void 6919104847fSDavid Xu sigqueue_delete_proc(struct proc *p, int signo) 6929104847fSDavid Xu { 6939104847fSDavid Xu sigset_t set; 6949104847fSDavid Xu 6959104847fSDavid Xu SIGEMPTYSET(set); 6969104847fSDavid Xu SIGADDSET(set, signo); 6979104847fSDavid Xu sigqueue_delete_set_proc(p, &set); 6989104847fSDavid Xu } 6999104847fSDavid Xu 700a5799a4fSKonstantin Belousov static void 7019104847fSDavid Xu sigqueue_delete_stopmask_proc(struct proc *p) 7029104847fSDavid Xu { 7039104847fSDavid Xu sigset_t set; 7049104847fSDavid Xu 7059104847fSDavid Xu SIGEMPTYSET(set); 7069104847fSDavid Xu SIGADDSET(set, SIGSTOP); 7079104847fSDavid Xu SIGADDSET(set, SIGTSTP); 7089104847fSDavid Xu SIGADDSET(set, SIGTTIN); 7099104847fSDavid Xu SIGADDSET(set, SIGTTOU); 7109104847fSDavid Xu sigqueue_delete_set_proc(p, &set); 7119104847fSDavid Xu } 7129104847fSDavid Xu 713fbbeeb6cSBruce Evans /* 7141968f37bSJohn Baldwin * Determine signal that should be delivered to thread td, the current 7151968f37bSJohn Baldwin * thread, 0 if none. If there is a pending stop signal with default 716fbbeeb6cSBruce Evans * action, the process stops in issignal(). 717fbbeeb6cSBruce Evans */ 718fbbeeb6cSBruce Evans int 7193cf3b9f0SJohn Baldwin cursig(struct thread *td) 720fbbeeb6cSBruce Evans { 721c9dfa2e0SJeff Roberson PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); 72290af4afaSJohn Baldwin mtx_assert(&td->td_proc->p_sigacts->ps_mtx, MA_OWNED); 723a54e85fdSJeff Roberson THREAD_LOCK_ASSERT(td, MA_NOTOWNED); 7243cf3b9f0SJohn Baldwin return (SIGPENDING(td) ? issignal(td) : 0); 725fbbeeb6cSBruce Evans } 726fbbeeb6cSBruce Evans 72779065dbaSBruce Evans /* 72879065dbaSBruce Evans * Arrange for ast() to handle unmasked pending signals on return to user 7299104847fSDavid Xu * mode. This must be called whenever a signal is added to td_sigqueue or 7304093529dSJeff Roberson * unmasked in td_sigmask. 73179065dbaSBruce Evans */ 73279065dbaSBruce Evans void 7334093529dSJeff Roberson signotify(struct thread *td) 73479065dbaSBruce Evans { 7354093529dSJeff Roberson 736ddd4d15eSMatt Macy PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); 7374093529dSJeff Roberson 738c6d31b83SKonstantin Belousov if (SIGPENDING(td)) 739c6d31b83SKonstantin Belousov ast_sched(td, TDA_SIG); 7408b94a061SJohn Baldwin } 7418b94a061SJohn Baldwin 742affd9185SKonstantin Belousov /* 743affd9185SKonstantin Belousov * Returns 1 (true) if altstack is configured for the thread, and the 744affd9185SKonstantin Belousov * passed stack bottom address falls into the altstack range. Handles 745affd9185SKonstantin Belousov * the 43 compat special case where the alt stack size is zero. 746affd9185SKonstantin Belousov */ 7478b94a061SJohn Baldwin int 7488b94a061SJohn Baldwin sigonstack(size_t sp) 7498b94a061SJohn Baldwin { 750affd9185SKonstantin Belousov struct thread *td; 7518b94a061SJohn Baldwin 752affd9185SKonstantin Belousov td = curthread; 753affd9185SKonstantin Belousov if ((td->td_pflags & TDP_ALTSTACK) == 0) 754affd9185SKonstantin Belousov return (0); 7551930e303SPoul-Henning Kamp #if defined(COMPAT_43) 7567e097daaSKonstantin Belousov if (SV_PROC_FLAG(td->td_proc, SV_AOUT) && td->td_sigstk.ss_size == 0) 757affd9185SKonstantin Belousov return ((td->td_sigstk.ss_flags & SS_ONSTACK) != 0); 7588b94a061SJohn Baldwin #endif 759affd9185SKonstantin Belousov return (sp >= (size_t)td->td_sigstk.ss_sp && 760affd9185SKonstantin Belousov sp < td->td_sigstk.ss_size + (size_t)td->td_sigstk.ss_sp); 7618b94a061SJohn Baldwin } 76279065dbaSBruce Evans 7636f841fb7SMarcel Moolenaar static __inline int 7646f841fb7SMarcel Moolenaar sigprop(int sig) 7652c42a146SMarcel Moolenaar { 7666f841fb7SMarcel Moolenaar 767ed6d876bSBrooks Davis if (sig > 0 && sig < nitems(sigproptbl)) 768ed6d876bSBrooks Davis return (sigproptbl[sig]); 7692c42a146SMarcel Moolenaar return (0); 770df8bae1dSRodney W. Grimes } 7712c42a146SMarcel Moolenaar 772350ae563SKonstantin Belousov static bool 773ea566832SEd Schouten sigact_flag_test(const struct sigaction *act, int flag) 774350ae563SKonstantin Belousov { 775350ae563SKonstantin Belousov 776c83655f3SKonstantin Belousov /* 777c83655f3SKonstantin Belousov * SA_SIGINFO is reset when signal disposition is set to 778c83655f3SKonstantin Belousov * ignore or default. Other flags are kept according to user 779c83655f3SKonstantin Belousov * settings. 780c83655f3SKonstantin Belousov */ 781c83655f3SKonstantin Belousov return ((act->sa_flags & flag) != 0 && (flag != SA_SIGINFO || 782c83655f3SKonstantin Belousov ((__sighandler_t *)act->sa_sigaction != SIG_IGN && 783c83655f3SKonstantin Belousov (__sighandler_t *)act->sa_sigaction != SIG_DFL))); 784350ae563SKonstantin Belousov } 785350ae563SKonstantin Belousov 7862c42a146SMarcel Moolenaar /* 7878f19eb88SIan Dowse * kern_sigaction 7882c42a146SMarcel Moolenaar * sigaction 78923eeeff7SPeter Wemm * freebsd4_sigaction 7902c42a146SMarcel Moolenaar * osigaction 7912c42a146SMarcel Moolenaar */ 7928f19eb88SIan Dowse int 793ea566832SEd Schouten kern_sigaction(struct thread *td, int sig, const struct sigaction *act, 794ea566832SEd Schouten struct sigaction *oact, int flags) 795df8bae1dSRodney W. Grimes { 79690af4afaSJohn Baldwin struct sigacts *ps; 7978f19eb88SIan Dowse struct proc *p = td->td_proc; 798df8bae1dSRodney W. Grimes 7992899d606SDag-Erling Smørgrav if (!_SIG_VALID(sig)) 8002c42a146SMarcel Moolenaar return (EINVAL); 801271ab240SKonstantin Belousov if (act != NULL && act->sa_handler != SIG_DFL && 802271ab240SKonstantin Belousov act->sa_handler != SIG_IGN && (act->sa_flags & ~(SA_ONSTACK | 803271ab240SKonstantin Belousov SA_RESTART | SA_RESETHAND | SA_NOCLDSTOP | SA_NODEFER | 804271ab240SKonstantin Belousov SA_NOCLDWAIT | SA_SIGINFO)) != 0) 8052d864174SKonstantin Belousov return (EINVAL); 8062c42a146SMarcel Moolenaar 807628d2653SJohn Baldwin PROC_LOCK(p); 808628d2653SJohn Baldwin ps = p->p_sigacts; 80990af4afaSJohn Baldwin mtx_lock(&ps->ps_mtx); 8102c42a146SMarcel Moolenaar if (oact) { 811fb441a88SKonstantin Belousov memset(oact, 0, sizeof(*oact)); 8122c42a146SMarcel Moolenaar oact->sa_mask = ps->ps_catchmask[_SIG_IDX(sig)]; 8132c42a146SMarcel Moolenaar if (SIGISMEMBER(ps->ps_sigonstack, sig)) 8142c42a146SMarcel Moolenaar oact->sa_flags |= SA_ONSTACK; 8152c42a146SMarcel Moolenaar if (!SIGISMEMBER(ps->ps_sigintr, sig)) 8162c42a146SMarcel Moolenaar oact->sa_flags |= SA_RESTART; 8172c42a146SMarcel Moolenaar if (SIGISMEMBER(ps->ps_sigreset, sig)) 8182c42a146SMarcel Moolenaar oact->sa_flags |= SA_RESETHAND; 8192c42a146SMarcel Moolenaar if (SIGISMEMBER(ps->ps_signodefer, sig)) 8202c42a146SMarcel Moolenaar oact->sa_flags |= SA_NODEFER; 82110c2b8e1SDavid E. O'Brien if (SIGISMEMBER(ps->ps_siginfo, sig)) { 8222c42a146SMarcel Moolenaar oact->sa_flags |= SA_SIGINFO; 82310c2b8e1SDavid E. O'Brien oact->sa_sigaction = 82410c2b8e1SDavid E. O'Brien (__siginfohandler_t *)ps->ps_sigact[_SIG_IDX(sig)]; 82510c2b8e1SDavid E. O'Brien } else 82610c2b8e1SDavid E. O'Brien oact->sa_handler = ps->ps_sigact[_SIG_IDX(sig)]; 82790af4afaSJohn Baldwin if (sig == SIGCHLD && ps->ps_flag & PS_NOCLDSTOP) 8282c42a146SMarcel Moolenaar oact->sa_flags |= SA_NOCLDSTOP; 82990af4afaSJohn Baldwin if (sig == SIGCHLD && ps->ps_flag & PS_NOCLDWAIT) 8302c42a146SMarcel Moolenaar oact->sa_flags |= SA_NOCLDWAIT; 8312c42a146SMarcel Moolenaar } 8322c42a146SMarcel Moolenaar if (act) { 8332c42a146SMarcel Moolenaar if ((sig == SIGKILL || sig == SIGSTOP) && 834628d2653SJohn Baldwin act->sa_handler != SIG_DFL) { 83590af4afaSJohn Baldwin mtx_unlock(&ps->ps_mtx); 836628d2653SJohn Baldwin PROC_UNLOCK(p); 8372c42a146SMarcel Moolenaar return (EINVAL); 838628d2653SJohn Baldwin } 8392c42a146SMarcel Moolenaar 840df8bae1dSRodney W. Grimes /* 841df8bae1dSRodney W. Grimes * Change setting atomically. 842df8bae1dSRodney W. Grimes */ 8432c42a146SMarcel Moolenaar 8442c42a146SMarcel Moolenaar ps->ps_catchmask[_SIG_IDX(sig)] = act->sa_mask; 8452c42a146SMarcel Moolenaar SIG_CANTMASK(ps->ps_catchmask[_SIG_IDX(sig)]); 846350ae563SKonstantin Belousov if (sigact_flag_test(act, SA_SIGINFO)) { 847aa7a4daeSPeter Wemm ps->ps_sigact[_SIG_IDX(sig)] = 848aa7a4daeSPeter Wemm (__sighandler_t *)act->sa_sigaction; 84980f42b55SIan Dowse SIGADDSET(ps->ps_siginfo, sig); 85080f42b55SIan Dowse } else { 85180f42b55SIan Dowse ps->ps_sigact[_SIG_IDX(sig)] = act->sa_handler; 8522c42a146SMarcel Moolenaar SIGDELSET(ps->ps_siginfo, sig); 8532c42a146SMarcel Moolenaar } 854350ae563SKonstantin Belousov if (!sigact_flag_test(act, SA_RESTART)) 8552c42a146SMarcel Moolenaar SIGADDSET(ps->ps_sigintr, sig); 856df8bae1dSRodney W. Grimes else 8572c42a146SMarcel Moolenaar SIGDELSET(ps->ps_sigintr, sig); 858350ae563SKonstantin Belousov if (sigact_flag_test(act, SA_ONSTACK)) 8592c42a146SMarcel Moolenaar SIGADDSET(ps->ps_sigonstack, sig); 860df8bae1dSRodney W. Grimes else 8612c42a146SMarcel Moolenaar SIGDELSET(ps->ps_sigonstack, sig); 862350ae563SKonstantin Belousov if (sigact_flag_test(act, SA_RESETHAND)) 8632c42a146SMarcel Moolenaar SIGADDSET(ps->ps_sigreset, sig); 8641e41c1b5SSteven Wallace else 8652c42a146SMarcel Moolenaar SIGDELSET(ps->ps_sigreset, sig); 866350ae563SKonstantin Belousov if (sigact_flag_test(act, SA_NODEFER)) 8672c42a146SMarcel Moolenaar SIGADDSET(ps->ps_signodefer, sig); 868289ccde0SPeter Wemm else 8692c42a146SMarcel Moolenaar SIGDELSET(ps->ps_signodefer, sig); 8702c42a146SMarcel Moolenaar if (sig == SIGCHLD) { 8712c42a146SMarcel Moolenaar if (act->sa_flags & SA_NOCLDSTOP) 87290af4afaSJohn Baldwin ps->ps_flag |= PS_NOCLDSTOP; 8736626c604SJulian Elischer else 87490af4afaSJohn Baldwin ps->ps_flag &= ~PS_NOCLDSTOP; 875ba1551caSIan Dowse if (act->sa_flags & SA_NOCLDWAIT) { 876245f17d4SJoerg Wunsch /* 8772c42a146SMarcel Moolenaar * Paranoia: since SA_NOCLDWAIT is implemented 8782c42a146SMarcel Moolenaar * by reparenting the dying child to PID 1 (and 8792c42a146SMarcel Moolenaar * trust it to reap the zombie), PID 1 itself 8802c42a146SMarcel Moolenaar * is forbidden to set SA_NOCLDWAIT. 881245f17d4SJoerg Wunsch */ 882245f17d4SJoerg Wunsch if (p->p_pid == 1) 88390af4afaSJohn Baldwin ps->ps_flag &= ~PS_NOCLDWAIT; 8846626c604SJulian Elischer else 88590af4afaSJohn Baldwin ps->ps_flag |= PS_NOCLDWAIT; 886245f17d4SJoerg Wunsch } else 88790af4afaSJohn Baldwin ps->ps_flag &= ~PS_NOCLDWAIT; 888ba1551caSIan Dowse if (ps->ps_sigact[_SIG_IDX(SIGCHLD)] == SIG_IGN) 88990af4afaSJohn Baldwin ps->ps_flag |= PS_CLDSIGIGN; 890ba1551caSIan Dowse else 89190af4afaSJohn Baldwin ps->ps_flag &= ~PS_CLDSIGIGN; 892df8bae1dSRodney W. Grimes } 893df8bae1dSRodney W. Grimes /* 89490af4afaSJohn Baldwin * Set bit in ps_sigignore for signals that are set to SIG_IGN, 8952c42a146SMarcel Moolenaar * and for signals set to SIG_DFL where the default is to 89690af4afaSJohn Baldwin * ignore. However, don't put SIGCONT in ps_sigignore, as we 8972c42a146SMarcel Moolenaar * have to restart the process. 898df8bae1dSRodney W. Grimes */ 8992c42a146SMarcel Moolenaar if (ps->ps_sigact[_SIG_IDX(sig)] == SIG_IGN || 900fd50a707SBrooks Davis (sigprop(sig) & SIGPROP_IGNORE && 9012c42a146SMarcel Moolenaar ps->ps_sigact[_SIG_IDX(sig)] == SIG_DFL)) { 9022c42a146SMarcel Moolenaar /* never to be seen again */ 9039104847fSDavid Xu sigqueue_delete_proc(p, sig); 9042c42a146SMarcel Moolenaar if (sig != SIGCONT) 9052c42a146SMarcel Moolenaar /* easier in psignal */ 90690af4afaSJohn Baldwin SIGADDSET(ps->ps_sigignore, sig); 90790af4afaSJohn Baldwin SIGDELSET(ps->ps_sigcatch, sig); 908645682fdSLuoqi Chen } else { 90990af4afaSJohn Baldwin SIGDELSET(ps->ps_sigignore, sig); 9102c42a146SMarcel Moolenaar if (ps->ps_sigact[_SIG_IDX(sig)] == SIG_DFL) 91190af4afaSJohn Baldwin SIGDELSET(ps->ps_sigcatch, sig); 9122c42a146SMarcel Moolenaar else 91390af4afaSJohn Baldwin SIGADDSET(ps->ps_sigcatch, sig); 9142c42a146SMarcel Moolenaar } 91523eeeff7SPeter Wemm #ifdef COMPAT_FREEBSD4 91623eeeff7SPeter Wemm if (ps->ps_sigact[_SIG_IDX(sig)] == SIG_IGN || 91723eeeff7SPeter Wemm ps->ps_sigact[_SIG_IDX(sig)] == SIG_DFL || 91823eeeff7SPeter Wemm (flags & KSA_FREEBSD4) == 0) 91923eeeff7SPeter Wemm SIGDELSET(ps->ps_freebsd4, sig); 92023eeeff7SPeter Wemm else 92123eeeff7SPeter Wemm SIGADDSET(ps->ps_freebsd4, sig); 92223eeeff7SPeter Wemm #endif 923e8ebc08fSPeter Wemm #ifdef COMPAT_43 924645682fdSLuoqi Chen if (ps->ps_sigact[_SIG_IDX(sig)] == SIG_IGN || 92523eeeff7SPeter Wemm ps->ps_sigact[_SIG_IDX(sig)] == SIG_DFL || 92623eeeff7SPeter Wemm (flags & KSA_OSIGSET) == 0) 927645682fdSLuoqi Chen SIGDELSET(ps->ps_osigset, sig); 928645682fdSLuoqi Chen else 929645682fdSLuoqi Chen SIGADDSET(ps->ps_osigset, sig); 930e8ebc08fSPeter Wemm #endif 931df8bae1dSRodney W. Grimes } 93290af4afaSJohn Baldwin mtx_unlock(&ps->ps_mtx); 933628d2653SJohn Baldwin PROC_UNLOCK(p); 9342c42a146SMarcel Moolenaar return (0); 9352c42a146SMarcel Moolenaar } 9362c42a146SMarcel Moolenaar 9372c42a146SMarcel Moolenaar #ifndef _SYS_SYSPROTO_H_ 9382c42a146SMarcel Moolenaar struct sigaction_args { 9392c42a146SMarcel Moolenaar int sig; 9402c42a146SMarcel Moolenaar struct sigaction *act; 9412c42a146SMarcel Moolenaar struct sigaction *oact; 9422c42a146SMarcel Moolenaar }; 9432c42a146SMarcel Moolenaar #endif 9442c42a146SMarcel Moolenaar int 945e052a8b9SEd Maste sys_sigaction(struct thread *td, struct sigaction_args *uap) 9462c42a146SMarcel Moolenaar { 9472c42a146SMarcel Moolenaar struct sigaction act, oact; 948e052a8b9SEd Maste struct sigaction *actp, *oactp; 9492c42a146SMarcel Moolenaar int error; 9502c42a146SMarcel Moolenaar 9516f841fb7SMarcel Moolenaar actp = (uap->act != NULL) ? &act : NULL; 9526f841fb7SMarcel Moolenaar oactp = (uap->oact != NULL) ? &oact : NULL; 9532c42a146SMarcel Moolenaar if (actp) { 9546f841fb7SMarcel Moolenaar error = copyin(uap->act, actp, sizeof(act)); 9552c42a146SMarcel Moolenaar if (error) 95644443757STim J. Robbins return (error); 9572c42a146SMarcel Moolenaar } 9588f19eb88SIan Dowse error = kern_sigaction(td, uap->sig, actp, oactp, 0); 95925d6dc06SJohn Baldwin if (oactp && !error) 9606f841fb7SMarcel Moolenaar error = copyout(oactp, uap->oact, sizeof(oact)); 9612c42a146SMarcel Moolenaar return (error); 9622c42a146SMarcel Moolenaar } 9632c42a146SMarcel Moolenaar 96423eeeff7SPeter Wemm #ifdef COMPAT_FREEBSD4 96523eeeff7SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 96623eeeff7SPeter Wemm struct freebsd4_sigaction_args { 96723eeeff7SPeter Wemm int sig; 96823eeeff7SPeter Wemm struct sigaction *act; 96923eeeff7SPeter Wemm struct sigaction *oact; 97023eeeff7SPeter Wemm }; 97123eeeff7SPeter Wemm #endif 97223eeeff7SPeter Wemm int 973e052a8b9SEd Maste freebsd4_sigaction(struct thread *td, struct freebsd4_sigaction_args *uap) 97423eeeff7SPeter Wemm { 97523eeeff7SPeter Wemm struct sigaction act, oact; 976e052a8b9SEd Maste struct sigaction *actp, *oactp; 97723eeeff7SPeter Wemm int error; 97823eeeff7SPeter Wemm 97923eeeff7SPeter Wemm actp = (uap->act != NULL) ? &act : NULL; 98023eeeff7SPeter Wemm oactp = (uap->oact != NULL) ? &oact : NULL; 98123eeeff7SPeter Wemm if (actp) { 98223eeeff7SPeter Wemm error = copyin(uap->act, actp, sizeof(act)); 98323eeeff7SPeter Wemm if (error) 98444443757STim J. Robbins return (error); 98523eeeff7SPeter Wemm } 98623eeeff7SPeter Wemm error = kern_sigaction(td, uap->sig, actp, oactp, KSA_FREEBSD4); 987a14e1189SJohn Baldwin if (oactp && !error) 98823eeeff7SPeter Wemm error = copyout(oactp, uap->oact, sizeof(oact)); 98923eeeff7SPeter Wemm return (error); 99023eeeff7SPeter Wemm } 99123eeeff7SPeter Wemm #endif /* COMAPT_FREEBSD4 */ 99223eeeff7SPeter Wemm 99331c8f3f0SMarcel Moolenaar #ifdef COMPAT_43 /* XXX - COMPAT_FBSD3 */ 9942c42a146SMarcel Moolenaar #ifndef _SYS_SYSPROTO_H_ 9952c42a146SMarcel Moolenaar struct osigaction_args { 9962c42a146SMarcel Moolenaar int signum; 9972c42a146SMarcel Moolenaar struct osigaction *nsa; 9982c42a146SMarcel Moolenaar struct osigaction *osa; 9992c42a146SMarcel Moolenaar }; 10002c42a146SMarcel Moolenaar #endif 10012c42a146SMarcel Moolenaar int 1002e052a8b9SEd Maste osigaction(struct thread *td, struct osigaction_args *uap) 10032c42a146SMarcel Moolenaar { 10042c42a146SMarcel Moolenaar struct osigaction sa; 10052c42a146SMarcel Moolenaar struct sigaction nsa, osa; 1006e052a8b9SEd Maste struct sigaction *nsap, *osap; 10072c42a146SMarcel Moolenaar int error; 10082c42a146SMarcel Moolenaar 10096f841fb7SMarcel Moolenaar if (uap->signum <= 0 || uap->signum >= ONSIG) 10106f841fb7SMarcel Moolenaar return (EINVAL); 1011fb99ab88SMatthew Dillon 10126f841fb7SMarcel Moolenaar nsap = (uap->nsa != NULL) ? &nsa : NULL; 10136f841fb7SMarcel Moolenaar osap = (uap->osa != NULL) ? &osa : NULL; 1014fb99ab88SMatthew Dillon 10152c42a146SMarcel Moolenaar if (nsap) { 10166f841fb7SMarcel Moolenaar error = copyin(uap->nsa, &sa, sizeof(sa)); 10172c42a146SMarcel Moolenaar if (error) 101844443757STim J. Robbins return (error); 10192c42a146SMarcel Moolenaar nsap->sa_handler = sa.sa_handler; 10202c42a146SMarcel Moolenaar nsap->sa_flags = sa.sa_flags; 10212c42a146SMarcel Moolenaar OSIG2SIG(sa.sa_mask, nsap->sa_mask); 10222c42a146SMarcel Moolenaar } 102323eeeff7SPeter Wemm error = kern_sigaction(td, uap->signum, nsap, osap, KSA_OSIGSET); 10242c42a146SMarcel Moolenaar if (osap && !error) { 10252c42a146SMarcel Moolenaar sa.sa_handler = osap->sa_handler; 10262c42a146SMarcel Moolenaar sa.sa_flags = osap->sa_flags; 10272c42a146SMarcel Moolenaar SIG2OSIG(osap->sa_mask, sa.sa_mask); 10286f841fb7SMarcel Moolenaar error = copyout(&sa, uap->osa, sizeof(sa)); 10292c42a146SMarcel Moolenaar } 10302c42a146SMarcel Moolenaar return (error); 10312c42a146SMarcel Moolenaar } 103223eeeff7SPeter Wemm 103373dbd3daSJohn Baldwin #if !defined(__i386__) 103423eeeff7SPeter Wemm /* Avoid replicating the same stub everywhere */ 103523eeeff7SPeter Wemm int 1036e052a8b9SEd Maste osigreturn(struct thread *td, struct osigreturn_args *uap) 103723eeeff7SPeter Wemm { 103823eeeff7SPeter Wemm 103923eeeff7SPeter Wemm return (nosys(td, (struct nosys_args *)uap)); 104023eeeff7SPeter Wemm } 104123eeeff7SPeter Wemm #endif 104231c8f3f0SMarcel Moolenaar #endif /* COMPAT_43 */ 1043df8bae1dSRodney W. Grimes 1044df8bae1dSRodney W. Grimes /* 1045df8bae1dSRodney W. Grimes * Initialize signal state for process 0; 1046df8bae1dSRodney W. Grimes * set to ignore signals that are ignored by default. 1047df8bae1dSRodney W. Grimes */ 1048df8bae1dSRodney W. Grimes void 1049e052a8b9SEd Maste siginit(struct proc *p) 1050df8bae1dSRodney W. Grimes { 10513e85b721SEd Maste int i; 105290af4afaSJohn Baldwin struct sigacts *ps; 1053df8bae1dSRodney W. Grimes 1054628d2653SJohn Baldwin PROC_LOCK(p); 105590af4afaSJohn Baldwin ps = p->p_sigacts; 105690af4afaSJohn Baldwin mtx_lock(&ps->ps_mtx); 1057350ae563SKonstantin Belousov for (i = 1; i <= NSIG; i++) { 1058fd50a707SBrooks Davis if (sigprop(i) & SIGPROP_IGNORE && i != SIGCONT) { 105990af4afaSJohn Baldwin SIGADDSET(ps->ps_sigignore, i); 1060350ae563SKonstantin Belousov } 1061350ae563SKonstantin Belousov } 106290af4afaSJohn Baldwin mtx_unlock(&ps->ps_mtx); 1063628d2653SJohn Baldwin PROC_UNLOCK(p); 1064df8bae1dSRodney W. Grimes } 1065df8bae1dSRodney W. Grimes 1066df8bae1dSRodney W. Grimes /* 1067350ae563SKonstantin Belousov * Reset specified signal to the default disposition. 1068350ae563SKonstantin Belousov */ 1069350ae563SKonstantin Belousov static void 1070350ae563SKonstantin Belousov sigdflt(struct sigacts *ps, int sig) 1071350ae563SKonstantin Belousov { 1072350ae563SKonstantin Belousov 1073350ae563SKonstantin Belousov mtx_assert(&ps->ps_mtx, MA_OWNED); 1074350ae563SKonstantin Belousov SIGDELSET(ps->ps_sigcatch, sig); 1075fd50a707SBrooks Davis if ((sigprop(sig) & SIGPROP_IGNORE) != 0 && sig != SIGCONT) 1076350ae563SKonstantin Belousov SIGADDSET(ps->ps_sigignore, sig); 1077350ae563SKonstantin Belousov ps->ps_sigact[_SIG_IDX(sig)] = SIG_DFL; 1078350ae563SKonstantin Belousov SIGDELSET(ps->ps_siginfo, sig); 1079350ae563SKonstantin Belousov } 1080350ae563SKonstantin Belousov 1081350ae563SKonstantin Belousov /* 1082df8bae1dSRodney W. Grimes * Reset signals for an exec of the specified process. 1083df8bae1dSRodney W. Grimes */ 1084df8bae1dSRodney W. Grimes void 1085a30ec4b9SDavid Xu execsigs(struct proc *p) 1086df8bae1dSRodney W. Grimes { 1087a30ec4b9SDavid Xu struct sigacts *ps; 1088a30ec4b9SDavid Xu struct thread *td; 1089df8bae1dSRodney W. Grimes 1090df8bae1dSRodney W. Grimes /* 1091df8bae1dSRodney W. Grimes * Reset caught signals. Held signals remain held 10924093529dSJeff Roberson * through td_sigmask (unless they were caught, 1093df8bae1dSRodney W. Grimes * and are now ignored by default). 1094df8bae1dSRodney W. Grimes */ 10959b3b1c5fSJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 1096628d2653SJohn Baldwin ps = p->p_sigacts; 109790af4afaSJohn Baldwin mtx_lock(&ps->ps_mtx); 1098079c5b9eSKyle Evans sig_drop_caught(p); 1099f3fe76ecSEd Schouten 1100f3fe76ecSEd Schouten /* 1101df8bae1dSRodney W. Grimes * Reset stack state to the user stack. 1102df8bae1dSRodney W. Grimes * Clear set of signals caught on the signal stack. 1103df8bae1dSRodney W. Grimes */ 1104469ec1ebSKonstantin Belousov td = curthread; 1105469ec1ebSKonstantin Belousov MPASS(td->td_proc == p); 1106a30ec4b9SDavid Xu td->td_sigstk.ss_flags = SS_DISABLE; 1107a30ec4b9SDavid Xu td->td_sigstk.ss_size = 0; 1108a30ec4b9SDavid Xu td->td_sigstk.ss_sp = 0; 1109a30ec4b9SDavid Xu td->td_pflags &= ~TDP_ALTSTACK; 111080e907a1SPeter Wemm /* 111180e907a1SPeter Wemm * Reset no zombies if child dies flag as Solaris does. 111280e907a1SPeter Wemm */ 111390af4afaSJohn Baldwin ps->ps_flag &= ~(PS_NOCLDWAIT | PS_CLDSIGIGN); 1114c7fd62daSDavid Malone if (ps->ps_sigact[_SIG_IDX(SIGCHLD)] == SIG_IGN) 1115c7fd62daSDavid Malone ps->ps_sigact[_SIG_IDX(SIGCHLD)] = SIG_DFL; 111690af4afaSJohn Baldwin mtx_unlock(&ps->ps_mtx); 1117df8bae1dSRodney W. Grimes } 1118df8bae1dSRodney W. Grimes 1119df8bae1dSRodney W. Grimes /* 1120e77daab1SJohn Baldwin * kern_sigprocmask() 11217c8fdcbdSMatthew Dillon * 1122628d2653SJohn Baldwin * Manipulate signal mask. 1123df8bae1dSRodney W. Grimes */ 1124e77daab1SJohn Baldwin int 11256b286ee8SKonstantin Belousov kern_sigprocmask(struct thread *td, int how, sigset_t *set, sigset_t *oset, 112684440afbSKonstantin Belousov int flags) 11272c42a146SMarcel Moolenaar { 11286b286ee8SKonstantin Belousov sigset_t new_block, oset1; 11296b286ee8SKonstantin Belousov struct proc *p; 11302c42a146SMarcel Moolenaar int error; 11312c42a146SMarcel Moolenaar 11326b286ee8SKonstantin Belousov p = td->td_proc; 113370778bbaSKonstantin Belousov if ((flags & SIGPROCMASK_PROC_LOCKED) != 0) 113470778bbaSKonstantin Belousov PROC_LOCK_ASSERT(p, MA_OWNED); 113570778bbaSKonstantin Belousov else 11366b286ee8SKonstantin Belousov PROC_LOCK(p); 113770778bbaSKonstantin Belousov mtx_assert(&p->p_sigacts->ps_mtx, (flags & SIGPROCMASK_PS_LOCKED) != 0 113870778bbaSKonstantin Belousov ? MA_OWNED : MA_NOTOWNED); 11392c42a146SMarcel Moolenaar if (oset != NULL) 11404093529dSJeff Roberson *oset = td->td_sigmask; 11412c42a146SMarcel Moolenaar 11422c42a146SMarcel Moolenaar error = 0; 11432c42a146SMarcel Moolenaar if (set != NULL) { 11442c42a146SMarcel Moolenaar switch (how) { 11452c42a146SMarcel Moolenaar case SIG_BLOCK: 1146645682fdSLuoqi Chen SIG_CANTMASK(*set); 11476b286ee8SKonstantin Belousov oset1 = td->td_sigmask; 11484093529dSJeff Roberson SIGSETOR(td->td_sigmask, *set); 11496b286ee8SKonstantin Belousov new_block = td->td_sigmask; 11506b286ee8SKonstantin Belousov SIGSETNAND(new_block, oset1); 11512c42a146SMarcel Moolenaar break; 11522c42a146SMarcel Moolenaar case SIG_UNBLOCK: 11534093529dSJeff Roberson SIGSETNAND(td->td_sigmask, *set); 11544093529dSJeff Roberson signotify(td); 1155407af02bSDavid Xu goto out; 11562c42a146SMarcel Moolenaar case SIG_SETMASK: 1157645682fdSLuoqi Chen SIG_CANTMASK(*set); 11586b286ee8SKonstantin Belousov oset1 = td->td_sigmask; 115984440afbSKonstantin Belousov if (flags & SIGPROCMASK_OLD) 11604093529dSJeff Roberson SIGSETLO(td->td_sigmask, *set); 1161645682fdSLuoqi Chen else 11624093529dSJeff Roberson td->td_sigmask = *set; 11636b286ee8SKonstantin Belousov new_block = td->td_sigmask; 11646b286ee8SKonstantin Belousov SIGSETNAND(new_block, oset1); 11654093529dSJeff Roberson signotify(td); 11662c42a146SMarcel Moolenaar break; 11672c42a146SMarcel Moolenaar default: 11682c42a146SMarcel Moolenaar error = EINVAL; 1169407af02bSDavid Xu goto out; 11702c42a146SMarcel Moolenaar } 11716b286ee8SKonstantin Belousov 11726b286ee8SKonstantin Belousov /* 11737df8f6abSKonstantin Belousov * The new_block set contains signals that were not previously 11746b286ee8SKonstantin Belousov * blocked, but are blocked now. 11756b286ee8SKonstantin Belousov * 11766b286ee8SKonstantin Belousov * In case we block any signal that was not previously blocked 11776b286ee8SKonstantin Belousov * for td, and process has the signal pending, try to schedule 1178407af02bSDavid Xu * signal delivery to some thread that does not block the 1179407af02bSDavid Xu * signal, possibly waking it up. 11806b286ee8SKonstantin Belousov */ 11816b286ee8SKonstantin Belousov if (p->p_numthreads != 1) 118280a8b0f3SKonstantin Belousov reschedule_signals(p, new_block, flags); 1183407af02bSDavid Xu } 11846b286ee8SKonstantin Belousov 1185407af02bSDavid Xu out: 118684440afbSKonstantin Belousov if (!(flags & SIGPROCMASK_PROC_LOCKED)) 11876b286ee8SKonstantin Belousov PROC_UNLOCK(p); 11882c42a146SMarcel Moolenaar return (error); 11892c42a146SMarcel Moolenaar } 11902c42a146SMarcel Moolenaar 1191d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1192df8bae1dSRodney W. Grimes struct sigprocmask_args { 1193df8bae1dSRodney W. Grimes int how; 11942c42a146SMarcel Moolenaar const sigset_t *set; 11952c42a146SMarcel Moolenaar sigset_t *oset; 1196df8bae1dSRodney W. Grimes }; 1197d2d3e875SBruce Evans #endif 119826f9a767SRodney W. Grimes int 1199e052a8b9SEd Maste sys_sigprocmask(struct thread *td, struct sigprocmask_args *uap) 1200df8bae1dSRodney W. Grimes { 12012c42a146SMarcel Moolenaar sigset_t set, oset; 12022c42a146SMarcel Moolenaar sigset_t *setp, *osetp; 12032c42a146SMarcel Moolenaar int error; 1204df8bae1dSRodney W. Grimes 12056f841fb7SMarcel Moolenaar setp = (uap->set != NULL) ? &set : NULL; 12066f841fb7SMarcel Moolenaar osetp = (uap->oset != NULL) ? &oset : NULL; 12072c42a146SMarcel Moolenaar if (setp) { 12086f841fb7SMarcel Moolenaar error = copyin(uap->set, setp, sizeof(set)); 12092c42a146SMarcel Moolenaar if (error) 12102c42a146SMarcel Moolenaar return (error); 1211df8bae1dSRodney W. Grimes } 1212e77daab1SJohn Baldwin error = kern_sigprocmask(td, uap->how, setp, osetp, 0); 12132c42a146SMarcel Moolenaar if (osetp && !error) { 12146f841fb7SMarcel Moolenaar error = copyout(osetp, uap->oset, sizeof(oset)); 12152c42a146SMarcel Moolenaar } 12162c42a146SMarcel Moolenaar return (error); 12172c42a146SMarcel Moolenaar } 12182c42a146SMarcel Moolenaar 121931c8f3f0SMarcel Moolenaar #ifdef COMPAT_43 /* XXX - COMPAT_FBSD3 */ 12202c42a146SMarcel Moolenaar #ifndef _SYS_SYSPROTO_H_ 12212c42a146SMarcel Moolenaar struct osigprocmask_args { 12222c42a146SMarcel Moolenaar int how; 12232c42a146SMarcel Moolenaar osigset_t mask; 12242c42a146SMarcel Moolenaar }; 12252c42a146SMarcel Moolenaar #endif 12262c42a146SMarcel Moolenaar int 1227e052a8b9SEd Maste osigprocmask(struct thread *td, struct osigprocmask_args *uap) 12282c42a146SMarcel Moolenaar { 12292c42a146SMarcel Moolenaar sigset_t set, oset; 12302c42a146SMarcel Moolenaar int error; 12312c42a146SMarcel Moolenaar 12322c42a146SMarcel Moolenaar OSIG2SIG(uap->mask, set); 1233e77daab1SJohn Baldwin error = kern_sigprocmask(td, uap->how, &set, &oset, 1); 1234b40ce416SJulian Elischer SIG2OSIG(oset, td->td_retval[0]); 1235df8bae1dSRodney W. Grimes return (error); 1236df8bae1dSRodney W. Grimes } 123731c8f3f0SMarcel Moolenaar #endif /* COMPAT_43 */ 1238df8bae1dSRodney W. Grimes 123926f9a767SRodney W. Grimes int 12408451d0ddSKip Macy sys_sigwait(struct thread *td, struct sigwait_args *uap) 1241a447cd8bSJeff Roberson { 12429104847fSDavid Xu ksiginfo_t ksi; 1243a447cd8bSJeff Roberson sigset_t set; 1244a447cd8bSJeff Roberson int error; 1245a447cd8bSJeff Roberson 1246a447cd8bSJeff Roberson error = copyin(uap->set, &set, sizeof(set)); 124736939a0aSDavid Xu if (error) { 124836939a0aSDavid Xu td->td_retval[0] = error; 124936939a0aSDavid Xu return (0); 125036939a0aSDavid Xu } 1251a447cd8bSJeff Roberson 12529104847fSDavid Xu error = kern_sigtimedwait(td, set, &ksi, NULL); 125336939a0aSDavid Xu if (error) { 1254acced8b0SKonstantin Belousov /* 1255acced8b0SKonstantin Belousov * sigwait() function shall not return EINTR, but 1256acced8b0SKonstantin Belousov * the syscall does. Non-ancient libc provides the 1257acced8b0SKonstantin Belousov * wrapper which hides EINTR. Otherwise, EINTR return 1258acced8b0SKonstantin Belousov * is used by libthr to handle required cancellation 1259acced8b0SKonstantin Belousov * point in the sigwait(). 1260acced8b0SKonstantin Belousov */ 12618e9a54eeSKonstantin Belousov if (error == EINTR && td->td_proc->p_osrel < P_OSREL_SIGWAIT) 1262afb36e28SKonstantin Belousov return (ERESTART); 126336939a0aSDavid Xu td->td_retval[0] = error; 126436939a0aSDavid Xu return (0); 126536939a0aSDavid Xu } 1266a447cd8bSJeff Roberson 12679104847fSDavid Xu error = copyout(&ksi.ksi_signo, uap->sig, sizeof(ksi.ksi_signo)); 126836939a0aSDavid Xu td->td_retval[0] = error; 126936939a0aSDavid Xu return (0); 1270a447cd8bSJeff Roberson } 12710c14ff0eSRobert Watson 1272a447cd8bSJeff Roberson int 12738451d0ddSKip Macy sys_sigtimedwait(struct thread *td, struct sigtimedwait_args *uap) 1274a447cd8bSJeff Roberson { 1275a447cd8bSJeff Roberson struct timespec ts; 1276a447cd8bSJeff Roberson struct timespec *timeout; 1277a447cd8bSJeff Roberson sigset_t set; 12789104847fSDavid Xu ksiginfo_t ksi; 1279a447cd8bSJeff Roberson int error; 1280a447cd8bSJeff Roberson 1281a447cd8bSJeff Roberson if (uap->timeout) { 1282a447cd8bSJeff Roberson error = copyin(uap->timeout, &ts, sizeof(ts)); 1283a447cd8bSJeff Roberson if (error) 1284a447cd8bSJeff Roberson return (error); 1285a447cd8bSJeff Roberson 1286a447cd8bSJeff Roberson timeout = &ts; 1287a447cd8bSJeff Roberson } else 1288a447cd8bSJeff Roberson timeout = NULL; 1289a447cd8bSJeff Roberson 1290a447cd8bSJeff Roberson error = copyin(uap->set, &set, sizeof(set)); 1291a447cd8bSJeff Roberson if (error) 1292a447cd8bSJeff Roberson return (error); 1293a447cd8bSJeff Roberson 12949104847fSDavid Xu error = kern_sigtimedwait(td, set, &ksi, timeout); 1295a447cd8bSJeff Roberson if (error) 1296a447cd8bSJeff Roberson return (error); 12979dde3bc9SDavid Xu 1298418228dfSDavid Xu if (uap->info) 12999104847fSDavid Xu error = copyout(&ksi.ksi_info, uap->info, sizeof(siginfo_t)); 13009104847fSDavid Xu 13019104847fSDavid Xu if (error == 0) 13029104847fSDavid Xu td->td_retval[0] = ksi.ksi_signo; 1303a447cd8bSJeff Roberson return (error); 1304a447cd8bSJeff Roberson } 1305a447cd8bSJeff Roberson 1306a447cd8bSJeff Roberson int 13078451d0ddSKip Macy sys_sigwaitinfo(struct thread *td, struct sigwaitinfo_args *uap) 1308a447cd8bSJeff Roberson { 13099104847fSDavid Xu ksiginfo_t ksi; 1310a447cd8bSJeff Roberson sigset_t set; 1311a447cd8bSJeff Roberson int error; 1312a447cd8bSJeff Roberson 1313a447cd8bSJeff Roberson error = copyin(uap->set, &set, sizeof(set)); 1314a447cd8bSJeff Roberson if (error) 1315a447cd8bSJeff Roberson return (error); 1316a447cd8bSJeff Roberson 13179104847fSDavid Xu error = kern_sigtimedwait(td, set, &ksi, NULL); 1318a447cd8bSJeff Roberson if (error) 1319a447cd8bSJeff Roberson return (error); 1320a447cd8bSJeff Roberson 1321418228dfSDavid Xu if (uap->info) 13229104847fSDavid Xu error = copyout(&ksi.ksi_info, uap->info, sizeof(siginfo_t)); 13239104847fSDavid Xu 13249104847fSDavid Xu if (error == 0) 13259104847fSDavid Xu td->td_retval[0] = ksi.ksi_signo; 1326a447cd8bSJeff Roberson return (error); 1327a447cd8bSJeff Roberson } 1328a447cd8bSJeff Roberson 132986be94fcSTycho Nightingale static void 133086be94fcSTycho Nightingale proc_td_siginfo_capture(struct thread *td, siginfo_t *si) 133186be94fcSTycho Nightingale { 133286be94fcSTycho Nightingale struct thread *thr; 133386be94fcSTycho Nightingale 133486be94fcSTycho Nightingale FOREACH_THREAD_IN_PROC(td->td_proc, thr) { 133586be94fcSTycho Nightingale if (thr == td) 133686be94fcSTycho Nightingale thr->td_si = *si; 133786be94fcSTycho Nightingale else 133886be94fcSTycho Nightingale thr->td_si.si_signo = 0; 133986be94fcSTycho Nightingale } 134086be94fcSTycho Nightingale } 134186be94fcSTycho Nightingale 1342c6511aeaSDavid Xu int 13439104847fSDavid Xu kern_sigtimedwait(struct thread *td, sigset_t waitset, ksiginfo_t *ksi, 1344a447cd8bSJeff Roberson struct timespec *timeout) 1345a447cd8bSJeff Roberson { 13463074d1b4SDavid Xu struct sigacts *ps; 1347407af02bSDavid Xu sigset_t saved_mask, new_block; 1348a447cd8bSJeff Roberson struct proc *p; 13494a700f3cSDmitry Chagin int error, sig, timevalid = 0; 13504a700f3cSDmitry Chagin sbintime_t sbt, precision, tsbt; 13514a700f3cSDmitry Chagin struct timespec ts; 1352ef401a85SKonstantin Belousov bool traced; 1353a447cd8bSJeff Roberson 1354a447cd8bSJeff Roberson p = td->td_proc; 1355a447cd8bSJeff Roberson error = 0; 1356ef401a85SKonstantin Belousov traced = false; 1357a447cd8bSJeff Roberson 1358dbec10e0SJonathan T. Looney /* Ensure the sigfastblock value is up to date. */ 1359dbec10e0SJonathan T. Looney sigfastblock_fetch(td); 1360dbec10e0SJonathan T. Looney 1361407af02bSDavid Xu if (timeout != NULL) { 13621089f031SDavid Xu if (timeout->tv_nsec >= 0 && timeout->tv_nsec < 1000000000) { 13631089f031SDavid Xu timevalid = 1; 13644a700f3cSDmitry Chagin ts = *timeout; 13654a700f3cSDmitry Chagin if (ts.tv_sec < INT32_MAX / 2) { 13664a700f3cSDmitry Chagin tsbt = tstosbt(ts); 13674a700f3cSDmitry Chagin precision = tsbt; 13684a700f3cSDmitry Chagin precision >>= tc_precexp; 13694a700f3cSDmitry Chagin if (TIMESEL(&sbt, tsbt)) 13704a700f3cSDmitry Chagin sbt += tc_tick_sbt; 13714a700f3cSDmitry Chagin sbt += tsbt; 13724a700f3cSDmitry Chagin } else 13734a700f3cSDmitry Chagin precision = sbt = 0; 13741089f031SDavid Xu } 13754a700f3cSDmitry Chagin } else 13764a700f3cSDmitry Chagin precision = sbt = 0; 1377407af02bSDavid Xu ksiginfo_init(ksi); 1378407af02bSDavid Xu /* Some signals can not be waited for. */ 1379407af02bSDavid Xu SIG_CANTMASK(waitset); 1380407af02bSDavid Xu ps = p->p_sigacts; 1381407af02bSDavid Xu PROC_LOCK(p); 1382407af02bSDavid Xu saved_mask = td->td_sigmask; 1383407af02bSDavid Xu SIGSETNAND(td->td_sigmask, waitset); 1384bc387624SKonstantin Belousov if ((p->p_sysent->sv_flags & SV_SIG_DISCIGN) != 0 || 1385b599982bSKonstantin Belousov !kern_sig_discard_ign) { 1386b599982bSKonstantin Belousov thread_lock(td); 1387b599982bSKonstantin Belousov td->td_flags |= TDF_SIGWAIT; 1388b599982bSKonstantin Belousov thread_unlock(td); 1389b599982bSKonstantin Belousov } 1390407af02bSDavid Xu for (;;) { 13913074d1b4SDavid Xu mtx_lock(&ps->ps_mtx); 13923cf3b9f0SJohn Baldwin sig = cursig(td); 13933074d1b4SDavid Xu mtx_unlock(&ps->ps_mtx); 139446e47c4fSKonstantin Belousov KASSERT(sig >= 0, ("sig %d", sig)); 1395407af02bSDavid Xu if (sig != 0 && SIGISMEMBER(waitset, sig)) { 1396407af02bSDavid Xu if (sigqueue_get(&td->td_sigqueue, sig, ksi) != 0 || 1397407af02bSDavid Xu sigqueue_get(&p->p_sigqueue, sig, ksi) != 0) { 1398407af02bSDavid Xu error = 0; 1399407af02bSDavid Xu break; 14003074d1b4SDavid Xu } 14017e0221a2SDavid Xu } 14027e0221a2SDavid Xu 1403407af02bSDavid Xu if (error != 0) 1404407af02bSDavid Xu break; 14053074d1b4SDavid Xu 1406a447cd8bSJeff Roberson /* 1407a447cd8bSJeff Roberson * POSIX says this must be checked after looking for pending 1408a447cd8bSJeff Roberson * signals. 1409a447cd8bSJeff Roberson */ 14104a700f3cSDmitry Chagin if (timeout != NULL && !timevalid) { 1411a447cd8bSJeff Roberson error = EINVAL; 1412407af02bSDavid Xu break; 1413a447cd8bSJeff Roberson } 1414a447cd8bSJeff Roberson 1415ef401a85SKonstantin Belousov if (traced) { 1416ef401a85SKonstantin Belousov error = EINTR; 1417ef401a85SKonstantin Belousov break; 1418ef401a85SKonstantin Belousov } 1419ef401a85SKonstantin Belousov 14204a700f3cSDmitry Chagin error = msleep_sbt(&p->p_sigacts, &p->p_mtx, PPAUSE | PCATCH, 14214a700f3cSDmitry Chagin "sigwait", sbt, precision, C_ABSOLUTE); 1422407af02bSDavid Xu 1423afb36e28SKonstantin Belousov /* The syscalls can not be restarted. */ 1424afb36e28SKonstantin Belousov if (error == ERESTART) 14253074d1b4SDavid Xu error = EINTR; 1426afb36e28SKonstantin Belousov 1427ef401a85SKonstantin Belousov /* 1428ef401a85SKonstantin Belousov * If PTRACE_SCE or PTRACE_SCX were set after 1429ef401a85SKonstantin Belousov * userspace entered the syscall, return spurious 1430ef401a85SKonstantin Belousov * EINTR after wait was done. Only do this as last 1431ef401a85SKonstantin Belousov * resort after rechecking for possible queued signals 1432ef401a85SKonstantin Belousov * and expired timeouts. 1433ef401a85SKonstantin Belousov */ 1434ef401a85SKonstantin Belousov if (error == 0 && (p->p_ptevents & PTRACE_SYSCALL) != 0) 1435ef401a85SKonstantin Belousov traced = true; 1436407af02bSDavid Xu } 1437b599982bSKonstantin Belousov thread_lock(td); 1438b599982bSKonstantin Belousov td->td_flags &= ~TDF_SIGWAIT; 1439b599982bSKonstantin Belousov thread_unlock(td); 14409dde3bc9SDavid Xu 1441407af02bSDavid Xu new_block = saved_mask; 1442407af02bSDavid Xu SIGSETNAND(new_block, td->td_sigmask); 1443407af02bSDavid Xu td->td_sigmask = saved_mask; 1444407af02bSDavid Xu /* 1445407af02bSDavid Xu * Fewer signals can be delivered to us, reschedule signal 1446407af02bSDavid Xu * notification. 1447407af02bSDavid Xu */ 1448407af02bSDavid Xu if (p->p_numthreads != 1) 1449407af02bSDavid Xu reschedule_signals(p, new_block, 0); 14505d217f17SJohn Birrell 1451407af02bSDavid Xu if (error == 0) { 145236160958SMark Johnston SDT_PROBE2(proc, , , signal__clear, sig, ksi); 14535d217f17SJohn Birrell 145456c06c4bSDavid Xu if (ksi->ksi_code == SI_TIMER) 145556c06c4bSDavid Xu itimer_accept(p, ksi->ksi_timerid, ksi); 14567e0221a2SDavid Xu 14577e0221a2SDavid Xu #ifdef KTRACE 14587e0221a2SDavid Xu if (KTRPOINT(td, KTR_PSIG)) { 14597e0221a2SDavid Xu sig_t action; 14607e0221a2SDavid Xu 14613074d1b4SDavid Xu mtx_lock(&ps->ps_mtx); 1462a447cd8bSJeff Roberson action = ps->ps_sigact[_SIG_IDX(sig)]; 146390af4afaSJohn Baldwin mtx_unlock(&ps->ps_mtx); 146461009552SJilles Tjoelker ktrpsig(sig, action, &td->td_sigmask, ksi->ksi_code); 14657e0221a2SDavid Xu } 1466a447cd8bSJeff Roberson #endif 146786be94fcSTycho Nightingale if (sig == SIGKILL) { 146886be94fcSTycho Nightingale proc_td_siginfo_capture(td, &ksi->ksi_info); 1469aaa92413SKonstantin Belousov sigexit(td, sig); 14703074d1b4SDavid Xu } 147186be94fcSTycho Nightingale } 1472a447cd8bSJeff Roberson PROC_UNLOCK(p); 1473a447cd8bSJeff Roberson return (error); 1474a447cd8bSJeff Roberson } 1475a447cd8bSJeff Roberson 14769104847fSDavid Xu #ifndef _SYS_SYSPROTO_H_ 14779104847fSDavid Xu struct sigpending_args { 14789104847fSDavid Xu sigset_t *set; 14799104847fSDavid Xu }; 14809104847fSDavid Xu #endif 1481a447cd8bSJeff Roberson int 1482e052a8b9SEd Maste sys_sigpending(struct thread *td, struct sigpending_args *uap) 1483df8bae1dSRodney W. Grimes { 1484b40ce416SJulian Elischer struct proc *p = td->td_proc; 14859104847fSDavid Xu sigset_t pending; 1486df8bae1dSRodney W. Grimes 1487628d2653SJohn Baldwin PROC_LOCK(p); 14889104847fSDavid Xu pending = p->p_sigqueue.sq_signals; 14899104847fSDavid Xu SIGSETOR(pending, td->td_sigqueue.sq_signals); 1490628d2653SJohn Baldwin PROC_UNLOCK(p); 14919104847fSDavid Xu return (copyout(&pending, uap->set, sizeof(sigset_t))); 14922c42a146SMarcel Moolenaar } 14932c42a146SMarcel Moolenaar 149431c8f3f0SMarcel Moolenaar #ifdef COMPAT_43 /* XXX - COMPAT_FBSD3 */ 14952c42a146SMarcel Moolenaar #ifndef _SYS_SYSPROTO_H_ 14962c42a146SMarcel Moolenaar struct osigpending_args { 14972c42a146SMarcel Moolenaar int dummy; 14982c42a146SMarcel Moolenaar }; 14992c42a146SMarcel Moolenaar #endif 15002c42a146SMarcel Moolenaar int 1501e052a8b9SEd Maste osigpending(struct thread *td, struct osigpending_args *uap) 15022c42a146SMarcel Moolenaar { 1503b40ce416SJulian Elischer struct proc *p = td->td_proc; 15049104847fSDavid Xu sigset_t pending; 1505b40ce416SJulian Elischer 1506628d2653SJohn Baldwin PROC_LOCK(p); 15079104847fSDavid Xu pending = p->p_sigqueue.sq_signals; 15089104847fSDavid Xu SIGSETOR(pending, td->td_sigqueue.sq_signals); 1509628d2653SJohn Baldwin PROC_UNLOCK(p); 15109104847fSDavid Xu SIG2OSIG(pending, td->td_retval[0]); 1511df8bae1dSRodney W. Grimes return (0); 1512df8bae1dSRodney W. Grimes } 151331c8f3f0SMarcel Moolenaar #endif /* COMPAT_43 */ 1514df8bae1dSRodney W. Grimes 15151930e303SPoul-Henning Kamp #if defined(COMPAT_43) 1516df8bae1dSRodney W. Grimes /* 1517df8bae1dSRodney W. Grimes * Generalized interface signal handler, 4.3-compatible. 1518df8bae1dSRodney W. Grimes */ 1519d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1520df8bae1dSRodney W. Grimes struct osigvec_args { 1521df8bae1dSRodney W. Grimes int signum; 1522df8bae1dSRodney W. Grimes struct sigvec *nsv; 1523df8bae1dSRodney W. Grimes struct sigvec *osv; 1524df8bae1dSRodney W. Grimes }; 1525d2d3e875SBruce Evans #endif 1526df8bae1dSRodney W. Grimes /* ARGSUSED */ 152726f9a767SRodney W. Grimes int 1528e052a8b9SEd Maste osigvec(struct thread *td, struct osigvec_args *uap) 1529df8bae1dSRodney W. Grimes { 1530df8bae1dSRodney W. Grimes struct sigvec vec; 15312c42a146SMarcel Moolenaar struct sigaction nsa, osa; 1532e052a8b9SEd Maste struct sigaction *nsap, *osap; 15332c42a146SMarcel Moolenaar int error; 1534df8bae1dSRodney W. Grimes 15356f841fb7SMarcel Moolenaar if (uap->signum <= 0 || uap->signum >= ONSIG) 15366f841fb7SMarcel Moolenaar return (EINVAL); 15376f841fb7SMarcel Moolenaar nsap = (uap->nsv != NULL) ? &nsa : NULL; 15386f841fb7SMarcel Moolenaar osap = (uap->osv != NULL) ? &osa : NULL; 15392c42a146SMarcel Moolenaar if (nsap) { 15406f841fb7SMarcel Moolenaar error = copyin(uap->nsv, &vec, sizeof(vec)); 15412c42a146SMarcel Moolenaar if (error) 1542df8bae1dSRodney W. Grimes return (error); 15432c42a146SMarcel Moolenaar nsap->sa_handler = vec.sv_handler; 15442c42a146SMarcel Moolenaar OSIG2SIG(vec.sv_mask, nsap->sa_mask); 15452c42a146SMarcel Moolenaar nsap->sa_flags = vec.sv_flags; 15462c42a146SMarcel Moolenaar nsap->sa_flags ^= SA_RESTART; /* opposite of SV_INTERRUPT */ 1547df8bae1dSRodney W. Grimes } 15485edadff9SJohn Baldwin error = kern_sigaction(td, uap->signum, nsap, osap, KSA_OSIGSET); 15492c42a146SMarcel Moolenaar if (osap && !error) { 15502c42a146SMarcel Moolenaar vec.sv_handler = osap->sa_handler; 15512c42a146SMarcel Moolenaar SIG2OSIG(osap->sa_mask, vec.sv_mask); 15522c42a146SMarcel Moolenaar vec.sv_flags = osap->sa_flags; 15532c42a146SMarcel Moolenaar vec.sv_flags &= ~SA_NOCLDWAIT; 15542c42a146SMarcel Moolenaar vec.sv_flags ^= SA_RESTART; 15556f841fb7SMarcel Moolenaar error = copyout(&vec, uap->osv, sizeof(vec)); 15562c42a146SMarcel Moolenaar } 15572c42a146SMarcel Moolenaar return (error); 1558df8bae1dSRodney W. Grimes } 1559df8bae1dSRodney W. Grimes 1560d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1561df8bae1dSRodney W. Grimes struct osigblock_args { 1562df8bae1dSRodney W. Grimes int mask; 1563df8bae1dSRodney W. Grimes }; 1564d2d3e875SBruce Evans #endif 156526f9a767SRodney W. Grimes int 1566e052a8b9SEd Maste osigblock(struct thread *td, struct osigblock_args *uap) 1567df8bae1dSRodney W. Grimes { 1568d6e029adSKonstantin Belousov sigset_t set, oset; 1569df8bae1dSRodney W. Grimes 15702c42a146SMarcel Moolenaar OSIG2SIG(uap->mask, set); 1571d6e029adSKonstantin Belousov kern_sigprocmask(td, SIG_BLOCK, &set, &oset, 0); 1572d6e029adSKonstantin Belousov SIG2OSIG(oset, td->td_retval[0]); 1573df8bae1dSRodney W. Grimes return (0); 1574df8bae1dSRodney W. Grimes } 1575df8bae1dSRodney W. Grimes 1576d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1577df8bae1dSRodney W. Grimes struct osigsetmask_args { 1578df8bae1dSRodney W. Grimes int mask; 1579df8bae1dSRodney W. Grimes }; 1580d2d3e875SBruce Evans #endif 158126f9a767SRodney W. Grimes int 1582e052a8b9SEd Maste osigsetmask(struct thread *td, struct osigsetmask_args *uap) 1583df8bae1dSRodney W. Grimes { 1584d6e029adSKonstantin Belousov sigset_t set, oset; 1585df8bae1dSRodney W. Grimes 15862c42a146SMarcel Moolenaar OSIG2SIG(uap->mask, set); 1587d6e029adSKonstantin Belousov kern_sigprocmask(td, SIG_SETMASK, &set, &oset, 0); 1588d6e029adSKonstantin Belousov SIG2OSIG(oset, td->td_retval[0]); 1589df8bae1dSRodney W. Grimes return (0); 1590df8bae1dSRodney W. Grimes } 15911930e303SPoul-Henning Kamp #endif /* COMPAT_43 */ 1592df8bae1dSRodney W. Grimes 1593df8bae1dSRodney W. Grimes /* 1594873fbcd7SRobert Watson * Suspend calling thread until signal, providing mask to be set in the 1595873fbcd7SRobert Watson * meantime. 1596df8bae1dSRodney W. Grimes */ 1597d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1598df8bae1dSRodney W. Grimes struct sigsuspend_args { 15992c42a146SMarcel Moolenaar const sigset_t *sigmask; 1600df8bae1dSRodney W. Grimes }; 1601d2d3e875SBruce Evans #endif 1602df8bae1dSRodney W. Grimes /* ARGSUSED */ 160326f9a767SRodney W. Grimes int 1604e052a8b9SEd Maste sys_sigsuspend(struct thread *td, struct sigsuspend_args *uap) 1605df8bae1dSRodney W. Grimes { 16062c42a146SMarcel Moolenaar sigset_t mask; 16072c42a146SMarcel Moolenaar int error; 16082c42a146SMarcel Moolenaar 16096f841fb7SMarcel Moolenaar error = copyin(uap->sigmask, &mask, sizeof(mask)); 16102c42a146SMarcel Moolenaar if (error) 16112c42a146SMarcel Moolenaar return (error); 16128f19eb88SIan Dowse return (kern_sigsuspend(td, mask)); 16138f19eb88SIan Dowse } 16148f19eb88SIan Dowse 16158f19eb88SIan Dowse int 16168f19eb88SIan Dowse kern_sigsuspend(struct thread *td, sigset_t mask) 16178f19eb88SIan Dowse { 16188f19eb88SIan Dowse struct proc *p = td->td_proc; 161984440afbSKonstantin Belousov int has_sig, sig; 1620df8bae1dSRodney W. Grimes 1621dbec10e0SJonathan T. Looney /* Ensure the sigfastblock value is up to date. */ 1622dbec10e0SJonathan T. Looney sigfastblock_fetch(td); 1623dbec10e0SJonathan T. Looney 1624df8bae1dSRodney W. Grimes /* 1625645682fdSLuoqi Chen * When returning from sigsuspend, we want 1626df8bae1dSRodney W. Grimes * the old mask to be restored after the 1627df8bae1dSRodney W. Grimes * signal handler has finished. Thus, we 1628df8bae1dSRodney W. Grimes * save it here and mark the sigacts structure 1629df8bae1dSRodney W. Grimes * to indicate this. 1630df8bae1dSRodney W. Grimes */ 1631628d2653SJohn Baldwin PROC_LOCK(p); 163284440afbSKonstantin Belousov kern_sigprocmask(td, SIG_SETMASK, &mask, &td->td_oldsigmask, 163384440afbSKonstantin Belousov SIGPROCMASK_PROC_LOCKED); 16345e26dcb5SJohn Baldwin td->td_pflags |= TDP_OLDMASK; 1635c6d31b83SKonstantin Belousov ast_sched(td, TDA_SIGSUSPEND); 163684440afbSKonstantin Belousov 163784440afbSKonstantin Belousov /* 163884440afbSKonstantin Belousov * Process signals now. Otherwise, we can get spurious wakeup 163984440afbSKonstantin Belousov * due to signal entered process queue, but delivered to other 164084440afbSKonstantin Belousov * thread. But sigsuspend should return only on signal 164184440afbSKonstantin Belousov * delivery. 164284440afbSKonstantin Belousov */ 1643afe1a688SKonstantin Belousov (p->p_sysent->sv_set_syscall_retval)(td, EINTR); 164484440afbSKonstantin Belousov for (has_sig = 0; !has_sig;) { 164584440afbSKonstantin Belousov while (msleep(&p->p_sigacts, &p->p_mtx, PPAUSE|PCATCH, "pause", 164684440afbSKonstantin Belousov 0) == 0) 16472c42a146SMarcel Moolenaar /* void */; 164884440afbSKonstantin Belousov thread_suspend_check(0); 164984440afbSKonstantin Belousov mtx_lock(&p->p_sigacts->ps_mtx); 165046e47c4fSKonstantin Belousov while ((sig = cursig(td)) != 0) { 165146e47c4fSKonstantin Belousov KASSERT(sig >= 0, ("sig %d", sig)); 165275c586a4SKonstantin Belousov has_sig += postsig(sig); 165346e47c4fSKonstantin Belousov } 165484440afbSKonstantin Belousov mtx_unlock(&p->p_sigacts->ps_mtx); 1655ef401a85SKonstantin Belousov 1656ef401a85SKonstantin Belousov /* 1657ef401a85SKonstantin Belousov * If PTRACE_SCE or PTRACE_SCX were set after 1658ef401a85SKonstantin Belousov * userspace entered the syscall, return spurious 1659ef401a85SKonstantin Belousov * EINTR. 1660ef401a85SKonstantin Belousov */ 1661ef401a85SKonstantin Belousov if ((p->p_ptevents & PTRACE_SYSCALL) != 0) 1662ef401a85SKonstantin Belousov has_sig += 1; 166384440afbSKonstantin Belousov } 1664628d2653SJohn Baldwin PROC_UNLOCK(p); 16652dd9ea6fSKonstantin Belousov td->td_errno = EINTR; 16662dd9ea6fSKonstantin Belousov td->td_pflags |= TDP_NERRNO; 166775c586a4SKonstantin Belousov return (EJUSTRETURN); 16682c42a146SMarcel Moolenaar } 16692c42a146SMarcel Moolenaar 167031c8f3f0SMarcel Moolenaar #ifdef COMPAT_43 /* XXX - COMPAT_FBSD3 */ 167197563428SAlexander Kabaev /* 167297563428SAlexander Kabaev * Compatibility sigsuspend call for old binaries. Note nonstandard calling 167397563428SAlexander Kabaev * convention: libc stub passes mask, not pointer, to save a copyin. 167497563428SAlexander Kabaev */ 16752c42a146SMarcel Moolenaar #ifndef _SYS_SYSPROTO_H_ 16762c42a146SMarcel Moolenaar struct osigsuspend_args { 16772c42a146SMarcel Moolenaar osigset_t mask; 16782c42a146SMarcel Moolenaar }; 16792c42a146SMarcel Moolenaar #endif 16802c42a146SMarcel Moolenaar /* ARGSUSED */ 16812c42a146SMarcel Moolenaar int 1682e052a8b9SEd Maste osigsuspend(struct thread *td, struct osigsuspend_args *uap) 16832c42a146SMarcel Moolenaar { 1684645682fdSLuoqi Chen sigset_t mask; 16852c42a146SMarcel Moolenaar 1686645682fdSLuoqi Chen OSIG2SIG(uap->mask, mask); 168784440afbSKonstantin Belousov return (kern_sigsuspend(td, mask)); 1688df8bae1dSRodney W. Grimes } 168931c8f3f0SMarcel Moolenaar #endif /* COMPAT_43 */ 1690df8bae1dSRodney W. Grimes 16911930e303SPoul-Henning Kamp #if defined(COMPAT_43) 1692d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1693df8bae1dSRodney W. Grimes struct osigstack_args { 1694df8bae1dSRodney W. Grimes struct sigstack *nss; 1695df8bae1dSRodney W. Grimes struct sigstack *oss; 1696df8bae1dSRodney W. Grimes }; 1697d2d3e875SBruce Evans #endif 1698df8bae1dSRodney W. Grimes /* ARGSUSED */ 169926f9a767SRodney W. Grimes int 1700e052a8b9SEd Maste osigstack(struct thread *td, struct osigstack_args *uap) 1701df8bae1dSRodney W. Grimes { 17025afe0c99SJohn Baldwin struct sigstack nss, oss; 1703fb99ab88SMatthew Dillon int error = 0; 1704fb99ab88SMatthew Dillon 1705d034d459SMarcel Moolenaar if (uap->nss != NULL) { 17065afe0c99SJohn Baldwin error = copyin(uap->nss, &nss, sizeof(nss)); 17075afe0c99SJohn Baldwin if (error) 17085afe0c99SJohn Baldwin return (error); 1709df8bae1dSRodney W. Grimes } 1710a30ec4b9SDavid Xu oss.ss_sp = td->td_sigstk.ss_sp; 17115afe0c99SJohn Baldwin oss.ss_onstack = sigonstack(cpu_getstack(td)); 17125afe0c99SJohn Baldwin if (uap->nss != NULL) { 1713a30ec4b9SDavid Xu td->td_sigstk.ss_sp = nss.ss_sp; 1714a30ec4b9SDavid Xu td->td_sigstk.ss_size = 0; 1715a30ec4b9SDavid Xu td->td_sigstk.ss_flags |= nss.ss_onstack & SS_ONSTACK; 1716a30ec4b9SDavid Xu td->td_pflags |= TDP_ALTSTACK; 17175afe0c99SJohn Baldwin } 17185afe0c99SJohn Baldwin if (uap->oss != NULL) 17195afe0c99SJohn Baldwin error = copyout(&oss, uap->oss, sizeof(oss)); 17205afe0c99SJohn Baldwin 1721fb99ab88SMatthew Dillon return (error); 1722df8bae1dSRodney W. Grimes } 17231930e303SPoul-Henning Kamp #endif /* COMPAT_43 */ 1724df8bae1dSRodney W. Grimes 1725d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1726df8bae1dSRodney W. Grimes struct sigaltstack_args { 17272c42a146SMarcel Moolenaar stack_t *ss; 17282c42a146SMarcel Moolenaar stack_t *oss; 1729df8bae1dSRodney W. Grimes }; 1730d2d3e875SBruce Evans #endif 1731df8bae1dSRodney W. Grimes /* ARGSUSED */ 173226f9a767SRodney W. Grimes int 1733e052a8b9SEd Maste sys_sigaltstack(struct thread *td, struct sigaltstack_args *uap) 1734df8bae1dSRodney W. Grimes { 17358f19eb88SIan Dowse stack_t ss, oss; 17368f19eb88SIan Dowse int error; 17378f19eb88SIan Dowse 17388f19eb88SIan Dowse if (uap->ss != NULL) { 17398f19eb88SIan Dowse error = copyin(uap->ss, &ss, sizeof(ss)); 17408f19eb88SIan Dowse if (error) 17418f19eb88SIan Dowse return (error); 17428f19eb88SIan Dowse } 17438f19eb88SIan Dowse error = kern_sigaltstack(td, (uap->ss != NULL) ? &ss : NULL, 17448f19eb88SIan Dowse (uap->oss != NULL) ? &oss : NULL); 17458f19eb88SIan Dowse if (error) 17468f19eb88SIan Dowse return (error); 17478f19eb88SIan Dowse if (uap->oss != NULL) 17488f19eb88SIan Dowse error = copyout(&oss, uap->oss, sizeof(stack_t)); 17498f19eb88SIan Dowse return (error); 17508f19eb88SIan Dowse } 17518f19eb88SIan Dowse 17528f19eb88SIan Dowse int 17538f19eb88SIan Dowse kern_sigaltstack(struct thread *td, stack_t *ss, stack_t *oss) 17548f19eb88SIan Dowse { 1755b40ce416SJulian Elischer struct proc *p = td->td_proc; 1756fb99ab88SMatthew Dillon int oonstack; 1757fb99ab88SMatthew Dillon 1758b40ce416SJulian Elischer oonstack = sigonstack(cpu_getstack(td)); 1759d034d459SMarcel Moolenaar 17608f19eb88SIan Dowse if (oss != NULL) { 1761a30ec4b9SDavid Xu *oss = td->td_sigstk; 1762a30ec4b9SDavid Xu oss->ss_flags = (td->td_pflags & TDP_ALTSTACK) 1763d034d459SMarcel Moolenaar ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE; 1764df8bae1dSRodney W. Grimes } 1765d034d459SMarcel Moolenaar 17668f19eb88SIan Dowse if (ss != NULL) { 1767a30ec4b9SDavid Xu if (oonstack) 1768cf60731bSJohn Baldwin return (EPERM); 1769a30ec4b9SDavid Xu if ((ss->ss_flags & ~SS_DISABLE) != 0) 1770cf60731bSJohn Baldwin return (EINVAL); 17718f19eb88SIan Dowse if (!(ss->ss_flags & SS_DISABLE)) { 17729104847fSDavid Xu if (ss->ss_size < p->p_sysent->sv_minsigstksz) 1773cf60731bSJohn Baldwin return (ENOMEM); 17749104847fSDavid Xu 1775a30ec4b9SDavid Xu td->td_sigstk = *ss; 1776a30ec4b9SDavid Xu td->td_pflags |= TDP_ALTSTACK; 1777628d2653SJohn Baldwin } else { 1778a30ec4b9SDavid Xu td->td_pflags &= ~TDP_ALTSTACK; 1779628d2653SJohn Baldwin } 1780d034d459SMarcel Moolenaar } 1781cf60731bSJohn Baldwin return (0); 1782df8bae1dSRodney W. Grimes } 1783df8bae1dSRodney W. Grimes 17840cc9fb75SKonstantin Belousov struct killpg1_ctx { 17850cc9fb75SKonstantin Belousov struct thread *td; 17860cc9fb75SKonstantin Belousov ksiginfo_t *ksi; 17870cc9fb75SKonstantin Belousov int sig; 17880cc9fb75SKonstantin Belousov bool sent; 17890cc9fb75SKonstantin Belousov bool found; 17900cc9fb75SKonstantin Belousov int ret; 17910cc9fb75SKonstantin Belousov }; 17920cc9fb75SKonstantin Belousov 17930cc9fb75SKonstantin Belousov static void 179469413598SMateusz Guzik killpg1_sendsig_locked(struct proc *p, struct killpg1_ctx *arg) 17950cc9fb75SKonstantin Belousov { 17960cc9fb75SKonstantin Belousov int err; 17970cc9fb75SKonstantin Belousov 17980cc9fb75SKonstantin Belousov err = p_cansignal(arg->td, p, arg->sig); 17990cc9fb75SKonstantin Belousov if (err == 0 && arg->sig != 0) 18000cc9fb75SKonstantin Belousov pksignal(p, arg->sig, arg->ksi); 18010cc9fb75SKonstantin Belousov if (err != ESRCH) 18020cc9fb75SKonstantin Belousov arg->found = true; 18030cc9fb75SKonstantin Belousov if (err == 0) 18040cc9fb75SKonstantin Belousov arg->sent = true; 18050cc9fb75SKonstantin Belousov else if (arg->ret == 0 && err != ESRCH && err != EPERM) 18060cc9fb75SKonstantin Belousov arg->ret = err; 18070cc9fb75SKonstantin Belousov } 18080cc9fb75SKonstantin Belousov 180969413598SMateusz Guzik static void 181069413598SMateusz Guzik killpg1_sendsig(struct proc *p, bool notself, struct killpg1_ctx *arg) 181169413598SMateusz Guzik { 181269413598SMateusz Guzik 181369413598SMateusz Guzik if (p->p_pid <= 1 || (p->p_flag & P_SYSTEM) != 0 || 181469413598SMateusz Guzik (notself && p == arg->td->td_proc) || p->p_state == PRS_NEW) 181569413598SMateusz Guzik return; 181669413598SMateusz Guzik 181769413598SMateusz Guzik PROC_LOCK(p); 181869413598SMateusz Guzik killpg1_sendsig_locked(p, arg); 181969413598SMateusz Guzik PROC_UNLOCK(p); 182069413598SMateusz Guzik } 182169413598SMateusz Guzik 182269413598SMateusz Guzik static void 182369413598SMateusz Guzik kill_processes_prison_cb(struct proc *p, void *arg) 182469413598SMateusz Guzik { 182569413598SMateusz Guzik struct killpg1_ctx *ctx = arg; 182669413598SMateusz Guzik 182769413598SMateusz Guzik if (p->p_pid <= 1 || (p->p_flag & P_SYSTEM) != 0 || 182869413598SMateusz Guzik (p == ctx->td->td_proc) || p->p_state == PRS_NEW) 182969413598SMateusz Guzik return; 183069413598SMateusz Guzik 183169413598SMateusz Guzik killpg1_sendsig_locked(p, ctx); 183269413598SMateusz Guzik } 183369413598SMateusz Guzik 1834d93f860cSPoul-Henning Kamp /* 1835d93f860cSPoul-Henning Kamp * Common code for kill process group/broadcast kill. 18364b59d172SKonstantin Belousov * td is the calling thread, as usual. 1837d93f860cSPoul-Henning Kamp */ 183837c84183SPoul-Henning Kamp static int 1839a3de221dSKonstantin Belousov killpg1(struct thread *td, int sig, int pgid, int all, ksiginfo_t *ksi) 1840d93f860cSPoul-Henning Kamp { 1841a3de221dSKonstantin Belousov struct proc *p; 1842d93f860cSPoul-Henning Kamp struct pgrp *pgrp; 18430cc9fb75SKonstantin Belousov struct killpg1_ctx arg; 1844d93f860cSPoul-Henning Kamp 18450cc9fb75SKonstantin Belousov arg.td = td; 18460cc9fb75SKonstantin Belousov arg.ksi = ksi; 18470cc9fb75SKonstantin Belousov arg.sig = sig; 18480cc9fb75SKonstantin Belousov arg.sent = false; 18490cc9fb75SKonstantin Belousov arg.found = false; 18500cc9fb75SKonstantin Belousov arg.ret = 0; 1851553629ebSJake Burkholder if (all) { 1852d93f860cSPoul-Henning Kamp /* 1853d93f860cSPoul-Henning Kamp * broadcast 1854d93f860cSPoul-Henning Kamp */ 185569413598SMateusz Guzik prison_proc_iterate(td->td_ucred->cr_prison, 185669413598SMateusz Guzik kill_processes_prison_cb, &arg); 1857553629ebSJake Burkholder } else { 18583360b485SKonstantin Belousov again: 1859ba626c1dSJohn Baldwin sx_slock(&proctree_lock); 1860f591779bSSeigo Tanimura if (pgid == 0) { 1861d93f860cSPoul-Henning Kamp /* 1862d93f860cSPoul-Henning Kamp * zero pgid means send to my process group. 1863d93f860cSPoul-Henning Kamp */ 18649c1ab3e0SJohn Baldwin pgrp = td->td_proc->p_pgrp; 1865f591779bSSeigo Tanimura PGRP_LOCK(pgrp); 1866f591779bSSeigo Tanimura } else { 1867d93f860cSPoul-Henning Kamp pgrp = pgfind(pgid); 1868f591779bSSeigo Tanimura if (pgrp == NULL) { 1869ba626c1dSJohn Baldwin sx_sunlock(&proctree_lock); 1870d93f860cSPoul-Henning Kamp return (ESRCH); 1871d93f860cSPoul-Henning Kamp } 1872f591779bSSeigo Tanimura } 1873ba626c1dSJohn Baldwin sx_sunlock(&proctree_lock); 18743360b485SKonstantin Belousov if (!sx_try_xlock(&pgrp->pg_killsx)) { 18753360b485SKonstantin Belousov PGRP_UNLOCK(pgrp); 18763360b485SKonstantin Belousov sx_xlock(&pgrp->pg_killsx); 18773360b485SKonstantin Belousov sx_xunlock(&pgrp->pg_killsx); 18783360b485SKonstantin Belousov goto again; 18793360b485SKonstantin Belousov } 18802e3c8fcbSPoul-Henning Kamp LIST_FOREACH(p, &pgrp->pg_members, p_pglist) { 18810cc9fb75SKonstantin Belousov killpg1_sendsig(p, false, &arg); 1882d93f860cSPoul-Henning Kamp } 1883f591779bSSeigo Tanimura PGRP_UNLOCK(pgrp); 18843360b485SKonstantin Belousov sx_xunlock(&pgrp->pg_killsx); 1885d93f860cSPoul-Henning Kamp } 18860cc9fb75SKonstantin Belousov MPASS(arg.ret != 0 || arg.found || !arg.sent); 18870cc9fb75SKonstantin Belousov if (arg.ret == 0 && !arg.sent) 18880cc9fb75SKonstantin Belousov arg.ret = arg.found ? EPERM : ESRCH; 18890cc9fb75SKonstantin Belousov return (arg.ret); 1890d93f860cSPoul-Henning Kamp } 1891d93f860cSPoul-Henning Kamp 1892d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1893df8bae1dSRodney W. Grimes struct kill_args { 1894df8bae1dSRodney W. Grimes int pid; 1895df8bae1dSRodney W. Grimes int signum; 1896df8bae1dSRodney W. Grimes }; 1897d2d3e875SBruce Evans #endif 1898df8bae1dSRodney W. Grimes /* ARGSUSED */ 189926f9a767SRodney W. Grimes int 19008451d0ddSKip Macy sys_kill(struct thread *td, struct kill_args *uap) 1901df8bae1dSRodney W. Grimes { 190234ad5ac2SEdward Tomasz Napierala 190334ad5ac2SEdward Tomasz Napierala return (kern_kill(td, uap->pid, uap->signum)); 190434ad5ac2SEdward Tomasz Napierala } 190534ad5ac2SEdward Tomasz Napierala 190634ad5ac2SEdward Tomasz Napierala int 190734ad5ac2SEdward Tomasz Napierala kern_kill(struct thread *td, pid_t pid, int signum) 190834ad5ac2SEdward Tomasz Napierala { 1909a3de221dSKonstantin Belousov ksiginfo_t ksi; 1910a3de221dSKonstantin Belousov struct proc *p; 191190af4afaSJohn Baldwin int error; 1912df8bae1dSRodney W. Grimes 19138890f5d0SPawel Jakub Dawidek /* 19148890f5d0SPawel Jakub Dawidek * A process in capability mode can send signals only to himself. 19158890f5d0SPawel Jakub Dawidek * The main rationale behind this is that abort(3) is implemented as 19168890f5d0SPawel Jakub Dawidek * kill(getpid(), SIGABRT). 19178890f5d0SPawel Jakub Dawidek */ 19186a4616a5SJake Freeland if (pid != td->td_proc->p_pid) { 19196a4616a5SJake Freeland if (CAP_TRACING(td)) 19206a4616a5SJake Freeland ktrcapfail(CAPFAIL_SIGNAL, &signum); 19216a4616a5SJake Freeland if (IN_CAPABILITY_MODE(td)) 19228890f5d0SPawel Jakub Dawidek return (ECAPMODE); 19236a4616a5SJake Freeland } 19248890f5d0SPawel Jakub Dawidek 192534ad5ac2SEdward Tomasz Napierala AUDIT_ARG_SIGNUM(signum); 192634ad5ac2SEdward Tomasz Napierala AUDIT_ARG_PID(pid); 192734ad5ac2SEdward Tomasz Napierala if ((u_int)signum > _SIG_MAXSIG) 1928df8bae1dSRodney W. Grimes return (EINVAL); 1929fb99ab88SMatthew Dillon 1930a3de221dSKonstantin Belousov ksiginfo_init(&ksi); 193134ad5ac2SEdward Tomasz Napierala ksi.ksi_signo = signum; 1932a3de221dSKonstantin Belousov ksi.ksi_code = SI_USER; 1933a3de221dSKonstantin Belousov ksi.ksi_pid = td->td_proc->p_pid; 1934a3de221dSKonstantin Belousov ksi.ksi_uid = td->td_ucred->cr_ruid; 1935a3de221dSKonstantin Belousov 193634ad5ac2SEdward Tomasz Napierala if (pid > 0) { 1937df8bae1dSRodney W. Grimes /* kill single process */ 193834ad5ac2SEdward Tomasz Napierala if ((p = pfind_any(pid)) == NULL) 193990af4afaSJohn Baldwin return (ESRCH); 194014961ba7SRobert Watson AUDIT_ARG_PROCESS(p); 194134ad5ac2SEdward Tomasz Napierala error = p_cansignal(td, p, signum); 194234ad5ac2SEdward Tomasz Napierala if (error == 0 && signum) 194334ad5ac2SEdward Tomasz Napierala pksignal(p, signum, &ksi); 1944628d2653SJohn Baldwin PROC_UNLOCK(p); 194590af4afaSJohn Baldwin return (error); 1946df8bae1dSRodney W. Grimes } 194734ad5ac2SEdward Tomasz Napierala switch (pid) { 1948df8bae1dSRodney W. Grimes case -1: /* broadcast signal */ 194934ad5ac2SEdward Tomasz Napierala return (killpg1(td, signum, 0, 1, &ksi)); 1950df8bae1dSRodney W. Grimes case 0: /* signal own process group */ 195134ad5ac2SEdward Tomasz Napierala return (killpg1(td, signum, 0, 0, &ksi)); 1952df8bae1dSRodney W. Grimes default: /* negative explicit process group */ 195334ad5ac2SEdward Tomasz Napierala return (killpg1(td, signum, -pid, 0, &ksi)); 1954df8bae1dSRodney W. Grimes } 195590af4afaSJohn Baldwin /* NOTREACHED */ 1956df8bae1dSRodney W. Grimes } 1957df8bae1dSRodney W. Grimes 1958cfb5f768SJonathan Anderson int 1959e052a8b9SEd Maste sys_pdkill(struct thread *td, struct pdkill_args *uap) 1960cfb5f768SJonathan Anderson { 1961cfb5f768SJonathan Anderson struct proc *p; 1962cfb5f768SJonathan Anderson int error; 1963cfb5f768SJonathan Anderson 1964cfb5f768SJonathan Anderson AUDIT_ARG_SIGNUM(uap->signum); 1965cfb5f768SJonathan Anderson AUDIT_ARG_FD(uap->fd); 1966cfb5f768SJonathan Anderson if ((u_int)uap->signum > _SIG_MAXSIG) 1967cfb5f768SJonathan Anderson return (EINVAL); 1968cfb5f768SJonathan Anderson 1969cbd92ce6SMatt Macy error = procdesc_find(td, uap->fd, &cap_pdkill_rights, &p); 1970cfb5f768SJonathan Anderson if (error) 1971cfb5f768SJonathan Anderson return (error); 1972cfb5f768SJonathan Anderson AUDIT_ARG_PROCESS(p); 1973cfb5f768SJonathan Anderson error = p_cansignal(td, p, uap->signum); 1974cfb5f768SJonathan Anderson if (error == 0 && uap->signum) 19758451d0ddSKip Macy kern_psignal(p, uap->signum); 1976cfb5f768SJonathan Anderson PROC_UNLOCK(p); 1977cfb5f768SJonathan Anderson return (error); 1978cfb5f768SJonathan Anderson } 1979cfb5f768SJonathan Anderson 19801930e303SPoul-Henning Kamp #if defined(COMPAT_43) 1981d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1982df8bae1dSRodney W. Grimes struct okillpg_args { 1983df8bae1dSRodney W. Grimes int pgid; 1984df8bae1dSRodney W. Grimes int signum; 1985df8bae1dSRodney W. Grimes }; 1986d2d3e875SBruce Evans #endif 1987df8bae1dSRodney W. Grimes /* ARGSUSED */ 198826f9a767SRodney W. Grimes int 1989a3de221dSKonstantin Belousov okillpg(struct thread *td, struct okillpg_args *uap) 1990df8bae1dSRodney W. Grimes { 1991a3de221dSKonstantin Belousov ksiginfo_t ksi; 1992df8bae1dSRodney W. Grimes 199314961ba7SRobert Watson AUDIT_ARG_SIGNUM(uap->signum); 199414961ba7SRobert Watson AUDIT_ARG_PID(uap->pgid); 19956c1534a7SPeter Wemm if ((u_int)uap->signum > _SIG_MAXSIG) 1996df8bae1dSRodney W. Grimes return (EINVAL); 19979104847fSDavid Xu 1998a3de221dSKonstantin Belousov ksiginfo_init(&ksi); 1999a3de221dSKonstantin Belousov ksi.ksi_signo = uap->signum; 2000a3de221dSKonstantin Belousov ksi.ksi_code = SI_USER; 2001a3de221dSKonstantin Belousov ksi.ksi_pid = td->td_proc->p_pid; 2002a3de221dSKonstantin Belousov ksi.ksi_uid = td->td_ucred->cr_ruid; 2003a3de221dSKonstantin Belousov return (killpg1(td, uap->signum, uap->pgid, 0, &ksi)); 2004df8bae1dSRodney W. Grimes } 20051930e303SPoul-Henning Kamp #endif /* COMPAT_43 */ 2006df8bae1dSRodney W. Grimes 20079104847fSDavid Xu #ifndef _SYS_SYSPROTO_H_ 20089104847fSDavid Xu struct sigqueue_args { 20099104847fSDavid Xu pid_t pid; 20109104847fSDavid Xu int signum; 20119104847fSDavid Xu /* union sigval */ void *value; 20129104847fSDavid Xu }; 20139104847fSDavid Xu #endif 20149104847fSDavid Xu int 20158451d0ddSKip Macy sys_sigqueue(struct thread *td, struct sigqueue_args *uap) 20169104847fSDavid Xu { 2017f19351aaSBrooks Davis union sigval sv; 2018f19351aaSBrooks Davis 2019f19351aaSBrooks Davis sv.sival_ptr = uap->value; 2020f19351aaSBrooks Davis 2021f19351aaSBrooks Davis return (kern_sigqueue(td, uap->pid, uap->signum, &sv)); 2022f19351aaSBrooks Davis } 2023f19351aaSBrooks Davis 2024f19351aaSBrooks Davis int 202553186bc1SKonstantin Belousov kern_sigqueue(struct thread *td, pid_t pid, int signumf, union sigval *value) 2026f19351aaSBrooks Davis { 20279104847fSDavid Xu ksiginfo_t ksi; 20289104847fSDavid Xu struct proc *p; 202953186bc1SKonstantin Belousov struct thread *td2; 203053186bc1SKonstantin Belousov u_int signum; 20319104847fSDavid Xu int error; 20329104847fSDavid Xu 203353186bc1SKonstantin Belousov signum = signumf & ~__SIGQUEUE_TID; 203453186bc1SKonstantin Belousov if (signum > _SIG_MAXSIG) 20359104847fSDavid Xu return (EINVAL); 20369104847fSDavid Xu 20379104847fSDavid Xu /* 20389104847fSDavid Xu * Specification says sigqueue can only send signal to 20399104847fSDavid Xu * single process. 20409104847fSDavid Xu */ 2041f19351aaSBrooks Davis if (pid <= 0) 20429104847fSDavid Xu return (EINVAL); 20439104847fSDavid Xu 204453186bc1SKonstantin Belousov if ((signumf & __SIGQUEUE_TID) == 0) { 2045537d0fb1SMateusz Guzik if ((p = pfind_any(pid)) == NULL) 20469104847fSDavid Xu return (ESRCH); 204753186bc1SKonstantin Belousov td2 = NULL; 204853186bc1SKonstantin Belousov } else { 204953186bc1SKonstantin Belousov p = td->td_proc; 205053186bc1SKonstantin Belousov td2 = tdfind((lwpid_t)pid, p->p_pid); 205153186bc1SKonstantin Belousov if (td2 == NULL) 205253186bc1SKonstantin Belousov return (ESRCH); 205353186bc1SKonstantin Belousov } 205453186bc1SKonstantin Belousov 2055f19351aaSBrooks Davis error = p_cansignal(td, p, signum); 2056f19351aaSBrooks Davis if (error == 0 && signum != 0) { 20579104847fSDavid Xu ksiginfo_init(&ksi); 2058a3de221dSKonstantin Belousov ksi.ksi_flags = KSI_SIGQ; 2059f19351aaSBrooks Davis ksi.ksi_signo = signum; 20609104847fSDavid Xu ksi.ksi_code = SI_QUEUE; 20619104847fSDavid Xu ksi.ksi_pid = td->td_proc->p_pid; 20629104847fSDavid Xu ksi.ksi_uid = td->td_ucred->cr_ruid; 2063f19351aaSBrooks Davis ksi.ksi_value = *value; 206453186bc1SKonstantin Belousov error = tdsendsignal(p, td2, ksi.ksi_signo, &ksi); 20659104847fSDavid Xu } 20669104847fSDavid Xu PROC_UNLOCK(p); 20679104847fSDavid Xu return (error); 20689104847fSDavid Xu } 20699104847fSDavid Xu 2070df8bae1dSRodney W. Grimes /* 2071df8bae1dSRodney W. Grimes * Send a signal to a process group. If checktty is 1, 2072df8bae1dSRodney W. Grimes * limit to members which have a controlling terminal. 2073df8bae1dSRodney W. Grimes */ 2074df8bae1dSRodney W. Grimes void 2075a3de221dSKonstantin Belousov pgsignal(struct pgrp *pgrp, int sig, int checkctty, ksiginfo_t *ksi) 2076df8bae1dSRodney W. Grimes { 2077a3de221dSKonstantin Belousov struct proc *p; 2078df8bae1dSRodney W. Grimes 2079628d2653SJohn Baldwin if (pgrp) { 2080f591779bSSeigo Tanimura PGRP_LOCK_ASSERT(pgrp, MA_OWNED); 2081628d2653SJohn Baldwin LIST_FOREACH(p, &pgrp->pg_members, p_pglist) { 2082628d2653SJohn Baldwin PROC_LOCK(p); 2083e806d352SJohn Baldwin if (p->p_state == PRS_NORMAL && 2084e806d352SJohn Baldwin (checkctty == 0 || p->p_flag & P_CONTROLT)) 2085a3de221dSKonstantin Belousov pksignal(p, sig, ksi); 2086628d2653SJohn Baldwin PROC_UNLOCK(p); 2087628d2653SJohn Baldwin } 2088628d2653SJohn Baldwin } 2089df8bae1dSRodney W. Grimes } 2090df8bae1dSRodney W. Grimes 2091e442f29fSKonstantin Belousov /* 2092e442f29fSKonstantin Belousov * Recalculate the signal mask and reset the signal disposition after 2093e442f29fSKonstantin Belousov * usermode frame for delivery is formed. Should be called after 2094e442f29fSKonstantin Belousov * mach-specific routine, because sysent->sv_sendsig() needs correct 2095e442f29fSKonstantin Belousov * ps_siginfo and signal mask. 2096e442f29fSKonstantin Belousov */ 2097e442f29fSKonstantin Belousov static void 2098e442f29fSKonstantin Belousov postsig_done(int sig, struct thread *td, struct sigacts *ps) 2099e442f29fSKonstantin Belousov { 2100e442f29fSKonstantin Belousov sigset_t mask; 2101e442f29fSKonstantin Belousov 2102e442f29fSKonstantin Belousov mtx_assert(&ps->ps_mtx, MA_OWNED); 2103e442f29fSKonstantin Belousov td->td_ru.ru_nsignals++; 2104e442f29fSKonstantin Belousov mask = ps->ps_catchmask[_SIG_IDX(sig)]; 2105e442f29fSKonstantin Belousov if (!SIGISMEMBER(ps->ps_signodefer, sig)) 2106e442f29fSKonstantin Belousov SIGADDSET(mask, sig); 2107e442f29fSKonstantin Belousov kern_sigprocmask(td, SIG_BLOCK, &mask, NULL, 2108e442f29fSKonstantin Belousov SIGPROCMASK_PROC_LOCKED | SIGPROCMASK_PS_LOCKED); 2109e442f29fSKonstantin Belousov if (SIGISMEMBER(ps->ps_sigreset, sig)) 2110e442f29fSKonstantin Belousov sigdflt(ps, sig); 2111e442f29fSKonstantin Belousov } 2112e442f29fSKonstantin Belousov 2113df8bae1dSRodney W. Grimes /* 21140c14ff0eSRobert Watson * Send a signal caused by a trap to the current thread. If it will be 21150c14ff0eSRobert Watson * caught immediately, deliver it with correct code. Otherwise, post it 21160c14ff0eSRobert Watson * normally. 2117df8bae1dSRodney W. Grimes */ 2118df8bae1dSRodney W. Grimes void 21199104847fSDavid Xu trapsignal(struct thread *td, ksiginfo_t *ksi) 2120df8bae1dSRodney W. Grimes { 21211bf4700bSJeff Roberson struct sigacts *ps; 21221bf4700bSJeff Roberson struct proc *p; 2123146fc63fSKonstantin Belousov sigset_t sigmask; 2124c5c981d4SMateusz Guzik int sig; 21251bf4700bSJeff Roberson 21261bf4700bSJeff Roberson p = td->td_proc; 21279104847fSDavid Xu sig = ksi->ksi_signo; 21289104847fSDavid Xu KASSERT(_SIG_VALID(sig), ("invalid signal")); 21299104847fSDavid Xu 2130a113b17fSKonstantin Belousov sigfastblock_fetch(td); 2131628d2653SJohn Baldwin PROC_LOCK(p); 2132ef3dab76STim J. Robbins ps = p->p_sigacts; 213390af4afaSJohn Baldwin mtx_lock(&ps->ps_mtx); 2134146fc63fSKonstantin Belousov sigmask = td->td_sigmask; 2135146fc63fSKonstantin Belousov if (td->td_sigblock_val != 0) 2136146fc63fSKonstantin Belousov SIGSETOR(sigmask, fastblock_mask); 213790af4afaSJohn Baldwin if ((p->p_flag & P_TRACED) == 0 && SIGISMEMBER(ps->ps_sigcatch, sig) && 2138146fc63fSKonstantin Belousov !SIGISMEMBER(sigmask, sig)) { 2139df8bae1dSRodney W. Grimes #ifdef KTRACE 2140374a15aaSJohn Baldwin if (KTRPOINT(curthread, KTR_PSIG)) 2141374a15aaSJohn Baldwin ktrpsig(sig, ps->ps_sigact[_SIG_IDX(sig)], 2142c5c981d4SMateusz Guzik &td->td_sigmask, ksi->ksi_code); 2143df8bae1dSRodney W. Grimes #endif 21449104847fSDavid Xu (*p->p_sysent->sv_sendsig)(ps->ps_sigact[_SIG_IDX(sig)], 21459104847fSDavid Xu ksi, &td->td_sigmask); 2146e442f29fSKonstantin Belousov postsig_done(sig, td, ps); 214790af4afaSJohn Baldwin mtx_unlock(&ps->ps_mtx); 21486f841fb7SMarcel Moolenaar } else { 2149f71a882fSDavid Xu /* 2150f71a882fSDavid Xu * Avoid a possible infinite loop if the thread 2151f71a882fSDavid Xu * masking the signal or process is ignoring the 2152f71a882fSDavid Xu * signal. 2153f71a882fSDavid Xu */ 2154146fc63fSKonstantin Belousov if (kern_forcesigexit && (SIGISMEMBER(sigmask, sig) || 2155f71a882fSDavid Xu ps->ps_sigact[_SIG_IDX(sig)] == SIG_IGN)) { 2156f71a882fSDavid Xu SIGDELSET(td->td_sigmask, sig); 2157f71a882fSDavid Xu SIGDELSET(ps->ps_sigcatch, sig); 2158f71a882fSDavid Xu SIGDELSET(ps->ps_sigignore, sig); 2159f71a882fSDavid Xu ps->ps_sigact[_SIG_IDX(sig)] = SIG_DFL; 2160146fc63fSKonstantin Belousov td->td_pflags &= ~TDP_SIGFASTBLOCK; 2161146fc63fSKonstantin Belousov td->td_sigblock_val = 0; 2162f71a882fSDavid Xu } 216390af4afaSJohn Baldwin mtx_unlock(&ps->ps_mtx); 21642c42a146SMarcel Moolenaar p->p_sig = sig; /* XXX to verify code */ 2165ad6eec7bSJohn Baldwin tdsendsignal(p, td, sig, ksi); 2166df8bae1dSRodney W. Grimes } 2167628d2653SJohn Baldwin PROC_UNLOCK(p); 2168df8bae1dSRodney W. Grimes } 2169df8bae1dSRodney W. Grimes 21704093529dSJeff Roberson static struct thread * 2171146fc63fSKonstantin Belousov sigtd(struct proc *p, int sig, bool fast_sigblock) 21724093529dSJeff Roberson { 21733074d1b4SDavid Xu struct thread *td, *signal_td; 21744093529dSJeff Roberson 21754093529dSJeff Roberson PROC_LOCK_ASSERT(p, MA_OWNED); 2176146fc63fSKonstantin Belousov MPASS(!fast_sigblock || p == curproc); 21774093529dSJeff Roberson 21784093529dSJeff Roberson /* 2179627451c1SDavid Xu * Check if current thread can handle the signal without 218015b7a831SKonstantin Belousov * switching context to another thread. 21814093529dSJeff Roberson */ 2182146fc63fSKonstantin Belousov if (curproc == p && !SIGISMEMBER(curthread->td_sigmask, sig) && 2183146fc63fSKonstantin Belousov (!fast_sigblock || curthread->td_sigblock_val == 0)) 2184627451c1SDavid Xu return (curthread); 2185dfe17248SKonstantin Belousov 2186dfe17248SKonstantin Belousov /* Find a non-stopped thread that does not mask the signal. */ 21873074d1b4SDavid Xu signal_td = NULL; 21883074d1b4SDavid Xu FOREACH_THREAD_IN_PROC(p, td) { 2189146fc63fSKonstantin Belousov if (!SIGISMEMBER(td->td_sigmask, sig) && (!fast_sigblock || 2190dfe17248SKonstantin Belousov td != curthread || td->td_sigblock_val == 0) && 2191dfe17248SKonstantin Belousov (td->td_flags & TDF_BOUNDARY) == 0) { 21923074d1b4SDavid Xu signal_td = td; 2193627451c1SDavid Xu break; 21943074d1b4SDavid Xu } 21953074d1b4SDavid Xu } 2196dfe17248SKonstantin Belousov /* Select random (first) thread if no better match was found. */ 21973074d1b4SDavid Xu if (signal_td == NULL) 21983074d1b4SDavid Xu signal_td = FIRST_THREAD_IN_PROC(p); 21993074d1b4SDavid Xu return (signal_td); 22004093529dSJeff Roberson } 22014093529dSJeff Roberson 2202df8bae1dSRodney W. Grimes /* 2203df8bae1dSRodney W. Grimes * Send the signal to the process. If the signal has an action, the action 2204df8bae1dSRodney W. Grimes * is usually performed by the target process rather than the caller; we add 2205df8bae1dSRodney W. Grimes * the signal to the set of pending signals for the process. 2206df8bae1dSRodney W. Grimes * 2207df8bae1dSRodney W. Grimes * Exceptions: 2208df8bae1dSRodney W. Grimes * o When a stop signal is sent to a sleeping process that takes the 2209df8bae1dSRodney W. Grimes * default action, the process is stopped without awakening it. 2210df8bae1dSRodney W. Grimes * o SIGCONT restarts stopped processes (or puts them back to sleep) 2211df8bae1dSRodney W. Grimes * regardless of the signal action (eg, blocked or ignored). 2212df8bae1dSRodney W. Grimes * 2213df8bae1dSRodney W. Grimes * Other ignored signals are discarded immediately. 22144dec0e67SRobert Watson * 22154dec0e67SRobert Watson * NB: This function may be entered from the debugger via the "kill" DDB 22164dec0e67SRobert Watson * command. There is little that can be done to mitigate the possibly messy 22174dec0e67SRobert Watson * side effects of this unwise possibility. 2218df8bae1dSRodney W. Grimes */ 2219df8bae1dSRodney W. Grimes void 22208451d0ddSKip Macy kern_psignal(struct proc *p, int sig) 2221df8bae1dSRodney W. Grimes { 2222a3de221dSKonstantin Belousov ksiginfo_t ksi; 2223a3de221dSKonstantin Belousov 2224a3de221dSKonstantin Belousov ksiginfo_init(&ksi); 2225a3de221dSKonstantin Belousov ksi.ksi_signo = sig; 2226a3de221dSKonstantin Belousov ksi.ksi_code = SI_KERNEL; 2227ad6eec7bSJohn Baldwin (void) tdsendsignal(p, NULL, sig, &ksi); 2228a3de221dSKonstantin Belousov } 2229a3de221dSKonstantin Belousov 2230ad6eec7bSJohn Baldwin int 2231a3de221dSKonstantin Belousov pksignal(struct proc *p, int sig, ksiginfo_t *ksi) 2232a3de221dSKonstantin Belousov { 2233a3de221dSKonstantin Belousov 2234ad6eec7bSJohn Baldwin return (tdsendsignal(p, NULL, sig, ksi)); 22359104847fSDavid Xu } 22369104847fSDavid Xu 2237cf7d9a8cSDavid Xu /* Utility function for finding a thread to send signal event to. */ 22389104847fSDavid Xu int 2239cf7d9a8cSDavid Xu sigev_findtd(struct proc *p, struct sigevent *sigev, struct thread **ttd) 22409104847fSDavid Xu { 2241cf7d9a8cSDavid Xu struct thread *td; 224241b3077aSJacques Vidrine 22436d7b314bSDavid Xu if (sigev->sigev_notify == SIGEV_THREAD_ID) { 2244cf7d9a8cSDavid Xu td = tdfind(sigev->sigev_notify_thread_id, p->p_pid); 22456d7b314bSDavid Xu if (td == NULL) 22466d7b314bSDavid Xu return (ESRCH); 2247cf7d9a8cSDavid Xu *ttd = td; 2248cf7d9a8cSDavid Xu } else { 2249cf7d9a8cSDavid Xu *ttd = NULL; 2250cf7d9a8cSDavid Xu PROC_LOCK(p); 22516d7b314bSDavid Xu } 2252cf7d9a8cSDavid Xu return (0); 22534093529dSJeff Roberson } 22544093529dSJeff Roberson 2255ad6eec7bSJohn Baldwin void 2256ad6eec7bSJohn Baldwin tdsignal(struct thread *td, int sig) 2257ad6eec7bSJohn Baldwin { 2258ad6eec7bSJohn Baldwin ksiginfo_t ksi; 2259ad6eec7bSJohn Baldwin 2260ad6eec7bSJohn Baldwin ksiginfo_init(&ksi); 2261ad6eec7bSJohn Baldwin ksi.ksi_signo = sig; 2262ad6eec7bSJohn Baldwin ksi.ksi_code = SI_KERNEL; 2263ad6eec7bSJohn Baldwin (void) tdsendsignal(td->td_proc, td, sig, &ksi); 2264ad6eec7bSJohn Baldwin } 2265ad6eec7bSJohn Baldwin 2266ad6eec7bSJohn Baldwin void 2267ad6eec7bSJohn Baldwin tdksignal(struct thread *td, int sig, ksiginfo_t *ksi) 2268ad6eec7bSJohn Baldwin { 2269ad6eec7bSJohn Baldwin 2270ad6eec7bSJohn Baldwin (void) tdsendsignal(td->td_proc, td, sig, ksi); 2271ad6eec7bSJohn Baldwin } 2272ad6eec7bSJohn Baldwin 2273d4c4ca85SMark Johnston static void 22749b86d3e5SKonstantin Belousov sig_sleepq_abort(struct thread *td, int intrval) 22759b86d3e5SKonstantin Belousov { 22769b86d3e5SKonstantin Belousov THREAD_LOCK_ASSERT(td, MA_OWNED); 22779b86d3e5SKonstantin Belousov 2278d4c4ca85SMark Johnston if (intrval == 0 && (td->td_flags & TDF_SIGWAIT) == 0) 22799b86d3e5SKonstantin Belousov thread_unlock(td); 2280d4c4ca85SMark Johnston else 2281d4c4ca85SMark Johnston sleepq_abort(td, intrval); 22829b86d3e5SKonstantin Belousov } 22839b86d3e5SKonstantin Belousov 2284cf7d9a8cSDavid Xu int 2285ad6eec7bSJohn Baldwin tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi) 22864093529dSJeff Roberson { 22879104847fSDavid Xu sig_t action; 22889104847fSDavid Xu sigqueue_t *sigqueue; 228990af4afaSJohn Baldwin struct sigacts *ps; 2290d4c4ca85SMark Johnston int intrval, prop, ret; 2291df8bae1dSRodney W. Grimes 2292cf7d9a8cSDavid Xu MPASS(td == NULL || p == td->td_proc); 22936d7b314bSDavid Xu PROC_LOCK_ASSERT(p, MA_OWNED); 22946d7b314bSDavid Xu 229541b3077aSJacques Vidrine if (!_SIG_VALID(sig)) 2296212bc4b3SDavid Xu panic("%s(): invalid signal %d", __func__, sig); 22974093529dSJeff Roberson 2298212bc4b3SDavid Xu KASSERT(ksi == NULL || !KSI_ONQ(ksi), ("%s: ksi on queue", __func__)); 22996d7b314bSDavid Xu 23006d7b314bSDavid Xu /* 23016d7b314bSDavid Xu * IEEE Std 1003.1-2001: return success when killing a zombie. 23026d7b314bSDavid Xu */ 23036d7b314bSDavid Xu if (p->p_state == PRS_ZOMBIE) { 23040a4f2ac3SKonstantin Belousov if (ksi != NULL && (ksi->ksi_flags & KSI_INS) != 0) 23056d7b314bSDavid Xu ksiginfo_tryfree(ksi); 2306d4c4ca85SMark Johnston return (0); 23076d7b314bSDavid Xu } 23086d7b314bSDavid Xu 230990af4afaSJohn Baldwin ps = p->p_sigacts; 23109e590ff0SKonstantin Belousov KNOTE_LOCKED(p->p_klist, NOTE_SIGNAL | sig); 23112c42a146SMarcel Moolenaar prop = sigprop(sig); 23124093529dSJeff Roberson 23136d7b314bSDavid Xu if (td == NULL) { 2314146fc63fSKonstantin Belousov td = sigtd(p, sig, false); 23156d7b314bSDavid Xu sigqueue = &p->p_sigqueue; 2316462314b3SMateusz Guzik } else 23179104847fSDavid Xu sigqueue = &td->td_sigqueue; 23184093529dSJeff Roberson 231936160958SMark Johnston SDT_PROBE3(proc, , , signal__send, td, p, sig); 23205d217f17SJohn Birrell 2321df8bae1dSRodney W. Grimes /* 2322bc387624SKonstantin Belousov * If the signal is being ignored, then we forget about it 2323bc387624SKonstantin Belousov * immediately, except when the target process executes 2324bc387624SKonstantin Belousov * sigwait(). (Note: we don't set SIGCONT in ps_sigignore, 2325bc387624SKonstantin Belousov * and if it is set to SIG_IGN, action will be SIG_DFL here.) 2326df8bae1dSRodney W. Grimes */ 232790af4afaSJohn Baldwin mtx_lock(&ps->ps_mtx); 23280fc32899SJohn Baldwin if (SIGISMEMBER(ps->ps_sigignore, sig)) { 2329bc387624SKonstantin Belousov if (kern_sig_discard_ign && 2330bc387624SKonstantin Belousov (p->p_sysent->sv_flags & SV_SIG_DISCIGN) == 0) { 233136160958SMark Johnston SDT_PROBE3(proc, , , signal__discard, td, p, sig); 23325d217f17SJohn Birrell 233390af4afaSJohn Baldwin mtx_unlock(&ps->ps_mtx); 23340a4f2ac3SKonstantin Belousov if (ksi != NULL && (ksi->ksi_flags & KSI_INS) != 0) 23356d7b314bSDavid Xu ksiginfo_tryfree(ksi); 2336d4c4ca85SMark Johnston return (0); 2337bc387624SKonstantin Belousov } else { 2338bc387624SKonstantin Belousov action = SIG_CATCH; 2339f17eb93dSKonstantin Belousov intrval = 0; 234090af4afaSJohn Baldwin } 2341f17eb93dSKonstantin Belousov } else { 2342f17eb93dSKonstantin Belousov if (SIGISMEMBER(td->td_sigmask, sig)) 2343df8bae1dSRodney W. Grimes action = SIG_HOLD; 234490af4afaSJohn Baldwin else if (SIGISMEMBER(ps->ps_sigcatch, sig)) 2345df8bae1dSRodney W. Grimes action = SIG_CATCH; 2346df8bae1dSRodney W. Grimes else 2347df8bae1dSRodney W. Grimes action = SIG_DFL; 234894f0972bSDavid Xu if (SIGISMEMBER(ps->ps_sigintr, sig)) 234994f0972bSDavid Xu intrval = EINTR; 235094f0972bSDavid Xu else 235194f0972bSDavid Xu intrval = ERESTART; 2352f17eb93dSKonstantin Belousov } 235390af4afaSJohn Baldwin mtx_unlock(&ps->ps_mtx); 2354df8bae1dSRodney W. Grimes 2355fd50a707SBrooks Davis if (prop & SIGPROP_CONT) 23569104847fSDavid Xu sigqueue_delete_stopmask_proc(p); 2357fd50a707SBrooks Davis else if (prop & SIGPROP_STOP) { 2358df8bae1dSRodney W. Grimes /* 2359df8bae1dSRodney W. Grimes * If sending a tty stop signal to a member of an orphaned 2360df8bae1dSRodney W. Grimes * process group, discard the signal here if the action 2361df8bae1dSRodney W. Grimes * is default; don't stop the process below if sleeping, 2362df8bae1dSRodney W. Grimes * and don't clear any pending SIGCONT. 2363df8bae1dSRodney W. Grimes */ 2364993a1699SKonstantin Belousov if ((prop & SIGPROP_TTYSTOP) != 0 && 23655844bd05SKonstantin Belousov (p->p_pgrp->pg_flags & PGRP_ORPHANED) != 0 && 2366993a1699SKonstantin Belousov action == SIG_DFL) { 23670a4f2ac3SKonstantin Belousov if (ksi != NULL && (ksi->ksi_flags & KSI_INS) != 0) 23686d7b314bSDavid Xu ksiginfo_tryfree(ksi); 2369d4c4ca85SMark Johnston return (0); 23706d7b314bSDavid Xu } 23719104847fSDavid Xu sigqueue_delete_proc(p, SIGCONT); 2372ebceaf6dSDavid Xu if (p->p_flag & P_CONTINUED) { 23736933e3c1SJulian Elischer p->p_flag &= ~P_CONTINUED; 2374ebceaf6dSDavid Xu PROC_LOCK(p->p_pptr); 2375ebceaf6dSDavid Xu sigqueue_take(p->p_ksi); 2376ebceaf6dSDavid Xu PROC_UNLOCK(p->p_pptr); 2377ebceaf6dSDavid Xu } 2378df8bae1dSRodney W. Grimes } 23793074d1b4SDavid Xu 23809104847fSDavid Xu ret = sigqueue_add(sigqueue, sig, ksi); 23819104847fSDavid Xu if (ret != 0) 23829104847fSDavid Xu return (ret); 23836d7b314bSDavid Xu signotify(td); 23845312b1c7SDavid Xu /* 23855312b1c7SDavid Xu * Defer further processing for signals which are held, 23865312b1c7SDavid Xu * except that stopped processes must be continued by SIGCONT. 23875312b1c7SDavid Xu */ 23885312b1c7SDavid Xu if (action == SIG_HOLD && 2389fd50a707SBrooks Davis !((prop & SIGPROP_CONT) && (p->p_flag & P_STOPPED_SIG))) 2390d4c4ca85SMark Johnston return (0); 239161a74c5cSJeff Roberson 239290d75f78SAlfred Perlstein /* 2393e602ba25SJulian Elischer * Some signals have a process-wide effect and a per-thread 2394e602ba25SJulian Elischer * component. Most processing occurs when the process next 2395e602ba25SJulian Elischer * tries to cross the user boundary, however there are some 23961968f37bSJohn Baldwin * times when processing needs to be done immediately, such as 2397e602ba25SJulian Elischer * waking up threads so that they can cross the user boundary. 23981968f37bSJohn Baldwin * We try to do the per-process part here. 2399df8bae1dSRodney W. Grimes */ 2400e602ba25SJulian Elischer if (P_SHOULDSTOP(p)) { 24010f14f15bSJohn Baldwin KASSERT(!(p->p_flag & P_WEXIT), 24020f14f15bSJohn Baldwin ("signal to stopped but exiting process")); 2403e602ba25SJulian Elischer if (sig == SIGKILL) { 2404137cf33dSDavid Xu /* 2405137cf33dSDavid Xu * If traced process is already stopped, 2406137cf33dSDavid Xu * then no further action is necessary. 2407137cf33dSDavid Xu */ 240883b718ebSDavid Xu if (p->p_flag & P_TRACED) 2409d4c4ca85SMark Johnston return (0); 2410df8bae1dSRodney W. Grimes /* 2411e602ba25SJulian Elischer * SIGKILL sets process running. 2412e602ba25SJulian Elischer * It will die elsewhere. 2413e602ba25SJulian Elischer * All threads must be restarted. 2414df8bae1dSRodney W. Grimes */ 2415482d099cSDavid Xu p->p_flag &= ~P_STOPPED_SIG; 2416e602ba25SJulian Elischer goto runfast; 2417e602ba25SJulian Elischer } 2418e602ba25SJulian Elischer 2419fd50a707SBrooks Davis if (prop & SIGPROP_CONT) { 2420137cf33dSDavid Xu /* 2421137cf33dSDavid Xu * If traced process is already stopped, 2422137cf33dSDavid Xu * then no further action is necessary. 2423137cf33dSDavid Xu */ 242483b718ebSDavid Xu if (p->p_flag & P_TRACED) 2425d4c4ca85SMark Johnston return (0); 2426e602ba25SJulian Elischer /* 2427e602ba25SJulian Elischer * If SIGCONT is default (or ignored), we continue the 24289104847fSDavid Xu * process but don't leave the signal in sigqueue as 24291d9c5696SJuli Mallett * it has no further action. If SIGCONT is held, we 2430e602ba25SJulian Elischer * continue the process and leave the signal in 24319104847fSDavid Xu * sigqueue. If the process catches SIGCONT, let it 2432e602ba25SJulian Elischer * handle the signal itself. If it isn't waiting on 2433e602ba25SJulian Elischer * an event, it goes back to run state. 2434e602ba25SJulian Elischer * Otherwise, process goes back to sleep state. 2435e602ba25SJulian Elischer */ 24361279572aSDavid Xu p->p_flag &= ~P_STOPPED_SIG; 24377b4a950aSDavid Xu PROC_SLOCK(p); 2438ebceaf6dSDavid Xu if (p->p_numthreads == p->p_suspcount) { 24397b4a950aSDavid Xu PROC_SUNLOCK(p); 24406933e3c1SJulian Elischer p->p_flag |= P_CONTINUED; 2441b4490c6eSKonstantin Belousov p->p_xsig = SIGCONT; 24427f96995eSDavid Xu PROC_LOCK(p->p_pptr); 2443ebceaf6dSDavid Xu childproc_continued(p); 24447f96995eSDavid Xu PROC_UNLOCK(p->p_pptr); 24457b4a950aSDavid Xu PROC_SLOCK(p); 2446ebceaf6dSDavid Xu } 2447e602ba25SJulian Elischer if (action == SIG_DFL) { 2448a54e85fdSJeff Roberson thread_unsuspend(p); 24497b4a950aSDavid Xu PROC_SUNLOCK(p); 24509104847fSDavid Xu sigqueue_delete(sigqueue, sig); 2451dc47fdf1SKonstantin Belousov goto out_cont; 2452a54e85fdSJeff Roberson } 2453a54e85fdSJeff Roberson if (action == SIG_CATCH) { 24548460a577SJohn Birrell /* 24558460a577SJohn Birrell * The process wants to catch it so it needs 24568460a577SJohn Birrell * to run at least one thread, but which one? 24578460a577SJohn Birrell */ 24587b4a950aSDavid Xu PROC_SUNLOCK(p); 2459e602ba25SJulian Elischer goto runfast; 2460e602ba25SJulian Elischer } 2461e602ba25SJulian Elischer /* 2462e602ba25SJulian Elischer * The signal is not ignored or caught. 2463e602ba25SJulian Elischer */ 246404774f23SJulian Elischer thread_unsuspend(p); 24657b4a950aSDavid Xu PROC_SUNLOCK(p); 2466dc47fdf1SKonstantin Belousov goto out_cont; 2467e602ba25SJulian Elischer } 2468e602ba25SJulian Elischer 2469fd50a707SBrooks Davis if (prop & SIGPROP_STOP) { 2470137cf33dSDavid Xu /* 2471137cf33dSDavid Xu * If traced process is already stopped, 2472137cf33dSDavid Xu * then no further action is necessary. 2473137cf33dSDavid Xu */ 247483b718ebSDavid Xu if (p->p_flag & P_TRACED) 2475d4c4ca85SMark Johnston return (0); 2476e602ba25SJulian Elischer /* 2477e602ba25SJulian Elischer * Already stopped, don't need to stop again 2478e602ba25SJulian Elischer * (If we did the shell could get confused). 247904774f23SJulian Elischer * Just make sure the signal STOP bit set. 2480e602ba25SJulian Elischer */ 24811279572aSDavid Xu p->p_flag |= P_STOPPED_SIG; 24829104847fSDavid Xu sigqueue_delete(sigqueue, sig); 2483d4c4ca85SMark Johnston return (0); 2484e602ba25SJulian Elischer } 2485e602ba25SJulian Elischer 2486e602ba25SJulian Elischer /* 2487e602ba25SJulian Elischer * All other kinds of signals: 2488e602ba25SJulian Elischer * If a thread is sleeping interruptibly, simulate a 2489e602ba25SJulian Elischer * wakeup so that when it is continued it will be made 2490e602ba25SJulian Elischer * runnable and can look at the signal. However, don't make 249104774f23SJulian Elischer * the PROCESS runnable, leave it stopped. 2492e602ba25SJulian Elischer * It may run a bit until it hits a thread_suspend_check(). 2493e602ba25SJulian Elischer */ 24947b4a950aSDavid Xu PROC_SLOCK(p); 2495a54e85fdSJeff Roberson thread_lock(td); 249661a74c5cSJeff Roberson if (TD_CAN_ABORT(td)) 2497d4c4ca85SMark Johnston sig_sleepq_abort(td, intrval); 249861a74c5cSJeff Roberson else 2499a54e85fdSJeff Roberson thread_unlock(td); 25007b4a950aSDavid Xu PROC_SUNLOCK(p); 2501d4c4ca85SMark Johnston return (0); 2502df8bae1dSRodney W. Grimes /* 25039a6a4cb5SPeter Wemm * Mutexes are short lived. Threads waiting on them will 25049a6a4cb5SPeter Wemm * hit thread_suspend_check() soon. 2505df8bae1dSRodney W. Grimes */ 2506e602ba25SJulian Elischer } else if (p->p_state == PRS_NORMAL) { 2507ec8297bdSDavid Xu if (p->p_flag & P_TRACED || action == SIG_CATCH) { 250894f0972bSDavid Xu tdsigwakeup(td, sig, action, intrval); 2509d4c4ca85SMark Johnston return (0); 251004774f23SJulian Elischer } 2511ec8297bdSDavid Xu 2512ec8297bdSDavid Xu MPASS(action == SIG_DFL); 2513ec8297bdSDavid Xu 2514fd50a707SBrooks Davis if (prop & SIGPROP_STOP) { 25150f14f15bSJohn Baldwin if (p->p_flag & (P_PPWAIT|P_WEXIT)) 2516d4c4ca85SMark Johnston return (0); 2517e574e444SDavid Xu p->p_flag |= P_STOPPED_SIG; 2518b4490c6eSKonstantin Belousov p->p_xsig = sig; 25197b4a950aSDavid Xu PROC_SLOCK(p); 2520d4c4ca85SMark Johnston sig_suspend_threads(td, p); 25214093529dSJeff Roberson if (p->p_numthreads == p->p_suspcount) { 2522ebceaf6dSDavid Xu /* 2523ebceaf6dSDavid Xu * only thread sending signal to another 2524ebceaf6dSDavid Xu * process can reach here, if thread is sending 2525ebceaf6dSDavid Xu * signal to its process, because thread does 2526ebceaf6dSDavid Xu * not suspend itself here, p_numthreads 2527ebceaf6dSDavid Xu * should never be equal to p_suspcount. 2528ebceaf6dSDavid Xu */ 2529ebceaf6dSDavid Xu thread_stopped(p); 25307b4a950aSDavid Xu PROC_SUNLOCK(p); 2531b4490c6eSKonstantin Belousov sigqueue_delete_proc(p, p->p_xsig); 25327b4a950aSDavid Xu } else 25337b4a950aSDavid Xu PROC_SUNLOCK(p); 2534d4c4ca85SMark Johnston return (0); 253535c32a76SDavid Xu } 2536e602ba25SJulian Elischer } else { 2537e602ba25SJulian Elischer /* Not in "NORMAL" state. discard the signal. */ 25389104847fSDavid Xu sigqueue_delete(sigqueue, sig); 2539d4c4ca85SMark Johnston return (0); 2540e602ba25SJulian Elischer } 2541e602ba25SJulian Elischer 2542b40ce416SJulian Elischer /* 2543e602ba25SJulian Elischer * The process is not stopped so we need to apply the signal to all the 2544e602ba25SJulian Elischer * running threads. 2545b40ce416SJulian Elischer */ 2546e602ba25SJulian Elischer runfast: 254794f0972bSDavid Xu tdsigwakeup(td, sig, action, intrval); 25487b4a950aSDavid Xu PROC_SLOCK(p); 2549e602ba25SJulian Elischer thread_unsuspend(p); 25507b4a950aSDavid Xu PROC_SUNLOCK(p); 2551dc47fdf1SKonstantin Belousov out_cont: 2552dc47fdf1SKonstantin Belousov itimer_proc_continue(p); 25532fd1ffefSKonstantin Belousov kqtimer_proc_continue(p); 255461a74c5cSJeff Roberson 2555d4c4ca85SMark Johnston return (0); 2556e602ba25SJulian Elischer } 2557e602ba25SJulian Elischer 2558e602ba25SJulian Elischer /* 2559e602ba25SJulian Elischer * The force of a signal has been directed against a single 2560e602ba25SJulian Elischer * thread. We need to see what we can do about knocking it 2561e602ba25SJulian Elischer * out of any sleep it may be in etc. 2562e602ba25SJulian Elischer */ 2563e602ba25SJulian Elischer static void 256494f0972bSDavid Xu tdsigwakeup(struct thread *td, int sig, sig_t action, int intrval) 2565e602ba25SJulian Elischer { 2566e602ba25SJulian Elischer struct proc *p = td->td_proc; 2567d4c4ca85SMark Johnston int prop; 2568e602ba25SJulian Elischer 25698b94a061SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 2570e602ba25SJulian Elischer prop = sigprop(sig); 2571a4c2da15SBruce Evans 25727b4a950aSDavid Xu PROC_SLOCK(p); 2573374ae2a3SJeff Roberson thread_lock(td); 2574e602ba25SJulian Elischer /* 2575aa0fa334SJulian Elischer * Bring the priority of a thread up if we want it to get 2576aef68c96SKonstantin Belousov * killed in this lifetime. Be careful to avoid bumping the 2577aef68c96SKonstantin Belousov * priority of the idle thread, since we still allow to signal 2578aef68c96SKonstantin Belousov * kernel processes. 2579e602ba25SJulian Elischer */ 2580fd50a707SBrooks Davis if (action == SIG_DFL && (prop & SIGPROP_KILL) != 0 && 2581aef68c96SKonstantin Belousov td->td_priority > PUSER && !TD_IS_IDLETHREAD(td)) 2582b3a4fb14SDavid Xu sched_prio(td, PUSER); 258380c4433cSJohn Baldwin if (TD_ON_SLEEPQ(td)) { 2584e602ba25SJulian Elischer /* 2585e602ba25SJulian Elischer * If thread is sleeping uninterruptibly 2586e602ba25SJulian Elischer * we can't interrupt the sleep... the signal will 2587e602ba25SJulian Elischer * be noticed when the process returns through 2588e602ba25SJulian Elischer * trap() or syscall(). 2589e602ba25SJulian Elischer */ 259044f3b092SJohn Baldwin if ((td->td_flags & TDF_SINTR) == 0) 2591374ae2a3SJeff Roberson goto out; 2592e602ba25SJulian Elischer /* 2593e602ba25SJulian Elischer * If SIGCONT is default (or ignored) and process is 2594e602ba25SJulian Elischer * asleep, we are finished; the process should not 2595e602ba25SJulian Elischer * be awakened. 2596df8bae1dSRodney W. Grimes */ 2597fd50a707SBrooks Davis if ((prop & SIGPROP_CONT) && action == SIG_DFL) { 2598a54e85fdSJeff Roberson thread_unlock(td); 25997b4a950aSDavid Xu PROC_SUNLOCK(p); 26009104847fSDavid Xu sigqueue_delete(&p->p_sigqueue, sig); 26014093529dSJeff Roberson /* 26024093529dSJeff Roberson * It may be on either list in this state. 26034093529dSJeff Roberson * Remove from both for now. 26044093529dSJeff Roberson */ 26059104847fSDavid Xu sigqueue_delete(&td->td_sigqueue, sig); 2606aa0fa334SJulian Elischer return; 2607df8bae1dSRodney W. Grimes } 2608df8bae1dSRodney W. Grimes 2609aa0fa334SJulian Elischer /* 2610a120a7a3SJohn Baldwin * Don't awaken a sleeping thread for SIGSTOP if the 2611a120a7a3SJohn Baldwin * STOP signal is deferred. 2612a120a7a3SJohn Baldwin */ 2613fd50a707SBrooks Davis if ((prop & SIGPROP_STOP) != 0 && (td->td_flags & (TDF_SBDRY | 26146f56cb8dSKonstantin Belousov TDF_SERESTART | TDF_SEINTR)) == TDF_SBDRY) 2615a120a7a3SJohn Baldwin goto out; 2616a120a7a3SJohn Baldwin 2617a120a7a3SJohn Baldwin /* 2618a4c2da15SBruce Evans * Give low priority threads a better chance to run. 2619aa0fa334SJulian Elischer */ 2620aef68c96SKonstantin Belousov if (td->td_priority > PUSER && !TD_IS_IDLETHREAD(td)) 2621b3a4fb14SDavid Xu sched_prio(td, PUSER); 2622ec8297bdSDavid Xu 2623d4c4ca85SMark Johnston sig_sleepq_abort(td, intrval); 262461a74c5cSJeff Roberson PROC_SUNLOCK(p); 262561a74c5cSJeff Roberson return; 262661a74c5cSJeff Roberson } 262761a74c5cSJeff Roberson 2628df8bae1dSRodney W. Grimes /* 2629a4c2da15SBruce Evans * Other states do nothing with the signal immediately, 2630df8bae1dSRodney W. Grimes * other than kicking ourselves if we are running. 2631df8bae1dSRodney W. Grimes * It will either never be noticed, or noticed very soon. 2632df8bae1dSRodney W. Grimes */ 2633a4c2da15SBruce Evans #ifdef SMP 263444f3b092SJohn Baldwin if (TD_IS_RUNNING(td) && td != curthread) 2635e602ba25SJulian Elischer forward_signal(td); 26363163861cSTor Egge #endif 263761a74c5cSJeff Roberson 2638374ae2a3SJeff Roberson out: 26397b4a950aSDavid Xu PROC_SUNLOCK(p); 2640374ae2a3SJeff Roberson thread_unlock(td); 2641a4c2da15SBruce Evans } 2642df8bae1dSRodney W. Grimes 264387a64872SKonstantin Belousov static void 2644140ceb5dSKonstantin Belousov ptrace_coredumpreq(struct thread *td, struct proc *p, 2645140ceb5dSKonstantin Belousov struct thr_coredump_req *tcq) 2646140ceb5dSKonstantin Belousov { 2647140ceb5dSKonstantin Belousov void *rl_cookie; 2648140ceb5dSKonstantin Belousov 2649140ceb5dSKonstantin Belousov if (p->p_sysent->sv_coredump == NULL) { 2650140ceb5dSKonstantin Belousov tcq->tc_error = ENOSYS; 2651140ceb5dSKonstantin Belousov return; 2652140ceb5dSKonstantin Belousov } 2653140ceb5dSKonstantin Belousov 2654140ceb5dSKonstantin Belousov rl_cookie = vn_rangelock_wlock(tcq->tc_vp, 0, OFF_MAX); 2655140ceb5dSKonstantin Belousov tcq->tc_error = p->p_sysent->sv_coredump(td, tcq->tc_vp, 2656140ceb5dSKonstantin Belousov tcq->tc_limit, tcq->tc_flags); 2657140ceb5dSKonstantin Belousov vn_rangelock_unlock(tcq->tc_vp, rl_cookie); 2658140ceb5dSKonstantin Belousov } 2659140ceb5dSKonstantin Belousov 2660140ceb5dSKonstantin Belousov static void 2661140ceb5dSKonstantin Belousov ptrace_syscallreq(struct thread *td, struct proc *p, 2662140ceb5dSKonstantin Belousov struct thr_syscall_req *tsr) 2663140ceb5dSKonstantin Belousov { 2664140ceb5dSKonstantin Belousov struct sysentvec *sv; 2665140ceb5dSKonstantin Belousov struct sysent *se; 2666140ceb5dSKonstantin Belousov register_t rv_saved[2]; 2667140ceb5dSKonstantin Belousov int error, nerror; 2668140ceb5dSKonstantin Belousov int sc; 2669140ceb5dSKonstantin Belousov bool audited, sy_thr_static; 2670140ceb5dSKonstantin Belousov 2671140ceb5dSKonstantin Belousov sv = p->p_sysent; 2672140ceb5dSKonstantin Belousov if (sv->sv_table == NULL || sv->sv_size < tsr->ts_sa.code) { 2673140ceb5dSKonstantin Belousov tsr->ts_ret.sr_error = ENOSYS; 2674140ceb5dSKonstantin Belousov return; 2675140ceb5dSKonstantin Belousov } 2676140ceb5dSKonstantin Belousov 2677140ceb5dSKonstantin Belousov sc = tsr->ts_sa.code; 2678140ceb5dSKonstantin Belousov if (sc == SYS_syscall || sc == SYS___syscall) { 2679974be51bSKonstantin Belousov sc = tsr->ts_sa.args[0]; 2680140ceb5dSKonstantin Belousov memmove(&tsr->ts_sa.args[0], &tsr->ts_sa.args[1], 2681140ceb5dSKonstantin Belousov sizeof(register_t) * (tsr->ts_nargs - 1)); 2682140ceb5dSKonstantin Belousov } 2683140ceb5dSKonstantin Belousov 2684140ceb5dSKonstantin Belousov tsr->ts_sa.callp = se = &sv->sv_table[sc]; 2685140ceb5dSKonstantin Belousov 2686140ceb5dSKonstantin Belousov VM_CNT_INC(v_syscall); 2687140ceb5dSKonstantin Belousov td->td_pticks = 0; 2688140ceb5dSKonstantin Belousov if (__predict_false(td->td_cowgen != atomic_load_int( 2689140ceb5dSKonstantin Belousov &td->td_proc->p_cowgen))) 2690140ceb5dSKonstantin Belousov thread_cow_update(td); 2691140ceb5dSKonstantin Belousov 269205296a0fSJake Freeland td->td_sa = tsr->ts_sa; 269305296a0fSJake Freeland 2694140ceb5dSKonstantin Belousov #ifdef CAPABILITY_MODE 269505296a0fSJake Freeland if ((se->sy_flags & SYF_CAPENABLED) == 0) { 269605296a0fSJake Freeland if (CAP_TRACING(td)) 269705296a0fSJake Freeland ktrcapfail(CAPFAIL_SYSCALL, NULL); 269805296a0fSJake Freeland if (IN_CAPABILITY_MODE(td)) { 2699140ceb5dSKonstantin Belousov tsr->ts_ret.sr_error = ECAPMODE; 2700140ceb5dSKonstantin Belousov return; 2701140ceb5dSKonstantin Belousov } 270205296a0fSJake Freeland } 2703140ceb5dSKonstantin Belousov #endif 2704140ceb5dSKonstantin Belousov 2705140ceb5dSKonstantin Belousov sy_thr_static = (se->sy_thrcnt & SY_THR_STATIC) != 0; 2706974be51bSKonstantin Belousov audited = AUDIT_SYSCALL_ENTER(sc, td) != 0; 2707140ceb5dSKonstantin Belousov 2708140ceb5dSKonstantin Belousov if (!sy_thr_static) { 270939024a89SKonstantin Belousov error = syscall_thread_enter(td, &se); 271039024a89SKonstantin Belousov sy_thr_static = (se->sy_thrcnt & SY_THR_STATIC) != 0; 2711140ceb5dSKonstantin Belousov if (error != 0) { 2712140ceb5dSKonstantin Belousov tsr->ts_ret.sr_error = error; 2713140ceb5dSKonstantin Belousov return; 2714140ceb5dSKonstantin Belousov } 2715140ceb5dSKonstantin Belousov } 2716140ceb5dSKonstantin Belousov 2717140ceb5dSKonstantin Belousov rv_saved[0] = td->td_retval[0]; 2718140ceb5dSKonstantin Belousov rv_saved[1] = td->td_retval[1]; 2719140ceb5dSKonstantin Belousov nerror = td->td_errno; 2720140ceb5dSKonstantin Belousov td->td_retval[0] = 0; 2721140ceb5dSKonstantin Belousov td->td_retval[1] = 0; 2722140ceb5dSKonstantin Belousov 2723140ceb5dSKonstantin Belousov #ifdef KDTRACE_HOOKS 2724140ceb5dSKonstantin Belousov if (se->sy_entry != 0) 2725140ceb5dSKonstantin Belousov (*systrace_probe_func)(&tsr->ts_sa, SYSTRACE_ENTRY, 0); 2726140ceb5dSKonstantin Belousov #endif 2727140ceb5dSKonstantin Belousov tsr->ts_ret.sr_error = se->sy_call(td, tsr->ts_sa.args); 2728140ceb5dSKonstantin Belousov #ifdef KDTRACE_HOOKS 2729140ceb5dSKonstantin Belousov if (se->sy_return != 0) 2730140ceb5dSKonstantin Belousov (*systrace_probe_func)(&tsr->ts_sa, SYSTRACE_RETURN, 2731974be51bSKonstantin Belousov tsr->ts_ret.sr_error != 0 ? -1 : td->td_retval[0]); 2732140ceb5dSKonstantin Belousov #endif 2733140ceb5dSKonstantin Belousov 2734140ceb5dSKonstantin Belousov tsr->ts_ret.sr_retval[0] = td->td_retval[0]; 2735140ceb5dSKonstantin Belousov tsr->ts_ret.sr_retval[1] = td->td_retval[1]; 2736140ceb5dSKonstantin Belousov td->td_retval[0] = rv_saved[0]; 2737140ceb5dSKonstantin Belousov td->td_retval[1] = rv_saved[1]; 2738140ceb5dSKonstantin Belousov td->td_errno = nerror; 2739140ceb5dSKonstantin Belousov 2740140ceb5dSKonstantin Belousov if (audited) 2741140ceb5dSKonstantin Belousov AUDIT_SYSCALL_EXIT(error, td); 2742140ceb5dSKonstantin Belousov if (!sy_thr_static) 2743140ceb5dSKonstantin Belousov syscall_thread_exit(td, se); 2744140ceb5dSKonstantin Belousov } 2745140ceb5dSKonstantin Belousov 2746140ceb5dSKonstantin Belousov static void 2747140ceb5dSKonstantin Belousov ptrace_remotereq(struct thread *td, int flag) 274887a64872SKonstantin Belousov { 274987a64872SKonstantin Belousov struct proc *p; 275087a64872SKonstantin Belousov 275187a64872SKonstantin Belousov MPASS(td == curthread); 275287a64872SKonstantin Belousov p = td->td_proc; 275387a64872SKonstantin Belousov PROC_LOCK_ASSERT(p, MA_OWNED); 2754140ceb5dSKonstantin Belousov if ((td->td_dbgflags & flag) == 0) 275587a64872SKonstantin Belousov return; 275687a64872SKonstantin Belousov KASSERT((p->p_flag & P_STOPPED_TRACE) != 0, ("not stopped")); 2757140ceb5dSKonstantin Belousov KASSERT(td->td_remotereq != NULL, ("td_remotereq is NULL")); 275887a64872SKonstantin Belousov 275987a64872SKonstantin Belousov PROC_UNLOCK(p); 2760140ceb5dSKonstantin Belousov switch (flag) { 2761140ceb5dSKonstantin Belousov case TDB_COREDUMPREQ: 2762140ceb5dSKonstantin Belousov ptrace_coredumpreq(td, p, td->td_remotereq); 2763140ceb5dSKonstantin Belousov break; 2764140ceb5dSKonstantin Belousov case TDB_SCREMOTEREQ: 2765140ceb5dSKonstantin Belousov ptrace_syscallreq(td, p, td->td_remotereq); 2766140ceb5dSKonstantin Belousov break; 2767140ceb5dSKonstantin Belousov default: 2768140ceb5dSKonstantin Belousov __unreachable(); 2769140ceb5dSKonstantin Belousov } 277087a64872SKonstantin Belousov PROC_LOCK(p); 2771140ceb5dSKonstantin Belousov 2772140ceb5dSKonstantin Belousov MPASS((td->td_dbgflags & flag) != 0); 2773140ceb5dSKonstantin Belousov td->td_dbgflags &= ~flag; 2774e6feeae2SKonstantin Belousov td->td_remotereq = NULL; 277587a64872SKonstantin Belousov wakeup(p); 277687a64872SKonstantin Belousov } 277787a64872SKonstantin Belousov 2778d4c4ca85SMark Johnston static void 2779c53fec76SKonstantin Belousov sig_suspend_threads(struct thread *td, struct proc *p) 2780d8267df7SDavid Xu { 2781d8267df7SDavid Xu struct thread *td2; 2782d8267df7SDavid Xu 2783d8267df7SDavid Xu PROC_LOCK_ASSERT(p, MA_OWNED); 27847b4a950aSDavid Xu PROC_SLOCK_ASSERT(p, MA_OWNED); 2785d8267df7SDavid Xu 2786d8267df7SDavid Xu FOREACH_THREAD_IN_PROC(p, td2) { 2787a54e85fdSJeff Roberson thread_lock(td2); 2788c6d31b83SKonstantin Belousov ast_sched_locked(td2, TDA_SUSPEND); 2789e24a6552SMark Johnston if (TD_IS_SLEEPING(td2) && (td2->td_flags & TDF_SINTR) != 0) { 2790f33a947bSKonstantin Belousov if (td2->td_flags & TDF_SBDRY) { 2791a120a7a3SJohn Baldwin /* 2792a120a7a3SJohn Baldwin * Once a thread is asleep with 27936f56cb8dSKonstantin Belousov * TDF_SBDRY and without TDF_SERESTART 27946f56cb8dSKonstantin Belousov * or TDF_SEINTR set, it should never 2795a120a7a3SJohn Baldwin * become suspended due to this check. 2796a120a7a3SJohn Baldwin */ 2797a120a7a3SJohn Baldwin KASSERT(!TD_IS_SUSPENDED(td2), 2798a120a7a3SJohn Baldwin ("thread with deferred stops suspended")); 279961a74c5cSJeff Roberson if (TD_SBDRY_INTR(td2)) { 2800d4c4ca85SMark Johnston sleepq_abort(td2, TD_SBDRY_ERRNO(td2)); 280161a74c5cSJeff Roberson continue; 2802f33a947bSKonstantin Belousov } 280361a74c5cSJeff Roberson } else if (!TD_IS_SUSPENDED(td2)) 280461a74c5cSJeff Roberson thread_suspend_one(td2); 2805f33a947bSKonstantin Belousov } else if (!TD_IS_SUSPENDED(td2)) { 2806d8267df7SDavid Xu #ifdef SMP 2807d8267df7SDavid Xu if (TD_IS_RUNNING(td2) && td2 != td) 2808d8267df7SDavid Xu forward_signal(td2); 2809d8267df7SDavid Xu #endif 2810d8267df7SDavid Xu } 2811a54e85fdSJeff Roberson thread_unlock(td2); 2812d8267df7SDavid Xu } 2813d8267df7SDavid Xu } 2814d8267df7SDavid Xu 281582a4538fSEric Badger /* 281682a4538fSEric Badger * Stop the process for an event deemed interesting to the debugger. If si is 281782a4538fSEric Badger * non-NULL, this is a signal exchange; the new signal requested by the 281882a4538fSEric Badger * debugger will be returned for handling. If si is NULL, this is some other 281982a4538fSEric Badger * type of interesting event. The debugger may request a signal be delivered in 282082a4538fSEric Badger * that case as well, however it will be deferred until it can be handled. 282182a4538fSEric Badger */ 2822cbf4e354SDavid Xu int 282382a4538fSEric Badger ptracestop(struct thread *td, int sig, ksiginfo_t *si) 28244cc9f52fSRobert Drehmel { 28254cc9f52fSRobert Drehmel struct proc *p = td->td_proc; 282682a4538fSEric Badger struct thread *td2; 282782a4538fSEric Badger ksiginfo_t ksi; 28284cc9f52fSRobert Drehmel 282930a9f26dSRobert Watson PROC_LOCK_ASSERT(p, MA_OWNED); 28300f14f15bSJohn Baldwin KASSERT(!(p->p_flag & P_WEXIT), ("Stopping exiting process")); 28314cc9f52fSRobert Drehmel WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, 2832aa89d8cdSJohn Baldwin &p->p_mtx.lock_object, "Stopping for traced signal"); 28334cc9f52fSRobert Drehmel 2834cbf4e354SDavid Xu td->td_xsig = sig; 283582a4538fSEric Badger 283682a4538fSEric Badger if (si == NULL || (si->ksi_flags & KSI_PTRACE) == 0) { 283782a4538fSEric Badger td->td_dbgflags |= TDB_XSIG; 2838515b7a0bSJohn Baldwin CTR4(KTR_PTRACE, "ptracestop: tid %d (pid %d) flags %#x sig %d", 2839515b7a0bSJohn Baldwin td->td_tid, p->p_pid, td->td_dbgflags, sig); 28407b4a950aSDavid Xu PROC_SLOCK(p); 2841904c5ec4SDavid Xu while ((p->p_flag & P_TRACED) && (td->td_dbgflags & TDB_XSIG)) { 284282a4538fSEric Badger if (P_KILLED(p)) { 284382a4538fSEric Badger /* 284482a4538fSEric Badger * Ensure that, if we've been PT_KILLed, the 284582a4538fSEric Badger * exit status reflects that. Another thread 284682a4538fSEric Badger * may also be in ptracestop(), having just 284782a4538fSEric Badger * received the SIGKILL, but this thread was 284882a4538fSEric Badger * unsuspended first. 284982a4538fSEric Badger */ 285082a4538fSEric Badger td->td_dbgflags &= ~TDB_XSIG; 285182a4538fSEric Badger td->td_xsig = SIGKILL; 285282a4538fSEric Badger p->p_ptevents = 0; 285382a4538fSEric Badger break; 285482a4538fSEric Badger } 28555fcfab6eSJohn Baldwin if (p->p_flag & P_SINGLE_EXIT && 28565fcfab6eSJohn Baldwin !(td->td_dbgflags & TDB_EXIT)) { 28575fcfab6eSJohn Baldwin /* 28585fcfab6eSJohn Baldwin * Ignore ptrace stops except for thread exit 28595fcfab6eSJohn Baldwin * events when the process exits. 28605fcfab6eSJohn Baldwin */ 2861904c5ec4SDavid Xu td->td_dbgflags &= ~TDB_XSIG; 28627b4a950aSDavid Xu PROC_SUNLOCK(p); 286382a4538fSEric Badger return (0); 2864cbf4e354SDavid Xu } 2865b7a25e63SKonstantin Belousov 2866cbf4e354SDavid Xu /* 2867b7a25e63SKonstantin Belousov * Make wait(2) work. Ensure that right after the 2868b7a25e63SKonstantin Belousov * attach, the thread which was decided to become the 2869b7a25e63SKonstantin Belousov * leader of attach gets reported to the waiter. 2870b7a25e63SKonstantin Belousov * Otherwise, just avoid overwriting another thread's 2871b7a25e63SKonstantin Belousov * assignment to p_xthread. If another thread has 2872b7a25e63SKonstantin Belousov * already set p_xthread, the current thread will get 2873b7a25e63SKonstantin Belousov * a chance to report itself upon the next iteration. 2874cbf4e354SDavid Xu */ 2875b7a25e63SKonstantin Belousov if ((td->td_dbgflags & TDB_FSTP) != 0 || 28767f649ddaSMark Johnston ((p->p_flag2 & P2_PTRACE_FSTP) == 0 && 2877b7a25e63SKonstantin Belousov p->p_xthread == NULL)) { 2878b4490c6eSKonstantin Belousov p->p_xsig = sig; 2879cbf4e354SDavid Xu p->p_xthread = td; 2880ab74c843SKonstantin Belousov 2881ab74c843SKonstantin Belousov /* 2882ab74c843SKonstantin Belousov * If we are on sleepqueue already, 2883ab74c843SKonstantin Belousov * let sleepqueue code decide if it 2884ab74c843SKonstantin Belousov * needs to go sleep after attach. 2885ab74c843SKonstantin Belousov */ 2886ab74c843SKonstantin Belousov if (td->td_wchan == NULL) 2887b7a25e63SKonstantin Belousov td->td_dbgflags &= ~TDB_FSTP; 2888ab74c843SKonstantin Belousov 2889b7a25e63SKonstantin Belousov p->p_flag2 &= ~P2_PTRACE_FSTP; 2890b7a25e63SKonstantin Belousov p->p_flag |= P_STOPPED_SIG | P_STOPPED_TRACE; 2891c53fec76SKonstantin Belousov sig_suspend_threads(td, p); 2892b7a25e63SKonstantin Belousov } 28936fa39a73SKonstantin Belousov if ((td->td_dbgflags & TDB_STOPATFORK) != 0) { 28946fa39a73SKonstantin Belousov td->td_dbgflags &= ~TDB_STOPATFORK; 28956fa39a73SKonstantin Belousov } 2896cbf4e354SDavid Xu stopme: 289768d311b6SKonstantin Belousov td->td_dbgflags |= TDB_SSWITCH; 28986ddcc233SKonstantin Belousov thread_suspend_switch(td, p); 289968d311b6SKonstantin Belousov td->td_dbgflags &= ~TDB_SSWITCH; 2900140ceb5dSKonstantin Belousov if ((td->td_dbgflags & (TDB_COREDUMPREQ | 2901140ceb5dSKonstantin Belousov TDB_SCREMOTEREQ)) != 0) { 2902140ceb5dSKonstantin Belousov MPASS((td->td_dbgflags & (TDB_COREDUMPREQ | 2903140ceb5dSKonstantin Belousov TDB_SCREMOTEREQ)) != 2904140ceb5dSKonstantin Belousov (TDB_COREDUMPREQ | TDB_SCREMOTEREQ)); 290587a64872SKonstantin Belousov PROC_SUNLOCK(p); 2906140ceb5dSKonstantin Belousov ptrace_remotereq(td, td->td_dbgflags & 2907140ceb5dSKonstantin Belousov (TDB_COREDUMPREQ | TDB_SCREMOTEREQ)); 290887a64872SKonstantin Belousov PROC_SLOCK(p); 290987a64872SKonstantin Belousov goto stopme; 291087a64872SKonstantin Belousov } 29117ce60f60SDavid Xu if (p->p_xthread == td) 29127ce60f60SDavid Xu p->p_xthread = NULL; 29137ce60f60SDavid Xu if (!(p->p_flag & P_TRACED)) 2914cbf4e354SDavid Xu break; 2915904c5ec4SDavid Xu if (td->td_dbgflags & TDB_SUSPEND) { 2916cbf4e354SDavid Xu if (p->p_flag & P_SINGLE_EXIT) 2917cbf4e354SDavid Xu break; 2918cbf4e354SDavid Xu goto stopme; 2919cbf4e354SDavid Xu } 2920cbf4e354SDavid Xu } 29217b4a950aSDavid Xu PROC_SUNLOCK(p); 292282a4538fSEric Badger } 292382a4538fSEric Badger 292482a4538fSEric Badger if (si != NULL && sig == td->td_xsig) { 292582a4538fSEric Badger /* Parent wants us to take the original signal unchanged. */ 292682a4538fSEric Badger si->ksi_flags |= KSI_HEAD; 292782a4538fSEric Badger if (sigqueue_add(&td->td_sigqueue, sig, si) != 0) 292882a4538fSEric Badger si->ksi_signo = 0; 292982a4538fSEric Badger } else if (td->td_xsig != 0) { 293082a4538fSEric Badger /* 293182a4538fSEric Badger * If parent wants us to take a new signal, then it will leave 293282a4538fSEric Badger * it in td->td_xsig; otherwise we just look for signals again. 293382a4538fSEric Badger */ 293482a4538fSEric Badger ksiginfo_init(&ksi); 293582a4538fSEric Badger ksi.ksi_signo = td->td_xsig; 293682a4538fSEric Badger ksi.ksi_flags |= KSI_PTRACE; 2937146fc63fSKonstantin Belousov td2 = sigtd(p, td->td_xsig, false); 293882a4538fSEric Badger tdsendsignal(p, td2, td->td_xsig, &ksi); 293982a4538fSEric Badger if (td != td2) 294082a4538fSEric Badger return (0); 294182a4538fSEric Badger } 294282a4538fSEric Badger 2943cbf4e354SDavid Xu return (td->td_xsig); 29444cc9f52fSRobert Drehmel } 29454cc9f52fSRobert Drehmel 29460bc52b0bSKonstantin Belousov static void 294780a8b0f3SKonstantin Belousov reschedule_signals(struct proc *p, sigset_t block, int flags) 29486b286ee8SKonstantin Belousov { 29496b286ee8SKonstantin Belousov struct sigacts *ps; 29506b286ee8SKonstantin Belousov struct thread *td; 2951407af02bSDavid Xu int sig; 2952146fc63fSKonstantin Belousov bool fastblk, pslocked; 29536b286ee8SKonstantin Belousov 29546b286ee8SKonstantin Belousov PROC_LOCK_ASSERT(p, MA_OWNED); 295570778bbaSKonstantin Belousov ps = p->p_sigacts; 2956146fc63fSKonstantin Belousov pslocked = (flags & SIGPROCMASK_PS_LOCKED) != 0; 2957146fc63fSKonstantin Belousov mtx_assert(&ps->ps_mtx, pslocked ? MA_OWNED : MA_NOTOWNED); 2958407af02bSDavid Xu if (SIGISEMPTY(p->p_siglist)) 2959407af02bSDavid Xu return; 2960407af02bSDavid Xu SIGSETAND(block, p->p_siglist); 2961146fc63fSKonstantin Belousov fastblk = (flags & SIGPROCMASK_FASTBLK) != 0; 296281f2e906SMark Johnston SIG_FOREACH(sig, &block) { 2963146fc63fSKonstantin Belousov td = sigtd(p, sig, fastblk); 2964146fc63fSKonstantin Belousov 2965146fc63fSKonstantin Belousov /* 2966146fc63fSKonstantin Belousov * If sigtd() selected us despite sigfastblock is 2967146fc63fSKonstantin Belousov * blocking, do not activate AST or wake us, to avoid 2968146fc63fSKonstantin Belousov * loop in AST handler. 2969146fc63fSKonstantin Belousov */ 2970146fc63fSKonstantin Belousov if (fastblk && td == curthread) 2971146fc63fSKonstantin Belousov continue; 2972146fc63fSKonstantin Belousov 29736b286ee8SKonstantin Belousov signotify(td); 2974146fc63fSKonstantin Belousov if (!pslocked) 29756b286ee8SKonstantin Belousov mtx_lock(&ps->ps_mtx); 2976396a0d44SKonstantin Belousov if (p->p_flag & P_TRACED || 2977396a0d44SKonstantin Belousov (SIGISMEMBER(ps->ps_sigcatch, sig) && 2978146fc63fSKonstantin Belousov !SIGISMEMBER(td->td_sigmask, sig))) { 2979407af02bSDavid Xu tdsigwakeup(td, sig, SIG_CATCH, 2980407af02bSDavid Xu (SIGISMEMBER(ps->ps_sigintr, sig) ? EINTR : 29816b286ee8SKonstantin Belousov ERESTART)); 2982146fc63fSKonstantin Belousov } 2983146fc63fSKonstantin Belousov if (!pslocked) 29846b286ee8SKonstantin Belousov mtx_unlock(&ps->ps_mtx); 29856b286ee8SKonstantin Belousov } 29866b286ee8SKonstantin Belousov } 29876b286ee8SKonstantin Belousov 29886b286ee8SKonstantin Belousov void 29896b286ee8SKonstantin Belousov tdsigcleanup(struct thread *td) 29906b286ee8SKonstantin Belousov { 29916b286ee8SKonstantin Belousov struct proc *p; 29926b286ee8SKonstantin Belousov sigset_t unblocked; 29936b286ee8SKonstantin Belousov 29946b286ee8SKonstantin Belousov p = td->td_proc; 29956b286ee8SKonstantin Belousov PROC_LOCK_ASSERT(p, MA_OWNED); 29966b286ee8SKonstantin Belousov 29976b286ee8SKonstantin Belousov sigqueue_flush(&td->td_sigqueue); 29986b286ee8SKonstantin Belousov if (p->p_numthreads == 1) 29996b286ee8SKonstantin Belousov return; 30006b286ee8SKonstantin Belousov 30016b286ee8SKonstantin Belousov /* 30026b286ee8SKonstantin Belousov * Since we cannot handle signals, notify signal post code 30036b286ee8SKonstantin Belousov * about this by filling the sigmask. 30046b286ee8SKonstantin Belousov * 30056b286ee8SKonstantin Belousov * Also, if needed, wake up thread(s) that do not block the 30066b286ee8SKonstantin Belousov * same signals as the exiting thread, since the thread might 30076b286ee8SKonstantin Belousov * have been selected for delivery and woken up. 30086b286ee8SKonstantin Belousov */ 30096b286ee8SKonstantin Belousov SIGFILLSET(unblocked); 30106b286ee8SKonstantin Belousov SIGSETNAND(unblocked, td->td_sigmask); 30116b286ee8SKonstantin Belousov SIGFILLSET(td->td_sigmask); 301280a8b0f3SKonstantin Belousov reschedule_signals(p, unblocked, 0); 30136b286ee8SKonstantin Belousov 30146b286ee8SKonstantin Belousov } 30156b286ee8SKonstantin Belousov 30163a1e5dd8SKonstantin Belousov static int 30173a1e5dd8SKonstantin Belousov sigdeferstop_curr_flags(int cflags) 3018a120a7a3SJohn Baldwin { 3019a120a7a3SJohn Baldwin 30203a1e5dd8SKonstantin Belousov MPASS((cflags & (TDF_SEINTR | TDF_SERESTART)) == 0 || 30213a1e5dd8SKonstantin Belousov (cflags & TDF_SBDRY) != 0); 30223a1e5dd8SKonstantin Belousov return (cflags & (TDF_SBDRY | TDF_SEINTR | TDF_SERESTART)); 3023a120a7a3SJohn Baldwin } 3024a120a7a3SJohn Baldwin 3025a120a7a3SJohn Baldwin /* 30263a1e5dd8SKonstantin Belousov * Defer the delivery of SIGSTOP for the current thread, according to 30273a1e5dd8SKonstantin Belousov * the requested mode. Returns previous flags, which must be restored 30283a1e5dd8SKonstantin Belousov * by sigallowstop(). 30293a1e5dd8SKonstantin Belousov * 30303a1e5dd8SKonstantin Belousov * TDF_SBDRY, TDF_SEINTR, and TDF_SERESTART flags are only set and 30313a1e5dd8SKonstantin Belousov * cleared by the current thread, which allow the lock-less read-only 30323a1e5dd8SKonstantin Belousov * accesses below. 3033a120a7a3SJohn Baldwin */ 3034e3612a4cSKonstantin Belousov int 303546e47c4fSKonstantin Belousov sigdeferstop_impl(int mode) 3036a120a7a3SJohn Baldwin { 3037593efaf9SJohn Baldwin struct thread *td; 30383a1e5dd8SKonstantin Belousov int cflags, nflags; 3039a120a7a3SJohn Baldwin 3040593efaf9SJohn Baldwin td = curthread; 30413a1e5dd8SKonstantin Belousov cflags = sigdeferstop_curr_flags(td->td_flags); 30423a1e5dd8SKonstantin Belousov switch (mode) { 30433a1e5dd8SKonstantin Belousov case SIGDEFERSTOP_NOP: 30443a1e5dd8SKonstantin Belousov nflags = cflags; 30453a1e5dd8SKonstantin Belousov break; 30463a1e5dd8SKonstantin Belousov case SIGDEFERSTOP_OFF: 30473a1e5dd8SKonstantin Belousov nflags = 0; 30483a1e5dd8SKonstantin Belousov break; 30493a1e5dd8SKonstantin Belousov case SIGDEFERSTOP_SILENT: 30503a1e5dd8SKonstantin Belousov nflags = (cflags | TDF_SBDRY) & ~(TDF_SEINTR | TDF_SERESTART); 30513a1e5dd8SKonstantin Belousov break; 30523a1e5dd8SKonstantin Belousov case SIGDEFERSTOP_EINTR: 30533a1e5dd8SKonstantin Belousov nflags = (cflags | TDF_SBDRY | TDF_SEINTR) & ~TDF_SERESTART; 30543a1e5dd8SKonstantin Belousov break; 30553a1e5dd8SKonstantin Belousov case SIGDEFERSTOP_ERESTART: 30563a1e5dd8SKonstantin Belousov nflags = (cflags | TDF_SBDRY | TDF_SERESTART) & ~TDF_SEINTR; 30573a1e5dd8SKonstantin Belousov break; 30583a1e5dd8SKonstantin Belousov default: 30593a1e5dd8SKonstantin Belousov panic("sigdeferstop: invalid mode %x", mode); 30603a1e5dd8SKonstantin Belousov break; 30613a1e5dd8SKonstantin Belousov } 306246e47c4fSKonstantin Belousov if (cflags == nflags) 306346e47c4fSKonstantin Belousov return (SIGDEFERSTOP_VAL_NCHG); 3064a120a7a3SJohn Baldwin thread_lock(td); 30653a1e5dd8SKonstantin Belousov td->td_flags = (td->td_flags & ~cflags) | nflags; 3066a120a7a3SJohn Baldwin thread_unlock(td); 30673a1e5dd8SKonstantin Belousov return (cflags); 30683a1e5dd8SKonstantin Belousov } 30693a1e5dd8SKonstantin Belousov 30703a1e5dd8SKonstantin Belousov /* 30713a1e5dd8SKonstantin Belousov * Restores the STOP handling mode, typically permitting the delivery 30723a1e5dd8SKonstantin Belousov * of SIGSTOP for the current thread. This does not immediately 30733a1e5dd8SKonstantin Belousov * suspend if a stop was posted. Instead, the thread will suspend 30743a1e5dd8SKonstantin Belousov * either via ast() or a subsequent interruptible sleep. 30753a1e5dd8SKonstantin Belousov */ 30763a1e5dd8SKonstantin Belousov void 307746e47c4fSKonstantin Belousov sigallowstop_impl(int prev) 30783a1e5dd8SKonstantin Belousov { 30793a1e5dd8SKonstantin Belousov struct thread *td; 30803a1e5dd8SKonstantin Belousov int cflags; 30813a1e5dd8SKonstantin Belousov 308246e47c4fSKonstantin Belousov KASSERT(prev != SIGDEFERSTOP_VAL_NCHG, ("failed sigallowstop")); 30833a1e5dd8SKonstantin Belousov KASSERT((prev & ~(TDF_SBDRY | TDF_SEINTR | TDF_SERESTART)) == 0, 30843a1e5dd8SKonstantin Belousov ("sigallowstop: incorrect previous mode %x", prev)); 30853a1e5dd8SKonstantin Belousov td = curthread; 30863a1e5dd8SKonstantin Belousov cflags = sigdeferstop_curr_flags(td->td_flags); 30873a1e5dd8SKonstantin Belousov if (cflags != prev) { 30883a1e5dd8SKonstantin Belousov thread_lock(td); 30893a1e5dd8SKonstantin Belousov td->td_flags = (td->td_flags & ~cflags) | prev; 30903a1e5dd8SKonstantin Belousov thread_unlock(td); 30913a1e5dd8SKonstantin Belousov } 3092a120a7a3SJohn Baldwin } 3093a120a7a3SJohn Baldwin 309481f2e906SMark Johnston enum sigstatus { 309581f2e906SMark Johnston SIGSTATUS_HANDLE, 309681f2e906SMark Johnston SIGSTATUS_HANDLED, 309781f2e906SMark Johnston SIGSTATUS_IGNORE, 309881f2e906SMark Johnston SIGSTATUS_SBDRY_STOP, 309981f2e906SMark Johnston }; 310081f2e906SMark Johnston 310181f2e906SMark Johnston /* 310281f2e906SMark Johnston * The thread has signal "sig" pending. Figure out what to do with it: 310381f2e906SMark Johnston * 310481f2e906SMark Johnston * _HANDLE -> the caller should handle the signal 310581f2e906SMark Johnston * _HANDLED -> handled internally, reload pending signal set 310681f2e906SMark Johnston * _IGNORE -> ignored, remove from the set of pending signals and try the 310781f2e906SMark Johnston * next pending signal 310881f2e906SMark Johnston * _SBDRY_STOP -> the signal should stop the thread but this is not 310981f2e906SMark Johnston * permitted in the current context 311081f2e906SMark Johnston */ 311181f2e906SMark Johnston static enum sigstatus 311281f2e906SMark Johnston sigprocess(struct thread *td, int sig) 311381f2e906SMark Johnston { 311481f2e906SMark Johnston struct proc *p; 311581f2e906SMark Johnston struct sigacts *ps; 311681f2e906SMark Johnston struct sigqueue *queue; 311781f2e906SMark Johnston ksiginfo_t ksi; 311881f2e906SMark Johnston int prop; 311981f2e906SMark Johnston 312081f2e906SMark Johnston KASSERT(_SIG_VALID(sig), ("%s: invalid signal %d", __func__, sig)); 312181f2e906SMark Johnston 312281f2e906SMark Johnston p = td->td_proc; 312381f2e906SMark Johnston ps = p->p_sigacts; 312481f2e906SMark Johnston mtx_assert(&ps->ps_mtx, MA_OWNED); 312581f2e906SMark Johnston PROC_LOCK_ASSERT(p, MA_OWNED); 312681f2e906SMark Johnston 312781f2e906SMark Johnston /* 312881f2e906SMark Johnston * We should allow pending but ignored signals below 312902a2aacbSKonstantin Belousov * if there is sigwait() active, or P_TRACED was 313081f2e906SMark Johnston * on when they were posted. 313181f2e906SMark Johnston */ 313281f2e906SMark Johnston if (SIGISMEMBER(ps->ps_sigignore, sig) && 313381f2e906SMark Johnston (p->p_flag & P_TRACED) == 0 && 313481f2e906SMark Johnston (td->td_flags & TDF_SIGWAIT) == 0) { 313581f2e906SMark Johnston return (SIGSTATUS_IGNORE); 313681f2e906SMark Johnston } 313781f2e906SMark Johnston 313802a2aacbSKonstantin Belousov /* 313902a2aacbSKonstantin Belousov * If the process is going to single-thread mode to prepare 314002a2aacbSKonstantin Belousov * for exit, there is no sense in delivering any signal 314102a2aacbSKonstantin Belousov * to usermode. Another important consequence is that 314202a2aacbSKonstantin Belousov * msleep(..., PCATCH, ...) now is only interruptible by a 314302a2aacbSKonstantin Belousov * suspend request. 314402a2aacbSKonstantin Belousov */ 314502a2aacbSKonstantin Belousov if ((p->p_flag2 & P2_WEXIT) != 0) 314602a2aacbSKonstantin Belousov return (SIGSTATUS_IGNORE); 314702a2aacbSKonstantin Belousov 314881f2e906SMark Johnston if ((p->p_flag & (P_TRACED | P_PPTRACE)) == P_TRACED) { 314981f2e906SMark Johnston /* 315081f2e906SMark Johnston * If traced, always stop. 315181f2e906SMark Johnston * Remove old signal from queue before the stop. 315281f2e906SMark Johnston * XXX shrug off debugger, it causes siginfo to 315381f2e906SMark Johnston * be thrown away. 315481f2e906SMark Johnston */ 315581f2e906SMark Johnston queue = &td->td_sigqueue; 315681f2e906SMark Johnston ksiginfo_init(&ksi); 315781f2e906SMark Johnston if (sigqueue_get(queue, sig, &ksi) == 0) { 315881f2e906SMark Johnston queue = &p->p_sigqueue; 315981f2e906SMark Johnston sigqueue_get(queue, sig, &ksi); 316081f2e906SMark Johnston } 316181f2e906SMark Johnston td->td_si = ksi.ksi_info; 316281f2e906SMark Johnston 316381f2e906SMark Johnston mtx_unlock(&ps->ps_mtx); 316481f2e906SMark Johnston sig = ptracestop(td, sig, &ksi); 316581f2e906SMark Johnston mtx_lock(&ps->ps_mtx); 316681f2e906SMark Johnston 316781f2e906SMark Johnston td->td_si.si_signo = 0; 316881f2e906SMark Johnston 316981f2e906SMark Johnston /* 317081f2e906SMark Johnston * Keep looking if the debugger discarded or 317181f2e906SMark Johnston * replaced the signal. 317281f2e906SMark Johnston */ 317381f2e906SMark Johnston if (sig == 0) 317481f2e906SMark Johnston return (SIGSTATUS_HANDLED); 317581f2e906SMark Johnston 317681f2e906SMark Johnston /* 317781f2e906SMark Johnston * If the signal became masked, re-queue it. 317881f2e906SMark Johnston */ 317981f2e906SMark Johnston if (SIGISMEMBER(td->td_sigmask, sig)) { 318081f2e906SMark Johnston ksi.ksi_flags |= KSI_HEAD; 318181f2e906SMark Johnston sigqueue_add(&p->p_sigqueue, sig, &ksi); 318281f2e906SMark Johnston return (SIGSTATUS_HANDLED); 318381f2e906SMark Johnston } 318481f2e906SMark Johnston 318581f2e906SMark Johnston /* 318681f2e906SMark Johnston * If the traced bit got turned off, requeue the signal and 318781f2e906SMark Johnston * reload the set of pending signals. This ensures that p_sig* 318881f2e906SMark Johnston * and p_sigact are consistent. 318981f2e906SMark Johnston */ 319081f2e906SMark Johnston if ((p->p_flag & P_TRACED) == 0) { 3191a24afbb4SKonstantin Belousov if ((ksi.ksi_flags & KSI_PTRACE) == 0) { 319281f2e906SMark Johnston ksi.ksi_flags |= KSI_HEAD; 319381f2e906SMark Johnston sigqueue_add(queue, sig, &ksi); 3194a24afbb4SKonstantin Belousov } 319581f2e906SMark Johnston return (SIGSTATUS_HANDLED); 319681f2e906SMark Johnston } 319781f2e906SMark Johnston } 319881f2e906SMark Johnston 319981f2e906SMark Johnston /* 320081f2e906SMark Johnston * Decide whether the signal should be returned. 320181f2e906SMark Johnston * Return the signal's number, or fall through 320281f2e906SMark Johnston * to clear it from the pending mask. 320381f2e906SMark Johnston */ 320481f2e906SMark Johnston switch ((intptr_t)p->p_sigacts->ps_sigact[_SIG_IDX(sig)]) { 320581f2e906SMark Johnston case (intptr_t)SIG_DFL: 320681f2e906SMark Johnston /* 320781f2e906SMark Johnston * Don't take default actions on system processes. 320881f2e906SMark Johnston */ 320981f2e906SMark Johnston if (p->p_pid <= 1) { 321081f2e906SMark Johnston #ifdef DIAGNOSTIC 321181f2e906SMark Johnston /* 321281f2e906SMark Johnston * Are you sure you want to ignore SIGSEGV 321381f2e906SMark Johnston * in init? XXX 321481f2e906SMark Johnston */ 321581f2e906SMark Johnston printf("Process (pid %lu) got signal %d\n", 321681f2e906SMark Johnston (u_long)p->p_pid, sig); 321781f2e906SMark Johnston #endif 321881f2e906SMark Johnston return (SIGSTATUS_IGNORE); 321981f2e906SMark Johnston } 322081f2e906SMark Johnston 322181f2e906SMark Johnston /* 322281f2e906SMark Johnston * If there is a pending stop signal to process with 322381f2e906SMark Johnston * default action, stop here, then clear the signal. 322481f2e906SMark Johnston * Traced or exiting processes should ignore stops. 322581f2e906SMark Johnston * Additionally, a member of an orphaned process group 322681f2e906SMark Johnston * should ignore tty stops. 322781f2e906SMark Johnston */ 322881f2e906SMark Johnston prop = sigprop(sig); 322981f2e906SMark Johnston if (prop & SIGPROP_STOP) { 323081f2e906SMark Johnston mtx_unlock(&ps->ps_mtx); 323181f2e906SMark Johnston if ((p->p_flag & (P_TRACED | P_WEXIT | 323281f2e906SMark Johnston P_SINGLE_EXIT)) != 0 || ((p->p_pgrp-> 323381f2e906SMark Johnston pg_flags & PGRP_ORPHANED) != 0 && 323481f2e906SMark Johnston (prop & SIGPROP_TTYSTOP) != 0)) { 323581f2e906SMark Johnston mtx_lock(&ps->ps_mtx); 323681f2e906SMark Johnston return (SIGSTATUS_IGNORE); 323781f2e906SMark Johnston } 323881f2e906SMark Johnston if (TD_SBDRY_INTR(td)) { 323981f2e906SMark Johnston KASSERT((td->td_flags & TDF_SBDRY) != 0, 324081f2e906SMark Johnston ("lost TDF_SBDRY")); 324181f2e906SMark Johnston mtx_lock(&ps->ps_mtx); 324281f2e906SMark Johnston return (SIGSTATUS_SBDRY_STOP); 324381f2e906SMark Johnston } 324481f2e906SMark Johnston WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, 324581f2e906SMark Johnston &p->p_mtx.lock_object, "Catching SIGSTOP"); 324681f2e906SMark Johnston sigqueue_delete(&td->td_sigqueue, sig); 324781f2e906SMark Johnston sigqueue_delete(&p->p_sigqueue, sig); 324881f2e906SMark Johnston p->p_flag |= P_STOPPED_SIG; 324981f2e906SMark Johnston p->p_xsig = sig; 325081f2e906SMark Johnston PROC_SLOCK(p); 3251c53fec76SKonstantin Belousov sig_suspend_threads(td, p); 325281f2e906SMark Johnston thread_suspend_switch(td, p); 325381f2e906SMark Johnston PROC_SUNLOCK(p); 325481f2e906SMark Johnston mtx_lock(&ps->ps_mtx); 325581f2e906SMark Johnston return (SIGSTATUS_HANDLED); 325681f2e906SMark Johnston } else if ((prop & SIGPROP_IGNORE) != 0 && 325781f2e906SMark Johnston (td->td_flags & TDF_SIGWAIT) == 0) { 325881f2e906SMark Johnston /* 325981f2e906SMark Johnston * Default action is to ignore; drop it if 326081f2e906SMark Johnston * not in kern_sigtimedwait(). 326181f2e906SMark Johnston */ 326281f2e906SMark Johnston return (SIGSTATUS_IGNORE); 326381f2e906SMark Johnston } else { 326481f2e906SMark Johnston return (SIGSTATUS_HANDLE); 326581f2e906SMark Johnston } 326681f2e906SMark Johnston 326781f2e906SMark Johnston case (intptr_t)SIG_IGN: 326881f2e906SMark Johnston if ((td->td_flags & TDF_SIGWAIT) == 0) 326981f2e906SMark Johnston return (SIGSTATUS_IGNORE); 327081f2e906SMark Johnston else 327181f2e906SMark Johnston return (SIGSTATUS_HANDLE); 327281f2e906SMark Johnston 327381f2e906SMark Johnston default: 327481f2e906SMark Johnston /* 327581f2e906SMark Johnston * This signal has an action, let postsig() process it. 327681f2e906SMark Johnston */ 327781f2e906SMark Johnston return (SIGSTATUS_HANDLE); 327881f2e906SMark Johnston } 327981f2e906SMark Johnston } 328081f2e906SMark Johnston 3281df8bae1dSRodney W. Grimes /* 3282df8bae1dSRodney W. Grimes * If the current process has received a signal (should be caught or cause 3283df8bae1dSRodney W. Grimes * termination, should interrupt current syscall), return the signal number. 3284df8bae1dSRodney W. Grimes * Stop signals with default action are processed immediately, then cleared; 3285df8bae1dSRodney W. Grimes * they aren't returned. This is checked after each entry to the system for 328681f2e906SMark Johnston * a syscall or trap (though this can usually be done without calling 328781f2e906SMark Johnston * issignal by checking the pending signal masks in cursig.) The normal call 3288df8bae1dSRodney W. Grimes * sequence is 3289df8bae1dSRodney W. Grimes * 3290e602ba25SJulian Elischer * while (sig = cursig(curthread)) 32912c42a146SMarcel Moolenaar * postsig(sig); 3292df8bae1dSRodney W. Grimes */ 32936711f10fSJohn Baldwin static int 32943cf3b9f0SJohn Baldwin issignal(struct thread *td) 3295df8bae1dSRodney W. Grimes { 3296e602ba25SJulian Elischer struct proc *p; 32974093529dSJeff Roberson sigset_t sigpending; 329881f2e906SMark Johnston int sig; 3299df8bae1dSRodney W. Grimes 3300e602ba25SJulian Elischer p = td->td_proc; 3301628d2653SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 330281f2e906SMark Johnston 3303df8bae1dSRodney W. Grimes for (;;) { 33049104847fSDavid Xu sigpending = td->td_sigqueue.sq_signals; 33056b286ee8SKonstantin Belousov SIGSETOR(sigpending, p->p_sigqueue.sq_signals); 33064093529dSJeff Roberson SIGSETNAND(sigpending, td->td_sigmask); 33074093529dSJeff Roberson 33086f56cb8dSKonstantin Belousov if ((p->p_flag & P_PPWAIT) != 0 || (td->td_flags & 33096f56cb8dSKonstantin Belousov (TDF_SBDRY | TDF_SERESTART | TDF_SEINTR)) == TDF_SBDRY) 33104093529dSJeff Roberson SIG_STOPSIGMASK(sigpending); 33114093529dSJeff Roberson if (SIGISEMPTY(sigpending)) /* no signal to send */ 3312df8bae1dSRodney W. Grimes return (0); 3313146fc63fSKonstantin Belousov 3314146fc63fSKonstantin Belousov /* 3315146fc63fSKonstantin Belousov * Do fast sigblock if requested by usermode. Since 3316146fc63fSKonstantin Belousov * we do know that there was a signal pending at this 3317146fc63fSKonstantin Belousov * point, set the FAST_SIGBLOCK_PEND as indicator for 3318146fc63fSKonstantin Belousov * usermode to perform a dummy call to 3319146fc63fSKonstantin Belousov * FAST_SIGBLOCK_UNBLOCK, which causes immediate 3320146fc63fSKonstantin Belousov * delivery of postponed pending signal. 3321146fc63fSKonstantin Belousov */ 3322146fc63fSKonstantin Belousov if ((td->td_pflags & TDP_SIGFASTBLOCK) != 0) { 3323146fc63fSKonstantin Belousov if (td->td_sigblock_val != 0) 3324146fc63fSKonstantin Belousov SIGSETNAND(sigpending, fastblock_mask); 3325146fc63fSKonstantin Belousov if (SIGISEMPTY(sigpending)) { 3326146fc63fSKonstantin Belousov td->td_pflags |= TDP_SIGFASTPENDING; 3327146fc63fSKonstantin Belousov return (0); 3328146fc63fSKonstantin Belousov } 3329146fc63fSKonstantin Belousov } 3330146fc63fSKonstantin Belousov 3331b7a25e63SKonstantin Belousov if ((p->p_flag & (P_TRACED | P_PPTRACE)) == P_TRACED && 3332b7a25e63SKonstantin Belousov (p->p_flag2 & P2_PTRACE_FSTP) != 0 && 3333b7a25e63SKonstantin Belousov SIGISMEMBER(sigpending, SIGSTOP)) { 3334b7a25e63SKonstantin Belousov /* 3335b7a25e63SKonstantin Belousov * If debugger just attached, always consume 3336b7a25e63SKonstantin Belousov * SIGSTOP from ptrace(PT_ATTACH) first, to 3337b7a25e63SKonstantin Belousov * execute the debugger attach ritual in 3338b7a25e63SKonstantin Belousov * order. 3339b7a25e63SKonstantin Belousov */ 3340b7a25e63SKonstantin Belousov td->td_dbgflags |= TDB_FSTP; 334181f2e906SMark Johnston SIGEMPTYSET(sigpending); 334281f2e906SMark Johnston SIGADDSET(sigpending, SIGSTOP); 3343b7a25e63SKonstantin Belousov } 33442a024a2bSSean Eric Fagan 334581f2e906SMark Johnston SIG_FOREACH(sig, &sigpending) { 334681f2e906SMark Johnston switch (sigprocess(td, sig)) { 334781f2e906SMark Johnston case SIGSTATUS_HANDLE: 334881f2e906SMark Johnston return (sig); 334981f2e906SMark Johnston case SIGSTATUS_HANDLED: 335081f2e906SMark Johnston goto next; 335181f2e906SMark Johnston case SIGSTATUS_IGNORE: 33529104847fSDavid Xu sigqueue_delete(&td->td_sigqueue, sig); 33536b286ee8SKonstantin Belousov sigqueue_delete(&p->p_sigqueue, sig); 335481f2e906SMark Johnston break; 335581f2e906SMark Johnston case SIGSTATUS_SBDRY_STOP: 335646e47c4fSKonstantin Belousov return (-1); 335746e47c4fSKonstantin Belousov } 3358df8bae1dSRodney W. Grimes } 3359b7a25e63SKonstantin Belousov next:; 3360df8bae1dSRodney W. Grimes } 3361df8bae1dSRodney W. Grimes } 3362df8bae1dSRodney W. Grimes 3363e574e444SDavid Xu void 3364e574e444SDavid Xu thread_stopped(struct proc *p) 3365e574e444SDavid Xu { 3366e574e444SDavid Xu int n; 3367e574e444SDavid Xu 3368e574e444SDavid Xu PROC_LOCK_ASSERT(p, MA_OWNED); 33697b4a950aSDavid Xu PROC_SLOCK_ASSERT(p, MA_OWNED); 3370e574e444SDavid Xu n = p->p_suspcount; 33717c9a98f1SDavid Xu if (p == curproc) 3372e574e444SDavid Xu n++; 3373e574e444SDavid Xu if ((p->p_flag & P_STOPPED_SIG) && (n == p->p_numthreads)) { 33747b4a950aSDavid Xu PROC_SUNLOCK(p); 3375407948a5SDavid Xu p->p_flag &= ~P_WAITED; 3376e574e444SDavid Xu PROC_LOCK(p->p_pptr); 33777f96995eSDavid Xu childproc_stopped(p, (p->p_flag & P_TRACED) ? 3378ebceaf6dSDavid Xu CLD_TRAPPED : CLD_STOPPED); 3379e574e444SDavid Xu PROC_UNLOCK(p->p_pptr); 33807b4a950aSDavid Xu PROC_SLOCK(p); 3381e574e444SDavid Xu } 3382e574e444SDavid Xu } 3383e574e444SDavid Xu 3384df8bae1dSRodney W. Grimes /* 3385df8bae1dSRodney W. Grimes * Take the action for the specified signal 3386df8bae1dSRodney W. Grimes * from the current set of pending signals. 3387df8bae1dSRodney W. Grimes */ 338875c586a4SKonstantin Belousov int 33890167b33bSKonstantin Belousov postsig(int sig) 3390df8bae1dSRodney W. Grimes { 33910167b33bSKonstantin Belousov struct thread *td; 33920167b33bSKonstantin Belousov struct proc *p; 3393628d2653SJohn Baldwin struct sigacts *ps; 33942c42a146SMarcel Moolenaar sig_t action; 33959104847fSDavid Xu ksiginfo_t ksi; 3396e442f29fSKonstantin Belousov sigset_t returnmask; 3397df8bae1dSRodney W. Grimes 33982c42a146SMarcel Moolenaar KASSERT(sig != 0, ("postsig")); 33995526d2d9SEivind Eklund 34000167b33bSKonstantin Belousov td = curthread; 34010167b33bSKonstantin Belousov p = td->td_proc; 34022ad7d304SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 3403628d2653SJohn Baldwin ps = p->p_sigacts; 340490af4afaSJohn Baldwin mtx_assert(&ps->ps_mtx, MA_OWNED); 34055da49fcbSDavid Xu ksiginfo_init(&ksi); 34066b286ee8SKonstantin Belousov if (sigqueue_get(&td->td_sigqueue, sig, &ksi) == 0 && 34076b286ee8SKonstantin Belousov sigqueue_get(&p->p_sigqueue, sig, &ksi) == 0) 340875c586a4SKonstantin Belousov return (0); 34099104847fSDavid Xu ksi.ksi_signo = sig; 341056c06c4bSDavid Xu if (ksi.ksi_code == SI_TIMER) 341156c06c4bSDavid Xu itimer_accept(p, ksi.ksi_timerid, &ksi); 34122c42a146SMarcel Moolenaar action = ps->ps_sigact[_SIG_IDX(sig)]; 3413df8bae1dSRodney W. Grimes #ifdef KTRACE 3414374a15aaSJohn Baldwin if (KTRPOINT(td, KTR_PSIG)) 34155e26dcb5SJohn Baldwin ktrpsig(sig, action, td->td_pflags & TDP_OLDMASK ? 341661009552SJilles Tjoelker &td->td_oldsigmask : &td->td_sigmask, ksi.ksi_code); 3417df8bae1dSRodney W. Grimes #endif 34182a024a2bSSean Eric Fagan 34198460a577SJohn Birrell if (action == SIG_DFL) { 3420df8bae1dSRodney W. Grimes /* 3421df8bae1dSRodney W. Grimes * Default action, where the default is to kill 3422df8bae1dSRodney W. Grimes * the process. (Other cases were ignored above.) 3423df8bae1dSRodney W. Grimes */ 342490af4afaSJohn Baldwin mtx_unlock(&ps->ps_mtx); 342586be94fcSTycho Nightingale proc_td_siginfo_capture(td, &ksi.ksi_info); 3426aaa92413SKonstantin Belousov sigexit(td, sig); 3427df8bae1dSRodney W. Grimes /* NOTREACHED */ 3428df8bae1dSRodney W. Grimes } else { 3429df8bae1dSRodney W. Grimes /* 3430df8bae1dSRodney W. Grimes * If we get here, the signal must be caught. 3431df8bae1dSRodney W. Grimes */ 3432cd735d8fSKonstantin Belousov KASSERT(action != SIG_IGN, ("postsig action %p", action)); 3433cd735d8fSKonstantin Belousov KASSERT(!SIGISMEMBER(td->td_sigmask, sig), 3434cd735d8fSKonstantin Belousov ("postsig action: blocked sig %d", sig)); 3435cd735d8fSKonstantin Belousov 3436df8bae1dSRodney W. Grimes /* 3437df8bae1dSRodney W. Grimes * Set the new mask value and also defer further 3438645682fdSLuoqi Chen * occurrences of this signal. 3439df8bae1dSRodney W. Grimes * 3440645682fdSLuoqi Chen * Special case: user has done a sigsuspend. Here the 3441df8bae1dSRodney W. Grimes * current mask is not of interest, but rather the 3442645682fdSLuoqi Chen * mask from before the sigsuspend is what we want 3443df8bae1dSRodney W. Grimes * restored after the signal processing is completed. 3444df8bae1dSRodney W. Grimes */ 34455e26dcb5SJohn Baldwin if (td->td_pflags & TDP_OLDMASK) { 34464093529dSJeff Roberson returnmask = td->td_oldsigmask; 34475e26dcb5SJohn Baldwin td->td_pflags &= ~TDP_OLDMASK; 3448df8bae1dSRodney W. Grimes } else 34494093529dSJeff Roberson returnmask = td->td_sigmask; 34502c42a146SMarcel Moolenaar 3451c90c9021SEd Schouten if (p->p_sig == sig) { 34526626c604SJulian Elischer p->p_sig = 0; 3453df8bae1dSRodney W. Grimes } 34549104847fSDavid Xu (*p->p_sysent->sv_sendsig)(action, &ksi, &returnmask); 3455e442f29fSKonstantin Belousov postsig_done(sig, td, ps); 3456df8bae1dSRodney W. Grimes } 345775c586a4SKonstantin Belousov return (1); 3458df8bae1dSRodney W. Grimes } 3459df8bae1dSRodney W. Grimes 34600c82fb26SKonstantin Belousov int 34610c82fb26SKonstantin Belousov sig_ast_checksusp(struct thread *td) 34620c82fb26SKonstantin Belousov { 34633d277851SKonstantin Belousov struct proc *p __diagused; 34640c82fb26SKonstantin Belousov int ret; 34650c82fb26SKonstantin Belousov 34660c82fb26SKonstantin Belousov p = td->td_proc; 34670c82fb26SKonstantin Belousov PROC_LOCK_ASSERT(p, MA_OWNED); 34680c82fb26SKonstantin Belousov 3469c6d31b83SKonstantin Belousov if (!td_ast_pending(td, TDA_SUSPEND)) 34700c82fb26SKonstantin Belousov return (0); 34710c82fb26SKonstantin Belousov 34720c82fb26SKonstantin Belousov ret = thread_suspend_check(1); 34730c82fb26SKonstantin Belousov MPASS(ret == 0 || ret == EINTR || ret == ERESTART); 34740c82fb26SKonstantin Belousov return (ret); 34750c82fb26SKonstantin Belousov } 34760c82fb26SKonstantin Belousov 34770c82fb26SKonstantin Belousov int 34780c82fb26SKonstantin Belousov sig_ast_needsigchk(struct thread *td) 34790c82fb26SKonstantin Belousov { 34800c82fb26SKonstantin Belousov struct proc *p; 34810c82fb26SKonstantin Belousov struct sigacts *ps; 34820c82fb26SKonstantin Belousov int ret, sig; 34830c82fb26SKonstantin Belousov 34840c82fb26SKonstantin Belousov p = td->td_proc; 34850c82fb26SKonstantin Belousov PROC_LOCK_ASSERT(p, MA_OWNED); 34860c82fb26SKonstantin Belousov 3487c6d31b83SKonstantin Belousov if (!td_ast_pending(td, TDA_SIG)) 34880c82fb26SKonstantin Belousov return (0); 34890c82fb26SKonstantin Belousov 34900c82fb26SKonstantin Belousov ps = p->p_sigacts; 34910c82fb26SKonstantin Belousov mtx_lock(&ps->ps_mtx); 34920c82fb26SKonstantin Belousov sig = cursig(td); 34930c82fb26SKonstantin Belousov if (sig == -1) { 34940c82fb26SKonstantin Belousov mtx_unlock(&ps->ps_mtx); 34950c82fb26SKonstantin Belousov KASSERT((td->td_flags & TDF_SBDRY) != 0, ("lost TDF_SBDRY")); 34960c82fb26SKonstantin Belousov KASSERT(TD_SBDRY_INTR(td), 34970c82fb26SKonstantin Belousov ("lost TDF_SERESTART of TDF_SEINTR")); 34980c82fb26SKonstantin Belousov KASSERT((td->td_flags & (TDF_SEINTR | TDF_SERESTART)) != 34990c82fb26SKonstantin Belousov (TDF_SEINTR | TDF_SERESTART), 35000c82fb26SKonstantin Belousov ("both TDF_SEINTR and TDF_SERESTART")); 35010c82fb26SKonstantin Belousov ret = TD_SBDRY_ERRNO(td); 35020c82fb26SKonstantin Belousov } else if (sig != 0) { 35030c82fb26SKonstantin Belousov ret = SIGISMEMBER(ps->ps_sigintr, sig) ? EINTR : ERESTART; 35040c82fb26SKonstantin Belousov mtx_unlock(&ps->ps_mtx); 35050c82fb26SKonstantin Belousov } else { 35060c82fb26SKonstantin Belousov mtx_unlock(&ps->ps_mtx); 35070c82fb26SKonstantin Belousov ret = 0; 35080c82fb26SKonstantin Belousov } 35090c82fb26SKonstantin Belousov 35100c82fb26SKonstantin Belousov /* 35110c82fb26SKonstantin Belousov * Do not go into sleep if this thread was the ptrace(2) 35120c82fb26SKonstantin Belousov * attach leader. cursig() consumed SIGSTOP from PT_ATTACH, 35130c82fb26SKonstantin Belousov * but we usually act on the signal by interrupting sleep, and 35140c82fb26SKonstantin Belousov * should do that here as well. 35150c82fb26SKonstantin Belousov */ 35160c82fb26SKonstantin Belousov if ((td->td_dbgflags & TDB_FSTP) != 0) { 35170c82fb26SKonstantin Belousov if (ret == 0) 35180c82fb26SKonstantin Belousov ret = EINTR; 35190c82fb26SKonstantin Belousov td->td_dbgflags &= ~TDB_FSTP; 35200c82fb26SKonstantin Belousov } 35210c82fb26SKonstantin Belousov 35220c82fb26SKonstantin Belousov return (ret); 35230c82fb26SKonstantin Belousov } 35240c82fb26SKonstantin Belousov 35250400be45SKonstantin Belousov int 35260400be45SKonstantin Belousov sig_intr(void) 35270400be45SKonstantin Belousov { 35280400be45SKonstantin Belousov struct thread *td; 35290400be45SKonstantin Belousov struct proc *p; 35300400be45SKonstantin Belousov int ret; 35310400be45SKonstantin Belousov 35320400be45SKonstantin Belousov td = curthread; 3533c6d31b83SKonstantin Belousov if (!td_ast_pending(td, TDA_SIG) && !td_ast_pending(td, TDA_SUSPEND)) 3534203dda8aSKonstantin Belousov return (0); 3535203dda8aSKonstantin Belousov 35360400be45SKonstantin Belousov p = td->td_proc; 35370400be45SKonstantin Belousov 35380400be45SKonstantin Belousov PROC_LOCK(p); 35390400be45SKonstantin Belousov ret = sig_ast_checksusp(td); 35400400be45SKonstantin Belousov if (ret == 0) 35410400be45SKonstantin Belousov ret = sig_ast_needsigchk(td); 35420400be45SKonstantin Belousov PROC_UNLOCK(p); 35430400be45SKonstantin Belousov return (ret); 35440400be45SKonstantin Belousov } 35450400be45SKonstantin Belousov 3546244ab566SKonstantin Belousov bool 3547244ab566SKonstantin Belousov curproc_sigkilled(void) 3548244ab566SKonstantin Belousov { 3549244ab566SKonstantin Belousov struct thread *td; 3550244ab566SKonstantin Belousov struct proc *p; 3551244ab566SKonstantin Belousov struct sigacts *ps; 3552244ab566SKonstantin Belousov bool res; 3553244ab566SKonstantin Belousov 3554244ab566SKonstantin Belousov td = curthread; 3555c6d31b83SKonstantin Belousov if (!td_ast_pending(td, TDA_SIG)) 3556244ab566SKonstantin Belousov return (false); 3557244ab566SKonstantin Belousov 3558244ab566SKonstantin Belousov p = td->td_proc; 3559244ab566SKonstantin Belousov PROC_LOCK(p); 3560244ab566SKonstantin Belousov ps = p->p_sigacts; 3561244ab566SKonstantin Belousov mtx_lock(&ps->ps_mtx); 3562244ab566SKonstantin Belousov res = SIGISMEMBER(td->td_sigqueue.sq_signals, SIGKILL) || 3563244ab566SKonstantin Belousov SIGISMEMBER(p->p_sigqueue.sq_signals, SIGKILL); 3564244ab566SKonstantin Belousov mtx_unlock(&ps->ps_mtx); 3565244ab566SKonstantin Belousov PROC_UNLOCK(p); 3566244ab566SKonstantin Belousov return (res); 3567244ab566SKonstantin Belousov } 3568244ab566SKonstantin Belousov 3569a70e9a13SKonstantin Belousov void 3570a70e9a13SKonstantin Belousov proc_wkilled(struct proc *p) 3571a70e9a13SKonstantin Belousov { 3572a70e9a13SKonstantin Belousov 3573a70e9a13SKonstantin Belousov PROC_LOCK_ASSERT(p, MA_OWNED); 3574e24a6552SMark Johnston if ((p->p_flag & P_WKILLED) == 0) 3575a70e9a13SKonstantin Belousov p->p_flag |= P_WKILLED; 3576a70e9a13SKonstantin Belousov } 3577a70e9a13SKonstantin Belousov 3578df8bae1dSRodney W. Grimes /* 3579df8bae1dSRodney W. Grimes * Kill the current process for stated reason. 3580df8bae1dSRodney W. Grimes */ 358126f9a767SRodney W. Grimes void 3582fe20aaecSRyan Libby killproc(struct proc *p, const char *why) 3583df8bae1dSRodney W. Grimes { 35849081e5e8SJohn Baldwin 35859081e5e8SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 3586c3209846SPawel Jakub Dawidek CTR3(KTR_PROC, "killproc: proc %p (pid %d, %s)", p, p->p_pid, 3587c3209846SPawel Jakub Dawidek p->p_comm); 3588af8beccaSKristof Provost log(LOG_ERR, "pid %d (%s), jid %d, uid %d, was killed: %s\n", 35894ae4822dSKristof Provost p->p_pid, p->p_comm, p->p_ucred->cr_prison->pr_id, 3590de2d0d29SKristof Provost p->p_ucred->cr_uid, why); 3591a70e9a13SKonstantin Belousov proc_wkilled(p); 35928451d0ddSKip Macy kern_psignal(p, SIGKILL); 3593df8bae1dSRodney W. Grimes } 3594df8bae1dSRodney W. Grimes 3595df8bae1dSRodney W. Grimes /* 3596df8bae1dSRodney W. Grimes * Force the current process to exit with the specified signal, dumping core 3597df8bae1dSRodney W. Grimes * if appropriate. We bypass the normal tests for masked and caught signals, 3598df8bae1dSRodney W. Grimes * allowing unrecoverable failures to terminate the process without changing 3599df8bae1dSRodney W. Grimes * signal state. Mark the accounting record with the signal termination. 3600df8bae1dSRodney W. Grimes * If dumping core, save the signal number for the debugger. Calls exit and 3601df8bae1dSRodney W. Grimes * does not return. 3602df8bae1dSRodney W. Grimes */ 3603aaa92413SKonstantin Belousov void 3604aaa92413SKonstantin Belousov sigexit(struct thread *td, int sig) 3605df8bae1dSRodney W. Grimes { 3606b40ce416SJulian Elischer struct proc *p = td->td_proc; 36076edbe561SEd Maste const char *coreinfo; 36086edbe561SEd Maste int rv; 3609df8bae1dSRodney W. Grimes 3610628d2653SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 36114493a13eSKonstantin Belousov proc_set_p2_wexit(p); 36124493a13eSKonstantin Belousov 3613df8bae1dSRodney W. Grimes p->p_acflag |= AXSIG; 3614f97c3df1SDavid Schultz /* 3615f97c3df1SDavid Schultz * We must be single-threading to generate a core dump. This 3616f97c3df1SDavid Schultz * ensures that the registers in the core file are up-to-date. 3617f97c3df1SDavid Schultz * Also, the ELF dump handler assumes that the thread list doesn't 3618f97c3df1SDavid Schultz * change out from under it. 3619f97c3df1SDavid Schultz * 3620f97c3df1SDavid Schultz * XXX If another thread attempts to single-thread before us 3621f97c3df1SDavid Schultz * (e.g. via fork()), we won't get a dump at all. 3622f97c3df1SDavid Schultz */ 3623fd50a707SBrooks Davis if ((sigprop(sig) & SIGPROP_CORE) && 3624fd50a707SBrooks Davis thread_single(p, SINGLE_NO_EXIT) == 0) { 36252c42a146SMarcel Moolenaar p->p_sig = sig; 3626c364e17eSAndrey A. Chernov /* 3627c364e17eSAndrey A. Chernov * Log signals which would cause core dumps 3628c364e17eSAndrey A. Chernov * (Log as LOG_INFO to appease those who don't want 3629c364e17eSAndrey A. Chernov * these messages.) 3630c364e17eSAndrey A. Chernov * XXX : Todo, as well as euid, write out ruid too 36314ae89b95SJohn Baldwin * Note that coredump() drops proc lock. 3632c364e17eSAndrey A. Chernov */ 36336edbe561SEd Maste rv = coredump(td); 36346edbe561SEd Maste switch (rv) { 36356edbe561SEd Maste case 0: 36362c42a146SMarcel Moolenaar sig |= WCOREFLAG; 36376edbe561SEd Maste coreinfo = " (core dumped)"; 36386edbe561SEd Maste break; 36396edbe561SEd Maste case EFAULT: 36406edbe561SEd Maste coreinfo = " (no core dump - bad address)"; 36416edbe561SEd Maste break; 36426edbe561SEd Maste case EINVAL: 36436edbe561SEd Maste coreinfo = " (no core dump - invalid argument)"; 36446edbe561SEd Maste break; 36456edbe561SEd Maste case EFBIG: 36466edbe561SEd Maste coreinfo = " (no core dump - too large)"; 36476edbe561SEd Maste break; 36486edbe561SEd Maste default: 36496edbe561SEd Maste coreinfo = " (no core dump - other error)"; 36501a6238d1SEd Maste break; 36516edbe561SEd Maste } 365257308494SJoerg Wunsch if (kern_logsigexit) 365357308494SJoerg Wunsch log(LOG_INFO, 3654af8beccaSKristof Provost "pid %d (%s), jid %d, uid %d: exited on " 36554ae4822dSKristof Provost "signal %d%s\n", p->p_pid, p->p_comm, 36564ae4822dSKristof Provost p->p_ucred->cr_prison->pr_id, 3657de2d0d29SKristof Provost td->td_ucred->cr_uid, 36586edbe561SEd Maste sig &~ WCOREFLAG, coreinfo); 36594ae89b95SJohn Baldwin } else 3660628d2653SJohn Baldwin PROC_UNLOCK(p); 3661aaa92413SKonstantin Belousov exit1(td, 0, sig); 3662df8bae1dSRodney W. Grimes /* NOTREACHED */ 3663df8bae1dSRodney W. Grimes } 3664df8bae1dSRodney W. Grimes 3665ebceaf6dSDavid Xu /* 36667f96995eSDavid Xu * Send queued SIGCHLD to parent when child process's state 36677f96995eSDavid Xu * is changed. 3668ebceaf6dSDavid Xu */ 36697f96995eSDavid Xu static void 36707f96995eSDavid Xu sigparent(struct proc *p, int reason, int status) 3671ebceaf6dSDavid Xu { 3672ebceaf6dSDavid Xu PROC_LOCK_ASSERT(p, MA_OWNED); 3673ebceaf6dSDavid Xu PROC_LOCK_ASSERT(p->p_pptr, MA_OWNED); 3674ebceaf6dSDavid Xu 3675ebceaf6dSDavid Xu if (p->p_ksi != NULL) { 3676ebceaf6dSDavid Xu p->p_ksi->ksi_signo = SIGCHLD; 3677ebceaf6dSDavid Xu p->p_ksi->ksi_code = reason; 36787f96995eSDavid Xu p->p_ksi->ksi_status = status; 3679ebceaf6dSDavid Xu p->p_ksi->ksi_pid = p->p_pid; 3680ebceaf6dSDavid Xu p->p_ksi->ksi_uid = p->p_ucred->cr_ruid; 3681ebceaf6dSDavid Xu if (KSI_ONQ(p->p_ksi)) 3682ebceaf6dSDavid Xu return; 3683ebceaf6dSDavid Xu } 3684ad6eec7bSJohn Baldwin pksignal(p->p_pptr, SIGCHLD, p->p_ksi); 3685ebceaf6dSDavid Xu } 3686ebceaf6dSDavid Xu 36877f96995eSDavid Xu static void 3688b20a9aa9SJilles Tjoelker childproc_jobstate(struct proc *p, int reason, int sig) 36897f96995eSDavid Xu { 36907f96995eSDavid Xu struct sigacts *ps; 36917f96995eSDavid Xu 36927f96995eSDavid Xu PROC_LOCK_ASSERT(p, MA_OWNED); 36937f96995eSDavid Xu PROC_LOCK_ASSERT(p->p_pptr, MA_OWNED); 36947f96995eSDavid Xu 36957f96995eSDavid Xu /* 36967f96995eSDavid Xu * Wake up parent sleeping in kern_wait(), also send 36977f96995eSDavid Xu * SIGCHLD to parent, but SIGCHLD does not guarantee 36987f96995eSDavid Xu * that parent will awake, because parent may masked 36997f96995eSDavid Xu * the signal. 37007f96995eSDavid Xu */ 37017f96995eSDavid Xu p->p_pptr->p_flag |= P_STATCHILD; 37027f96995eSDavid Xu wakeup(p->p_pptr); 37037f96995eSDavid Xu 37047f96995eSDavid Xu ps = p->p_pptr->p_sigacts; 37057f96995eSDavid Xu mtx_lock(&ps->ps_mtx); 37067f96995eSDavid Xu if ((ps->ps_flag & PS_NOCLDSTOP) == 0) { 37077f96995eSDavid Xu mtx_unlock(&ps->ps_mtx); 3708b20a9aa9SJilles Tjoelker sigparent(p, reason, sig); 37097f96995eSDavid Xu } else 37107f96995eSDavid Xu mtx_unlock(&ps->ps_mtx); 37117f96995eSDavid Xu } 37127f96995eSDavid Xu 37137f96995eSDavid Xu void 37147f96995eSDavid Xu childproc_stopped(struct proc *p, int reason) 37157f96995eSDavid Xu { 3716b4490c6eSKonstantin Belousov 3717b4490c6eSKonstantin Belousov childproc_jobstate(p, reason, p->p_xsig); 37187f96995eSDavid Xu } 37197f96995eSDavid Xu 3720ebceaf6dSDavid Xu void 3721ebceaf6dSDavid Xu childproc_continued(struct proc *p) 3722ebceaf6dSDavid Xu { 37237f96995eSDavid Xu childproc_jobstate(p, CLD_CONTINUED, SIGCONT); 3724ebceaf6dSDavid Xu } 3725ebceaf6dSDavid Xu 3726ebceaf6dSDavid Xu void 3727ebceaf6dSDavid Xu childproc_exited(struct proc *p) 3728ebceaf6dSDavid Xu { 3729b4490c6eSKonstantin Belousov int reason, status; 3730ebceaf6dSDavid Xu 3731b4490c6eSKonstantin Belousov if (WCOREDUMP(p->p_xsig)) { 3732b4490c6eSKonstantin Belousov reason = CLD_DUMPED; 3733b4490c6eSKonstantin Belousov status = WTERMSIG(p->p_xsig); 3734b4490c6eSKonstantin Belousov } else if (WIFSIGNALED(p->p_xsig)) { 3735b4490c6eSKonstantin Belousov reason = CLD_KILLED; 3736b4490c6eSKonstantin Belousov status = WTERMSIG(p->p_xsig); 3737b4490c6eSKonstantin Belousov } else { 3738b4490c6eSKonstantin Belousov reason = CLD_EXITED; 3739b4490c6eSKonstantin Belousov status = p->p_xexit; 3740b4490c6eSKonstantin Belousov } 37417f96995eSDavid Xu /* 37427f96995eSDavid Xu * XXX avoid calling wakeup(p->p_pptr), the work is 37437f96995eSDavid Xu * done in exit1(). 37447f96995eSDavid Xu */ 37457f96995eSDavid Xu sigparent(p, reason, status); 3746ebceaf6dSDavid Xu } 3747ebceaf6dSDavid Xu 3748f1fe1e02SMariusz Zaborski #define MAX_NUM_CORE_FILES 100000 3749cc37baeaSStephen J. Kiernan #ifndef NUM_CORE_FILES 3750cc37baeaSStephen J. Kiernan #define NUM_CORE_FILES 5 3751cc37baeaSStephen J. Kiernan #endif 3752cc37baeaSStephen J. Kiernan CTASSERT(NUM_CORE_FILES >= 0 && NUM_CORE_FILES <= MAX_NUM_CORE_FILES); 3753cc37baeaSStephen J. Kiernan static int num_cores = NUM_CORE_FILES; 3754e7228204SAlfred Perlstein 3755e7228204SAlfred Perlstein static int 3756e7228204SAlfred Perlstein sysctl_debug_num_cores_check (SYSCTL_HANDLER_ARGS) 3757e7228204SAlfred Perlstein { 3758e7228204SAlfred Perlstein int error; 3759e7228204SAlfred Perlstein int new_val; 3760e7228204SAlfred Perlstein 3761c5105012SKonstantin Belousov new_val = num_cores; 3762e7228204SAlfred Perlstein error = sysctl_handle_int(oidp, &new_val, 0, req); 3763e7228204SAlfred Perlstein if (error != 0 || req->newptr == NULL) 3764e7228204SAlfred Perlstein return (error); 3765cc37baeaSStephen J. Kiernan if (new_val > MAX_NUM_CORE_FILES) 3766cc37baeaSStephen J. Kiernan new_val = MAX_NUM_CORE_FILES; 3767e7228204SAlfred Perlstein if (new_val < 0) 3768e7228204SAlfred Perlstein new_val = 0; 3769e7228204SAlfred Perlstein num_cores = new_val; 3770e7228204SAlfred Perlstein return (0); 3771e7228204SAlfred Perlstein } 37727029da5cSPawel Biernacki SYSCTL_PROC(_debug, OID_AUTO, ncores, 3773fe27f1dbSAlexander Motin CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 0, sizeof(int), 37747029da5cSPawel Biernacki sysctl_debug_num_cores_check, "I", 37756cad1a5dSMariusz Zaborski "Maximum number of generated process corefiles while using index format"); 3776e7228204SAlfred Perlstein 37776026dcd7SMark Johnston #define GZIP_SUFFIX ".gz" 37786026dcd7SMark Johnston #define ZSTD_SUFFIX ".zst" 3779aa14e9b7SMark Johnston 378078f57a9cSMark Johnston int compress_user_cores = 0; 3781e7228204SAlfred Perlstein 378278f57a9cSMark Johnston static int 378378f57a9cSMark Johnston sysctl_compress_user_cores(SYSCTL_HANDLER_ARGS) 378478f57a9cSMark Johnston { 378578f57a9cSMark Johnston int error, val; 378678f57a9cSMark Johnston 378778f57a9cSMark Johnston val = compress_user_cores; 378878f57a9cSMark Johnston error = sysctl_handle_int(oidp, &val, 0, req); 378978f57a9cSMark Johnston if (error != 0 || req->newptr == NULL) 379078f57a9cSMark Johnston return (error); 379178f57a9cSMark Johnston if (val != 0 && !compressor_avail(val)) 379278f57a9cSMark Johnston return (EINVAL); 379378f57a9cSMark Johnston compress_user_cores = val; 379478f57a9cSMark Johnston return (error); 379578f57a9cSMark Johnston } 37967029da5cSPawel Biernacki SYSCTL_PROC(_kern, OID_AUTO, compress_user_cores, 37977029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, 0, sizeof(int), 37987029da5cSPawel Biernacki sysctl_compress_user_cores, "I", 37996026dcd7SMark Johnston "Enable compression of user corefiles (" 38006026dcd7SMark Johnston __XSTRING(COMPRESS_GZIP) " = gzip, " 38016026dcd7SMark Johnston __XSTRING(COMPRESS_ZSTD) " = zstd)"); 380278f57a9cSMark Johnston 380378f57a9cSMark Johnston int compress_user_cores_level = 6; 380478f57a9cSMark Johnston SYSCTL_INT(_kern, OID_AUTO, compress_user_cores_level, CTLFLAG_RWTUN, 380578f57a9cSMark Johnston &compress_user_cores_level, 0, 380678f57a9cSMark Johnston "Corefile compression level"); 3807e7228204SAlfred Perlstein 38085bc0ff88SMateusz Guzik /* 38095bc0ff88SMateusz Guzik * Protect the access to corefilename[] by allproc_lock. 38105bc0ff88SMateusz Guzik */ 38115bc0ff88SMateusz Guzik #define corefilename_lock allproc_lock 38125bc0ff88SMateusz Guzik 38136d1ab6edSWarner Losh static char corefilename[MAXPATHLEN] = {"%N.core"}; 3814fb4cdc96SMariusz Zaborski TUNABLE_STR("kern.corefile", corefilename, sizeof(corefilename)); 38155bc0ff88SMateusz Guzik 38165bc0ff88SMateusz Guzik static int 38175bc0ff88SMateusz Guzik sysctl_kern_corefile(SYSCTL_HANDLER_ARGS) 38185bc0ff88SMateusz Guzik { 38195bc0ff88SMateusz Guzik int error; 38205bc0ff88SMateusz Guzik 38215bc0ff88SMateusz Guzik sx_xlock(&corefilename_lock); 38225bc0ff88SMateusz Guzik error = sysctl_handle_string(oidp, corefilename, sizeof(corefilename), 38235bc0ff88SMateusz Guzik req); 38245bc0ff88SMateusz Guzik sx_xunlock(&corefilename_lock); 38255bc0ff88SMateusz Guzik 38265bc0ff88SMateusz Guzik return (error); 38275bc0ff88SMateusz Guzik } 3828fb4cdc96SMariusz Zaborski SYSCTL_PROC(_kern, OID_AUTO, corefile, CTLTYPE_STRING | CTLFLAG_RW | 38295bc0ff88SMateusz Guzik CTLFLAG_MPSAFE, 0, 0, sysctl_kern_corefile, "A", 38305bc0ff88SMateusz Guzik "Process corefile name format string"); 3831c5edb423SSean Eric Fagan 38320dea6e3cSMariusz Zaborski static void 38330dea6e3cSMariusz Zaborski vnode_close_locked(struct thread *td, struct vnode *vp) 38340dea6e3cSMariusz Zaborski { 38350dea6e3cSMariusz Zaborski 3836b249ce48SMateusz Guzik VOP_UNLOCK(vp); 38370dea6e3cSMariusz Zaborski vn_close(vp, FWRITE, td->td_ucred, td); 38380dea6e3cSMariusz Zaborski } 38390dea6e3cSMariusz Zaborski 38400dea6e3cSMariusz Zaborski /* 38410dea6e3cSMariusz Zaborski * If the core format has a %I in it, then we need to check 38420dea6e3cSMariusz Zaborski * for existing corefiles before defining a name. 3843f1fe1e02SMariusz Zaborski * To do this we iterate over 0..ncores to find a 38440dea6e3cSMariusz Zaborski * non-existing core file name to use. If all core files are 38450dea6e3cSMariusz Zaborski * already used we choose the oldest one. 38460dea6e3cSMariusz Zaborski */ 38470dea6e3cSMariusz Zaborski static int 38480dea6e3cSMariusz Zaborski corefile_open_last(struct thread *td, char *name, int indexpos, 3849f1fe1e02SMariusz Zaborski int indexlen, int ncores, struct vnode **vpp) 38500dea6e3cSMariusz Zaborski { 38510dea6e3cSMariusz Zaborski struct vnode *oldvp, *nextvp, *vp; 38520dea6e3cSMariusz Zaborski struct vattr vattr; 38530dea6e3cSMariusz Zaborski struct nameidata nd; 38540dea6e3cSMariusz Zaborski int error, i, flags, oflags, cmode; 3855f1fe1e02SMariusz Zaborski char ch; 38560dea6e3cSMariusz Zaborski struct timespec lasttime; 38570dea6e3cSMariusz Zaborski 38580dea6e3cSMariusz Zaborski nextvp = oldvp = NULL; 38590dea6e3cSMariusz Zaborski cmode = S_IRUSR | S_IWUSR; 38600dea6e3cSMariusz Zaborski oflags = VN_OPEN_NOAUDIT | VN_OPEN_NAMECACHE | 38610dea6e3cSMariusz Zaborski (capmode_coredump ? VN_OPEN_NOCAPCHECK : 0); 38620dea6e3cSMariusz Zaborski 3863f1fe1e02SMariusz Zaborski for (i = 0; i < ncores; i++) { 38640dea6e3cSMariusz Zaborski flags = O_CREAT | FWRITE | O_NOFOLLOW; 3865f1fe1e02SMariusz Zaborski 3866f1fe1e02SMariusz Zaborski ch = name[indexpos + indexlen]; 3867f1fe1e02SMariusz Zaborski (void)snprintf(name + indexpos, indexlen + 1, "%.*u", indexlen, 3868f1fe1e02SMariusz Zaborski i); 3869f1fe1e02SMariusz Zaborski name[indexpos + indexlen] = ch; 38700dea6e3cSMariusz Zaborski 38717e1d3eefSMateusz Guzik NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, name); 38720dea6e3cSMariusz Zaborski error = vn_open_cred(&nd, &flags, cmode, oflags, td->td_ucred, 38730dea6e3cSMariusz Zaborski NULL); 38740dea6e3cSMariusz Zaborski if (error != 0) 38750dea6e3cSMariusz Zaborski break; 38760dea6e3cSMariusz Zaborski 38770dea6e3cSMariusz Zaborski vp = nd.ni_vp; 3878bb92cd7bSMateusz Guzik NDFREE_PNBUF(&nd); 38790dea6e3cSMariusz Zaborski if ((flags & O_CREAT) == O_CREAT) { 38800dea6e3cSMariusz Zaborski nextvp = vp; 38810dea6e3cSMariusz Zaborski break; 38820dea6e3cSMariusz Zaborski } 38830dea6e3cSMariusz Zaborski 38840dea6e3cSMariusz Zaborski error = VOP_GETATTR(vp, &vattr, td->td_ucred); 38850dea6e3cSMariusz Zaborski if (error != 0) { 38860dea6e3cSMariusz Zaborski vnode_close_locked(td, vp); 38870dea6e3cSMariusz Zaborski break; 38880dea6e3cSMariusz Zaborski } 38890dea6e3cSMariusz Zaborski 38900dea6e3cSMariusz Zaborski if (oldvp == NULL || 38910dea6e3cSMariusz Zaborski lasttime.tv_sec > vattr.va_mtime.tv_sec || 38920dea6e3cSMariusz Zaborski (lasttime.tv_sec == vattr.va_mtime.tv_sec && 38930dea6e3cSMariusz Zaborski lasttime.tv_nsec >= vattr.va_mtime.tv_nsec)) { 38940dea6e3cSMariusz Zaborski if (oldvp != NULL) 3895e298466eSAndriy Gapon vn_close(oldvp, FWRITE, td->td_ucred, td); 38960dea6e3cSMariusz Zaborski oldvp = vp; 3897e298466eSAndriy Gapon VOP_UNLOCK(oldvp); 38980dea6e3cSMariusz Zaborski lasttime = vattr.va_mtime; 38990dea6e3cSMariusz Zaborski } else { 39000dea6e3cSMariusz Zaborski vnode_close_locked(td, vp); 39010dea6e3cSMariusz Zaborski } 39020dea6e3cSMariusz Zaborski } 39030dea6e3cSMariusz Zaborski 39040dea6e3cSMariusz Zaborski if (oldvp != NULL) { 390589f2ab06SKonstantin Belousov if (nextvp == NULL) { 390689f2ab06SKonstantin Belousov if ((td->td_proc->p_flag & P_SUGID) != 0) { 390789f2ab06SKonstantin Belousov error = EFAULT; 3908e298466eSAndriy Gapon vn_close(oldvp, FWRITE, td->td_ucred, td); 390989f2ab06SKonstantin Belousov } else { 391089f2ab06SKonstantin Belousov nextvp = oldvp; 3911e298466eSAndriy Gapon error = vn_lock(nextvp, LK_EXCLUSIVE); 3912e298466eSAndriy Gapon if (error != 0) { 3913e298466eSAndriy Gapon vn_close(nextvp, FWRITE, td->td_ucred, 3914e298466eSAndriy Gapon td); 3915e298466eSAndriy Gapon nextvp = NULL; 3916e298466eSAndriy Gapon } 391789f2ab06SKonstantin Belousov } 391889f2ab06SKonstantin Belousov } else { 3919e298466eSAndriy Gapon vn_close(oldvp, FWRITE, td->td_ucred, td); 392089f2ab06SKonstantin Belousov } 39210dea6e3cSMariusz Zaborski } 39220dea6e3cSMariusz Zaborski if (error != 0) { 39230dea6e3cSMariusz Zaborski if (nextvp != NULL) 39240dea6e3cSMariusz Zaborski vnode_close_locked(td, oldvp); 39250dea6e3cSMariusz Zaborski } else { 39260dea6e3cSMariusz Zaborski *vpp = nextvp; 39270dea6e3cSMariusz Zaborski } 39280dea6e3cSMariusz Zaborski 39290dea6e3cSMariusz Zaborski return (error); 39300dea6e3cSMariusz Zaborski } 39310dea6e3cSMariusz Zaborski 3932c5edb423SSean Eric Fagan /* 3933c345faeaSPawel Jakub Dawidek * corefile_open(comm, uid, pid, td, compress, vpp, namep) 3934c345faeaSPawel Jakub Dawidek * Expand the name described in corefilename, using name, uid, and pid 3935c345faeaSPawel Jakub Dawidek * and open/create core file. 3936c5edb423SSean Eric Fagan * corefilename is a printf-like string, with three format specifiers: 3937c5edb423SSean Eric Fagan * %N name of process ("name") 3938c5edb423SSean Eric Fagan * %P process id (pid) 3939c5edb423SSean Eric Fagan * %U user id (uid) 3940c5edb423SSean Eric Fagan * For example, "%N.core" is the default; they can be disabled completely 3941c5edb423SSean Eric Fagan * by using "/dev/null", or all core files can be stored in "/cores/%U/%N-%P". 3942c5edb423SSean Eric Fagan * This is controlled by the sysctl variable kern.corefile (see above). 3943c5edb423SSean Eric Fagan */ 3944c345faeaSPawel Jakub Dawidek static int 3945c345faeaSPawel Jakub Dawidek corefile_open(const char *comm, uid_t uid, pid_t pid, struct thread *td, 39469d3ecb7eSEric van Gyzen int compress, int signum, struct vnode **vpp, char **namep) 39478b43b535SAlfred Perlstein { 394836b208e0SRobert Watson struct sbuf sb; 39490dea6e3cSMariusz Zaborski struct nameidata nd; 395036b208e0SRobert Watson const char *format; 3951c345faeaSPawel Jakub Dawidek char *hostname, *name; 3952f1fe1e02SMariusz Zaborski int cmode, error, flags, i, indexpos, indexlen, oflags, ncores; 3953c5edb423SSean Eric Fagan 3954b7402d82SAlfred Perlstein hostname = NULL; 39558b43b535SAlfred Perlstein format = corefilename; 3956086053a3SPawel Jakub Dawidek name = malloc(MAXPATHLEN, M_TEMP, M_WAITOK | M_ZERO); 3957f1fe1e02SMariusz Zaborski indexlen = 0; 3958e7228204SAlfred Perlstein indexpos = -1; 3959f1fe1e02SMariusz Zaborski ncores = num_cores; 3960c52ff611SPawel Jakub Dawidek (void)sbuf_new(&sb, name, MAXPATHLEN, SBUF_FIXEDLEN); 39615bc0ff88SMateusz Guzik sx_slock(&corefilename_lock); 396229146f1aSPawel Jakub Dawidek for (i = 0; format[i] != '\0'; i++) { 3963c5edb423SSean Eric Fagan switch (format[i]) { 3964c5edb423SSean Eric Fagan case '%': /* Format character */ 3965c5edb423SSean Eric Fagan i++; 3966c5edb423SSean Eric Fagan switch (format[i]) { 3967c5edb423SSean Eric Fagan case '%': 396836b208e0SRobert Watson sbuf_putc(&sb, '%'); 3969c5edb423SSean Eric Fagan break; 3970e7228204SAlfred Perlstein case 'H': /* hostname */ 3971b7402d82SAlfred Perlstein if (hostname == NULL) { 3972b7402d82SAlfred Perlstein hostname = malloc(MAXHOSTNAMELEN, 3973086053a3SPawel Jakub Dawidek M_TEMP, M_WAITOK); 3974b7402d82SAlfred Perlstein } 3975e7228204SAlfred Perlstein getcredhostname(td->td_ucred, hostname, 3976b7402d82SAlfred Perlstein MAXHOSTNAMELEN); 39770a713948SAlexander Motin sbuf_cat(&sb, hostname); 3978e7228204SAlfred Perlstein break; 3979e7228204SAlfred Perlstein case 'I': /* autoincrementing index */ 3980f1fe1e02SMariusz Zaborski if (indexpos != -1) { 3981f1fe1e02SMariusz Zaborski sbuf_printf(&sb, "%%I"); 3982f1fe1e02SMariusz Zaborski break; 3983f1fe1e02SMariusz Zaborski } 3984f1fe1e02SMariusz Zaborski 3985f1fe1e02SMariusz Zaborski indexpos = sbuf_len(&sb); 3986f1fe1e02SMariusz Zaborski sbuf_printf(&sb, "%u", ncores - 1); 3987f1fe1e02SMariusz Zaborski indexlen = sbuf_len(&sb) - indexpos; 3988e7228204SAlfred Perlstein break; 3989c5edb423SSean Eric Fagan case 'N': /* process name */ 3990c52ff611SPawel Jakub Dawidek sbuf_printf(&sb, "%s", comm); 3991c5edb423SSean Eric Fagan break; 3992c5edb423SSean Eric Fagan case 'P': /* process id */ 399336b208e0SRobert Watson sbuf_printf(&sb, "%u", pid); 3994c5edb423SSean Eric Fagan break; 39959d3ecb7eSEric van Gyzen case 'S': /* signal number */ 39969d3ecb7eSEric van Gyzen sbuf_printf(&sb, "%i", signum); 39979d3ecb7eSEric van Gyzen break; 3998c5edb423SSean Eric Fagan case 'U': /* user id */ 399936b208e0SRobert Watson sbuf_printf(&sb, "%u", uid); 4000c5edb423SSean Eric Fagan break; 4001c5edb423SSean Eric Fagan default: 40028b43b535SAlfred Perlstein log(LOG_ERR, 400336b208e0SRobert Watson "Unknown format character %c in " 400436b208e0SRobert Watson "corename `%s'\n", format[i], format); 400529146f1aSPawel Jakub Dawidek break; 4006c5edb423SSean Eric Fagan } 4007c5edb423SSean Eric Fagan break; 4008c5edb423SSean Eric Fagan default: 400936b208e0SRobert Watson sbuf_putc(&sb, format[i]); 40106c08be2bSPawel Jakub Dawidek break; 4011c5edb423SSean Eric Fagan } 4012c5edb423SSean Eric Fagan } 40135bc0ff88SMateusz Guzik sx_sunlock(&corefilename_lock); 4014b7402d82SAlfred Perlstein free(hostname, M_TEMP); 401578f57a9cSMark Johnston if (compress == COMPRESS_GZIP) 40160a713948SAlexander Motin sbuf_cat(&sb, GZIP_SUFFIX); 40176026dcd7SMark Johnston else if (compress == COMPRESS_ZSTD) 40180a713948SAlexander Motin sbuf_cat(&sb, ZSTD_SUFFIX); 40194d369413SMatthew D Fleming if (sbuf_error(&sb) != 0) { 402036b208e0SRobert Watson log(LOG_ERR, "pid %ld (%s), uid (%lu): corename is too " 4021c52ff611SPawel Jakub Dawidek "long\n", (long)pid, comm, (u_long)uid); 4022b7402d82SAlfred Perlstein sbuf_delete(&sb); 4023c52ff611SPawel Jakub Dawidek free(name, M_TEMP); 4024c345faeaSPawel Jakub Dawidek return (ENOMEM); 4025c5edb423SSean Eric Fagan } 402636b208e0SRobert Watson sbuf_finish(&sb); 402736b208e0SRobert Watson sbuf_delete(&sb); 4028e7228204SAlfred Perlstein 4029e7228204SAlfred Perlstein if (indexpos != -1) { 4030f1fe1e02SMariusz Zaborski error = corefile_open_last(td, name, indexpos, indexlen, ncores, 4031f1fe1e02SMariusz Zaborski vpp); 40320dea6e3cSMariusz Zaborski if (error != 0) { 4033e7228204SAlfred Perlstein log(LOG_ERR, 4034e7228204SAlfred Perlstein "pid %d (%s), uid (%u): Path `%s' failed " 4035e7228204SAlfred Perlstein "on initial open test, error = %d\n", 4036c52ff611SPawel Jakub Dawidek pid, comm, uid, name, error); 4037c345faeaSPawel Jakub Dawidek } 40380dea6e3cSMariusz Zaborski } else { 40390dea6e3cSMariusz Zaborski cmode = S_IRUSR | S_IWUSR; 40400dea6e3cSMariusz Zaborski oflags = VN_OPEN_NOAUDIT | VN_OPEN_NAMECACHE | 40410dea6e3cSMariusz Zaborski (capmode_coredump ? VN_OPEN_NOCAPCHECK : 0); 40420dea6e3cSMariusz Zaborski flags = O_CREAT | FWRITE | O_NOFOLLOW; 404389f2ab06SKonstantin Belousov if ((td->td_proc->p_flag & P_SUGID) != 0) 404489f2ab06SKonstantin Belousov flags |= O_EXCL; 40450dea6e3cSMariusz Zaborski 40467e1d3eefSMateusz Guzik NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, name); 40470dea6e3cSMariusz Zaborski error = vn_open_cred(&nd, &flags, cmode, oflags, td->td_ucred, 40480dea6e3cSMariusz Zaborski NULL); 40490dea6e3cSMariusz Zaborski if (error == 0) { 40500dea6e3cSMariusz Zaborski *vpp = nd.ni_vp; 4051bb92cd7bSMateusz Guzik NDFREE_PNBUF(&nd); 4052c345faeaSPawel Jakub Dawidek } 4053c345faeaSPawel Jakub Dawidek } 4054c345faeaSPawel Jakub Dawidek 40550dea6e3cSMariusz Zaborski if (error != 0) { 4056c345faeaSPawel Jakub Dawidek #ifdef AUDIT 4057c345faeaSPawel Jakub Dawidek audit_proc_coredump(td, name, error); 4058c345faeaSPawel Jakub Dawidek #endif 4059c52ff611SPawel Jakub Dawidek free(name, M_TEMP); 4060c345faeaSPawel Jakub Dawidek return (error); 4061e7228204SAlfred Perlstein } 4062c345faeaSPawel Jakub Dawidek *namep = name; 4063c345faeaSPawel Jakub Dawidek return (0); 406436b208e0SRobert Watson } 4065c5edb423SSean Eric Fagan 4066df8bae1dSRodney W. Grimes /* 4067fca666a1SJulian Elischer * Dump a process' core. The main routine does some 4068fca666a1SJulian Elischer * policy checking, and creates the name of the coredump; 4069fca666a1SJulian Elischer * then it passes on a vnode and a size limit to the process-specific 4070fca666a1SJulian Elischer * coredump routine if there is one; if there _is not_ one, it returns 4071fca666a1SJulian Elischer * ENOSYS; otherwise it returns the error from the process-specific routine. 4072fca666a1SJulian Elischer */ 4073fca666a1SJulian Elischer 4074fca666a1SJulian Elischer static int 4075b40ce416SJulian Elischer coredump(struct thread *td) 4076fca666a1SJulian Elischer { 4077b40ce416SJulian Elischer struct proc *p = td->td_proc; 4078f06f465dSPawel Jakub Dawidek struct ucred *cred = td->td_ucred; 4079f06f465dSPawel Jakub Dawidek struct vnode *vp; 408006ae1e91SMatthew Dillon struct flock lf; 4081fca666a1SJulian Elischer struct vattr vattr; 40827739d927SMateusz Guzik size_t fullpathsize; 4083c345faeaSPawel Jakub Dawidek int error, error1, locked; 4084fca666a1SJulian Elischer char *name; /* name of corefile */ 4085539c9eefSKonstantin Belousov void *rl_cookie; 4086fca666a1SJulian Elischer off_t limit; 4087842ab62bSRui Paulo char *fullpath, *freepath = NULL; 4088349fcda4SWarner Losh struct sbuf *sb; 4089fca666a1SJulian Elischer 40904ae89b95SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 4091f97c3df1SDavid Schultz MPASS((p->p_flag & P_HADTHREADS) == 0 || p->p_singlethread == td); 4092fca666a1SJulian Elischer 4093677258f7SKonstantin Belousov if (!do_coredump || (!sugid_coredump && (p->p_flag & P_SUGID) != 0) || 4094677258f7SKonstantin Belousov (p->p_flag2 & P2_NOTRACE) != 0) { 4095628d2653SJohn Baldwin PROC_UNLOCK(p); 4096fca666a1SJulian Elischer return (EFAULT); 4097628d2653SJohn Baldwin } 4098fca666a1SJulian Elischer 4099fca666a1SJulian Elischer /* 410035a2598fSSean Eric Fagan * Note that the bulk of limit checking is done after 410135a2598fSSean Eric Fagan * the corefile is created. The exception is if the limit 410235a2598fSSean Eric Fagan * for corefiles is 0, in which case we don't bother 410335a2598fSSean Eric Fagan * creating the corefile at all. This layout means that 410435a2598fSSean Eric Fagan * a corefile is truncated instead of not being created, 410535a2598fSSean Eric Fagan * if it is larger than the limit. 4106fca666a1SJulian Elischer */ 4107f6f6d240SMateusz Guzik limit = (off_t)lim_cur(td, RLIMIT_CORE); 4108b8fdb0d9SEdward Tomasz Napierala if (limit == 0 || racct_get_available(p, RACCT_CORE) == 0) { 4109628d2653SJohn Baldwin PROC_UNLOCK(p); 411091d5354aSJohn Baldwin return (EFBIG); 411157274c51SChristian S.J. Peron } 4112b8fdb0d9SEdward Tomasz Napierala PROC_UNLOCK(p); 411335a2598fSSean Eric Fagan 4114aa14e9b7SMark Johnston error = corefile_open(p->p_comm, cred->cr_uid, p->p_pid, td, 41159d3ecb7eSEric van Gyzen compress_user_cores, p->p_sig, &vp, &name); 4116c345faeaSPawel Jakub Dawidek if (error != 0) 4117fca666a1SJulian Elischer return (error); 411806ae1e91SMatthew Dillon 4119539c9eefSKonstantin Belousov /* 4120539c9eefSKonstantin Belousov * Don't dump to non-regular files or files with links. 412189f2ab06SKonstantin Belousov * Do not dump into system files. Effective user must own the corefile. 4122539c9eefSKonstantin Belousov */ 4123f06f465dSPawel Jakub Dawidek if (vp->v_type != VREG || VOP_GETATTR(vp, &vattr, cred) != 0 || 41247a29e0bfSKonstantin Belousov vattr.va_nlink != 1 || (vp->v_vflag & VV_SYSTEM) != 0 || 412589f2ab06SKonstantin Belousov vattr.va_uid != cred->cr_uid) { 4126b249ce48SMateusz Guzik VOP_UNLOCK(vp); 4127832dafadSDon Lewis error = EFAULT; 4128dacbc9dbSKonstantin Belousov goto out; 4129832dafadSDon Lewis } 4130832dafadSDon Lewis 4131b249ce48SMateusz Guzik VOP_UNLOCK(vp); 4132539c9eefSKonstantin Belousov 4133539c9eefSKonstantin Belousov /* Postpone other writers, including core dumps of other processes. */ 4134539c9eefSKonstantin Belousov rl_cookie = vn_rangelock_wlock(vp, 0, OFF_MAX); 4135539c9eefSKonstantin Belousov 413606ae1e91SMatthew Dillon lf.l_whence = SEEK_SET; 413706ae1e91SMatthew Dillon lf.l_start = 0; 413806ae1e91SMatthew Dillon lf.l_len = 0; 413906ae1e91SMatthew Dillon lf.l_type = F_WRLCK; 4140c447f5b2SRobert Watson locked = (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &lf, F_FLOCK) == 0); 414106ae1e91SMatthew Dillon 4142fca666a1SJulian Elischer VATTR_NULL(&vattr); 4143fca666a1SJulian Elischer vattr.va_size = 0; 41446141e04aSJohn-Mark Gurney if (set_core_nodump_flag) 41456141e04aSJohn-Mark Gurney vattr.va_flags = UF_NODUMP; 4146cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 41470359a12eSAttilio Rao VOP_SETATTR(vp, &vattr, cred); 4148b249ce48SMateusz Guzik VOP_UNLOCK(vp); 4149628d2653SJohn Baldwin PROC_LOCK(p); 4150fca666a1SJulian Elischer p->p_acflag |= ACORE; 4151628d2653SJohn Baldwin PROC_UNLOCK(p); 4152fca666a1SJulian Elischer 415323c6445aSPawel Jakub Dawidek if (p->p_sysent->sv_coredump != NULL) { 415478f57a9cSMark Johnston error = p->p_sysent->sv_coredump(td, vp, limit, 0); 415523c6445aSPawel Jakub Dawidek } else { 415623c6445aSPawel Jakub Dawidek error = ENOSYS; 415723c6445aSPawel Jakub Dawidek } 4158fca666a1SJulian Elischer 4159c447f5b2SRobert Watson if (locked) { 416006ae1e91SMatthew Dillon lf.l_type = F_UNLCK; 416106ae1e91SMatthew Dillon VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_FLOCK); 4162c447f5b2SRobert Watson } 4163539c9eefSKonstantin Belousov vn_rangelock_unlock(vp, rl_cookie); 4164dacbc9dbSKonstantin Belousov 4165842ab62bSRui Paulo /* 4166842ab62bSRui Paulo * Notify the userland helper that a process triggered a core dump. 4167842ab62bSRui Paulo * This allows the helper to run an automated debugging session. 4168842ab62bSRui Paulo */ 4169dacbc9dbSKonstantin Belousov if (error != 0 || coredump_devctl == 0) 4170842ab62bSRui Paulo goto out; 4171349fcda4SWarner Losh sb = sbuf_new_auto(); 4172feabaaf9SMateusz Guzik if (vn_fullpath_global(p->p_textvp, &fullpath, &freepath) != 0) 4173349fcda4SWarner Losh goto out2; 41740a713948SAlexander Motin sbuf_cat(sb, "comm=\""); 4175349fcda4SWarner Losh devctl_safe_quote_sb(sb, fullpath); 4176842ab62bSRui Paulo free(freepath, M_TEMP); 41770a713948SAlexander Motin sbuf_cat(sb, "\" core=\""); 4178349fcda4SWarner Losh 4179349fcda4SWarner Losh /* 4180349fcda4SWarner Losh * We can't lookup core file vp directly. When we're replacing a core, and 4181349fcda4SWarner Losh * other random times, we flush the name cache, so it will fail. Instead, 4182349fcda4SWarner Losh * if the path of the core is relative, add the current dir in front if it. 4183349fcda4SWarner Losh */ 4184349fcda4SWarner Losh if (name[0] != '/') { 41857739d927SMateusz Guzik fullpathsize = MAXPATHLEN; 41867739d927SMateusz Guzik freepath = malloc(fullpathsize, M_TEMP, M_WAITOK); 4187feabaaf9SMateusz Guzik if (vn_getcwd(freepath, &fullpath, &fullpathsize) != 0) { 41887739d927SMateusz Guzik free(freepath, M_TEMP); 4189349fcda4SWarner Losh goto out2; 4190349fcda4SWarner Losh } 4191349fcda4SWarner Losh devctl_safe_quote_sb(sb, fullpath); 41927739d927SMateusz Guzik free(freepath, M_TEMP); 4193349fcda4SWarner Losh sbuf_putc(sb, '/'); 4194349fcda4SWarner Losh } 4195349fcda4SWarner Losh devctl_safe_quote_sb(sb, name); 41960a713948SAlexander Motin sbuf_putc(sb, '"'); 4197349fcda4SWarner Losh if (sbuf_finish(sb) == 0) 4198349fcda4SWarner Losh devctl_notify("kernel", "signal", "coredump", sbuf_data(sb)); 4199349fcda4SWarner Losh out2: 4200349fcda4SWarner Losh sbuf_delete(sb); 4201842ab62bSRui Paulo out: 4202dacbc9dbSKonstantin Belousov error1 = vn_close(vp, FWRITE, cred, td); 4203dacbc9dbSKonstantin Belousov if (error == 0) 4204dacbc9dbSKonstantin Belousov error = error1; 420557274c51SChristian S.J. Peron #ifdef AUDIT 420657274c51SChristian S.J. Peron audit_proc_coredump(td, name, error); 420757274c51SChristian S.J. Peron #endif 420857274c51SChristian S.J. Peron free(name, M_TEMP); 4209fca666a1SJulian Elischer return (error); 4210fca666a1SJulian Elischer } 4211fca666a1SJulian Elischer 4212fca666a1SJulian Elischer /* 42130c14ff0eSRobert Watson * Nonexistent system call-- signal process (may want to handle it). Flag 42140c14ff0eSRobert Watson * error in case process won't see signal immediately (blocked or ignored). 4215df8bae1dSRodney W. Grimes */ 4216d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 4217df8bae1dSRodney W. Grimes struct nosys_args { 4218df8bae1dSRodney W. Grimes int dummy; 4219df8bae1dSRodney W. Grimes }; 4220d2d3e875SBruce Evans #endif 4221df8bae1dSRodney W. Grimes /* ARGSUSED */ 422226f9a767SRodney W. Grimes int 4223e052a8b9SEd Maste nosys(struct thread *td, struct nosys_args *args) 4224df8bae1dSRodney W. Grimes { 4225f5a077c3SKonstantin Belousov struct proc *p; 4226f5a077c3SKonstantin Belousov 4227f5a077c3SKonstantin Belousov p = td->td_proc; 4228b40ce416SJulian Elischer 42295804a162SKonstantin Belousov if (SV_PROC_FLAG(p, SV_SIGSYS) != 0 && kern_signosys) { 4230628d2653SJohn Baldwin PROC_LOCK(p); 4231888aefefSKonstantin Belousov tdsignal(td, SIGSYS); 4232628d2653SJohn Baldwin PROC_UNLOCK(p); 4233b82b4ae7SKonstantin Belousov } 42347ceeb35bSKonstantin Belousov if (kern_lognosys == 1 || kern_lognosys == 3) { 4235f5a077c3SKonstantin Belousov uprintf("pid %d comm %s: nosys %d\n", p->p_pid, p->p_comm, 4236f5a077c3SKonstantin Belousov td->td_sa.code); 42377ceeb35bSKonstantin Belousov } 423818f917a9SBrooks Davis if (kern_lognosys == 2 || kern_lognosys == 3 || 423918f917a9SBrooks Davis (p->p_pid == 1 && (kern_lognosys & 3) == 0)) { 42407ceeb35bSKonstantin Belousov printf("pid %d comm %s: nosys %d\n", p->p_pid, p->p_comm, 42417ceeb35bSKonstantin Belousov td->td_sa.code); 42427ceeb35bSKonstantin Belousov } 4243f5216b9aSBruce Evans return (ENOSYS); 4244df8bae1dSRodney W. Grimes } 4245831d27a9SDon Lewis 4246831d27a9SDon Lewis /* 42470c14ff0eSRobert Watson * Send a SIGIO or SIGURG signal to a process or process group using stored 42480c14ff0eSRobert Watson * credentials rather than those of the current process. 4249831d27a9SDon Lewis */ 4250831d27a9SDon Lewis void 4251e052a8b9SEd Maste pgsigio(struct sigio **sigiop, int sig, int checkctty) 4252831d27a9SDon Lewis { 4253a3de221dSKonstantin Belousov ksiginfo_t ksi; 4254f1320723SAlfred Perlstein struct sigio *sigio; 4255831d27a9SDon Lewis 4256a3de221dSKonstantin Belousov ksiginfo_init(&ksi); 4257a3de221dSKonstantin Belousov ksi.ksi_signo = sig; 4258a3de221dSKonstantin Belousov ksi.ksi_code = SI_KERNEL; 4259a3de221dSKonstantin Belousov 4260f1320723SAlfred Perlstein SIGIO_LOCK(); 4261f1320723SAlfred Perlstein sigio = *sigiop; 4262f1320723SAlfred Perlstein if (sigio == NULL) { 4263f1320723SAlfred Perlstein SIGIO_UNLOCK(); 4264f1320723SAlfred Perlstein return; 4265f1320723SAlfred Perlstein } 4266831d27a9SDon Lewis if (sigio->sio_pgid > 0) { 4267628d2653SJohn Baldwin PROC_LOCK(sigio->sio_proc); 42682b87b6d4SRobert Watson if (CANSIGIO(sigio->sio_ucred, sigio->sio_proc->p_ucred)) 42698451d0ddSKip Macy kern_psignal(sigio->sio_proc, sig); 4270628d2653SJohn Baldwin PROC_UNLOCK(sigio->sio_proc); 4271831d27a9SDon Lewis } else if (sigio->sio_pgid < 0) { 4272831d27a9SDon Lewis struct proc *p; 4273831d27a9SDon Lewis 4274f591779bSSeigo Tanimura PGRP_LOCK(sigio->sio_pgrp); 4275628d2653SJohn Baldwin LIST_FOREACH(p, &sigio->sio_pgrp->pg_members, p_pglist) { 4276628d2653SJohn Baldwin PROC_LOCK(p); 4277e806d352SJohn Baldwin if (p->p_state == PRS_NORMAL && 4278e806d352SJohn Baldwin CANSIGIO(sigio->sio_ucred, p->p_ucred) && 4279831d27a9SDon Lewis (checkctty == 0 || (p->p_flag & P_CONTROLT))) 42808451d0ddSKip Macy kern_psignal(p, sig); 4281628d2653SJohn Baldwin PROC_UNLOCK(p); 4282628d2653SJohn Baldwin } 4283f591779bSSeigo Tanimura PGRP_UNLOCK(sigio->sio_pgrp); 4284831d27a9SDon Lewis } 4285f1320723SAlfred Perlstein SIGIO_UNLOCK(); 4286831d27a9SDon Lewis } 4287cb679c38SJonathan Lemon 4288cb679c38SJonathan Lemon static int 4289cb679c38SJonathan Lemon filt_sigattach(struct knote *kn) 4290cb679c38SJonathan Lemon { 4291cb679c38SJonathan Lemon struct proc *p = curproc; 4292cb679c38SJonathan Lemon 4293cb679c38SJonathan Lemon kn->kn_ptr.p_proc = p; 4294cb679c38SJonathan Lemon kn->kn_flags |= EV_CLEAR; /* automatically set */ 4295cb679c38SJonathan Lemon 42969e590ff0SKonstantin Belousov knlist_add(p->p_klist, kn, 0); 4297cb679c38SJonathan Lemon 4298cb679c38SJonathan Lemon return (0); 4299cb679c38SJonathan Lemon } 4300cb679c38SJonathan Lemon 4301cb679c38SJonathan Lemon static void 4302cb679c38SJonathan Lemon filt_sigdetach(struct knote *kn) 4303cb679c38SJonathan Lemon { 4304ed410b78SKonstantin Belousov knlist_remove(kn->kn_knlist, kn, 0); 4305cb679c38SJonathan Lemon } 4306cb679c38SJonathan Lemon 4307cb679c38SJonathan Lemon /* 4308cb679c38SJonathan Lemon * signal knotes are shared with proc knotes, so we apply a mask to 4309cb679c38SJonathan Lemon * the hint in order to differentiate them from process hints. This 4310cb679c38SJonathan Lemon * could be avoided by using a signal-specific knote list, but probably 4311cb679c38SJonathan Lemon * isn't worth the trouble. 4312cb679c38SJonathan Lemon */ 4313cb679c38SJonathan Lemon static int 4314cb679c38SJonathan Lemon filt_signal(struct knote *kn, long hint) 4315cb679c38SJonathan Lemon { 4316cb679c38SJonathan Lemon 4317cb679c38SJonathan Lemon if (hint & NOTE_SIGNAL) { 4318cb679c38SJonathan Lemon hint &= ~NOTE_SIGNAL; 4319cb679c38SJonathan Lemon 4320cb679c38SJonathan Lemon if (kn->kn_id == hint) 4321cb679c38SJonathan Lemon kn->kn_data++; 4322cb679c38SJonathan Lemon } 4323cb679c38SJonathan Lemon return (kn->kn_data != 0); 4324cb679c38SJonathan Lemon } 432590af4afaSJohn Baldwin 432690af4afaSJohn Baldwin struct sigacts * 432790af4afaSJohn Baldwin sigacts_alloc(void) 432890af4afaSJohn Baldwin { 432990af4afaSJohn Baldwin struct sigacts *ps; 433090af4afaSJohn Baldwin 433190af4afaSJohn Baldwin ps = malloc(sizeof(struct sigacts), M_SUBPROC, M_WAITOK | M_ZERO); 4332ce8daaadSMateusz Guzik refcount_init(&ps->ps_refcnt, 1); 433390af4afaSJohn Baldwin mtx_init(&ps->ps_mtx, "sigacts", NULL, MTX_DEF); 433490af4afaSJohn Baldwin return (ps); 433590af4afaSJohn Baldwin } 433690af4afaSJohn Baldwin 433790af4afaSJohn Baldwin void 433890af4afaSJohn Baldwin sigacts_free(struct sigacts *ps) 433990af4afaSJohn Baldwin { 434090af4afaSJohn Baldwin 4341c959c237SMateusz Guzik if (refcount_release(&ps->ps_refcnt) == 0) 4342c959c237SMateusz Guzik return; 434390af4afaSJohn Baldwin mtx_destroy(&ps->ps_mtx); 434490af4afaSJohn Baldwin free(ps, M_SUBPROC); 434590af4afaSJohn Baldwin } 434690af4afaSJohn Baldwin 434790af4afaSJohn Baldwin struct sigacts * 434890af4afaSJohn Baldwin sigacts_hold(struct sigacts *ps) 434990af4afaSJohn Baldwin { 4350c959c237SMateusz Guzik 4351c959c237SMateusz Guzik refcount_acquire(&ps->ps_refcnt); 435290af4afaSJohn Baldwin return (ps); 435390af4afaSJohn Baldwin } 435490af4afaSJohn Baldwin 435590af4afaSJohn Baldwin void 435690af4afaSJohn Baldwin sigacts_copy(struct sigacts *dest, struct sigacts *src) 435790af4afaSJohn Baldwin { 435890af4afaSJohn Baldwin 435990af4afaSJohn Baldwin KASSERT(dest->ps_refcnt == 1, ("sigacts_copy to shared dest")); 436090af4afaSJohn Baldwin mtx_lock(&src->ps_mtx); 436190af4afaSJohn Baldwin bcopy(src, dest, offsetof(struct sigacts, ps_refcnt)); 436290af4afaSJohn Baldwin mtx_unlock(&src->ps_mtx); 436390af4afaSJohn Baldwin } 436490af4afaSJohn Baldwin 436590af4afaSJohn Baldwin int 436690af4afaSJohn Baldwin sigacts_shared(struct sigacts *ps) 436790af4afaSJohn Baldwin { 436890af4afaSJohn Baldwin 4369d00c8ea4SMateusz Guzik return (ps->ps_refcnt > 1); 437090af4afaSJohn Baldwin } 4371079c5b9eSKyle Evans 4372079c5b9eSKyle Evans void 4373079c5b9eSKyle Evans sig_drop_caught(struct proc *p) 4374079c5b9eSKyle Evans { 4375079c5b9eSKyle Evans int sig; 4376079c5b9eSKyle Evans struct sigacts *ps; 4377079c5b9eSKyle Evans 4378079c5b9eSKyle Evans ps = p->p_sigacts; 4379079c5b9eSKyle Evans PROC_LOCK_ASSERT(p, MA_OWNED); 4380079c5b9eSKyle Evans mtx_assert(&ps->ps_mtx, MA_OWNED); 438181f2e906SMark Johnston SIG_FOREACH(sig, &ps->ps_sigcatch) { 4382079c5b9eSKyle Evans sigdflt(ps, sig); 4383079c5b9eSKyle Evans if ((sigprop(sig) & SIGPROP_IGNORE) != 0) 4384079c5b9eSKyle Evans sigqueue_delete_proc(p, sig); 4385079c5b9eSKyle Evans } 4386079c5b9eSKyle Evans } 4387146fc63fSKonstantin Belousov 4388a113b17fSKonstantin Belousov static void 4389a113b17fSKonstantin Belousov sigfastblock_failed(struct thread *td, bool sendsig, bool write) 4390a113b17fSKonstantin Belousov { 4391a113b17fSKonstantin Belousov ksiginfo_t ksi; 4392a113b17fSKonstantin Belousov 4393a113b17fSKonstantin Belousov /* 4394a113b17fSKonstantin Belousov * Prevent further fetches and SIGSEGVs, allowing thread to 4395a113b17fSKonstantin Belousov * issue syscalls despite corruption. 4396a113b17fSKonstantin Belousov */ 4397a113b17fSKonstantin Belousov sigfastblock_clear(td); 4398a113b17fSKonstantin Belousov 4399a113b17fSKonstantin Belousov if (!sendsig) 4400a113b17fSKonstantin Belousov return; 4401a113b17fSKonstantin Belousov ksiginfo_init_trap(&ksi); 4402a113b17fSKonstantin Belousov ksi.ksi_signo = SIGSEGV; 4403a113b17fSKonstantin Belousov ksi.ksi_code = write ? SEGV_ACCERR : SEGV_MAPERR; 4404a113b17fSKonstantin Belousov ksi.ksi_addr = td->td_sigblock_ptr; 4405a113b17fSKonstantin Belousov trapsignal(td, &ksi); 4406a113b17fSKonstantin Belousov } 4407a113b17fSKonstantin Belousov 4408a113b17fSKonstantin Belousov static bool 4409a113b17fSKonstantin Belousov sigfastblock_fetch_sig(struct thread *td, bool sendsig, uint32_t *valp) 4410a113b17fSKonstantin Belousov { 4411a113b17fSKonstantin Belousov uint32_t res; 4412a113b17fSKonstantin Belousov 4413a113b17fSKonstantin Belousov if ((td->td_pflags & TDP_SIGFASTBLOCK) == 0) 4414a113b17fSKonstantin Belousov return (true); 4415a113b17fSKonstantin Belousov if (fueword32((void *)td->td_sigblock_ptr, &res) == -1) { 4416a113b17fSKonstantin Belousov sigfastblock_failed(td, sendsig, false); 4417a113b17fSKonstantin Belousov return (false); 4418a113b17fSKonstantin Belousov } 4419a113b17fSKonstantin Belousov *valp = res; 4420a113b17fSKonstantin Belousov td->td_sigblock_val = res & ~SIGFASTBLOCK_FLAGS; 4421a113b17fSKonstantin Belousov return (true); 4422a113b17fSKonstantin Belousov } 4423a113b17fSKonstantin Belousov 4424fb3c434bSKonstantin Belousov static void 4425fb3c434bSKonstantin Belousov sigfastblock_resched(struct thread *td, bool resched) 4426fb3c434bSKonstantin Belousov { 4427fb3c434bSKonstantin Belousov struct proc *p; 4428fb3c434bSKonstantin Belousov 4429fb3c434bSKonstantin Belousov if (resched) { 4430fb3c434bSKonstantin Belousov p = td->td_proc; 4431fb3c434bSKonstantin Belousov PROC_LOCK(p); 4432fb3c434bSKonstantin Belousov reschedule_signals(p, td->td_sigmask, 0); 4433fb3c434bSKonstantin Belousov PROC_UNLOCK(p); 4434fb3c434bSKonstantin Belousov } 4435c6d31b83SKonstantin Belousov ast_sched(td, TDA_SIG); 4436fb3c434bSKonstantin Belousov } 4437fb3c434bSKonstantin Belousov 4438146fc63fSKonstantin Belousov int 4439146fc63fSKonstantin Belousov sys_sigfastblock(struct thread *td, struct sigfastblock_args *uap) 4440146fc63fSKonstantin Belousov { 4441146fc63fSKonstantin Belousov struct proc *p; 4442146fc63fSKonstantin Belousov int error, res; 4443146fc63fSKonstantin Belousov uint32_t oldval; 4444146fc63fSKonstantin Belousov 4445146fc63fSKonstantin Belousov error = 0; 4446a113b17fSKonstantin Belousov p = td->td_proc; 4447146fc63fSKonstantin Belousov switch (uap->cmd) { 4448146fc63fSKonstantin Belousov case SIGFASTBLOCK_SETPTR: 4449146fc63fSKonstantin Belousov if ((td->td_pflags & TDP_SIGFASTBLOCK) != 0) { 4450146fc63fSKonstantin Belousov error = EBUSY; 4451146fc63fSKonstantin Belousov break; 4452146fc63fSKonstantin Belousov } 4453146fc63fSKonstantin Belousov if (((uintptr_t)(uap->ptr) & (sizeof(uint32_t) - 1)) != 0) { 4454146fc63fSKonstantin Belousov error = EINVAL; 4455146fc63fSKonstantin Belousov break; 4456146fc63fSKonstantin Belousov } 4457146fc63fSKonstantin Belousov td->td_pflags |= TDP_SIGFASTBLOCK; 4458146fc63fSKonstantin Belousov td->td_sigblock_ptr = uap->ptr; 4459146fc63fSKonstantin Belousov break; 4460146fc63fSKonstantin Belousov 4461146fc63fSKonstantin Belousov case SIGFASTBLOCK_UNBLOCK: 4462a113b17fSKonstantin Belousov if ((td->td_pflags & TDP_SIGFASTBLOCK) == 0) { 4463146fc63fSKonstantin Belousov error = EINVAL; 4464146fc63fSKonstantin Belousov break; 4465146fc63fSKonstantin Belousov } 4466a113b17fSKonstantin Belousov 4467a113b17fSKonstantin Belousov for (;;) { 4468a113b17fSKonstantin Belousov res = casueword32(td->td_sigblock_ptr, 4469a113b17fSKonstantin Belousov SIGFASTBLOCK_PEND, &oldval, 0); 4470146fc63fSKonstantin Belousov if (res == -1) { 4471146fc63fSKonstantin Belousov error = EFAULT; 4472a113b17fSKonstantin Belousov sigfastblock_failed(td, false, true); 4473146fc63fSKonstantin Belousov break; 4474146fc63fSKonstantin Belousov } 4475a113b17fSKonstantin Belousov if (res == 0) 4476a113b17fSKonstantin Belousov break; 4477a113b17fSKonstantin Belousov MPASS(res == 1); 4478146fc63fSKonstantin Belousov if (oldval != SIGFASTBLOCK_PEND) { 4479146fc63fSKonstantin Belousov error = EBUSY; 4480146fc63fSKonstantin Belousov break; 4481146fc63fSKonstantin Belousov } 4482146fc63fSKonstantin Belousov error = thread_check_susp(td, false); 4483146fc63fSKonstantin Belousov if (error != 0) 4484146fc63fSKonstantin Belousov break; 4485146fc63fSKonstantin Belousov } 4486a113b17fSKonstantin Belousov if (error != 0) 4487a113b17fSKonstantin Belousov break; 4488a113b17fSKonstantin Belousov 4489a113b17fSKonstantin Belousov /* 4490a113b17fSKonstantin Belousov * td_sigblock_val is cleared there, but not on a 4491a113b17fSKonstantin Belousov * syscall exit. The end effect is that a single 4492a113b17fSKonstantin Belousov * interruptible sleep, while user sigblock word is 4493a113b17fSKonstantin Belousov * set, might return EINTR or ERESTART to usermode 4494a113b17fSKonstantin Belousov * without delivering signal. All further sleeps, 4495a113b17fSKonstantin Belousov * until userspace clears the word and does 4496a113b17fSKonstantin Belousov * sigfastblock(UNBLOCK), observe current word and no 4497a113b17fSKonstantin Belousov * longer get interrupted. It is slight 4498a113b17fSKonstantin Belousov * non-conformance, with alternative to have read the 4499a113b17fSKonstantin Belousov * sigblock word on each syscall entry. 4500a113b17fSKonstantin Belousov */ 4501146fc63fSKonstantin Belousov td->td_sigblock_val = 0; 4502146fc63fSKonstantin Belousov 4503146fc63fSKonstantin Belousov /* 4504146fc63fSKonstantin Belousov * Rely on normal ast mechanism to deliver pending 4505146fc63fSKonstantin Belousov * signals to current thread. But notify others about 4506146fc63fSKonstantin Belousov * fake unblock. 4507146fc63fSKonstantin Belousov */ 4508fb3c434bSKonstantin Belousov sigfastblock_resched(td, error == 0 && p->p_numthreads != 1); 4509fb3c434bSKonstantin Belousov 4510146fc63fSKonstantin Belousov break; 4511146fc63fSKonstantin Belousov 4512146fc63fSKonstantin Belousov case SIGFASTBLOCK_UNSETPTR: 4513146fc63fSKonstantin Belousov if ((td->td_pflags & TDP_SIGFASTBLOCK) == 0) { 4514146fc63fSKonstantin Belousov error = EINVAL; 4515146fc63fSKonstantin Belousov break; 4516146fc63fSKonstantin Belousov } 4517a113b17fSKonstantin Belousov if (!sigfastblock_fetch_sig(td, false, &oldval)) { 4518146fc63fSKonstantin Belousov error = EFAULT; 4519146fc63fSKonstantin Belousov break; 4520146fc63fSKonstantin Belousov } 4521146fc63fSKonstantin Belousov if (oldval != 0 && oldval != SIGFASTBLOCK_PEND) { 4522146fc63fSKonstantin Belousov error = EBUSY; 4523146fc63fSKonstantin Belousov break; 4524146fc63fSKonstantin Belousov } 4525a113b17fSKonstantin Belousov sigfastblock_clear(td); 4526146fc63fSKonstantin Belousov break; 4527146fc63fSKonstantin Belousov 4528146fc63fSKonstantin Belousov default: 4529146fc63fSKonstantin Belousov error = EINVAL; 4530146fc63fSKonstantin Belousov break; 4531146fc63fSKonstantin Belousov } 4532146fc63fSKonstantin Belousov return (error); 4533146fc63fSKonstantin Belousov } 4534146fc63fSKonstantin Belousov 4535146fc63fSKonstantin Belousov void 4536a113b17fSKonstantin Belousov sigfastblock_clear(struct thread *td) 4537146fc63fSKonstantin Belousov { 4538a113b17fSKonstantin Belousov bool resched; 4539146fc63fSKonstantin Belousov 4540146fc63fSKonstantin Belousov if ((td->td_pflags & TDP_SIGFASTBLOCK) == 0) 4541146fc63fSKonstantin Belousov return; 4542a113b17fSKonstantin Belousov td->td_sigblock_val = 0; 454300ebd809SKonstantin Belousov resched = (td->td_pflags & TDP_SIGFASTPENDING) != 0 || 454400ebd809SKonstantin Belousov SIGPENDING(td); 4545a113b17fSKonstantin Belousov td->td_pflags &= ~(TDP_SIGFASTBLOCK | TDP_SIGFASTPENDING); 4546fb3c434bSKonstantin Belousov sigfastblock_resched(td, resched); 4547146fc63fSKonstantin Belousov } 4548146fc63fSKonstantin Belousov 4549146fc63fSKonstantin Belousov void 4550a113b17fSKonstantin Belousov sigfastblock_fetch(struct thread *td) 4551146fc63fSKonstantin Belousov { 4552a113b17fSKonstantin Belousov uint32_t val; 4553146fc63fSKonstantin Belousov 4554a113b17fSKonstantin Belousov (void)sigfastblock_fetch_sig(td, true, &val); 4555a113b17fSKonstantin Belousov } 4556146fc63fSKonstantin Belousov 45570bc52b0bSKonstantin Belousov static void 45580bc52b0bSKonstantin Belousov sigfastblock_setpend1(struct thread *td) 4559a113b17fSKonstantin Belousov { 4560a113b17fSKonstantin Belousov int res; 4561a113b17fSKonstantin Belousov uint32_t oldval; 4562a113b17fSKonstantin Belousov 4563513320c0SKonstantin Belousov if ((td->td_pflags & TDP_SIGFASTPENDING) == 0) 4564a113b17fSKonstantin Belousov return; 4565a113b17fSKonstantin Belousov res = fueword32((void *)td->td_sigblock_ptr, &oldval); 4566a113b17fSKonstantin Belousov if (res == -1) { 4567a113b17fSKonstantin Belousov sigfastblock_failed(td, true, false); 4568a113b17fSKonstantin Belousov return; 4569a113b17fSKonstantin Belousov } 4570a113b17fSKonstantin Belousov for (;;) { 4571a113b17fSKonstantin Belousov res = casueword32(td->td_sigblock_ptr, oldval, &oldval, 4572a113b17fSKonstantin Belousov oldval | SIGFASTBLOCK_PEND); 4573a113b17fSKonstantin Belousov if (res == -1) { 4574a113b17fSKonstantin Belousov sigfastblock_failed(td, true, true); 4575a113b17fSKonstantin Belousov return; 4576a113b17fSKonstantin Belousov } 4577a113b17fSKonstantin Belousov if (res == 0) { 4578a113b17fSKonstantin Belousov td->td_sigblock_val = oldval & ~SIGFASTBLOCK_FLAGS; 4579a113b17fSKonstantin Belousov td->td_pflags &= ~TDP_SIGFASTPENDING; 4580a113b17fSKonstantin Belousov break; 4581a113b17fSKonstantin Belousov } 4582a113b17fSKonstantin Belousov MPASS(res == 1); 4583a113b17fSKonstantin Belousov if (thread_check_susp(td, false) != 0) 4584a113b17fSKonstantin Belousov break; 4585a113b17fSKonstantin Belousov } 4586146fc63fSKonstantin Belousov } 45870bc52b0bSKonstantin Belousov 45884fced864SKonstantin Belousov static void 45890bc52b0bSKonstantin Belousov sigfastblock_setpend(struct thread *td, bool resched) 45900bc52b0bSKonstantin Belousov { 45910bc52b0bSKonstantin Belousov struct proc *p; 45920bc52b0bSKonstantin Belousov 45930bc52b0bSKonstantin Belousov sigfastblock_setpend1(td); 45940bc52b0bSKonstantin Belousov if (resched) { 45950bc52b0bSKonstantin Belousov p = td->td_proc; 45960bc52b0bSKonstantin Belousov PROC_LOCK(p); 45970bc52b0bSKonstantin Belousov reschedule_signals(p, fastblock_mask, SIGPROCMASK_FASTBLK); 45980bc52b0bSKonstantin Belousov PROC_UNLOCK(p); 45990bc52b0bSKonstantin Belousov } 46000bc52b0bSKonstantin Belousov } 4601