xref: /illumos-gate/usr/src/uts/common/os/core.c (revision 3db86aab554edbb4244c8d1a1c90f152eee768af)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 #include <sys/param.h>
34 #include <sys/types.h>
35 #include <sys/time.h>
36 #include <sys/sysmacros.h>
37 #include <sys/proc.h>
38 #include <sys/systm.h>
39 #include <sys/cred.h>
40 #include <sys/user.h>
41 #include <sys/utsname.h>
42 #include <sys/errno.h>
43 #include <sys/signal.h>
44 #include <sys/siginfo.h>
45 #include <sys/fault.h>
46 #include <sys/syscall.h>
47 #include <sys/ucontext.h>
48 #include <sys/prsystm.h>
49 #include <sys/vnode.h>
50 #include <sys/var.h>
51 #include <sys/file.h>
52 #include <sys/pathname.h>
53 #include <sys/vfs.h>
54 #include <sys/exec.h>
55 #include <sys/debug.h>
56 #include <sys/stack.h>
57 #include <sys/kmem.h>
58 #include <sys/schedctl.h>
59 #include <sys/core.h>
60 #include <sys/corectl.h>
61 #include <sys/cmn_err.h>
62 #include <vm/as.h>
63 #include <sys/rctl.h>
64 #include <sys/nbmlock.h>
65 #include <sys/stat.h>
66 #include <sys/zone.h>
67 #include <sys/contract/process_impl.h>
68 
69 /*
70  * Processes running within a zone potentially dump core in 3 locations,
71  * based on the per-process, per-zone, and the global zone's core settings.
72  *
73  * Per-zone and global zone settings are often referred to as "global"
74  * settings since they apply to the system (or zone) as a whole, as
75  * opposed to a particular process.
76  */
77 enum core_types {
78 	CORE_PROC,	/* Use per-process settings */
79 	CORE_ZONE,	/* Use per-zone settings */
80 	CORE_GLOBAL	/* Use global zone settings */
81 };
82 
83 /*
84  * Log information about "global" core dumps to syslog.
85  */
86 static void
87 core_log(struct core_globals *cg, int error, const char *why, const char *path,
88     zoneid_t zoneid)
89 {
90 	proc_t *p = curproc;
91 	pid_t pid = p->p_pid;
92 	char *fn = PTOU(p)->u_comm;
93 
94 	if (!(cg->core_options & CC_GLOBAL_LOG))
95 		return;
96 
97 	if (path == NULL)
98 		zcmn_err(zoneid, CE_NOTE, "core_log: %s[%d] %s", fn, pid, why);
99 	else if (error == 0)
100 		zcmn_err(zoneid, CE_NOTE, "core_log: %s[%d] %s: %s", fn, pid,
101 		    why, path);
102 	else
103 		zcmn_err(zoneid, CE_NOTE, "core_log: %s[%d] %s, errno=%d: %s",
104 		    fn, pid, why, error, path);
105 }
106 
107 /*
108  * Private version of vn_remove().
109  * Refuse to unlink a directory or an unwritable file.
110  * Also allow the process to access files normally inaccessible due to
111  * chroot(2) or Zone limitations.
112  */
113 static int
114 remove_core_file(char *fp, enum core_types core_type)
115 {
116 	vnode_t *vp = NULL;		/* entry vnode */
117 	vnode_t *dvp;			/* ptr to parent dir vnode */
118 	vfs_t *dvfsp;
119 	int error;
120 	int in_crit = 0;
121 	pathname_t pn;			/* name of entry */
122 	vnode_t *startvp, *rootvp;
123 
124 	if ((error = pn_get(fp, UIO_SYSSPACE, &pn)) != 0)
125 		return (error);
126 	/*
127 	 * Determine what rootvp to use.
128 	 */
129 	if (core_type == CORE_PROC) {
130 		rootvp = (PTOU(curproc)->u_rdir == NULL ?
131 		    curproc->p_zone->zone_rootvp : PTOU(curproc)->u_rdir);
132 		startvp = (fp[0] == '/' ? rootvp : PTOU(curproc)->u_cdir);
133 	} else if (core_type == CORE_ZONE) {
134 		startvp = curproc->p_zone->zone_rootvp;
135 		rootvp = curproc->p_zone->zone_rootvp;
136 	} else {
137 		ASSERT(core_type == CORE_GLOBAL);
138 		startvp = rootdir;
139 		rootvp = rootdir;
140 	}
141 	VN_HOLD(startvp);
142 	if (rootvp != rootdir)
143 		VN_HOLD(rootvp);
144 	if ((error = lookuppnvp(&pn, NULL, NO_FOLLOW, &dvp, &vp, rootvp,
145 	    startvp, CRED())) != 0) {
146 		pn_free(&pn);
147 		return (error);
148 	}
149 	/*
150 	 * Succeed if there is no file.
151 	 * Fail if the file is not a regular file.
152 	 * Fail if the filesystem is mounted read-only.
153 	 * Fail if the file is not writeable.
154 	 * Fail if the file has NBMAND share reservations.
155 	 */
156 	if (vp == NULL)
157 		error = 0;
158 	else if (vp->v_type != VREG)
159 		error = EACCES;
160 	else if ((dvfsp = dvp->v_vfsp) != NULL &&
161 	    (dvfsp->vfs_flag & VFS_RDONLY))
162 		error = EROFS;
163 	else if ((error = VOP_ACCESS(vp, VWRITE, 0, CRED())) == 0) {
164 		if (nbl_need_check(vp)) {
165 			nbl_start_crit(vp, RW_READER);
166 			in_crit = 1;
167 			if (nbl_share_conflict(vp, NBL_REMOVE)) {
168 				error = EACCES;
169 			}
170 		}
171 		if (!error) {
172 			error = VOP_REMOVE(dvp, pn.pn_path, CRED());
173 		}
174 	}
175 
176 	pn_free(&pn);
177 	if (vp != NULL) {
178 		if (in_crit)
179 			nbl_end_crit(vp);
180 		VN_RELE(vp);
181 	}
182 	VN_RELE(dvp);
183 	return (error);
184 }
185 
186 /*
187  * Create the core file in a location that may be normally inaccessible due
188  * to chroot(2) or Zone limitations.
189  */
190 static int
191 create_core_file(char *fp, enum core_types core_type, vnode_t **vpp)
192 {
193 	int error;
194 	mode_t perms = (S_IRUSR | S_IWUSR);
195 	pathname_t pn;
196 	char *file;
197 	vnode_t *vp;
198 	vnode_t *dvp;
199 	vattr_t vattr;
200 	cred_t *credp = CRED();
201 
202 	if (core_type == CORE_PROC) {
203 		file = fp;
204 		dvp = NULL;	/* regular lookup */
205 	} else {
206 		vnode_t *startvp, *rootvp;
207 
208 		ASSERT(core_type == CORE_ZONE || core_type == CORE_GLOBAL);
209 		/*
210 		 * This is tricky because we want to dump the core in
211 		 * a location which may normally be inaccessible
212 		 * to us (due to chroot(2) limitations, or zone
213 		 * membership), and hence need to overcome u_rdir
214 		 * restrictions.  The basic idea is to separate
215 		 * the path from the filename, lookup the
216 		 * pathname separately (starting from the global
217 		 * zone's root directory), and then open the
218 		 * file starting at the directory vnode.
219 		 */
220 		if (error = pn_get(fp, UIO_SYSSPACE, &pn))
221 			return (error);
222 
223 		if (core_type == CORE_ZONE) {
224 			startvp = rootvp = curproc->p_zone->zone_rootvp;
225 		} else {
226 			startvp = rootvp = rootdir;
227 		}
228 		/*
229 		 * rootvp and startvp will be VN_RELE()'d by lookuppnvp() if
230 		 * necessary.
231 		 */
232 		VN_HOLD(startvp);
233 		if (rootvp != rootdir)
234 			VN_HOLD(rootvp);
235 		/*
236 		 * Do a lookup on the full path, ignoring the actual file, but
237 		 * finding the vnode for the directory.  It's OK if the file
238 		 * doesn't exist -- it most likely won't since we just removed
239 		 * it.
240 		 */
241 		error = lookuppnvp(&pn, NULL, FOLLOW, &dvp, NULLVPP,
242 		    rootvp, startvp, credp);
243 		pn_free(&pn);
244 		if (error != 0)
245 			return (error);
246 		ASSERT(dvp != NULL);
247 		/*
248 		 * Now find the final component in the path (ie, the name of
249 		 * the core file).
250 		 */
251 		if (error = pn_get(fp, UIO_SYSSPACE, &pn)) {
252 			VN_RELE(dvp);
253 			return (error);
254 		}
255 		pn_setlast(&pn);
256 		file = pn.pn_path;
257 	}
258 	error =  vn_openat(file, UIO_SYSSPACE, FWRITE | FTRUNC | FEXCL |
259 	    FCREAT | FOFFMAX, perms, &vp, CRCREAT, u.u_cmask, dvp);
260 	if (core_type != CORE_PROC) {
261 		VN_RELE(dvp);
262 		pn_free(&pn);
263 	}
264 	/*
265 	 * Don't dump a core file owned by "nobody".
266 	 */
267 	vattr.va_mask = AT_UID;
268 	if (error == 0 &&
269 	    (VOP_GETATTR(vp, &vattr, 0, credp) != 0 ||
270 	    vattr.va_uid != crgetuid(credp))) {
271 		(void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0,
272 		    credp);
273 		VN_RELE(vp);
274 		(void) remove_core_file(fp, core_type);
275 		error = EACCES;
276 	}
277 	*vpp = vp;
278 	return (error);
279 }
280 
281 /*
282  * Install the specified held cred into the process, and return a pointer to
283  * the held cred which was previously the value of p->p_cred.
284  */
285 static cred_t *
286 set_cred(proc_t *p, cred_t *newcr)
287 {
288 	cred_t *oldcr;
289 	uid_t olduid, newuid;
290 
291 	/*
292 	 * Place a hold on the existing cred, and then install the new
293 	 * cred into the proc structure.
294 	 */
295 	mutex_enter(&p->p_crlock);
296 	oldcr = p->p_cred;
297 	crhold(oldcr);
298 	p->p_cred = newcr;
299 	mutex_exit(&p->p_crlock);
300 
301 	ASSERT(crgetzoneid(oldcr) == crgetzoneid(newcr));
302 
303 	/*
304 	 * If the real uid is changing, keep the per-user process
305 	 * counts accurate.
306 	 */
307 	olduid = crgetruid(oldcr);
308 	newuid = crgetruid(newcr);
309 	if (olduid != newuid) {
310 		zoneid_t zoneid = crgetzoneid(newcr);
311 
312 		mutex_enter(&pidlock);
313 		upcount_dec(olduid, zoneid);
314 		upcount_inc(newuid, zoneid);
315 		mutex_exit(&pidlock);
316 	}
317 
318 	/*
319 	 * Broadcast the new cred to all the other threads.  The old
320 	 * cred can be safely returned because we have a hold on it.
321 	 */
322 	crset(p, newcr);
323 	return (oldcr);
324 }
325 
326 static int
327 do_core(char *fp, int sig, enum core_types core_type, struct core_globals *cg)
328 {
329 	proc_t *p = curproc;
330 	cred_t *credp = CRED();
331 	rlim64_t rlimit;
332 	vnode_t *vp;
333 	int error = 0;
334 	struct execsw *eswp;
335 	cred_t *ocredp = NULL;
336 	int is_setid = 0;
337 	core_content_t content;
338 	uid_t uid;
339 	gid_t gid;
340 
341 	if (core_type == CORE_GLOBAL || core_type == CORE_ZONE) {
342 		mutex_enter(&cg->core_lock);
343 		content = cg->core_content;
344 		mutex_exit(&cg->core_lock);
345 		rlimit = cg->core_rlimit;
346 	} else {
347 		mutex_enter(&p->p_lock);
348 		rlimit = rctl_enforced_value(rctlproc_legacy[RLIMIT_CORE],
349 		    p->p_rctls, p);
350 		content = corectl_content_value(p->p_content);
351 		mutex_exit(&p->p_lock);
352 	}
353 
354 	if (rlimit == 0)
355 		return (EFBIG);
356 
357 	/*
358 	 * If SNOCD is set, or if the effective, real, and saved ids do
359 	 * not match up, no one but a privileged user is allowed to view
360 	 * this core file.  Set the credentials and the owner to root.
361 	 */
362 	if ((p->p_flag & SNOCD) ||
363 	    (uid = crgetuid(credp)) != crgetruid(credp) ||
364 	    uid != crgetsuid(credp) ||
365 	    (gid = crgetgid(credp)) != crgetrgid(credp) ||
366 	    gid != crgetsgid(credp)) {
367 		/*
368 		 * Because this is insecure against certain forms of file
369 		 * system attack, do it only if set-id core files have been
370 		 * enabled via corectl(CC_GLOBAL_SETID | CC_PROCESS_SETID).
371 		 */
372 		if (((core_type == CORE_GLOBAL || core_type == CORE_ZONE) &&
373 		    !(cg->core_options & CC_GLOBAL_SETID)) ||
374 		    (core_type == CORE_PROC &&
375 		    !(cg->core_options & CC_PROCESS_SETID)))
376 			return (ENOTSUP);
377 
378 		is_setid = 1;
379 	}
380 
381 	/*
382 	 * If we are doing a "global" core dump or a set-id core dump,
383 	 * use kcred to do the dumping.
384 	 */
385 	if (core_type == CORE_GLOBAL || core_type == CORE_ZONE || is_setid) {
386 		/*
387 		 * Use the zone's "kcred" to prevent privilege
388 		 * escalation.
389 		 */
390 		credp = zone_get_kcred(getzoneid());
391 		ASSERT(credp != NULL);
392 		ocredp = set_cred(p, credp);
393 	}
394 
395 	/*
396 	 * First remove any existing core file, then
397 	 * open the new core file with (O_EXCL|O_CREAT).
398 	 *
399 	 * The reasons for doing this are manifold:
400 	 *
401 	 * For security reasons, we don't want root processes
402 	 * to dump core through a symlink because that would
403 	 * allow a malicious user to clobber any file on
404 	 * the system if s/he could convince a root process,
405 	 * perhaps a set-uid root process that s/he started,
406 	 * to dump core in a directory writable by that user.
407 	 * Similar security reasons apply to hard links.
408 	 * For symmetry we do this unconditionally, not
409 	 * just for root processes.
410 	 *
411 	 * If the process has the core file mmap()d into the
412 	 * address space, we would be modifying the address
413 	 * space that we are trying to dump if we did not first
414 	 * remove the core file.  (The command "file core"
415 	 * is the canonical example of this possibility.)
416 	 *
417 	 * Opening the core file with O_EXCL|O_CREAT ensures than
418 	 * two concurrent core dumps don't clobber each other.
419 	 * One is bound to lose; we don't want to make both lose.
420 	 */
421 	if ((error = remove_core_file(fp, core_type)) == 0) {
422 		error = create_core_file(fp, core_type, &vp);
423 	}
424 
425 	/*
426 	 * Now that vn_open is complete, reset the process's credentials if
427 	 * we changed them, and make 'credp' point to kcred used
428 	 * above.  We use 'credp' to do i/o on the core file below, but leave
429 	 * p->p_cred set to the original credential to allow the core file
430 	 * to record this information.
431 	 */
432 	if (ocredp != NULL)
433 		credp = set_cred(p, ocredp);
434 
435 	if (error == 0) {
436 		int closerr;
437 #if defined(__sparc)
438 		(void) flush_user_windows_to_stack(NULL);
439 #endif
440 #ifdef SUN_SRC_COMPAT
441 		u.u_acflag |= ACORE;
442 #endif
443 		if ((eswp = u.u_execsw) == NULL ||
444 		    (eswp = findexec_by_magic(eswp->exec_magic)) == NULL) {
445 			error = ENOSYS;
446 		} else {
447 			error = eswp->exec_core(vp, p, credp, rlimit, sig,
448 			    content);
449 			rw_exit(eswp->exec_lock);
450 		}
451 
452 		closerr = VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, credp);
453 		VN_RELE(vp);
454 		if (error == 0)
455 			error = closerr;
456 	}
457 
458 	if (ocredp != NULL)
459 		crfree(credp);
460 
461 	return (error);
462 }
463 
464 /*
465  * Convert a core name pattern to a pathname.
466  */
467 static int
468 expand_string(const char *pat, char *fp, int size, cred_t *cr)
469 {
470 	proc_t *p = curproc;
471 	char buf[24];
472 	int len, i;
473 	char *s;
474 	char c;
475 
476 	while ((c = *pat++) != '\0') {
477 		if (size < 2)
478 			return (ENAMETOOLONG);
479 		if (c != '%') {
480 			size--;
481 			*fp++ = c;
482 			continue;
483 		}
484 		if ((c = *pat++) == '\0') {
485 			size--;
486 			*fp++ = '%';
487 			break;
488 		}
489 		switch (c) {
490 		case 'p':	/* pid */
491 			(void) sprintf((s = buf), "%d", p->p_pid);
492 			break;
493 		case 'u':	/* effective uid */
494 			(void) sprintf((s = buf), "%d", crgetuid(p->p_cred));
495 			break;
496 		case 'g':	/* effective gid */
497 			(void) sprintf((s = buf), "%d", crgetgid(p->p_cred));
498 			break;
499 		case 'f':	/* exec'd filename */
500 			s = PTOU(p)->u_comm;
501 			break;
502 		case 'd':	/* exec'd dirname */
503 			/*
504 			 * Even if pathname caching is disabled, we should
505 			 * be able to lookup the pathname for a directory.
506 			 */
507 			if (p->p_execdir != NULL && vnodetopath(NULL,
508 			    p->p_execdir, fp, size, cr) == 0) {
509 				len = (int)strlen(fp);
510 				ASSERT(len < size);
511 				ASSERT(len >= 1);
512 				ASSERT(fp[0] == '/');
513 
514 				/*
515 				 * Strip off the leading slash.
516 				 */
517 				for (i = 0; i < len; i++) {
518 					fp[i] = fp[i + 1];
519 				}
520 
521 				len--;
522 
523 				size -= len;
524 				fp += len;
525 			} else {
526 				*fp = '\0';
527 			}
528 
529 			continue;
530 		case 'n':	/* system nodename */
531 			s = uts_nodename();
532 			break;
533 		case 'm':	/* machine (sun4u, etc) */
534 			s = utsname.machine;
535 			break;
536 		case 't':	/* decimal value of time(2) */
537 			(void) sprintf((s = buf), "%ld", gethrestime_sec());
538 			break;
539 		case 'z':
540 			s = p->p_zone->zone_name;
541 			break;
542 		case '%':
543 			(void) strcpy((s = buf), "%");
544 			break;
545 		default:
546 			s = buf;
547 			buf[0] = '%';
548 			buf[1] = c;
549 			buf[2] = '\0';
550 			break;
551 		}
552 		len = (int)strlen(s);
553 		if ((size -= len) <= 0)
554 			return (ENAMETOOLONG);
555 		(void) strcpy(fp, s);
556 		fp += len;
557 	}
558 
559 	*fp = '\0';
560 	return (0);
561 }
562 
563 static int
564 dump_one_core(int sig, rlim64_t rlimit, enum core_types core_type,
565     struct core_globals *cg, char **name)
566 {
567 	refstr_t *rp;
568 	proc_t *p = curproc;
569 	zoneid_t zoneid;
570 	int error;
571 	char *fp;
572 	cred_t *cr;
573 
574 	ASSERT(core_type == CORE_ZONE || core_type == CORE_GLOBAL);
575 	zoneid = (core_type == CORE_ZONE ? getzoneid() : GLOBAL_ZONEID);
576 
577 	mutex_enter(&cg->core_lock);
578 	if ((rp = cg->core_file) != NULL)
579 		refstr_hold(rp);
580 	mutex_exit(&cg->core_lock);
581 	if (rp == NULL) {
582 		core_log(cg, 0, "no global core file pattern exists", NULL,
583 		    zoneid);
584 		return (1);	/* core file not generated */
585 	}
586 	fp = kmem_alloc(MAXPATHLEN, KM_SLEEP);
587 	cr = zone_get_kcred(getzoneid());
588 	error = expand_string(refstr_value(rp), fp, MAXPATHLEN, cr);
589 	crfree(cr);
590 	if (error != 0) {
591 		core_log(cg, 0, "global core file pattern too long",
592 		    refstr_value(rp), zoneid);
593 	} else if ((error = do_core(fp, sig, core_type, cg)) == 0) {
594 		core_log(cg, 0, "core dumped", fp, zoneid);
595 	} else if (error == ENOTSUP) {
596 		core_log(cg, 0, "setid process, core not dumped", fp, zoneid);
597 	} else if (error == ENOSPC) {
598 		core_log(cg, 0, "no space left on device, core truncated",
599 		    fp, zoneid);
600 	} else if (error == EFBIG) {
601 		if (rlimit == 0)
602 			core_log(cg, 0, "core rlimit is zero, core not dumped",
603 			    fp, zoneid);
604 		else
605 			core_log(cg, 0, "core rlimit exceeded, core truncated",
606 			    fp, zoneid);
607 		/*
608 		 * In addition to the core result logging, we
609 		 * may also have explicit actions defined on
610 		 * core file size violations via the resource
611 		 * control framework.
612 		 */
613 		mutex_enter(&p->p_lock);
614 		(void) rctl_action(rctlproc_legacy[RLIMIT_CORE],
615 		    p->p_rctls, p, RCA_SAFE);
616 		mutex_exit(&p->p_lock);
617 	} else {
618 		core_log(cg, error, "core dump failed", fp, zoneid);
619 	}
620 	refstr_rele(rp);
621 	if (name != NULL)
622 		*name = fp;
623 	else
624 		kmem_free(fp, MAXPATHLEN);
625 	return (error);
626 }
627 
628 int
629 core(int sig, int ext)
630 {
631 	proc_t *p = curproc;
632 	klwp_t *lwp = ttolwp(curthread);
633 	refstr_t *rp;
634 	char *fp_process = NULL, *fp_global = NULL, *fp_zone = NULL;
635 	int error1 = 1;
636 	int error2 = 1;
637 	int error3 = 1;
638 	k_sigset_t sigmask;
639 	k_sigset_t sighold;
640 	rlim64_t rlimit;
641 	struct core_globals *my_cg, *global_cg;
642 
643 	global_cg = zone_getspecific(core_zone_key, global_zone);
644 	ASSERT(global_cg != NULL);
645 
646 	my_cg = zone_getspecific(core_zone_key, curproc->p_zone);
647 	ASSERT(my_cg != NULL);
648 
649 	/* core files suppressed? */
650 	if (!(my_cg->core_options & (CC_PROCESS_PATH|CC_GLOBAL_PATH)) &&
651 	    !(global_cg->core_options & CC_GLOBAL_PATH)) {
652 		if (!ext && p->p_ct_process != NULL)
653 			contract_process_core(p->p_ct_process, p, sig,
654 			    NULL, NULL, NULL);
655 		return (1);
656 	}
657 
658 	/*
659 	 * Block all signals except SIGHUP, SIGINT, SIGKILL, and SIGTERM.
660 	 * These signals are allowed to interrupt the core dump.
661 	 * SIGQUIT is not allowed because it is supposed to make a core.
662 	 * Additionally, get current limit on core file size for handling later
663 	 * error reporting.
664 	 */
665 	mutex_enter(&p->p_lock);
666 
667 	p->p_flag |= SDOCORE;
668 	schedctl_finish_sigblock(curthread);
669 	sigmask = curthread->t_hold;	/* remember for later */
670 	sigfillset(&sighold);
671 	if (!sigismember(&sigmask, SIGHUP))
672 		sigdelset(&sighold, SIGHUP);
673 	if (!sigismember(&sigmask, SIGINT))
674 		sigdelset(&sighold, SIGINT);
675 	if (!sigismember(&sigmask, SIGKILL))
676 		sigdelset(&sighold, SIGKILL);
677 	if (!sigismember(&sigmask, SIGTERM))
678 		sigdelset(&sighold, SIGTERM);
679 	curthread->t_hold = sighold;
680 
681 	rlimit = rctl_enforced_value(rctlproc_legacy[RLIMIT_CORE], p->p_rctls,
682 	    p);
683 
684 	mutex_exit(&p->p_lock);
685 
686 	/*
687 	 * Undo any watchpoints.
688 	 */
689 	pr_free_watched_pages(p);
690 
691 	/*
692 	 * The presence of a current signal prevents file i/o
693 	 * from succeeding over a network.  We copy the current
694 	 * signal information to the side and cancel the current
695 	 * signal so that the core dump will succeed.
696 	 */
697 	ASSERT(lwp->lwp_cursig == sig);
698 	lwp->lwp_cursig = 0;
699 	lwp->lwp_extsig = 0;
700 	if (lwp->lwp_curinfo == NULL)
701 		bzero(&lwp->lwp_siginfo, sizeof (k_siginfo_t));
702 	else {
703 		bcopy(&lwp->lwp_curinfo->sq_info,
704 		    &lwp->lwp_siginfo, sizeof (k_siginfo_t));
705 		siginfofree(lwp->lwp_curinfo);
706 		lwp->lwp_curinfo = NULL;
707 	}
708 
709 	/*
710 	 * Convert the core file name patterns into path names
711 	 * and call do_core() to write the core files.
712 	 */
713 
714 	if (my_cg->core_options & CC_PROCESS_PATH) {
715 		mutex_enter(&p->p_lock);
716 		if (p->p_corefile != NULL)
717 			rp = corectl_path_value(p->p_corefile);
718 		else
719 			rp = NULL;
720 		mutex_exit(&p->p_lock);
721 		if (rp != NULL) {
722 			fp_process = kmem_alloc(MAXPATHLEN, KM_SLEEP);
723 			error1 = expand_string(refstr_value(rp),
724 				fp_process, MAXPATHLEN, p->p_cred);
725 			if (error1 == 0)
726 				error1 = do_core(fp_process, sig, CORE_PROC,
727 				    my_cg);
728 			refstr_rele(rp);
729 		}
730 	}
731 
732 	if (my_cg->core_options & CC_GLOBAL_PATH)
733 		error2 = dump_one_core(sig, rlimit, CORE_ZONE, my_cg,
734 		    &fp_global);
735 	if (global_cg != my_cg && (global_cg->core_options & CC_GLOBAL_PATH))
736 		error3 = dump_one_core(sig, rlimit, CORE_GLOBAL, global_cg,
737 		    &fp_zone);
738 
739 	/*
740 	 * Restore the signal hold mask.
741 	 */
742 	mutex_enter(&p->p_lock);
743 	curthread->t_hold = sigmask;
744 	mutex_exit(&p->p_lock);
745 
746 	if (!ext && p->p_ct_process != NULL)
747 		contract_process_core(p->p_ct_process, p, sig,
748 		    error1 == 0 ? fp_process : NULL,
749 		    error2 == 0 ? fp_global : NULL,
750 		    error3 == 0 ? fp_zone : NULL);
751 
752 	if (fp_process != NULL)
753 		kmem_free(fp_process, MAXPATHLEN);
754 	if (fp_global != NULL)
755 		kmem_free(fp_global, MAXPATHLEN);
756 	if (fp_zone != NULL)
757 		kmem_free(fp_zone, MAXPATHLEN);
758 
759 	/*
760 	 * Return non-zero if no core file was created.
761 	 */
762 	return (error1 != 0 && error2 != 0 && error3 != 0);
763 }
764 
765 /*
766  * Maximum chunk size for dumping core files,
767  * size in pages, patchable in /etc/system
768  */
769 uint_t	core_chunk = 32;
770 
771 /*
772  * Common code to core dump process memory.  The core_seg routine does i/o
773  * using core_write() below, and so it has the same failure semantics.
774  */
775 int
776 core_seg(proc_t *p, vnode_t *vp, offset_t offset, caddr_t addr, size_t size,
777     rlim64_t rlimit, cred_t *credp)
778 {
779 	caddr_t eaddr;
780 	caddr_t base;
781 	size_t len;
782 	int err = 0;
783 
784 	eaddr = addr + size;
785 	for (base = addr; base < eaddr; base += len) {
786 		len = eaddr - base;
787 		if (as_memory(p->p_as, &base, &len) != 0)
788 			return (0);
789 		/*
790 		 * Reduce len to a reasonable value so that we don't
791 		 * overwhelm the VM system with a monstrously large
792 		 * single write and cause pageout to stop running.
793 		 */
794 		if (len > (size_t)core_chunk * PAGESIZE)
795 		    len = (size_t)core_chunk * PAGESIZE;
796 
797 		err = core_write(vp, UIO_USERSPACE,
798 		    offset + (size_t)(base - addr), base, len, rlimit, credp);
799 
800 		if (err == 0) {
801 			/*
802 			 * Give pageout a chance to run.
803 			 * Also allow core dumping to be interruptible.
804 			 */
805 			err = delay_sig(1);
806 		}
807 		if (err)
808 			return (err);
809 	}
810 	return (0);
811 }
812 
813 /*
814  * Wrapper around vn_rdwr to perform writes to a core file.  For core files,
815  * we always want to write as much as we possibly can, and then make sure to
816  * return either 0 to the caller (for success), or the actual errno value.
817  * By using this function, the caller can omit additional code for handling
818  * retries and errors for partial writes returned by vn_rdwr.  If vn_rdwr
819  * unexpectedly returns zero but no progress has been made, we return ENOSPC.
820  */
821 int
822 core_write(vnode_t *vp, enum uio_seg segflg, offset_t offset,
823     const void *buf, size_t len, rlim64_t rlimit, cred_t *credp)
824 {
825 	ssize_t resid = len;
826 	int error = 0;
827 
828 	while (len != 0) {
829 		error = vn_rdwr(UIO_WRITE, vp, (caddr_t)buf, len, offset,
830 		    segflg, 0, rlimit, credp, &resid);
831 
832 		if (error != 0)
833 			break;
834 
835 		if (resid >= len)
836 			return (ENOSPC);
837 
838 		buf = (const char *)buf + len - resid;
839 		offset += len - resid;
840 		len = resid;
841 	}
842 
843 	return (error);
844 }
845