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 /* 28 * Copyright 2012 DEY Storage Systems, Inc. All rights reserved. 29 */ 30 31 #include <sys/types.h> 32 #include <sys/param.h> 33 #include <sys/thread.h> 34 #include <sys/sysmacros.h> 35 #include <sys/signal.h> 36 #include <sys/cred.h> 37 #include <sys/priv.h> 38 #include <sys/user.h> 39 #include <sys/file.h> 40 #include <sys/errno.h> 41 #include <sys/vnode.h> 42 #include <sys/mode.h> 43 #include <sys/vfs.h> 44 #include <sys/mman.h> 45 #include <sys/kmem.h> 46 #include <sys/proc.h> 47 #include <sys/pathname.h> 48 #include <sys/cmn_err.h> 49 #include <sys/systm.h> 50 #include <sys/elf.h> 51 #include <sys/vmsystm.h> 52 #include <sys/debug.h> 53 #include <sys/procfs.h> 54 #include <sys/regset.h> 55 #include <sys/auxv.h> 56 #include <sys/exec.h> 57 #include <sys/prsystm.h> 58 #include <sys/utsname.h> 59 #include <sys/zone.h> 60 #include <vm/as.h> 61 #include <vm/rm.h> 62 #include <sys/modctl.h> 63 #include <sys/systeminfo.h> 64 #include <sys/machelf.h> 65 #include <sys/sunddi.h> 66 #include "elf_impl.h" 67 #if defined(__i386) || defined(__i386_COMPAT) 68 #include <sys/sysi86.h> 69 #endif 70 71 void 72 setup_note_header(Phdr *v, proc_t *p) 73 { 74 int nlwp = p->p_lwpcnt; 75 int nzomb = p->p_zombcnt; 76 int nfd; 77 size_t size; 78 prcred_t *pcrp; 79 uf_info_t *fip; 80 uf_entry_t *ufp; 81 int fd; 82 83 fip = P_FINFO(p); 84 nfd = 0; 85 mutex_enter(&fip->fi_lock); 86 for (fd = 0; fd < fip->fi_nfiles; fd++) { 87 UF_ENTER(ufp, fip, fd); 88 if ((ufp->uf_file != NULL) && (ufp->uf_file->f_count > 0)) 89 nfd++; 90 UF_EXIT(ufp); 91 } 92 mutex_exit(&fip->fi_lock); 93 94 v[0].p_type = PT_NOTE; 95 v[0].p_flags = PF_R; 96 v[0].p_filesz = (sizeof (Note) * (9 + 2 * nlwp + nzomb + nfd)) 97 + roundup(sizeof (psinfo_t), sizeof (Word)) 98 + roundup(sizeof (pstatus_t), sizeof (Word)) 99 + roundup(prgetprivsize(), sizeof (Word)) 100 + roundup(priv_get_implinfo_size(), sizeof (Word)) 101 + roundup(strlen(platform) + 1, sizeof (Word)) 102 + roundup(strlen(p->p_zone->zone_name) + 1, sizeof (Word)) 103 + roundup(__KERN_NAUXV_IMPL * sizeof (aux_entry_t), sizeof (Word)) 104 + roundup(sizeof (utsname), sizeof (Word)) 105 + roundup(sizeof (core_content_t), sizeof (Word)) 106 + (nlwp + nzomb) * roundup(sizeof (lwpsinfo_t), sizeof (Word)) 107 + nlwp * roundup(sizeof (lwpstatus_t), sizeof (Word)) 108 + nfd * roundup(sizeof (prfdinfo_t), sizeof (Word)); 109 110 size = sizeof (prcred_t) + sizeof (gid_t) * (ngroups_max - 1); 111 pcrp = kmem_alloc(size, KM_SLEEP); 112 prgetcred(p, pcrp); 113 if (pcrp->pr_ngroups != 0) { 114 v[0].p_filesz += sizeof (Note) + roundup(sizeof (prcred_t) + 115 sizeof (gid_t) * (pcrp->pr_ngroups - 1), sizeof (Word)); 116 } else { 117 v[0].p_filesz += sizeof (Note) + 118 roundup(sizeof (prcred_t), sizeof (Word)); 119 } 120 kmem_free(pcrp, size); 121 122 123 #if defined(__i386) || defined(__i386_COMPAT) 124 mutex_enter(&p->p_ldtlock); 125 size = prnldt(p) * sizeof (struct ssd); 126 mutex_exit(&p->p_ldtlock); 127 if (size != 0) 128 v[0].p_filesz += sizeof (Note) + roundup(size, sizeof (Word)); 129 #endif /* __i386 || __i386_COMPAT */ 130 131 if ((size = prhasx(p)? prgetprxregsize(p) : 0) != 0) 132 v[0].p_filesz += nlwp * sizeof (Note) 133 + nlwp * roundup(size, sizeof (Word)); 134 135 #if defined(__sparc) 136 /* 137 * Figure out the number and sizes of register windows. 138 */ 139 { 140 kthread_t *t = p->p_tlist; 141 do { 142 if ((size = prnwindows(ttolwp(t))) != 0) { 143 size = sizeof (gwindows_t) - 144 (SPARC_MAXREGWINDOW - size) * 145 sizeof (struct rwindow); 146 v[0].p_filesz += sizeof (Note) + 147 roundup(size, sizeof (Word)); 148 } 149 } while ((t = t->t_forw) != p->p_tlist); 150 } 151 /* 152 * Space for the Ancillary State Registers. 153 */ 154 if (p->p_model == DATAMODEL_LP64) 155 v[0].p_filesz += nlwp * sizeof (Note) 156 + nlwp * roundup(sizeof (asrset_t), sizeof (Word)); 157 #endif /* __sparc */ 158 } 159 160 int 161 write_elfnotes(proc_t *p, int sig, vnode_t *vp, offset_t offset, 162 rlim64_t rlimit, cred_t *credp, core_content_t content) 163 { 164 union { 165 psinfo_t psinfo; 166 pstatus_t pstatus; 167 lwpsinfo_t lwpsinfo; 168 lwpstatus_t lwpstatus; 169 #if defined(__sparc) 170 gwindows_t gwindows; 171 asrset_t asrset; 172 #endif /* __sparc */ 173 char xregs[1]; 174 aux_entry_t auxv[__KERN_NAUXV_IMPL]; 175 prcred_t pcred; 176 prpriv_t ppriv; 177 priv_impl_info_t prinfo; 178 struct utsname uts; 179 } *bigwad; 180 181 size_t xregsize = prhasx(p)? prgetprxregsize(p) : 0; 182 size_t crsize = sizeof (prcred_t) + sizeof (gid_t) * (ngroups_max - 1); 183 size_t psize = prgetprivsize(); 184 size_t bigsize = MAX(psize, MAX(sizeof (*bigwad), 185 MAX(xregsize, crsize))); 186 187 priv_impl_info_t *prii; 188 189 lwpdir_t *ldp; 190 lwpent_t *lep; 191 kthread_t *t; 192 klwp_t *lwp; 193 user_t *up; 194 int i; 195 int nlwp; 196 int nzomb; 197 int error; 198 uchar_t oldsig; 199 uf_info_t *fip; 200 int fd; 201 vnode_t *vroot; 202 203 #if defined(__i386) || defined(__i386_COMPAT) 204 struct ssd *ssd; 205 size_t ssdsize; 206 #endif /* __i386 || __i386_COMPAT */ 207 208 bigsize = MAX(bigsize, priv_get_implinfo_size()); 209 210 bigwad = kmem_alloc(bigsize, KM_SLEEP); 211 212 /* 213 * The order of the elfnote entries should be same here 214 * and in the gcore(1) command. Synchronization is 215 * needed between the kernel and gcore(1). 216 */ 217 218 /* 219 * Get the psinfo, and set the wait status to indicate that a core was 220 * dumped. We have to forge this since p->p_wcode is not set yet. 221 */ 222 mutex_enter(&p->p_lock); 223 prgetpsinfo(p, &bigwad->psinfo); 224 mutex_exit(&p->p_lock); 225 bigwad->psinfo.pr_wstat = wstat(CLD_DUMPED, sig); 226 227 error = elfnote(vp, &offset, NT_PSINFO, sizeof (bigwad->psinfo), 228 (caddr_t)&bigwad->psinfo, rlimit, credp); 229 if (error) 230 goto done; 231 232 /* 233 * Modify t_whystop and lwp_cursig so it appears that the current LWP 234 * is stopped after faulting on the signal that caused the core dump. 235 * As a result, prgetstatus() will record that signal, the saved 236 * lwp_siginfo, and its signal handler in the core file status. We 237 * restore lwp_cursig in case a subsequent signal was received while 238 * dumping core. 239 */ 240 mutex_enter(&p->p_lock); 241 lwp = ttolwp(curthread); 242 243 oldsig = lwp->lwp_cursig; 244 lwp->lwp_cursig = (uchar_t)sig; 245 curthread->t_whystop = PR_FAULTED; 246 247 prgetstatus(p, &bigwad->pstatus, p->p_zone); 248 bigwad->pstatus.pr_lwp.pr_why = 0; 249 250 curthread->t_whystop = 0; 251 lwp->lwp_cursig = oldsig; 252 mutex_exit(&p->p_lock); 253 254 error = elfnote(vp, &offset, NT_PSTATUS, sizeof (bigwad->pstatus), 255 (caddr_t)&bigwad->pstatus, rlimit, credp); 256 if (error) 257 goto done; 258 259 error = elfnote(vp, &offset, NT_PLATFORM, strlen(platform) + 1, 260 platform, rlimit, credp); 261 if (error) 262 goto done; 263 264 up = PTOU(p); 265 for (i = 0; i < __KERN_NAUXV_IMPL; i++) { 266 bigwad->auxv[i].a_type = up->u_auxv[i].a_type; 267 bigwad->auxv[i].a_un.a_val = up->u_auxv[i].a_un.a_val; 268 } 269 error = elfnote(vp, &offset, NT_AUXV, sizeof (bigwad->auxv), 270 (caddr_t)bigwad->auxv, rlimit, credp); 271 if (error) 272 goto done; 273 274 bcopy(&utsname, &bigwad->uts, sizeof (struct utsname)); 275 if (!INGLOBALZONE(p)) { 276 bcopy(p->p_zone->zone_nodename, &bigwad->uts.nodename, 277 _SYS_NMLN); 278 } 279 error = elfnote(vp, &offset, NT_UTSNAME, sizeof (struct utsname), 280 (caddr_t)&bigwad->uts, rlimit, credp); 281 if (error) 282 goto done; 283 284 prgetcred(p, &bigwad->pcred); 285 286 if (bigwad->pcred.pr_ngroups != 0) { 287 crsize = sizeof (prcred_t) + 288 sizeof (gid_t) * (bigwad->pcred.pr_ngroups - 1); 289 } else 290 crsize = sizeof (prcred_t); 291 292 error = elfnote(vp, &offset, NT_PRCRED, crsize, 293 (caddr_t)&bigwad->pcred, rlimit, credp); 294 if (error) 295 goto done; 296 297 error = elfnote(vp, &offset, NT_CONTENT, sizeof (core_content_t), 298 (caddr_t)&content, rlimit, credp); 299 if (error) 300 goto done; 301 302 prgetpriv(p, &bigwad->ppriv); 303 304 error = elfnote(vp, &offset, NT_PRPRIV, psize, 305 (caddr_t)&bigwad->ppriv, rlimit, credp); 306 if (error) 307 goto done; 308 309 prii = priv_hold_implinfo(); 310 error = elfnote(vp, &offset, NT_PRPRIVINFO, priv_get_implinfo_size(), 311 (caddr_t)prii, rlimit, credp); 312 priv_release_implinfo(); 313 if (error) 314 goto done; 315 316 /* zone can't go away as long as process exists */ 317 error = elfnote(vp, &offset, NT_ZONENAME, 318 strlen(p->p_zone->zone_name) + 1, p->p_zone->zone_name, 319 rlimit, credp); 320 if (error) 321 goto done; 322 323 324 /* open file table */ 325 vroot = PTOU(p)->u_rdir; 326 if (vroot == NULL) 327 vroot = rootdir; 328 329 VN_HOLD(vroot); 330 331 fip = P_FINFO(p); 332 333 for (fd = 0; fd < fip->fi_nfiles; fd++) { 334 uf_entry_t *ufp; 335 vnode_t *fvp; 336 struct file *fp; 337 vattr_t vattr; 338 prfdinfo_t fdinfo; 339 340 bzero(&fdinfo, sizeof (fdinfo)); 341 342 mutex_enter(&fip->fi_lock); 343 UF_ENTER(ufp, fip, fd); 344 if (((fp = ufp->uf_file) == NULL) || (fp->f_count < 1)) { 345 UF_EXIT(ufp); 346 mutex_exit(&fip->fi_lock); 347 continue; 348 } 349 350 fdinfo.pr_fd = fd; 351 fdinfo.pr_fdflags = ufp->uf_flag; 352 fdinfo.pr_fileflags = fp->f_flag2; 353 fdinfo.pr_fileflags <<= 16; 354 fdinfo.pr_fileflags |= fp->f_flag; 355 if ((fdinfo.pr_fileflags & (FSEARCH | FEXEC)) == 0) 356 fdinfo.pr_fileflags += FOPEN; 357 fdinfo.pr_offset = fp->f_offset; 358 359 360 fvp = fp->f_vnode; 361 VN_HOLD(fvp); 362 UF_EXIT(ufp); 363 mutex_exit(&fip->fi_lock); 364 365 /* 366 * There are some vnodes that have no corresponding 367 * path. Its reasonable for this to fail, in which 368 * case the path will remain an empty string. 369 */ 370 (void) vnodetopath(vroot, fvp, fdinfo.pr_path, 371 sizeof (fdinfo.pr_path), credp); 372 373 error = VOP_GETATTR(fvp, &vattr, 0, credp, NULL); 374 if (error != 0) { 375 VN_RELE(fvp); 376 VN_RELE(vroot); 377 goto done; 378 } 379 380 if (fvp->v_type == VSOCK) 381 fdinfo.pr_fileflags |= sock_getfasync(fvp); 382 383 VN_RELE(fvp); 384 385 /* 386 * This logic mirrors fstat(), which we cannot use 387 * directly, as it calls copyout(). 388 */ 389 fdinfo.pr_major = getmajor(vattr.va_fsid); 390 fdinfo.pr_minor = getminor(vattr.va_fsid); 391 fdinfo.pr_ino = (ino64_t)vattr.va_nodeid; 392 fdinfo.pr_mode = VTTOIF(vattr.va_type) | vattr.va_mode; 393 fdinfo.pr_uid = vattr.va_uid; 394 fdinfo.pr_gid = vattr.va_gid; 395 fdinfo.pr_rmajor = getmajor(vattr.va_rdev); 396 fdinfo.pr_rminor = getminor(vattr.va_rdev); 397 fdinfo.pr_size = (off64_t)vattr.va_size; 398 399 error = elfnote(vp, &offset, NT_FDINFO, 400 sizeof (fdinfo), &fdinfo, rlimit, credp); 401 if (error) { 402 goto done; 403 } 404 } 405 406 #if defined(__i386) || defined(__i386_COMPAT) 407 mutex_enter(&p->p_ldtlock); 408 ssdsize = prnldt(p) * sizeof (struct ssd); 409 if (ssdsize != 0) { 410 ssd = kmem_alloc(ssdsize, KM_SLEEP); 411 prgetldt(p, ssd); 412 error = elfnote(vp, &offset, NT_LDT, ssdsize, 413 (caddr_t)ssd, rlimit, credp); 414 kmem_free(ssd, ssdsize); 415 } 416 mutex_exit(&p->p_ldtlock); 417 if (error) 418 goto done; 419 #endif /* __i386 || defined(__i386_COMPAT) */ 420 421 nlwp = p->p_lwpcnt; 422 nzomb = p->p_zombcnt; 423 /* for each entry in the lwp directory ... */ 424 for (ldp = p->p_lwpdir; nlwp + nzomb != 0; ldp++) { 425 426 if ((lep = ldp->ld_entry) == NULL) /* empty slot */ 427 continue; 428 429 if ((t = lep->le_thread) != NULL) { /* active lwp */ 430 ASSERT(nlwp != 0); 431 nlwp--; 432 lwp = ttolwp(t); 433 mutex_enter(&p->p_lock); 434 prgetlwpsinfo(t, &bigwad->lwpsinfo); 435 mutex_exit(&p->p_lock); 436 } else { /* zombie lwp */ 437 ASSERT(nzomb != 0); 438 nzomb--; 439 bzero(&bigwad->lwpsinfo, sizeof (bigwad->lwpsinfo)); 440 bigwad->lwpsinfo.pr_lwpid = lep->le_lwpid; 441 bigwad->lwpsinfo.pr_state = SZOMB; 442 bigwad->lwpsinfo.pr_sname = 'Z'; 443 bigwad->lwpsinfo.pr_start.tv_sec = lep->le_start; 444 } 445 error = elfnote(vp, &offset, NT_LWPSINFO, 446 sizeof (bigwad->lwpsinfo), (caddr_t)&bigwad->lwpsinfo, 447 rlimit, credp); 448 if (error) 449 goto done; 450 if (t == NULL) /* nothing more to do for a zombie */ 451 continue; 452 453 mutex_enter(&p->p_lock); 454 if (t == curthread) { 455 /* 456 * Modify t_whystop and lwp_cursig so it appears that 457 * the current LWP is stopped after faulting on the 458 * signal that caused the core dump. As a result, 459 * prgetlwpstatus() will record that signal, the saved 460 * lwp_siginfo, and its signal handler in the core file 461 * status. We restore lwp_cursig in case a subsequent 462 * signal was received while dumping core. 463 */ 464 oldsig = lwp->lwp_cursig; 465 lwp->lwp_cursig = (uchar_t)sig; 466 t->t_whystop = PR_FAULTED; 467 468 prgetlwpstatus(t, &bigwad->lwpstatus, p->p_zone); 469 bigwad->lwpstatus.pr_why = 0; 470 471 t->t_whystop = 0; 472 lwp->lwp_cursig = oldsig; 473 } else { 474 prgetlwpstatus(t, &bigwad->lwpstatus, p->p_zone); 475 } 476 mutex_exit(&p->p_lock); 477 error = elfnote(vp, &offset, NT_LWPSTATUS, 478 sizeof (bigwad->lwpstatus), (caddr_t)&bigwad->lwpstatus, 479 rlimit, credp); 480 if (error) 481 goto done; 482 483 #if defined(__sparc) 484 /* 485 * Unspilled SPARC register windows. 486 */ 487 { 488 size_t size = prnwindows(lwp); 489 490 if (size != 0) { 491 size = sizeof (gwindows_t) - 492 (SPARC_MAXREGWINDOW - size) * 493 sizeof (struct rwindow); 494 prgetwindows(lwp, &bigwad->gwindows); 495 error = elfnote(vp, &offset, NT_GWINDOWS, 496 size, (caddr_t)&bigwad->gwindows, 497 rlimit, credp); 498 if (error) 499 goto done; 500 } 501 } 502 /* 503 * Ancillary State Registers. 504 */ 505 if (p->p_model == DATAMODEL_LP64) { 506 prgetasregs(lwp, bigwad->asrset); 507 error = elfnote(vp, &offset, NT_ASRS, 508 sizeof (asrset_t), (caddr_t)bigwad->asrset, 509 rlimit, credp); 510 if (error) 511 goto done; 512 } 513 #endif /* __sparc */ 514 515 if (xregsize) { 516 prgetprxregs(lwp, bigwad->xregs); 517 error = elfnote(vp, &offset, NT_PRXREG, 518 xregsize, bigwad->xregs, rlimit, credp); 519 if (error) 520 goto done; 521 } 522 } 523 ASSERT(nlwp == 0); 524 525 done: 526 kmem_free(bigwad, bigsize); 527 return (error); 528 } 529