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 2007 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 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 #include <sys/param.h> 33 #include <sys/types.h> 34 #include <sys/time.h> 35 #include <sys/sysmacros.h> 36 #include <sys/proc.h> 37 #include <sys/systm.h> 38 #include <sys/cred.h> 39 #include <sys/user.h> 40 #include <sys/utsname.h> 41 #include <sys/errno.h> 42 #include <sys/signal.h> 43 #include <sys/siginfo.h> 44 #include <sys/fault.h> 45 #include <sys/syscall.h> 46 #include <sys/ucontext.h> 47 #include <sys/prsystm.h> 48 #include <sys/vnode.h> 49 #include <sys/var.h> 50 #include <sys/file.h> 51 #include <sys/pathname.h> 52 #include <sys/vfs.h> 53 #include <sys/exec.h> 54 #include <sys/debug.h> 55 #include <sys/stack.h> 56 #include <sys/kmem.h> 57 #include <sys/schedctl.h> 58 #include <sys/core.h> 59 #include <sys/corectl.h> 60 #include <sys/cmn_err.h> 61 #include <vm/as.h> 62 #include <sys/rctl.h> 63 #include <sys/nbmlock.h> 64 #include <sys/stat.h> 65 #include <sys/zone.h> 66 #include <sys/contract/process_impl.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 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 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 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 * 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 PTOU(curproc)->u_acflag |= ACORE; 442 #endif 443 if ((eswp = PTOU(curproc)->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, NULL); 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), "%u", crgetuid(p->p_cred)); 495 break; 496 case 'g': /* effective gid */ 497 (void) sprintf((s = buf), "%u", 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 lwp->lwp_siginfo.si_signo = sig; 703 lwp->lwp_siginfo.si_code = SI_NOINFO; 704 } else { 705 bcopy(&lwp->lwp_curinfo->sq_info, 706 &lwp->lwp_siginfo, sizeof (k_siginfo_t)); 707 siginfofree(lwp->lwp_curinfo); 708 lwp->lwp_curinfo = NULL; 709 } 710 711 /* 712 * Convert the core file name patterns into path names 713 * and call do_core() to write the core files. 714 */ 715 716 if (my_cg->core_options & CC_PROCESS_PATH) { 717 mutex_enter(&p->p_lock); 718 if (p->p_corefile != NULL) 719 rp = corectl_path_value(p->p_corefile); 720 else 721 rp = NULL; 722 mutex_exit(&p->p_lock); 723 if (rp != NULL) { 724 fp_process = kmem_alloc(MAXPATHLEN, KM_SLEEP); 725 error1 = expand_string(refstr_value(rp), 726 fp_process, MAXPATHLEN, p->p_cred); 727 if (error1 == 0) 728 error1 = do_core(fp_process, sig, CORE_PROC, 729 my_cg); 730 refstr_rele(rp); 731 } 732 } 733 734 if (my_cg->core_options & CC_GLOBAL_PATH) 735 error2 = dump_one_core(sig, rlimit, CORE_ZONE, my_cg, 736 &fp_global); 737 if (global_cg != my_cg && (global_cg->core_options & CC_GLOBAL_PATH)) 738 error3 = dump_one_core(sig, rlimit, CORE_GLOBAL, global_cg, 739 &fp_zone); 740 741 /* 742 * Restore the signal hold mask. 743 */ 744 mutex_enter(&p->p_lock); 745 curthread->t_hold = sigmask; 746 mutex_exit(&p->p_lock); 747 748 if (!ext && p->p_ct_process != NULL) 749 contract_process_core(p->p_ct_process, p, sig, 750 error1 == 0 ? fp_process : NULL, 751 error2 == 0 ? fp_global : NULL, 752 error3 == 0 ? fp_zone : NULL); 753 754 if (fp_process != NULL) 755 kmem_free(fp_process, MAXPATHLEN); 756 if (fp_global != NULL) 757 kmem_free(fp_global, MAXPATHLEN); 758 if (fp_zone != NULL) 759 kmem_free(fp_zone, MAXPATHLEN); 760 761 /* 762 * Return non-zero if no core file was created. 763 */ 764 return (error1 != 0 && error2 != 0 && error3 != 0); 765 } 766 767 /* 768 * Maximum chunk size for dumping core files, 769 * size in pages, patchable in /etc/system 770 */ 771 uint_t core_chunk = 32; 772 773 /* 774 * Common code to core dump process memory. The core_seg routine does i/o 775 * using core_write() below, and so it has the same failure semantics. 776 */ 777 int 778 core_seg(proc_t *p, vnode_t *vp, offset_t offset, caddr_t addr, size_t size, 779 rlim64_t rlimit, cred_t *credp) 780 { 781 caddr_t eaddr; 782 caddr_t base; 783 size_t len; 784 int err = 0; 785 786 eaddr = addr + size; 787 for (base = addr; base < eaddr; base += len) { 788 len = eaddr - base; 789 if (as_memory(p->p_as, &base, &len) != 0) 790 return (0); 791 /* 792 * Reduce len to a reasonable value so that we don't 793 * overwhelm the VM system with a monstrously large 794 * single write and cause pageout to stop running. 795 */ 796 if (len > (size_t)core_chunk * PAGESIZE) 797 len = (size_t)core_chunk * PAGESIZE; 798 799 err = core_write(vp, UIO_USERSPACE, 800 offset + (size_t)(base - addr), base, len, rlimit, credp); 801 802 if (err == 0) { 803 /* 804 * Give pageout a chance to run. 805 * Also allow core dumping to be interruptible. 806 */ 807 err = delay_sig(1); 808 } 809 if (err) 810 return (err); 811 } 812 return (0); 813 } 814 815 /* 816 * Wrapper around vn_rdwr to perform writes to a core file. For core files, 817 * we always want to write as much as we possibly can, and then make sure to 818 * return either 0 to the caller (for success), or the actual errno value. 819 * By using this function, the caller can omit additional code for handling 820 * retries and errors for partial writes returned by vn_rdwr. If vn_rdwr 821 * unexpectedly returns zero but no progress has been made, we return ENOSPC. 822 */ 823 int 824 core_write(vnode_t *vp, enum uio_seg segflg, offset_t offset, 825 const void *buf, size_t len, rlim64_t rlimit, cred_t *credp) 826 { 827 ssize_t resid = len; 828 int error = 0; 829 830 while (len != 0) { 831 error = vn_rdwr(UIO_WRITE, vp, (caddr_t)buf, len, offset, 832 segflg, 0, rlimit, credp, &resid); 833 834 if (error != 0) 835 break; 836 837 if (resid >= len) 838 return (ENOSPC); 839 840 buf = (const char *)buf + len - resid; 841 offset += len - resid; 842 len = resid; 843 } 844 845 return (error); 846 } 847