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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2016 by Delphix. All rights reserved.
25 * Copyright 2019 Joyent Inc.
26 */
27
28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
30
31 #include <sys/param.h>
32 #include <sys/types.h>
33 #include <sys/time.h>
34 #include <sys/sysmacros.h>
35 #include <sys/proc.h>
36 #include <sys/systm.h>
37 #include <sys/cred.h>
38 #include <sys/user.h>
39 #include <sys/utsname.h>
40 #include <sys/errno.h>
41 #include <sys/signal.h>
42 #include <sys/siginfo.h>
43 #include <sys/fault.h>
44 #include <sys/syscall.h>
45 #include <sys/ucontext.h>
46 #include <sys/prsystm.h>
47 #include <sys/vnode.h>
48 #include <sys/var.h>
49 #include <sys/file.h>
50 #include <sys/pathname.h>
51 #include <sys/vfs.h>
52 #include <sys/exec.h>
53 #include <sys/debug.h>
54 #include <sys/stack.h>
55 #include <sys/kmem.h>
56 #include <sys/schedctl.h>
57 #include <sys/core.h>
58 #include <sys/corectl.h>
59 #include <sys/cmn_err.h>
60 #include <vm/as.h>
61 #include <sys/rctl.h>
62 #include <sys/nbmlock.h>
63 #include <sys/stat.h>
64 #include <sys/zone.h>
65 #include <sys/contract/process_impl.h>
66 #include <sys/ddi.h>
67
68 /*
69 * Processes running within a zone potentially dump core in 3 locations,
70 * based on the per-process, per-zone, and the global zone's core settings.
71 *
72 * Per-zone and global zone settings are often referred to as "global"
73 * settings since they apply to the system (or zone) as a whole, as
74 * opposed to a particular process.
75 */
76 enum core_types {
77 CORE_PROC, /* Use per-process settings */
78 CORE_ZONE, /* Use per-zone settings */
79 CORE_GLOBAL /* Use global zone settings */
80 };
81
82 /*
83 * Log information about "global" core dumps to syslog.
84 */
85 static void
core_log(struct core_globals * cg,int error,const char * why,const char * path,zoneid_t zoneid)86 core_log(struct core_globals *cg, int error, const char *why, const char *path,
87 zoneid_t zoneid)
88 {
89 proc_t *p = curproc;
90 pid_t pid = p->p_pid;
91 char *fn = PTOU(p)->u_comm;
92
93 if (!(cg->core_options & CC_GLOBAL_LOG))
94 return;
95
96 if (path == NULL)
97 zcmn_err(zoneid, CE_NOTE, "core_log: %s[%d] %s", fn, pid, why);
98 else if (error == 0)
99 zcmn_err(zoneid, CE_NOTE, "core_log: %s[%d] %s: %s", fn, pid,
100 why, path);
101 else
102 zcmn_err(zoneid, CE_NOTE, "core_log: %s[%d] %s, errno=%d: %s",
103 fn, pid, why, error, path);
104 }
105
106 /*
107 * Private version of vn_remove().
108 * Refuse to unlink a directory or an unwritable file.
109 * Also allow the process to access files normally inaccessible due to
110 * chroot(2) or Zone limitations.
111 */
112 static int
remove_core_file(char * fp,enum core_types core_type)113 remove_core_file(char *fp, enum core_types core_type)
114 {
115 vnode_t *vp = NULL; /* entry vnode */
116 vnode_t *dvp; /* ptr to parent dir vnode */
117 vfs_t *dvfsp;
118 int error;
119 int in_crit = 0;
120 pathname_t pn; /* name of entry */
121 vnode_t *startvp, *rootvp;
122
123 if ((error = pn_get(fp, UIO_SYSSPACE, &pn)) != 0)
124 return (error);
125 /*
126 * Determine what rootvp to use.
127 */
128 if (core_type == CORE_PROC) {
129 rootvp = (PTOU(curproc)->u_rdir == NULL ?
130 curproc->p_zone->zone_rootvp : PTOU(curproc)->u_rdir);
131 startvp = (fp[0] == '/' ? rootvp : PTOU(curproc)->u_cdir);
132 } else if (core_type == CORE_ZONE) {
133 startvp = curproc->p_zone->zone_rootvp;
134 rootvp = curproc->p_zone->zone_rootvp;
135 } else {
136 ASSERT(core_type == CORE_GLOBAL);
137 startvp = rootdir;
138 rootvp = rootdir;
139 }
140 VN_HOLD(startvp);
141 if (rootvp != rootdir)
142 VN_HOLD(rootvp);
143 if ((error = lookuppnvp(&pn, NULL, NO_FOLLOW, &dvp, &vp, rootvp,
144 startvp, CRED())) != 0) {
145 pn_free(&pn);
146 return (error);
147 }
148 /*
149 * Succeed if there is no file.
150 * Fail if the file is not a regular file.
151 * Fail if the filesystem is mounted read-only.
152 * Fail if the file is not writeable.
153 * Fail if the file has NBMAND share reservations.
154 */
155 if (vp == NULL)
156 error = 0;
157 else if (vp->v_type != VREG)
158 error = EACCES;
159 else if ((dvfsp = dvp->v_vfsp) != NULL &&
160 (dvfsp->vfs_flag & VFS_RDONLY))
161 error = EROFS;
162 else if ((error = VOP_ACCESS(vp, VWRITE, 0, CRED(), NULL)) == 0) {
163 if (nbl_need_check(vp)) {
164 nbl_start_crit(vp, RW_READER);
165 in_crit = 1;
166 if (nbl_share_conflict(vp, NBL_REMOVE, NULL)) {
167 error = EACCES;
168 }
169 }
170 if (!error) {
171 error = VOP_REMOVE(dvp, pn.pn_path, CRED(), NULL, 0);
172 }
173 }
174
175 pn_free(&pn);
176 if (vp != NULL) {
177 if (in_crit)
178 nbl_end_crit(vp);
179 VN_RELE(vp);
180 }
181 VN_RELE(dvp);
182 return (error);
183 }
184
185 /*
186 * Create the core file in a location that may be normally inaccessible due
187 * to chroot(2) or Zone limitations.
188 */
189 static int
create_core_file(char * fp,enum core_types core_type,vnode_t ** vpp)190 create_core_file(char *fp, enum core_types core_type, vnode_t **vpp)
191 {
192 int error;
193 mode_t perms = (S_IRUSR | S_IWUSR);
194 pathname_t pn;
195 char *file;
196 vnode_t *vp;
197 vnode_t *dvp;
198 vattr_t vattr;
199 cred_t *credp = CRED();
200
201 if (core_type == CORE_PROC) {
202 file = fp;
203 dvp = NULL; /* regular lookup */
204 } else {
205 vnode_t *startvp, *rootvp;
206
207 ASSERT(core_type == CORE_ZONE || core_type == CORE_GLOBAL);
208 /*
209 * This is tricky because we want to dump the core in
210 * a location which may normally be inaccessible
211 * to us (due to chroot(2) limitations, or zone
212 * membership), and hence need to overcome u_rdir
213 * restrictions. The basic idea is to separate
214 * the path from the filename, lookup the
215 * pathname separately (starting from the global
216 * zone's root directory), and then open the
217 * file starting at the directory vnode.
218 */
219 if (error = pn_get(fp, UIO_SYSSPACE, &pn))
220 return (error);
221
222 if (core_type == CORE_ZONE) {
223 startvp = rootvp = curproc->p_zone->zone_rootvp;
224 } else {
225 startvp = rootvp = rootdir;
226 }
227 /*
228 * rootvp and startvp will be VN_RELE()'d by lookuppnvp() if
229 * necessary.
230 */
231 VN_HOLD(startvp);
232 if (rootvp != rootdir)
233 VN_HOLD(rootvp);
234 /*
235 * Do a lookup on the full path, ignoring the actual file, but
236 * finding the vnode for the directory. It's OK if the file
237 * doesn't exist -- it most likely won't since we just removed
238 * it.
239 */
240 error = lookuppnvp(&pn, NULL, FOLLOW, &dvp, NULLVPP,
241 rootvp, startvp, credp);
242 pn_free(&pn);
243 if (error != 0)
244 return (error);
245 ASSERT(dvp != NULL);
246 /*
247 * Now find the final component in the path (ie, the name of
248 * the core file).
249 */
250 if (error = pn_get(fp, UIO_SYSSPACE, &pn)) {
251 VN_RELE(dvp);
252 return (error);
253 }
254 pn_setlast(&pn);
255 file = pn.pn_path;
256 }
257 error = vn_openat(file, UIO_SYSSPACE,
258 FWRITE | FTRUNC | FEXCL | FCREAT | FOFFMAX,
259 perms, &vp, CRCREAT, PTOU(curproc)->u_cmask, dvp, -1);
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, NULL) != 0 ||
270 vattr.va_uid != crgetuid(credp))) {
271 (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0,
272 credp, NULL);
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 *
set_cred(proc_t * p,cred_t * newcr)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
do_core(char * fp,int sig,enum core_types core_type,struct core_globals * cg)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 they could convince a root process,
405 * perhaps a set-uid root process that they 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 if ((eswp = PTOU(curproc)->u_execsw) == NULL ||
441 (eswp = findexec_by_magic(eswp->exec_magic)) == NULL) {
442 error = ENOSYS;
443 } else {
444 error = eswp->exec_core(vp, p, credp, rlimit, sig,
445 content);
446 rw_exit(eswp->exec_lock);
447 }
448
449 closerr = VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, credp, NULL);
450 VN_RELE(vp);
451 if (error == 0)
452 error = closerr;
453 }
454
455 if (ocredp != NULL)
456 crfree(credp);
457
458 return (error);
459 }
460
461 /*
462 * Convert a core name pattern to a pathname.
463 */
464 static int
expand_string(const char * pat,char * fp,int size,cred_t * cr)465 expand_string(const char *pat, char *fp, int size, cred_t *cr)
466 {
467 proc_t *p = curproc;
468 char buf[24];
469 int len, i;
470 char *s;
471 char c;
472
473 while ((c = *pat++) != '\0') {
474 if (size < 2)
475 return (ENAMETOOLONG);
476 if (c != '%') {
477 size--;
478 *fp++ = c;
479 continue;
480 }
481 if ((c = *pat++) == '\0') {
482 size--;
483 *fp++ = '%';
484 break;
485 }
486 switch (c) {
487 case 'p': /* pid */
488 (void) sprintf((s = buf), "%d", p->p_pid);
489 break;
490 case 'u': /* effective uid */
491 (void) sprintf((s = buf), "%u", crgetuid(p->p_cred));
492 break;
493 case 'g': /* effective gid */
494 (void) sprintf((s = buf), "%u", crgetgid(p->p_cred));
495 break;
496 case 'f': /* exec'd filename */
497 s = PTOU(p)->u_comm;
498 break;
499 case 'd': /* exec'd dirname */
500 /*
501 * Even if pathname caching is disabled, we should
502 * be able to lookup the pathname for a directory.
503 */
504 if (p->p_execdir != NULL && vnodetopath(NULL,
505 p->p_execdir, fp, size, cr) == 0) {
506 len = (int)strlen(fp);
507 ASSERT(len < size);
508 ASSERT(len >= 1);
509 ASSERT(fp[0] == '/');
510
511 /*
512 * Strip off the leading slash.
513 */
514 for (i = 0; i < len; i++) {
515 fp[i] = fp[i + 1];
516 }
517
518 len--;
519
520 size -= len;
521 fp += len;
522 } else {
523 *fp = '\0';
524 }
525
526 continue;
527 case 'n': /* system nodename */
528 s = uts_nodename();
529 break;
530 case 'm': /* machine (sun4u, etc) */
531 s = utsname.machine;
532 break;
533 case 't': /* decimal value of time(2) */
534 (void) sprintf((s = buf), "%ld", gethrestime_sec());
535 break;
536 case 'z':
537 s = p->p_zone->zone_name;
538 break;
539 case 'Z':
540 /* This is zonepath + "/root/", except for GZ */
541 s = p->p_zone->zone_rootpath;
542 break;
543 case '%':
544 (void) strcpy((s = buf), "%");
545 break;
546 default:
547 s = buf;
548 buf[0] = '%';
549 buf[1] = c;
550 buf[2] = '\0';
551 break;
552 }
553 len = (int)strlen(s);
554 if ((size -= len) <= 0)
555 return (ENAMETOOLONG);
556 (void) strcpy(fp, s);
557 /* strip trailing "/root/" from non-GZ zonepath string */
558 if (c == 'Z' && len > 6) {
559 len -= 6;
560 ASSERT(strncmp(fp + len, "/root/", 6) == 0);
561 }
562 fp += len;
563 }
564
565 *fp = '\0';
566 return (0);
567 }
568
569 static int
dump_one_core(int sig,rlim64_t rlimit,enum core_types core_type,struct core_globals * cg,char ** name)570 dump_one_core(int sig, rlim64_t rlimit, enum core_types core_type,
571 struct core_globals *cg, char **name)
572 {
573 refstr_t *rp;
574 proc_t *p = curproc;
575 zoneid_t zoneid;
576 int error;
577 char *fp;
578 cred_t *cr;
579
580 ASSERT(core_type == CORE_ZONE || core_type == CORE_GLOBAL);
581 zoneid = (core_type == CORE_ZONE ? getzoneid() : GLOBAL_ZONEID);
582
583 mutex_enter(&cg->core_lock);
584 if ((rp = cg->core_file) != NULL)
585 refstr_hold(rp);
586 mutex_exit(&cg->core_lock);
587 if (rp == NULL) {
588 core_log(cg, 0, "no global core file pattern exists", NULL,
589 zoneid);
590 return (1); /* core file not generated */
591 }
592 fp = kmem_alloc(MAXPATHLEN, KM_SLEEP);
593 cr = zone_get_kcred(getzoneid());
594 error = expand_string(refstr_value(rp), fp, MAXPATHLEN, cr);
595 crfree(cr);
596 if (error != 0) {
597 core_log(cg, 0, "global core file pattern too long",
598 refstr_value(rp), zoneid);
599 } else if ((error = do_core(fp, sig, core_type, cg)) == 0) {
600 core_log(cg, 0, "core dumped", fp, zoneid);
601 } else if (error == ENOTSUP) {
602 core_log(cg, 0, "setid process, core not dumped", fp, zoneid);
603 } else if (error == ENOSPC) {
604 core_log(cg, 0, "no space left on device, core truncated",
605 fp, zoneid);
606 } else if (error == EFBIG) {
607 if (rlimit == 0)
608 core_log(cg, 0, "core rlimit is zero, core not dumped",
609 fp, zoneid);
610 else
611 core_log(cg, 0, "core rlimit exceeded, core truncated",
612 fp, zoneid);
613 /*
614 * In addition to the core result logging, we
615 * may also have explicit actions defined on
616 * core file size violations via the resource
617 * control framework.
618 */
619 mutex_enter(&p->p_lock);
620 (void) rctl_action(rctlproc_legacy[RLIMIT_CORE],
621 p->p_rctls, p, RCA_SAFE);
622 mutex_exit(&p->p_lock);
623 } else {
624 core_log(cg, error, "core dump failed", fp, zoneid);
625 }
626 refstr_rele(rp);
627 if (name != NULL)
628 *name = fp;
629 else
630 kmem_free(fp, MAXPATHLEN);
631 return (error);
632 }
633
634 int
core(int sig,int ext)635 core(int sig, int ext)
636 {
637 proc_t *p = curproc;
638 klwp_t *lwp = ttolwp(curthread);
639 refstr_t *rp;
640 char *fp_process = NULL, *fp_global = NULL, *fp_zone = NULL;
641 int error1 = 1;
642 int error2 = 1;
643 int error3 = 1;
644 k_sigset_t sigmask;
645 k_sigset_t sighold;
646 rlim64_t rlimit;
647 struct core_globals *my_cg, *global_cg;
648
649 global_cg = zone_getspecific(core_zone_key, global_zone);
650 ASSERT(global_cg != NULL);
651
652 my_cg = zone_getspecific(core_zone_key, curproc->p_zone);
653 ASSERT(my_cg != NULL);
654
655 /* core files suppressed? */
656 if (!(my_cg->core_options & (CC_PROCESS_PATH|CC_GLOBAL_PATH)) &&
657 !(global_cg->core_options & CC_GLOBAL_PATH)) {
658 if (!ext && p->p_ct_process != NULL)
659 contract_process_core(p->p_ct_process, p, sig,
660 NULL, NULL, NULL);
661 return (1);
662 }
663
664 /*
665 * Block all signals except SIGHUP, SIGINT, SIGKILL, and SIGTERM; no
666 * other signal may interrupt a core dump. For each signal, we
667 * explicitly unblock it and set it in p_siginfo to allow for some
668 * minimal error reporting. Additionally, we get the current limit on
669 * core file size for handling later error reporting.
670 */
671 mutex_enter(&p->p_lock);
672
673 p->p_flag |= SDOCORE;
674 schedctl_finish_sigblock(curthread);
675 sigmask = curthread->t_hold; /* remember for later */
676 sigfillset(&sighold);
677 if (!sigismember(&sigmask, SIGHUP))
678 sigdelset(&sighold, SIGHUP);
679 if (!sigismember(&sigmask, SIGINT))
680 sigdelset(&sighold, SIGINT);
681 if (!sigismember(&sigmask, SIGKILL))
682 sigdelset(&sighold, SIGKILL);
683 if (!sigismember(&sigmask, SIGTERM))
684 sigdelset(&sighold, SIGTERM);
685
686 sigaddset(&p->p_siginfo, SIGHUP);
687 sigaddset(&p->p_siginfo, SIGINT);
688 sigaddset(&p->p_siginfo, SIGKILL);
689 sigaddset(&p->p_siginfo, SIGTERM);
690
691 curthread->t_hold = sighold;
692
693 rlimit = rctl_enforced_value(rctlproc_legacy[RLIMIT_CORE], p->p_rctls,
694 p);
695
696 mutex_exit(&p->p_lock);
697
698 /*
699 * Undo any watchpoints.
700 */
701 pr_free_watched_pages(p);
702
703 /*
704 * The presence of a current signal prevents file i/o
705 * from succeeding over a network. We copy the current
706 * signal information to the side and cancel the current
707 * signal so that the core dump will succeed.
708 */
709 ASSERT(lwp->lwp_cursig == sig);
710 lwp->lwp_cursig = 0;
711 lwp->lwp_extsig = 0;
712 if (lwp->lwp_curinfo == NULL) {
713 bzero(&lwp->lwp_siginfo, sizeof (k_siginfo_t));
714 lwp->lwp_siginfo.si_signo = sig;
715 lwp->lwp_siginfo.si_code = SI_NOINFO;
716 } else {
717 bcopy(&lwp->lwp_curinfo->sq_info,
718 &lwp->lwp_siginfo, sizeof (k_siginfo_t));
719 siginfofree(lwp->lwp_curinfo);
720 lwp->lwp_curinfo = NULL;
721 }
722
723 /*
724 * Convert the core file name patterns into path names
725 * and call do_core() to write the core files.
726 */
727
728 if (my_cg->core_options & CC_PROCESS_PATH) {
729 mutex_enter(&p->p_lock);
730 if (p->p_corefile != NULL)
731 rp = corectl_path_value(p->p_corefile);
732 else
733 rp = NULL;
734 mutex_exit(&p->p_lock);
735 if (rp != NULL) {
736 fp_process = kmem_alloc(MAXPATHLEN, KM_SLEEP);
737 error1 = expand_string(refstr_value(rp),
738 fp_process, MAXPATHLEN, p->p_cred);
739 if (error1 == 0)
740 error1 = do_core(fp_process, sig, CORE_PROC,
741 my_cg);
742 refstr_rele(rp);
743 }
744 }
745
746 if (my_cg->core_options & CC_GLOBAL_PATH)
747 error2 = dump_one_core(sig, rlimit, CORE_ZONE, my_cg,
748 &fp_global);
749 if (global_cg != my_cg && (global_cg->core_options & CC_GLOBAL_PATH))
750 error3 = dump_one_core(sig, rlimit, CORE_GLOBAL, global_cg,
751 &fp_zone);
752
753 /*
754 * Restore the signal hold mask.
755 */
756 mutex_enter(&p->p_lock);
757 curthread->t_hold = sigmask;
758 mutex_exit(&p->p_lock);
759
760 if (!ext && p->p_ct_process != NULL)
761 contract_process_core(p->p_ct_process, p, sig,
762 error1 == 0 ? fp_process : NULL,
763 error2 == 0 ? fp_global : NULL,
764 error3 == 0 ? fp_zone : NULL);
765
766 if (fp_process != NULL)
767 kmem_free(fp_process, MAXPATHLEN);
768 if (fp_global != NULL)
769 kmem_free(fp_global, MAXPATHLEN);
770 if (fp_zone != NULL)
771 kmem_free(fp_zone, MAXPATHLEN);
772
773 /*
774 * Return non-zero if no core file was created.
775 */
776 return (error1 != 0 && error2 != 0 && error3 != 0);
777 }
778
779 /*
780 * Maximum chunk size for dumping core files,
781 * size in pages, patchable in /etc/system
782 */
783 uint_t core_chunk = 32;
784
785 /*
786 * The delay between core_write() calls, in microseconds. The default
787 * matches one "normal" clock tick, or 10 milliseconds.
788 */
789 clock_t core_delay_usec = 10000;
790
791 /*
792 * Common code to core dump process memory. The core_seg routine does i/o
793 * using core_write() below, and so it has the same failure semantics.
794 */
795 int
core_seg(proc_t * p,vnode_t * vp,u_offset_t offset,caddr_t addr,size_t size,rlim64_t rlimit,cred_t * credp)796 core_seg(proc_t *p, vnode_t *vp, u_offset_t offset, caddr_t addr, size_t size,
797 rlim64_t rlimit, cred_t *credp)
798 {
799 caddr_t eaddr;
800 caddr_t base;
801 size_t len;
802 int err = 0;
803
804 if (offset > OFF_MAX || offset + size > OFF_MAX ||
805 offset + size < offset) {
806 return (EOVERFLOW);
807 }
808
809 eaddr = addr + size;
810 for (base = addr; base < eaddr; base += len) {
811 len = eaddr - base;
812 if (as_memory(p->p_as, &base, &len) != 0)
813 return (0);
814
815 /*
816 * Reduce len to a reasonable value so that we don't
817 * overwhelm the VM system with a monstrously large
818 * single write and cause pageout to stop running.
819 */
820 if (len > (size_t)core_chunk * PAGESIZE)
821 len = (size_t)core_chunk * PAGESIZE;
822
823 err = core_write(vp, UIO_USERSPACE,
824 offset + (size_t)(base - addr), base, len, rlimit, credp);
825
826 if (err)
827 return (err);
828
829 /*
830 * If we have taken a signal, return EINTR to allow the dump
831 * to be aborted.
832 */
833 if (issig(JUSTLOOKING) && issig(FORREAL))
834 return (EINTR);
835 }
836
837 return (0);
838 }
839
840 /*
841 * Wrapper around vn_rdwr to perform writes to a core file. For core files,
842 * we always want to write as much as we possibly can, and then make sure to
843 * return either 0 to the caller (for success), or the actual errno value.
844 * By using this function, the caller can omit additional code for handling
845 * retries and errors for partial writes returned by vn_rdwr. If vn_rdwr
846 * unexpectedly returns zero but no progress has been made, we return ENOSPC.
847 */
848 int
core_write(vnode_t * vp,enum uio_seg segflg,u_offset_t offset,const void * buf,size_t len,rlim64_t rlimit,cred_t * credp)849 core_write(vnode_t *vp, enum uio_seg segflg, u_offset_t offset,
850 const void *buf, size_t len, rlim64_t rlimit, cred_t *credp)
851 {
852 ssize_t resid = len;
853 int error = 0;
854
855 if (offset > OFF_MAX || offset + len > OFF_MAX ||
856 offset + len < offset) {
857 return (EOVERFLOW);
858 }
859
860 while (len != 0) {
861 error = vn_rdwr(UIO_WRITE, vp, (caddr_t)buf, len,
862 (offset_t)offset, segflg, 0, rlimit, credp, &resid);
863
864 if (error != 0)
865 break;
866
867 if (resid >= len)
868 return (ENOSPC);
869
870 buf = (const char *)buf + len - resid;
871 offset += len - resid;
872 len = resid;
873 }
874
875 return (error);
876 }
877