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