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>
41ce51f799SKyle 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>
48ce51f799SKyle 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
54*3ce3b342SKyle Evans static int coredump(struct thread *td, const char **);
55d5bc81e6SKyle Evans
56d5bc81e6SKyle Evans int compress_user_cores = 0;
57d5bc81e6SKyle Evans
58ce51f799SKyle Evans static SLIST_HEAD(, coredumper) coredumpers =
59ce51f799SKyle Evans SLIST_HEAD_INITIALIZER(coredumpers);
60ce51f799SKyle Evans static struct rmlock coredump_rmlock;
61ce51f799SKyle Evans RM_SYSINIT(coredump_lock, &coredump_rmlock, "coredump_lock");
62ce51f799SKyle 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
sysctl_compress_user_cores(SYSCTL_HANDLER_ARGS)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
102ce51f799SKyle Evans void
coredumper_register(struct coredumper * cd)103ce51f799SKyle Evans coredumper_register(struct coredumper *cd)
104ce51f799SKyle Evans {
105ce51f799SKyle Evans
106ce51f799SKyle Evans blockcount_init(&cd->cd_refcount);
107ce51f799SKyle Evans rm_wlock(&coredump_rmlock);
108ce51f799SKyle Evans SLIST_INSERT_HEAD(&coredumpers, cd, cd_entry);
109ce51f799SKyle Evans rm_wunlock(&coredump_rmlock);
110ce51f799SKyle Evans }
111ce51f799SKyle Evans
112ce51f799SKyle Evans void
coredumper_unregister(struct coredumper * cd)113ce51f799SKyle Evans coredumper_unregister(struct coredumper *cd)
114ce51f799SKyle Evans {
115ce51f799SKyle Evans
116ce51f799SKyle Evans rm_wlock(&coredump_rmlock);
117ce51f799SKyle Evans SLIST_REMOVE(&coredumpers, cd, coredumper, cd_entry);
118ce51f799SKyle Evans rm_wunlock(&coredump_rmlock);
119ce51f799SKyle Evans
120ce51f799SKyle Evans /*
121ce51f799SKyle Evans * Wait for any in-process coredumps to finish before returning.
122ce51f799SKyle Evans */
123ce51f799SKyle Evans blockcount_wait(&cd->cd_refcount, NULL, "dumpwait", 0);
124ce51f799SKyle Evans }
125ce51f799SKyle 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
sigexit(struct thread * td,int sig)135d5bc81e6SKyle Evans sigexit(struct thread *td, int sig)
136d5bc81e6SKyle Evans {
137d5bc81e6SKyle Evans struct proc *p = td->td_proc;
138d5bc81e6SKyle Evans int rv;
139d5bc81e6SKyle Evans bool logexit;
140d5bc81e6SKyle Evans
141d5bc81e6SKyle Evans PROC_LOCK_ASSERT(p, MA_OWNED);
142d5bc81e6SKyle Evans proc_set_p2_wexit(p);
143d5bc81e6SKyle Evans
144d5bc81e6SKyle Evans p->p_acflag |= AXSIG;
145d5bc81e6SKyle Evans if ((p->p_flag2 & P2_LOGSIGEXIT_CTL) == 0)
146d5bc81e6SKyle Evans logexit = kern_logsigexit != 0;
147d5bc81e6SKyle Evans else
148d5bc81e6SKyle Evans logexit = (p->p_flag2 & P2_LOGSIGEXIT_ENABLE) != 0;
149d5bc81e6SKyle Evans
150d5bc81e6SKyle Evans /*
151d5bc81e6SKyle Evans * We must be single-threading to generate a core dump. This
152d5bc81e6SKyle Evans * ensures that the registers in the core file are up-to-date.
153d5bc81e6SKyle Evans * Also, the ELF dump handler assumes that the thread list doesn't
154d5bc81e6SKyle Evans * change out from under it.
155d5bc81e6SKyle Evans *
156d5bc81e6SKyle Evans * XXX If another thread attempts to single-thread before us
157d5bc81e6SKyle Evans * (e.g. via fork()), we won't get a dump at all.
158d5bc81e6SKyle Evans */
159d5bc81e6SKyle Evans if (sig_do_core(sig) && thread_single(p, SINGLE_NO_EXIT) == 0) {
160*3ce3b342SKyle Evans const char *err = NULL;
161*3ce3b342SKyle Evans
162d5bc81e6SKyle Evans p->p_sig = sig;
163d5bc81e6SKyle Evans /*
164d5bc81e6SKyle Evans * Log signals which would cause core dumps
165d5bc81e6SKyle Evans * (Log as LOG_INFO to appease those who don't want
166d5bc81e6SKyle Evans * these messages.)
167d5bc81e6SKyle Evans * XXX : Todo, as well as euid, write out ruid too
168d5bc81e6SKyle Evans * Note that coredump() drops proc lock.
169d5bc81e6SKyle Evans */
170*3ce3b342SKyle Evans rv = coredump(td, &err);
171*3ce3b342SKyle Evans if (rv == 0) {
172*3ce3b342SKyle Evans MPASS(err == NULL);
173d5bc81e6SKyle Evans sig |= WCOREFLAG;
174*3ce3b342SKyle Evans } else if (err == NULL) {
175*3ce3b342SKyle Evans switch (rv) {
176d5bc81e6SKyle Evans case EFAULT:
177*3ce3b342SKyle Evans err = "bad address";
178d5bc81e6SKyle Evans break;
179d5bc81e6SKyle Evans case EINVAL:
180*3ce3b342SKyle Evans err = "invalild argument";
181d5bc81e6SKyle Evans break;
182d5bc81e6SKyle Evans case EFBIG:
183*3ce3b342SKyle Evans err = "too large";
184d5bc81e6SKyle Evans break;
185d5bc81e6SKyle Evans default:
186*3ce3b342SKyle Evans err = "other error";
187d5bc81e6SKyle Evans break;
188d5bc81e6SKyle Evans }
189*3ce3b342SKyle Evans }
190d5bc81e6SKyle Evans if (logexit)
191d5bc81e6SKyle Evans log(LOG_INFO,
192d5bc81e6SKyle Evans "pid %d (%s), jid %d, uid %d: exited on "
193*3ce3b342SKyle Evans "signal %d (%s%s)\n", p->p_pid, p->p_comm,
194d5bc81e6SKyle Evans p->p_ucred->cr_prison->pr_id,
195*3ce3b342SKyle Evans td->td_ucred->cr_uid, sig &~ WCOREFLAG,
196*3ce3b342SKyle Evans err != NULL ? "no core dump - " : "core dumped",
197*3ce3b342SKyle Evans err != NULL ? err : "");
198d5bc81e6SKyle Evans } else
199d5bc81e6SKyle Evans PROC_UNLOCK(p);
200d5bc81e6SKyle Evans exit1(td, 0, sig);
201d5bc81e6SKyle Evans /* NOTREACHED */
202d5bc81e6SKyle Evans }
203d5bc81e6SKyle Evans
204d5bc81e6SKyle Evans
205d5bc81e6SKyle Evans /*
206d5bc81e6SKyle Evans * Dump a process' core. The main routine does some
207d5bc81e6SKyle Evans * policy checking, and creates the name of the coredump;
208d5bc81e6SKyle Evans * then it passes on a vnode and a size limit to the process-specific
209d5bc81e6SKyle Evans * coredump routine if there is one; if there _is not_ one, it returns
210d5bc81e6SKyle Evans * ENOSYS; otherwise it returns the error from the process-specific routine.
211d5bc81e6SKyle Evans */
212d5bc81e6SKyle Evans static int
coredump(struct thread * td,const char ** errmsg)213*3ce3b342SKyle Evans coredump(struct thread *td, const char **errmsg)
214d5bc81e6SKyle Evans {
215ce51f799SKyle Evans struct coredumper *iter, *chosen;
216d5bc81e6SKyle Evans struct proc *p = td->td_proc;
217ce51f799SKyle Evans struct rm_priotracker tracker;
218d5bc81e6SKyle Evans off_t limit;
219ce51f799SKyle Evans int error, priority;
220d5bc81e6SKyle Evans
221d5bc81e6SKyle Evans PROC_LOCK_ASSERT(p, MA_OWNED);
222d5bc81e6SKyle Evans MPASS((p->p_flag & P_HADTHREADS) == 0 || p->p_singlethread == td);
223d5bc81e6SKyle Evans
224d5bc81e6SKyle Evans if (!do_coredump || (!sugid_coredump && (p->p_flag & P_SUGID) != 0) ||
225d5bc81e6SKyle Evans (p->p_flag2 & P2_NOTRACE) != 0) {
226d5bc81e6SKyle Evans PROC_UNLOCK(p);
227*3ce3b342SKyle Evans
228*3ce3b342SKyle Evans if (!do_coredump)
229*3ce3b342SKyle Evans *errmsg = "denied by kern.coredump";
230*3ce3b342SKyle Evans else if ((p->p_flag2 & P2_NOTRACE) != 0)
231*3ce3b342SKyle Evans *errmsg = "process has trace disabled";
232*3ce3b342SKyle Evans else
233*3ce3b342SKyle Evans *errmsg = "sugid process denied by kern.sugid_coredump";
234d5bc81e6SKyle Evans return (EFAULT);
235d5bc81e6SKyle Evans }
236d5bc81e6SKyle Evans
237d5bc81e6SKyle Evans /*
238d5bc81e6SKyle Evans * Note that the bulk of limit checking is done after
239d5bc81e6SKyle Evans * the corefile is created. The exception is if the limit
240d5bc81e6SKyle Evans * for corefiles is 0, in which case we don't bother
241d5bc81e6SKyle Evans * creating the corefile at all. This layout means that
242d5bc81e6SKyle Evans * a corefile is truncated instead of not being created,
243d5bc81e6SKyle Evans * if it is larger than the limit.
244d5bc81e6SKyle Evans */
245d5bc81e6SKyle Evans limit = (off_t)lim_cur(td, RLIMIT_CORE);
246d5bc81e6SKyle Evans if (limit == 0 || racct_get_available(p, RACCT_CORE) == 0) {
247d5bc81e6SKyle Evans PROC_UNLOCK(p);
248*3ce3b342SKyle Evans *errmsg = "coredumpsize limit is 0";
249d5bc81e6SKyle Evans return (EFBIG);
250d5bc81e6SKyle Evans }
251d5bc81e6SKyle Evans
252ce51f799SKyle Evans rm_rlock(&coredump_rmlock, &tracker);
253ce51f799SKyle Evans priority = -1;
254ce51f799SKyle Evans chosen = NULL;
255ce51f799SKyle Evans SLIST_FOREACH(iter, &coredumpers, cd_entry) {
256ce51f799SKyle Evans if (iter->cd_probe == NULL) {
257ce51f799SKyle Evans /*
258ce51f799SKyle Evans * If we haven't found anything of a higher priority
259ce51f799SKyle Evans * yet, we'll call this a GENERIC. Ideally, we want
260ce51f799SKyle Evans * coredumper modules to include a probe function.
261ce51f799SKyle Evans */
262ce51f799SKyle Evans if (priority < 0) {
263ce51f799SKyle Evans priority = COREDUMPER_GENERIC;
264ce51f799SKyle Evans chosen = iter;
265ce51f799SKyle Evans }
266ce51f799SKyle Evans
267ce51f799SKyle Evans continue;
268ce51f799SKyle Evans }
269ce51f799SKyle Evans
270ce51f799SKyle Evans error = (*iter->cd_probe)(td);
271ce51f799SKyle Evans if (error < 0)
272ce51f799SKyle Evans continue;
273ce51f799SKyle Evans
274ce51f799SKyle Evans /*
275ce51f799SKyle Evans * Higher priority than previous options.
276ce51f799SKyle Evans */
277ce51f799SKyle Evans if (error > priority) {
278ce51f799SKyle Evans priority = error;
279ce51f799SKyle Evans chosen = iter;
280ce51f799SKyle Evans }
281ce51f799SKyle Evans }
282ce51f799SKyle Evans
283ce51f799SKyle Evans /*
284ce51f799SKyle Evans * Acquire our refcount before we drop the lock so that
285ce51f799SKyle Evans * coredumper_unregister() can safely assume that the refcount will only
286ce51f799SKyle Evans * go down once it's dropped the rmlock.
287ce51f799SKyle Evans */
288ce51f799SKyle Evans blockcount_acquire(&chosen->cd_refcount, 1);
289ce51f799SKyle Evans rm_runlock(&coredump_rmlock, &tracker);
290ce51f799SKyle Evans
291ce51f799SKyle Evans /* Currently, we always have the vnode dumper built in. */
292ce51f799SKyle Evans MPASS(chosen != NULL);
293ce51f799SKyle Evans error = ((*chosen->cd_handle)(td, limit));
294d5bc81e6SKyle Evans PROC_LOCK_ASSERT(p, MA_NOTOWNED);
295d5bc81e6SKyle Evans
296ce51f799SKyle Evans blockcount_release(&chosen->cd_refcount, 1);
297ce51f799SKyle Evans
298d5bc81e6SKyle Evans return (error);
299d5bc81e6SKyle Evans }
300