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