1 /* $NetBSD: core_elf32.c,v 1.51 2017/01/25 17:55:47 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2001 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 /* 39 * core_elf32.c/core_elf64.c: Support for the Elf32/Elf64 core file format. 40 */ 41 42 #include <sys/cdefs.h> 43 __KERNEL_RCSID(1, "$NetBSD: core_elf32.c,v 1.51 2017/01/25 17:55:47 christos Exp $"); 44 45 #ifdef _KERNEL_OPT 46 #include "opt_coredump.h" 47 #include "opt_compat_netbsd32.h" 48 #endif 49 50 #ifndef ELFSIZE 51 #define ELFSIZE 32 52 #endif 53 54 #include <sys/param.h> 55 #include <sys/systm.h> 56 #include <sys/proc.h> 57 #include <sys/vnode.h> 58 #include <sys/exec.h> 59 #include <sys/exec_elf.h> 60 #include <sys/ptrace.h> 61 #include <sys/kmem.h> 62 #include <sys/kauth.h> 63 64 #include <machine/reg.h> 65 66 #include <uvm/uvm_extern.h> 67 68 #ifdef COREDUMP 69 70 struct writesegs_state { 71 Elf_Phdr *psections; 72 proc_t *p; 73 off_t secoff; 74 size_t npsections; 75 }; 76 77 /* 78 * We need to know how big the 'notes' are before we write the main header. 79 * To avoid problems with double-processing we save the data. 80 */ 81 struct note_buf { 82 struct note_buf *nb_next; 83 unsigned char nb_data[4096 - sizeof (void *)]; 84 }; 85 86 struct note_state { 87 struct note_buf *ns_first; 88 struct note_buf *ns_last; 89 unsigned int ns_count; /* Of full buffers */ 90 unsigned int ns_offset; /* Write point in last buffer */ 91 }; 92 93 static int ELFNAMEEND(coredump_getseghdrs)(struct uvm_coredump_state *); 94 95 static int ELFNAMEEND(coredump_notes)(struct lwp *, struct note_state *); 96 static int ELFNAMEEND(coredump_note)(struct lwp *, struct note_state *); 97 98 /* The 'note' section names and data are always 4-byte aligned. */ 99 #define ELFROUNDSIZE 4 /* XXX Should it be sizeof(Elf_Word)? */ 100 101 #define elf_process_read_regs CONCAT(process_read_regs, ELFSIZE) 102 #define elf_process_read_fpregs CONCAT(process_read_fpregs, ELFSIZE) 103 #define elf_reg CONCAT(process_reg, ELFSIZE) 104 #define elf_fpreg CONCAT(process_fpreg, ELFSIZE) 105 106 int 107 ELFNAMEEND(coredump)(struct lwp *l, struct coredump_iostate *cookie) 108 { 109 Elf_Ehdr ehdr; 110 Elf_Shdr shdr; 111 Elf_Phdr *psections; 112 size_t psectionssize; 113 int npsections; 114 struct writesegs_state ws; 115 off_t notestart; 116 size_t notesize; 117 int error, i; 118 119 struct note_state ns; 120 struct note_buf *nb; 121 122 psections = NULL; 123 124 /* Get all of the notes (mostly all the registers). */ 125 ns.ns_first = kmem_alloc(sizeof *ns.ns_first, KM_SLEEP); 126 ns.ns_last = ns.ns_first; 127 ns.ns_count = 0; 128 ns.ns_offset = 0; 129 error = ELFNAMEEND(coredump_notes)(l, &ns); 130 ns.ns_last->nb_next = NULL; 131 if (error) 132 goto out; 133 notesize = ns.ns_count * sizeof nb->nb_data + ns.ns_offset; 134 135 /* 136 * We have to make a total of 3 passes across the map: 137 * 138 * 1. Count the number of map entries (the number of 139 * PT_LOAD sections in the dump). 140 * 141 * 2. Write the P-section headers. 142 * 143 * 3. Write the P-sections. 144 */ 145 146 /* Pass 1: count the entries. */ 147 npsections = uvm_coredump_count_segs(l->l_proc); 148 /* Allow for the PT_NOTE section. */ 149 npsections++; 150 151 /* Build the main elf header */ 152 memset(&ehdr.e_ident[EI_PAD], 0, sizeof(ehdr.e_ident) - EI_PAD); 153 memcpy(ehdr.e_ident, ELFMAG, SELFMAG); 154 #if ELFSIZE == 32 155 ehdr.e_ident[EI_CLASS] = ELFCLASS32; 156 #elif ELFSIZE == 64 157 ehdr.e_ident[EI_CLASS] = ELFCLASS64; 158 #endif 159 ehdr.e_ident[EI_DATA] = ELFDEFNNAME(MACHDEP_ENDIANNESS); 160 ehdr.e_ident[EI_VERSION] = EV_CURRENT; 161 /* XXX Should be the OSABI/ABI version of the executable. */ 162 ehdr.e_ident[EI_OSABI] = ELFOSABI_SYSV; 163 ehdr.e_ident[EI_ABIVERSION] = 0; 164 165 ehdr.e_type = ET_CORE; 166 /* XXX This should be the e_machine of the executable. */ 167 ehdr.e_machine = ELFDEFNNAME(MACHDEP_ID); 168 ehdr.e_version = EV_CURRENT; 169 ehdr.e_entry = 0; 170 ehdr.e_flags = 0; 171 ehdr.e_ehsize = sizeof(ehdr); 172 ehdr.e_phentsize = sizeof(Elf_Phdr); 173 if (npsections < PN_XNUM) { 174 ehdr.e_phnum = npsections; 175 ehdr.e_shentsize = 0; 176 ehdr.e_shnum = 0; 177 ehdr.e_shoff = 0; 178 ehdr.e_phoff = sizeof(ehdr); 179 } else { 180 ehdr.e_phnum = PN_XNUM; 181 ehdr.e_shentsize = sizeof(Elf_Shdr); 182 ehdr.e_shnum = 1; 183 ehdr.e_shoff = sizeof(ehdr); 184 ehdr.e_phoff = sizeof(ehdr) + sizeof(shdr); 185 } 186 ehdr.e_shstrndx = 0; 187 188 #ifdef ELF_MD_COREDUMP_SETUP 189 ELF_MD_COREDUMP_SETUP(l, &ehdr); 190 #endif 191 192 /* Write out the ELF header. */ 193 error = coredump_write(cookie, UIO_SYSSPACE, &ehdr, sizeof(ehdr)); 194 if (error) 195 goto out; 196 197 /* Write out sections, if needed */ 198 if (npsections >= PN_XNUM) { 199 memset(&shdr, 0, sizeof(shdr)); 200 shdr.sh_type = SHT_NULL; 201 shdr.sh_info = npsections; 202 error = coredump_write(cookie, UIO_SYSSPACE, &shdr, 203 sizeof(shdr)); 204 if (error) 205 goto out; 206 } 207 208 psectionssize = npsections * sizeof(*psections); 209 notestart = ehdr.e_phoff + psectionssize; 210 211 psections = kmem_zalloc(psectionssize, KM_SLEEP); 212 213 /* Pass 2: now find the P-section headers. */ 214 ws.secoff = notestart + notesize; 215 ws.psections = psections; 216 ws.npsections = npsections - 1; 217 ws.p = l->l_proc; 218 error = uvm_coredump_walkmap(l->l_proc, ELFNAMEEND(coredump_getseghdrs), 219 &ws); 220 if (error) 221 goto out; 222 if (ws.npsections != 0) { 223 /* A section went away */ 224 error = ENOMEM; 225 goto out; 226 } 227 228 /* Add the PT_NOTE header after the P-section headers. */ 229 ws.psections->p_type = PT_NOTE; 230 ws.psections->p_offset = notestart; 231 ws.psections->p_vaddr = 0; 232 ws.psections->p_paddr = 0; 233 ws.psections->p_filesz = notesize; 234 ws.psections->p_memsz = 0; 235 ws.psections->p_flags = PF_R; 236 ws.psections->p_align = ELFROUNDSIZE; 237 238 /* Write the P-section headers followed by the PT_NOTE header */ 239 error = coredump_write(cookie, UIO_SYSSPACE, psections, psectionssize); 240 if (error) 241 goto out; 242 243 #ifdef DIAGNOSTIC 244 if (coredump_offset(cookie) != notestart) 245 panic("coredump: offset %lld != notestart %lld", 246 (long long) coredump_offset(cookie), 247 (long long) notestart); 248 #endif 249 250 /* Write out the notes. */ 251 for (nb = ns.ns_first; nb != NULL; nb = nb->nb_next) { 252 error = coredump_write(cookie, UIO_SYSSPACE, nb->nb_data, 253 nb->nb_next == NULL ? ns.ns_offset : sizeof nb->nb_data); 254 if (error) 255 goto out; 256 } 257 258 /* Finally, write the sections themselves. */ 259 for (i = 0; i < npsections - 1; i++) { 260 if (psections[i].p_filesz == 0) 261 continue; 262 263 #ifdef DIAGNOSTIC 264 if (coredump_offset(cookie) != psections[i].p_offset) 265 panic("coredump: offset %lld != p_offset[%d] %lld", 266 (long long) coredump_offset(cookie), i, 267 (long long) psections[i].p_filesz); 268 #endif 269 270 error = coredump_write(cookie, UIO_USERSPACE, 271 (void *)(vaddr_t)psections[i].p_vaddr, 272 psections[i].p_filesz); 273 if (error) 274 goto out; 275 } 276 277 out: 278 if (psections) 279 kmem_free(psections, psectionssize); 280 while ((nb = ns.ns_first) != NULL) { 281 ns.ns_first = nb->nb_next; 282 kmem_free(nb, sizeof *nb); 283 } 284 return (error); 285 } 286 287 static int 288 ELFNAMEEND(coredump_getseghdrs)(struct uvm_coredump_state *us) 289 { 290 struct writesegs_state *ws = us->cookie; 291 Elf_Phdr phdr; 292 vsize_t size, realsize; 293 vaddr_t end; 294 int error; 295 296 /* Don't overrun if there are more sections */ 297 if (ws->npsections == 0) 298 return ENOMEM; 299 ws->npsections--; 300 301 size = us->end - us->start; 302 realsize = us->realend - us->start; 303 end = us->realend; 304 305 /* Don't bother writing out trailing zeros */ 306 while (realsize > 0) { 307 long buf[1024 / sizeof(long)]; 308 size_t slen = realsize > sizeof(buf) ? sizeof(buf) : realsize; 309 const long *ep; 310 int i; 311 312 end -= slen; 313 if ((error = copyin_proc(ws->p, (void *)end, buf, slen)) != 0) 314 return error; 315 316 ep = (const long *) &buf[slen / sizeof(buf[0])]; 317 for (i = 0, ep--; buf <= ep; ep--, i++) { 318 if (*ep) 319 break; 320 } 321 realsize -= i * sizeof(buf[0]); 322 if (i * sizeof(buf[0]) < slen) 323 break; 324 } 325 326 phdr.p_type = PT_LOAD; 327 phdr.p_offset = ws->secoff; 328 phdr.p_vaddr = us->start; 329 phdr.p_paddr = 0; 330 phdr.p_filesz = realsize; 331 phdr.p_memsz = size; 332 phdr.p_flags = 0; 333 if (us->prot & VM_PROT_READ) 334 phdr.p_flags |= PF_R; 335 if (us->prot & VM_PROT_WRITE) 336 phdr.p_flags |= PF_W; 337 if (us->prot & VM_PROT_EXECUTE) 338 phdr.p_flags |= PF_X; 339 phdr.p_align = PAGE_SIZE; 340 341 ws->secoff += phdr.p_filesz; 342 *ws->psections++ = phdr; 343 344 return (0); 345 } 346 347 static void 348 coredump_note_procinfo(struct lwp *l, struct note_state *ns) 349 { 350 struct proc *p; 351 struct netbsd_elfcore_procinfo cpi; 352 struct lwp *l0; 353 sigset_t ss1, ss2; 354 355 p = l->l_proc; 356 357 /* First, write an elfcore_procinfo. */ 358 cpi.cpi_version = NETBSD_ELFCORE_PROCINFO_VERSION; 359 cpi.cpi_cpisize = sizeof(cpi); 360 cpi.cpi_signo = p->p_sigctx.ps_info._signo; 361 cpi.cpi_sigcode = p->p_sigctx.ps_info._code; 362 cpi.cpi_siglwp = p->p_sigctx.ps_lwp; 363 364 /* 365 * XXX This should be per-LWP. 366 */ 367 ss1 = p->p_sigpend.sp_set; 368 sigemptyset(&ss2); 369 LIST_FOREACH(l0, &p->p_lwps, l_sibling) { 370 sigplusset(&l0->l_sigpend.sp_set, &ss1); 371 sigplusset(&l0->l_sigmask, &ss2); 372 } 373 memcpy(&cpi.cpi_sigpend, &ss1, sizeof(cpi.cpi_sigpend)); 374 memcpy(&cpi.cpi_sigmask, &ss2, sizeof(cpi.cpi_sigmask)); 375 memcpy(&cpi.cpi_sigignore, &p->p_sigctx.ps_sigignore, 376 sizeof(cpi.cpi_sigignore)); 377 memcpy(&cpi.cpi_sigcatch, &p->p_sigctx.ps_sigcatch, 378 sizeof(cpi.cpi_sigcatch)); 379 380 cpi.cpi_pid = p->p_pid; 381 mutex_enter(proc_lock); 382 cpi.cpi_ppid = p->p_pptr->p_pid; 383 cpi.cpi_pgrp = p->p_pgid; 384 cpi.cpi_sid = p->p_session->s_sid; 385 mutex_exit(proc_lock); 386 387 cpi.cpi_ruid = kauth_cred_getuid(l->l_cred); 388 cpi.cpi_euid = kauth_cred_geteuid(l->l_cred); 389 cpi.cpi_svuid = kauth_cred_getsvuid(l->l_cred); 390 391 cpi.cpi_rgid = kauth_cred_getgid(l->l_cred); 392 cpi.cpi_egid = kauth_cred_getegid(l->l_cred); 393 cpi.cpi_svgid = kauth_cred_getsvgid(l->l_cred); 394 395 cpi.cpi_nlwps = p->p_nlwps; 396 (void)strncpy(cpi.cpi_name, p->p_comm, sizeof(cpi.cpi_name)); 397 cpi.cpi_name[sizeof(cpi.cpi_name) - 1] = '\0'; 398 399 ELFNAMEEND(coredump_savenote)(ns, ELF_NOTE_NETBSD_CORE_PROCINFO, 400 ELF_NOTE_NETBSD_CORE_NAME, &cpi, sizeof(cpi)); 401 } 402 403 static int 404 coredump_note_auxv(struct lwp *l, struct note_state *ns) 405 { 406 struct ps_strings pss; 407 int error; 408 struct proc *p = l->l_proc; 409 void *uauxv, *kauxv; 410 411 if ((error = copyin_psstrings(p, &pss)) != 0) 412 return error; 413 414 if (pss.ps_envstr == NULL) 415 return EIO; 416 417 size_t ptrsz = PROC_PTRSZ(p); 418 uauxv = (void *)((char *)pss.ps_envstr + (pss.ps_nenvstr + 1) * ptrsz); 419 size_t len = p->p_execsw->es_arglen; 420 421 kauxv = kmem_alloc(len, KM_SLEEP); 422 error = copyin_proc(p, uauxv, kauxv, len); 423 if (error == 0) { 424 ELFNAMEEND(coredump_savenote)(ns, ELF_NOTE_NETBSD_CORE_AUXV, 425 ELF_NOTE_NETBSD_CORE_NAME, kauxv, len); 426 } 427 428 kmem_free(kauxv, len); 429 return error; 430 } 431 432 static int 433 ELFNAMEEND(coredump_notes)(struct lwp *l, struct note_state *ns) 434 { 435 int error; 436 struct lwp *l0; 437 struct proc *p = l->l_proc; 438 439 coredump_note_procinfo(l, ns); 440 error = coredump_note_auxv(l, ns); 441 if (error) 442 return error; 443 444 /* XXX Add hook for machdep per-proc notes. */ 445 446 /* 447 * Now write the register info for the thread that caused the 448 * coredump. 449 */ 450 error = ELFNAMEEND(coredump_note)(l, ns); 451 if (error) 452 return error; 453 454 /* 455 * Now, for each LWP, write the register info and any other 456 * per-LWP notes. 457 * Lock in case this is a gcore requested dump. 458 */ 459 mutex_enter(p->p_lock); 460 LIST_FOREACH(l0, &p->p_lwps, l_sibling) { 461 if (l0 == l) /* we've taken care of this thread */ 462 continue; 463 error = ELFNAMEEND(coredump_note)(l0, ns); 464 if (error) 465 break; 466 } 467 mutex_exit(p->p_lock); 468 469 return error; 470 } 471 472 static int 473 ELFNAMEEND(coredump_note)(struct lwp *l, struct note_state *ns) 474 { 475 int error; 476 char name[64]; 477 elf_reg intreg; 478 #ifdef PT_GETFPREGS 479 elf_fpreg freg; 480 size_t freglen; 481 #endif 482 483 snprintf(name, sizeof(name), "%s@%d", 484 ELF_NOTE_NETBSD_CORE_NAME, l->l_lid); 485 486 error = elf_process_read_regs(l, &intreg); 487 if (error) 488 return (error); 489 490 ELFNAMEEND(coredump_savenote)(ns, PT_GETREGS, name, &intreg, 491 sizeof(intreg)); 492 493 #ifdef PT_GETFPREGS 494 freglen = sizeof(freg); 495 error = elf_process_read_fpregs(l, &freg, &freglen); 496 if (error) 497 return (error); 498 499 ELFNAMEEND(coredump_savenote)(ns, PT_GETFPREGS, name, &freg, freglen); 500 #endif 501 /* XXX Add hook for machdep per-LWP notes. */ 502 return (0); 503 } 504 505 static void 506 save_note_bytes(struct note_state *ns, const void *data, size_t len) 507 { 508 struct note_buf *nb = ns->ns_last; 509 size_t copylen; 510 unsigned char *wp; 511 512 /* 513 * Just copy the data into a buffer list. 514 * All but the last buffer is full. 515 */ 516 for (;;) { 517 copylen = min(len, sizeof nb->nb_data - ns->ns_offset); 518 wp = nb->nb_data + ns->ns_offset; 519 memcpy(wp, data, copylen); 520 if (copylen == len) 521 break; 522 nb->nb_next = kmem_alloc(sizeof *nb->nb_next, KM_SLEEP); 523 nb = nb->nb_next; 524 ns->ns_last = nb; 525 ns->ns_count++; 526 ns->ns_offset = 0; 527 len -= copylen; 528 data = (const unsigned char *)data + copylen; 529 } 530 531 while (copylen & (ELFROUNDSIZE - 1)) 532 wp[copylen++] = 0; 533 534 ns->ns_offset += copylen; 535 } 536 537 void 538 ELFNAMEEND(coredump_savenote)(struct note_state *ns, unsigned int type, 539 const char *name, void *data, size_t data_len) 540 { 541 Elf_Nhdr nhdr; 542 543 nhdr.n_namesz = strlen(name) + 1; 544 nhdr.n_descsz = data_len; 545 nhdr.n_type = type; 546 547 save_note_bytes(ns, &nhdr, sizeof (nhdr)); 548 save_note_bytes(ns, name, nhdr.n_namesz); 549 save_note_bytes(ns, data, data_len); 550 } 551 552 #else /* COREDUMP */ 553 554 int 555 ELFNAMEEND(coredump)(struct lwp *l, struct coredump_iostate *cookie) 556 { 557 558 return ENOSYS; 559 } 560 561 #endif /* COREDUMP */ 562