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  * Copyright (c) 2016 by Delphix. All rights reserved.
  26  */
  27 
  28 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  29 /*        All Rights Reserved   */
  30 
  31 #include <sys/param.h>
  32 #include <sys/types.h>
  33 #include <sys/time.h>
  34 #include <sys/sysmacros.h>
  35 #include <sys/proc.h>
  36 #include <sys/systm.h>
  37 #include <sys/cred.h>
  38 #include <sys/user.h>
  39 #include <sys/utsname.h>
  40 #include <sys/errno.h>
  41 #include <sys/signal.h>
  42 #include <sys/siginfo.h>
  43 #include <sys/fault.h>
  44 #include <sys/syscall.h>
  45 #include <sys/ucontext.h>
  46 #include <sys/prsystm.h>
  47 #include <sys/vnode.h>
  48 #include <sys/var.h>
  49 #include <sys/file.h>
  50 #include <sys/pathname.h>
  51 #include <sys/vfs.h>
  52 #include <sys/exec.h>
  53 #include <sys/debug.h>
  54 #include <sys/stack.h>
  55 #include <sys/kmem.h>
  56 #include <sys/schedctl.h>
  57 #include <sys/core.h>
  58 #include <sys/corectl.h>
  59 #include <sys/cmn_err.h>
  60 #include <vm/as.h>
  61 #include <sys/rctl.h>
  62 #include <sys/nbmlock.h>
  63 #include <sys/stat.h>
  64 #include <sys/zone.h>
  65 #include <sys/contract/process_impl.h>
  66 #include <sys/ddi.h>
  67 
  68 /*
  69  * Processes running within a zone potentially dump core in 3 locations,
  70  * based on the per-process, per-zone, and the global zone's core settings.
  71  *
  72  * Per-zone and global zone settings are often referred to as "global"
  73  * settings since they apply to the system (or zone) as a whole, as
  74  * opposed to a particular process.
  75  */
  76 enum core_types {
  77         CORE_PROC,      /* Use per-process settings */
  78         CORE_ZONE,      /* Use per-zone settings */
  79         CORE_GLOBAL     /* Use global zone settings */
  80 };
  81 
  82 /*
  83  * Log information about "global" core dumps to syslog.
  84  */
  85 static void
  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 they could convince a root process,
 405          * perhaps a set-uid root process that they started,
 406          * to dump core in a directory writable by that user.
 407          * Similar security reasons apply to hard links.
 408          * For symmetry we do this unconditionally, not
 409          * just for root processes.
 410          *
 411          * If the process has the core file mmap()d into the
 412          * address space, we would be modifying the address
 413          * space that we are trying to dump if we did not first
 414          * remove the core file.  (The command "file core"
 415          * is the canonical example of this possibility.)
 416          *
 417          * Opening the core file with O_EXCL|O_CREAT ensures than
 418          * two concurrent core dumps don't clobber each other.
 419          * One is bound to lose; we don't want to make both lose.
 420          */
 421         if ((error = remove_core_file(fp, core_type)) == 0) {
 422                 error = create_core_file(fp, core_type, &vp);
 423         }
 424 
 425         /*
 426          * Now that vn_open is complete, reset the process's credentials if
 427          * we changed them, and make 'credp' point to kcred used
 428          * above.  We use 'credp' to do i/o on the core file below, but leave
 429          * p->p_cred set to the original credential to allow the core file
 430          * to record this information.
 431          */
 432         if (ocredp != NULL)
 433                 credp = set_cred(p, ocredp);
 434 
 435         if (error == 0) {
 436                 int closerr;
 437 #if defined(__sparc)
 438                 (void) flush_user_windows_to_stack(NULL);
 439 #endif
 440                 if ((eswp = PTOU(curproc)->u_execsw) == NULL ||
 441                     (eswp = findexec_by_magic(eswp->exec_magic)) == NULL) {
 442                         error = ENOSYS;
 443                 } else {
 444                         error = eswp->exec_core(vp, p, credp, rlimit, sig,
 445                             content);
 446                         rw_exit(eswp->exec_lock);
 447                 }
 448 
 449                 closerr = VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, credp, NULL);
 450                 VN_RELE(vp);
 451                 if (error == 0)
 452                         error = closerr;
 453         }
 454 
 455         if (ocredp != NULL)
 456                 crfree(credp);
 457 
 458         return (error);
 459 }
 460 
 461 /*
 462  * Convert a core name pattern to a pathname.
 463  */
 464 static int
 465 expand_string(const char *pat, char *fp, int size, cred_t *cr)
 466 {
 467         proc_t *p = curproc;
 468         char buf[24];
 469         int len, i;
 470         char *s;
 471         char c;
 472 
 473         while ((c = *pat++) != '\0') {
 474                 if (size < 2)
 475                         return (ENAMETOOLONG);
 476                 if (c != '%') {
 477                         size--;
 478                         *fp++ = c;
 479                         continue;
 480                 }
 481                 if ((c = *pat++) == '\0') {
 482                         size--;
 483                         *fp++ = '%';
 484                         break;
 485                 }
 486                 switch (c) {
 487                 case 'p':       /* pid */
 488                         (void) sprintf((s = buf), "%d", p->p_pid);
 489                         break;
 490                 case 'u':       /* effective uid */
 491                         (void) sprintf((s = buf), "%u", crgetuid(p->p_cred));
 492                         break;
 493                 case 'g':       /* effective gid */
 494                         (void) sprintf((s = buf), "%u", crgetgid(p->p_cred));
 495                         break;
 496                 case 'f':       /* exec'd filename */
 497                         s = PTOU(p)->u_comm;
 498                         break;
 499                 case 'd':       /* exec'd dirname */
 500                         /*
 501                          * Even if pathname caching is disabled, we should
 502                          * be able to lookup the pathname for a directory.
 503                          */
 504                         if (p->p_execdir != NULL && vnodetopath(NULL,
 505                             p->p_execdir, fp, size, cr) == 0) {
 506                                 len = (int)strlen(fp);
 507                                 ASSERT(len < size);
 508                                 ASSERT(len >= 1);
 509                                 ASSERT(fp[0] == '/');
 510 
 511                                 /*
 512                                  * Strip off the leading slash.
 513                                  */
 514                                 for (i = 0; i < len; i++) {
 515                                         fp[i] = fp[i + 1];
 516                                 }
 517 
 518                                 len--;
 519 
 520                                 size -= len;
 521                                 fp += len;
 522                         } else {
 523                                 *fp = '\0';
 524                         }
 525 
 526                         continue;
 527                 case 'n':       /* system nodename */
 528                         s = uts_nodename();
 529                         break;
 530                 case 'm':       /* machine (sun4u, etc) */
 531                         s = utsname.machine;
 532                         break;
 533                 case 't':       /* decimal value of time(2) */
 534                         (void) sprintf((s = buf), "%ld", gethrestime_sec());
 535                         break;
 536                 case 'z':
 537                         s = p->p_zone->zone_name;
 538                         break;
 539                 case 'Z':
 540                         /* This is zonepath + "/root/", except for GZ */
 541                         s = p->p_zone->zone_rootpath;
 542                         break;
 543                 case '%':
 544                         (void) strcpy((s = buf), "%");
 545                         break;
 546                 default:
 547                         s = buf;
 548                         buf[0] = '%';
 549                         buf[1] = c;
 550                         buf[2] = '\0';
 551                         break;
 552                 }
 553                 len = (int)strlen(s);
 554                 if ((size -= len) <= 0)
 555                         return (ENAMETOOLONG);
 556                 (void) strcpy(fp, s);
 557                 /* strip trailing "/root/" from non-GZ zonepath string */
 558                 if (c == 'Z' && len > 6) {
 559                         len -= 6;
 560                         ASSERT(strncmp(fp + len, "/root/", 6) == 0);
 561                 }
 562                 fp += len;
 563         }
 564 
 565         *fp = '\0';
 566         return (0);
 567 }
 568 
 569 static int
 570 dump_one_core(int sig, rlim64_t rlimit, enum core_types core_type,
 571     struct core_globals *cg, char **name)
 572 {
 573         refstr_t *rp;
 574         proc_t *p = curproc;
 575         zoneid_t zoneid;
 576         int error;
 577         char *fp;
 578         cred_t *cr;
 579 
 580         ASSERT(core_type == CORE_ZONE || core_type == CORE_GLOBAL);
 581         zoneid = (core_type == CORE_ZONE ? getzoneid() : GLOBAL_ZONEID);
 582 
 583         mutex_enter(&cg->core_lock);
 584         if ((rp = cg->core_file) != NULL)
 585                 refstr_hold(rp);
 586         mutex_exit(&cg->core_lock);
 587         if (rp == NULL) {
 588                 core_log(cg, 0, "no global core file pattern exists", NULL,
 589                     zoneid);
 590                 return (1);     /* core file not generated */
 591         }
 592         fp = kmem_alloc(MAXPATHLEN, KM_SLEEP);
 593         cr = zone_get_kcred(getzoneid());
 594         error = expand_string(refstr_value(rp), fp, MAXPATHLEN, cr);
 595         crfree(cr);
 596         if (error != 0) {
 597                 core_log(cg, 0, "global core file pattern too long",
 598                     refstr_value(rp), zoneid);
 599         } else if ((error = do_core(fp, sig, core_type, cg)) == 0) {
 600                 core_log(cg, 0, "core dumped", fp, zoneid);
 601         } else if (error == ENOTSUP) {
 602                 core_log(cg, 0, "setid process, core not dumped", fp, zoneid);
 603         } else if (error == ENOSPC) {
 604                 core_log(cg, 0, "no space left on device, core truncated",
 605                     fp, zoneid);
 606         } else if (error == EFBIG) {
 607                 if (rlimit == 0)
 608                         core_log(cg, 0, "core rlimit is zero, core not dumped",
 609                             fp, zoneid);
 610                 else
 611                         core_log(cg, 0, "core rlimit exceeded, core truncated",
 612                             fp, zoneid);
 613                 /*
 614                  * In addition to the core result logging, we
 615                  * may also have explicit actions defined on
 616                  * core file size violations via the resource
 617                  * control framework.
 618                  */
 619                 mutex_enter(&p->p_lock);
 620                 (void) rctl_action(rctlproc_legacy[RLIMIT_CORE],
 621                     p->p_rctls, p, RCA_SAFE);
 622                 mutex_exit(&p->p_lock);
 623         } else {
 624                 core_log(cg, error, "core dump failed", fp, zoneid);
 625         }
 626         refstr_rele(rp);
 627         if (name != NULL)
 628                 *name = fp;
 629         else
 630                 kmem_free(fp, MAXPATHLEN);
 631         return (error);
 632 }
 633 
 634 int
 635 core(int sig, int ext)
 636 {
 637         proc_t *p = curproc;
 638         klwp_t *lwp = ttolwp(curthread);
 639         refstr_t *rp;
 640         char *fp_process = NULL, *fp_global = NULL, *fp_zone = NULL;
 641         int error1 = 1;
 642         int error2 = 1;
 643         int error3 = 1;
 644         k_sigset_t sigmask;
 645         k_sigset_t sighold;
 646         rlim64_t rlimit;
 647         struct core_globals *my_cg, *global_cg;
 648 
 649         global_cg = zone_getspecific(core_zone_key, global_zone);
 650         ASSERT(global_cg != NULL);
 651 
 652         my_cg = zone_getspecific(core_zone_key, curproc->p_zone);
 653         ASSERT(my_cg != NULL);
 654 
 655         /* core files suppressed? */
 656         if (!(my_cg->core_options & (CC_PROCESS_PATH|CC_GLOBAL_PATH)) &&
 657             !(global_cg->core_options & CC_GLOBAL_PATH)) {
 658                 if (!ext && p->p_ct_process != NULL)
 659                         contract_process_core(p->p_ct_process, p, sig,
 660                             NULL, NULL, NULL);
 661                 return (1);
 662         }
 663 
 664         /*
 665          * Block all signals except SIGHUP, SIGINT, SIGKILL, and SIGTERM; no
 666          * other signal may interrupt a core dump.  For each signal, we
 667          * explicitly unblock it and set it in p_siginfo to allow for some
 668          * minimal error reporting.  Additionally, we get the current limit on
 669          * core file size for handling later error reporting.
 670          */
 671         mutex_enter(&p->p_lock);
 672 
 673         p->p_flag |= SDOCORE;
 674         schedctl_finish_sigblock(curthread);
 675         sigmask = curthread->t_hold; /* remember for later */
 676         sigfillset(&sighold);
 677         if (!sigismember(&sigmask, SIGHUP))
 678                 sigdelset(&sighold, SIGHUP);
 679         if (!sigismember(&sigmask, SIGINT))
 680                 sigdelset(&sighold, SIGINT);
 681         if (!sigismember(&sigmask, SIGKILL))
 682                 sigdelset(&sighold, SIGKILL);
 683         if (!sigismember(&sigmask, SIGTERM))
 684                 sigdelset(&sighold, SIGTERM);
 685 
 686         sigaddset(&p->p_siginfo, SIGHUP);
 687         sigaddset(&p->p_siginfo, SIGINT);
 688         sigaddset(&p->p_siginfo, SIGKILL);
 689         sigaddset(&p->p_siginfo, SIGTERM);
 690 
 691         curthread->t_hold = sighold;
 692 
 693         rlimit = rctl_enforced_value(rctlproc_legacy[RLIMIT_CORE], p->p_rctls,
 694             p);
 695 
 696         mutex_exit(&p->p_lock);
 697 
 698         /*
 699          * Undo any watchpoints.
 700          */
 701         pr_free_watched_pages(p);
 702 
 703         /*
 704          * The presence of a current signal prevents file i/o
 705          * from succeeding over a network.  We copy the current
 706          * signal information to the side and cancel the current
 707          * signal so that the core dump will succeed.
 708          */
 709         ASSERT(lwp->lwp_cursig == sig);
 710         lwp->lwp_cursig = 0;
 711         lwp->lwp_extsig = 0;
 712         if (lwp->lwp_curinfo == NULL) {
 713                 bzero(&lwp->lwp_siginfo, sizeof (k_siginfo_t));
 714                 lwp->lwp_siginfo.si_signo = sig;
 715                 lwp->lwp_siginfo.si_code = SI_NOINFO;
 716         } else {
 717                 bcopy(&lwp->lwp_curinfo->sq_info,
 718                     &lwp->lwp_siginfo, sizeof (k_siginfo_t));
 719                 siginfofree(lwp->lwp_curinfo);
 720                 lwp->lwp_curinfo = NULL;
 721         }
 722 
 723         /*
 724          * Convert the core file name patterns into path names
 725          * and call do_core() to write the core files.
 726          */
 727 
 728         if (my_cg->core_options & CC_PROCESS_PATH) {
 729                 mutex_enter(&p->p_lock);
 730                 if (p->p_corefile != NULL)
 731                         rp = corectl_path_value(p->p_corefile);
 732                 else
 733                         rp = NULL;
 734                 mutex_exit(&p->p_lock);
 735                 if (rp != NULL) {
 736                         fp_process = kmem_alloc(MAXPATHLEN, KM_SLEEP);
 737                         error1 = expand_string(refstr_value(rp),
 738                             fp_process, MAXPATHLEN, p->p_cred);
 739                         if (error1 == 0)
 740                                 error1 = do_core(fp_process, sig, CORE_PROC,
 741                                     my_cg);
 742                         refstr_rele(rp);
 743                 }
 744         }
 745 
 746         if (my_cg->core_options & CC_GLOBAL_PATH)
 747                 error2 = dump_one_core(sig, rlimit, CORE_ZONE, my_cg,
 748                     &fp_global);
 749         if (global_cg != my_cg && (global_cg->core_options & CC_GLOBAL_PATH))
 750                 error3 = dump_one_core(sig, rlimit, CORE_GLOBAL, global_cg,
 751                     &fp_zone);
 752 
 753         /*
 754          * Restore the signal hold mask.
 755          */
 756         mutex_enter(&p->p_lock);
 757         curthread->t_hold = sigmask;
 758         mutex_exit(&p->p_lock);
 759 
 760         if (!ext && p->p_ct_process != NULL)
 761                 contract_process_core(p->p_ct_process, p, sig,
 762                     error1 == 0 ? fp_process : NULL,
 763                     error2 == 0 ? fp_global : NULL,
 764                     error3 == 0 ? fp_zone : NULL);
 765 
 766         if (fp_process != NULL)
 767                 kmem_free(fp_process, MAXPATHLEN);
 768         if (fp_global != NULL)
 769                 kmem_free(fp_global, MAXPATHLEN);
 770         if (fp_zone != NULL)
 771                 kmem_free(fp_zone, MAXPATHLEN);
 772 
 773         /*
 774          * Return non-zero if no core file was created.
 775          */
 776         return (error1 != 0 && error2 != 0 && error3 != 0);
 777 }
 778 
 779 /*
 780  * Maximum chunk size for dumping core files,
 781  * size in pages, patchable in /etc/system
 782  */
 783 uint_t  core_chunk = 32;
 784 
 785 /*
 786  * The delay between core_write() calls, in microseconds.  The default
 787  * matches one "normal" clock tick, or 10 milliseconds.
 788  */
 789 clock_t core_delay_usec = 10000;
 790 
 791 /*
 792  * Common code to core dump process memory.  The core_seg routine does i/o
 793  * using core_write() below, and so it has the same failure semantics.
 794  */
 795 int
 796 core_seg(proc_t *p, vnode_t *vp, offset_t offset, caddr_t addr, size_t size,
 797     rlim64_t rlimit, cred_t *credp)
 798 {
 799         caddr_t eaddr;
 800         caddr_t base;
 801         size_t len;
 802         int err = 0;
 803 
 804         eaddr = addr + size;
 805         for (base = addr; base < eaddr; base += len) {
 806                 len = eaddr - base;
 807                 if (as_memory(p->p_as, &base, &len) != 0)
 808                         return (0);
 809 
 810                 /*
 811                  * Reduce len to a reasonable value so that we don't
 812                  * overwhelm the VM system with a monstrously large
 813                  * single write and cause pageout to stop running.
 814                  */
 815                 if (len > (size_t)core_chunk * PAGESIZE)
 816                         len = (size_t)core_chunk * PAGESIZE;
 817 
 818                 err = core_write(vp, UIO_USERSPACE,
 819                     offset + (size_t)(base - addr), base, len, rlimit, credp);
 820 
 821                 if (err)
 822                         return (err);
 823 
 824                 /*
 825                  * If we have taken a signal, return EINTR to allow the dump
 826                  * to be aborted.
 827                  */
 828                 if (issig(JUSTLOOKING) && issig(FORREAL))
 829                         return (EINTR);
 830         }
 831 
 832         return (0);
 833 }
 834 
 835 /*
 836  * Wrapper around vn_rdwr to perform writes to a core file.  For core files,
 837  * we always want to write as much as we possibly can, and then make sure to
 838  * return either 0 to the caller (for success), or the actual errno value.
 839  * By using this function, the caller can omit additional code for handling
 840  * retries and errors for partial writes returned by vn_rdwr.  If vn_rdwr
 841  * unexpectedly returns zero but no progress has been made, we return ENOSPC.
 842  */
 843 int
 844 core_write(vnode_t *vp, enum uio_seg segflg, offset_t offset,
 845     const void *buf, size_t len, rlim64_t rlimit, cred_t *credp)
 846 {
 847         ssize_t resid = len;
 848         int error = 0;
 849 
 850         while (len != 0) {
 851                 error = vn_rdwr(UIO_WRITE, vp, (caddr_t)buf, len, offset,
 852                     segflg, 0, rlimit, credp, &resid);
 853 
 854                 if (error != 0)
 855                         break;
 856 
 857                 if (resid >= len)
 858                         return (ENOSPC);
 859 
 860                 buf = (const char *)buf + len - resid;
 861                 offset += len - resid;
 862                 len = resid;
 863         }
 864 
 865         return (error);
 866 }