1d5bc81e6SKyle Evans /* 2d5bc81e6SKyle Evans * SPDX-License-Identifier: BSD-3-Clause 3d5bc81e6SKyle Evans * 4d5bc81e6SKyle Evans * Copyright (c) 1982, 1986, 1989, 1991, 1993 5d5bc81e6SKyle Evans * The Regents of the University of California. All rights reserved. 6d5bc81e6SKyle Evans * (c) UNIX System Laboratories, Inc. 7d5bc81e6SKyle Evans * All or some portions of this file are derived from material licensed 8d5bc81e6SKyle Evans * to the University of California by American Telephone and Telegraph 9d5bc81e6SKyle Evans * Co. or Unix System Laboratories, Inc. and are reproduced herein with 10d5bc81e6SKyle Evans * the permission of UNIX System Laboratories, Inc. 11d5bc81e6SKyle Evans * 12d5bc81e6SKyle Evans * Redistribution and use in source and binary forms, with or without 13d5bc81e6SKyle Evans * modification, are permitted provided that the following conditions 14d5bc81e6SKyle Evans * are met: 15d5bc81e6SKyle Evans * 1. Redistributions of source code must retain the above copyright 16d5bc81e6SKyle Evans * notice, this list of conditions and the following disclaimer. 17d5bc81e6SKyle Evans * 2. Redistributions in binary form must reproduce the above copyright 18d5bc81e6SKyle Evans * notice, this list of conditions and the following disclaimer in the 19d5bc81e6SKyle Evans * documentation and/or other materials provided with the distribution. 20d5bc81e6SKyle Evans * 3. Neither the name of the University nor the names of its contributors 21d5bc81e6SKyle Evans * may be used to endorse or promote products derived from this software 22d5bc81e6SKyle Evans * without specific prior written permission. 23d5bc81e6SKyle Evans * 24d5bc81e6SKyle Evans * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25d5bc81e6SKyle Evans * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26d5bc81e6SKyle Evans * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27d5bc81e6SKyle Evans * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28d5bc81e6SKyle Evans * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29d5bc81e6SKyle Evans * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30d5bc81e6SKyle Evans * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31d5bc81e6SKyle Evans * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32d5bc81e6SKyle Evans * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33d5bc81e6SKyle Evans * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34d5bc81e6SKyle Evans * SUCH DAMAGE. 35d5bc81e6SKyle Evans */ 36d5bc81e6SKyle Evans 37d5bc81e6SKyle Evans #include <sys/param.h> 38d5bc81e6SKyle Evans #include <sys/acct.h> 39d5bc81e6SKyle Evans #include <sys/compressor.h> 40d5bc81e6SKyle Evans #include <sys/jail.h> 41*ce51f799SKyle Evans #include <sys/kernel.h> 42d5bc81e6SKyle Evans #include <sys/lock.h> 43d5bc81e6SKyle Evans #include <sys/mutex.h> 44d5bc81e6SKyle Evans #include <sys/proc.h> 45d5bc81e6SKyle Evans #include <sys/signalvar.h> 46d5bc81e6SKyle Evans #include <sys/racct.h> 47d5bc81e6SKyle Evans #include <sys/resourcevar.h> 48*ce51f799SKyle Evans #include <sys/rmlock.h> 49d5bc81e6SKyle Evans #include <sys/sysctl.h> 50d5bc81e6SKyle Evans #include <sys/syslog.h> 51d5bc81e6SKyle Evans #include <sys/ucoredump.h> 52d5bc81e6SKyle Evans #include <sys/wait.h> 53d5bc81e6SKyle Evans 54d5bc81e6SKyle Evans static int coredump(struct thread *td); 55d5bc81e6SKyle Evans 56d5bc81e6SKyle Evans int compress_user_cores = 0; 57d5bc81e6SKyle Evans 58*ce51f799SKyle Evans static SLIST_HEAD(, coredumper) coredumpers = 59*ce51f799SKyle Evans SLIST_HEAD_INITIALIZER(coredumpers); 60*ce51f799SKyle Evans static struct rmlock coredump_rmlock; 61*ce51f799SKyle Evans RM_SYSINIT(coredump_lock, &coredump_rmlock, "coredump_lock"); 62*ce51f799SKyle Evans 63d5bc81e6SKyle Evans static int kern_logsigexit = 1; 64d5bc81e6SKyle Evans SYSCTL_INT(_kern, KERN_LOGSIGEXIT, logsigexit, CTLFLAG_RW, 65d5bc81e6SKyle Evans &kern_logsigexit, 0, 66d5bc81e6SKyle Evans "Log processes quitting on abnormal signals to syslog(3)"); 67d5bc81e6SKyle Evans 68d5bc81e6SKyle Evans static int sugid_coredump; 69d5bc81e6SKyle Evans SYSCTL_INT(_kern, OID_AUTO, sugid_coredump, CTLFLAG_RWTUN, 70d5bc81e6SKyle Evans &sugid_coredump, 0, "Allow setuid and setgid processes to dump core"); 71d5bc81e6SKyle Evans 72d5bc81e6SKyle Evans static int do_coredump = 1; 73d5bc81e6SKyle Evans SYSCTL_INT(_kern, OID_AUTO, coredump, CTLFLAG_RW, 74d5bc81e6SKyle Evans &do_coredump, 0, "Enable/Disable coredumps"); 75d5bc81e6SKyle Evans 76d5bc81e6SKyle Evans static int 77d5bc81e6SKyle Evans sysctl_compress_user_cores(SYSCTL_HANDLER_ARGS) 78d5bc81e6SKyle Evans { 79d5bc81e6SKyle Evans int error, val; 80d5bc81e6SKyle Evans 81d5bc81e6SKyle Evans val = compress_user_cores; 82d5bc81e6SKyle Evans error = sysctl_handle_int(oidp, &val, 0, req); 83d5bc81e6SKyle Evans if (error != 0 || req->newptr == NULL) 84d5bc81e6SKyle Evans return (error); 85d5bc81e6SKyle Evans if (val != 0 && !compressor_avail(val)) 86d5bc81e6SKyle Evans return (EINVAL); 87d5bc81e6SKyle Evans compress_user_cores = val; 88d5bc81e6SKyle Evans return (error); 89d5bc81e6SKyle Evans } 90d5bc81e6SKyle Evans SYSCTL_PROC(_kern, OID_AUTO, compress_user_cores, 91d5bc81e6SKyle Evans CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, 0, sizeof(int), 92d5bc81e6SKyle Evans sysctl_compress_user_cores, "I", 93d5bc81e6SKyle Evans "Enable compression of user corefiles (" 94d5bc81e6SKyle Evans __XSTRING(COMPRESS_GZIP) " = gzip, " 95d5bc81e6SKyle Evans __XSTRING(COMPRESS_ZSTD) " = zstd)"); 96d5bc81e6SKyle Evans 97d5bc81e6SKyle Evans int compress_user_cores_level = 6; 98d5bc81e6SKyle Evans SYSCTL_INT(_kern, OID_AUTO, compress_user_cores_level, CTLFLAG_RWTUN, 99d5bc81e6SKyle Evans &compress_user_cores_level, 0, 100d5bc81e6SKyle Evans "Corefile compression level"); 101d5bc81e6SKyle Evans 102*ce51f799SKyle Evans void 103*ce51f799SKyle Evans coredumper_register(struct coredumper *cd) 104*ce51f799SKyle Evans { 105*ce51f799SKyle Evans 106*ce51f799SKyle Evans blockcount_init(&cd->cd_refcount); 107*ce51f799SKyle Evans rm_wlock(&coredump_rmlock); 108*ce51f799SKyle Evans SLIST_INSERT_HEAD(&coredumpers, cd, cd_entry); 109*ce51f799SKyle Evans rm_wunlock(&coredump_rmlock); 110*ce51f799SKyle Evans } 111*ce51f799SKyle Evans 112*ce51f799SKyle Evans void 113*ce51f799SKyle Evans coredumper_unregister(struct coredumper *cd) 114*ce51f799SKyle Evans { 115*ce51f799SKyle Evans 116*ce51f799SKyle Evans rm_wlock(&coredump_rmlock); 117*ce51f799SKyle Evans SLIST_REMOVE(&coredumpers, cd, coredumper, cd_entry); 118*ce51f799SKyle Evans rm_wunlock(&coredump_rmlock); 119*ce51f799SKyle Evans 120*ce51f799SKyle Evans /* 121*ce51f799SKyle Evans * Wait for any in-process coredumps to finish before returning. 122*ce51f799SKyle Evans */ 123*ce51f799SKyle Evans blockcount_wait(&cd->cd_refcount, NULL, "dumpwait", 0); 124*ce51f799SKyle Evans } 125*ce51f799SKyle Evans 126d5bc81e6SKyle Evans /* 127d5bc81e6SKyle Evans * Force the current process to exit with the specified signal, dumping core 128d5bc81e6SKyle Evans * if appropriate. We bypass the normal tests for masked and caught signals, 129d5bc81e6SKyle Evans * allowing unrecoverable failures to terminate the process without changing 130d5bc81e6SKyle Evans * signal state. Mark the accounting record with the signal termination. 131d5bc81e6SKyle Evans * If dumping core, save the signal number for the debugger. Calls exit and 132d5bc81e6SKyle Evans * does not return. 133d5bc81e6SKyle Evans */ 134d5bc81e6SKyle Evans void 135d5bc81e6SKyle Evans sigexit(struct thread *td, int sig) 136d5bc81e6SKyle Evans { 137d5bc81e6SKyle Evans struct proc *p = td->td_proc; 138d5bc81e6SKyle Evans const char *coreinfo; 139d5bc81e6SKyle Evans int rv; 140d5bc81e6SKyle Evans bool logexit; 141d5bc81e6SKyle Evans 142d5bc81e6SKyle Evans PROC_LOCK_ASSERT(p, MA_OWNED); 143d5bc81e6SKyle Evans proc_set_p2_wexit(p); 144d5bc81e6SKyle Evans 145d5bc81e6SKyle Evans p->p_acflag |= AXSIG; 146d5bc81e6SKyle Evans if ((p->p_flag2 & P2_LOGSIGEXIT_CTL) == 0) 147d5bc81e6SKyle Evans logexit = kern_logsigexit != 0; 148d5bc81e6SKyle Evans else 149d5bc81e6SKyle Evans logexit = (p->p_flag2 & P2_LOGSIGEXIT_ENABLE) != 0; 150d5bc81e6SKyle Evans 151d5bc81e6SKyle Evans /* 152d5bc81e6SKyle Evans * We must be single-threading to generate a core dump. This 153d5bc81e6SKyle Evans * ensures that the registers in the core file are up-to-date. 154d5bc81e6SKyle Evans * Also, the ELF dump handler assumes that the thread list doesn't 155d5bc81e6SKyle Evans * change out from under it. 156d5bc81e6SKyle Evans * 157d5bc81e6SKyle Evans * XXX If another thread attempts to single-thread before us 158d5bc81e6SKyle Evans * (e.g. via fork()), we won't get a dump at all. 159d5bc81e6SKyle Evans */ 160d5bc81e6SKyle Evans if (sig_do_core(sig) && thread_single(p, SINGLE_NO_EXIT) == 0) { 161d5bc81e6SKyle Evans p->p_sig = sig; 162d5bc81e6SKyle Evans /* 163d5bc81e6SKyle Evans * Log signals which would cause core dumps 164d5bc81e6SKyle Evans * (Log as LOG_INFO to appease those who don't want 165d5bc81e6SKyle Evans * these messages.) 166d5bc81e6SKyle Evans * XXX : Todo, as well as euid, write out ruid too 167d5bc81e6SKyle Evans * Note that coredump() drops proc lock. 168d5bc81e6SKyle Evans */ 169d5bc81e6SKyle Evans rv = coredump(td); 170d5bc81e6SKyle Evans switch (rv) { 171d5bc81e6SKyle Evans case 0: 172d5bc81e6SKyle Evans sig |= WCOREFLAG; 173d5bc81e6SKyle Evans coreinfo = " (core dumped)"; 174d5bc81e6SKyle Evans break; 175d5bc81e6SKyle Evans case EFAULT: 176d5bc81e6SKyle Evans coreinfo = " (no core dump - bad address)"; 177d5bc81e6SKyle Evans break; 178d5bc81e6SKyle Evans case EINVAL: 179d5bc81e6SKyle Evans coreinfo = " (no core dump - invalid argument)"; 180d5bc81e6SKyle Evans break; 181d5bc81e6SKyle Evans case EFBIG: 182d5bc81e6SKyle Evans coreinfo = " (no core dump - too large)"; 183d5bc81e6SKyle Evans break; 184d5bc81e6SKyle Evans default: 185d5bc81e6SKyle Evans coreinfo = " (no core dump - other error)"; 186d5bc81e6SKyle Evans break; 187d5bc81e6SKyle Evans } 188d5bc81e6SKyle Evans if (logexit) 189d5bc81e6SKyle Evans log(LOG_INFO, 190d5bc81e6SKyle Evans "pid %d (%s), jid %d, uid %d: exited on " 191d5bc81e6SKyle Evans "signal %d%s\n", p->p_pid, p->p_comm, 192d5bc81e6SKyle Evans p->p_ucred->cr_prison->pr_id, 193d5bc81e6SKyle Evans td->td_ucred->cr_uid, 194d5bc81e6SKyle Evans sig &~ WCOREFLAG, coreinfo); 195d5bc81e6SKyle Evans } else 196d5bc81e6SKyle Evans PROC_UNLOCK(p); 197d5bc81e6SKyle Evans exit1(td, 0, sig); 198d5bc81e6SKyle Evans /* NOTREACHED */ 199d5bc81e6SKyle Evans } 200d5bc81e6SKyle Evans 201d5bc81e6SKyle Evans 202d5bc81e6SKyle Evans /* 203d5bc81e6SKyle Evans * Dump a process' core. The main routine does some 204d5bc81e6SKyle Evans * policy checking, and creates the name of the coredump; 205d5bc81e6SKyle Evans * then it passes on a vnode and a size limit to the process-specific 206d5bc81e6SKyle Evans * coredump routine if there is one; if there _is not_ one, it returns 207d5bc81e6SKyle Evans * ENOSYS; otherwise it returns the error from the process-specific routine. 208d5bc81e6SKyle Evans */ 209d5bc81e6SKyle Evans static int 210d5bc81e6SKyle Evans coredump(struct thread *td) 211d5bc81e6SKyle Evans { 212*ce51f799SKyle Evans struct coredumper *iter, *chosen; 213d5bc81e6SKyle Evans struct proc *p = td->td_proc; 214*ce51f799SKyle Evans struct rm_priotracker tracker; 215d5bc81e6SKyle Evans off_t limit; 216*ce51f799SKyle Evans int error, priority; 217d5bc81e6SKyle Evans 218d5bc81e6SKyle Evans PROC_LOCK_ASSERT(p, MA_OWNED); 219d5bc81e6SKyle Evans MPASS((p->p_flag & P_HADTHREADS) == 0 || p->p_singlethread == td); 220d5bc81e6SKyle Evans 221d5bc81e6SKyle Evans if (!do_coredump || (!sugid_coredump && (p->p_flag & P_SUGID) != 0) || 222d5bc81e6SKyle Evans (p->p_flag2 & P2_NOTRACE) != 0) { 223d5bc81e6SKyle Evans PROC_UNLOCK(p); 224d5bc81e6SKyle Evans return (EFAULT); 225d5bc81e6SKyle Evans } 226d5bc81e6SKyle Evans 227d5bc81e6SKyle Evans /* 228d5bc81e6SKyle Evans * Note that the bulk of limit checking is done after 229d5bc81e6SKyle Evans * the corefile is created. The exception is if the limit 230d5bc81e6SKyle Evans * for corefiles is 0, in which case we don't bother 231d5bc81e6SKyle Evans * creating the corefile at all. This layout means that 232d5bc81e6SKyle Evans * a corefile is truncated instead of not being created, 233d5bc81e6SKyle Evans * if it is larger than the limit. 234d5bc81e6SKyle Evans */ 235d5bc81e6SKyle Evans limit = (off_t)lim_cur(td, RLIMIT_CORE); 236d5bc81e6SKyle Evans if (limit == 0 || racct_get_available(p, RACCT_CORE) == 0) { 237d5bc81e6SKyle Evans PROC_UNLOCK(p); 238d5bc81e6SKyle Evans return (EFBIG); 239d5bc81e6SKyle Evans } 240d5bc81e6SKyle Evans 241*ce51f799SKyle Evans rm_rlock(&coredump_rmlock, &tracker); 242*ce51f799SKyle Evans priority = -1; 243*ce51f799SKyle Evans chosen = NULL; 244*ce51f799SKyle Evans SLIST_FOREACH(iter, &coredumpers, cd_entry) { 245*ce51f799SKyle Evans if (iter->cd_probe == NULL) { 246*ce51f799SKyle Evans /* 247*ce51f799SKyle Evans * If we haven't found anything of a higher priority 248*ce51f799SKyle Evans * yet, we'll call this a GENERIC. Ideally, we want 249*ce51f799SKyle Evans * coredumper modules to include a probe function. 250*ce51f799SKyle Evans */ 251*ce51f799SKyle Evans if (priority < 0) { 252*ce51f799SKyle Evans priority = COREDUMPER_GENERIC; 253*ce51f799SKyle Evans chosen = iter; 254*ce51f799SKyle Evans } 255*ce51f799SKyle Evans 256*ce51f799SKyle Evans continue; 257*ce51f799SKyle Evans } 258*ce51f799SKyle Evans 259*ce51f799SKyle Evans error = (*iter->cd_probe)(td); 260*ce51f799SKyle Evans if (error < 0) 261*ce51f799SKyle Evans continue; 262*ce51f799SKyle Evans 263*ce51f799SKyle Evans /* 264*ce51f799SKyle Evans * Higher priority than previous options. 265*ce51f799SKyle Evans */ 266*ce51f799SKyle Evans if (error > priority) { 267*ce51f799SKyle Evans priority = error; 268*ce51f799SKyle Evans chosen = iter; 269*ce51f799SKyle Evans } 270*ce51f799SKyle Evans } 271*ce51f799SKyle Evans 272*ce51f799SKyle Evans /* 273*ce51f799SKyle Evans * Acquire our refcount before we drop the lock so that 274*ce51f799SKyle Evans * coredumper_unregister() can safely assume that the refcount will only 275*ce51f799SKyle Evans * go down once it's dropped the rmlock. 276*ce51f799SKyle Evans */ 277*ce51f799SKyle Evans blockcount_acquire(&chosen->cd_refcount, 1); 278*ce51f799SKyle Evans rm_runlock(&coredump_rmlock, &tracker); 279*ce51f799SKyle Evans 280*ce51f799SKyle Evans /* Currently, we always have the vnode dumper built in. */ 281*ce51f799SKyle Evans MPASS(chosen != NULL); 282*ce51f799SKyle Evans error = ((*chosen->cd_handle)(td, limit)); 283d5bc81e6SKyle Evans PROC_LOCK_ASSERT(p, MA_NOTOWNED); 284d5bc81e6SKyle Evans 285*ce51f799SKyle Evans blockcount_release(&chosen->cd_refcount, 1); 286*ce51f799SKyle Evans 287d5bc81e6SKyle Evans return (error); 288d5bc81e6SKyle Evans } 289