xref: /freebsd/sys/kern/kern_ucoredump.c (revision ce51f79913aa28a32217a424845a2649019535af)
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