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