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