1 /* $NetBSD: core_elf32.c,v 1.57 2018/09/03 16:29:35 riastradh 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.57 2018/09/03 16:29:35 riastradh 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 /* 162 * NetBSD sets generic SYSV OSABI and ABI version 0 163 * Native ELF files are distinguishable with NetBSD specific notes 164 */ 165 ehdr.e_ident[EI_OSABI] = ELFOSABI_SYSV; 166 ehdr.e_ident[EI_ABIVERSION] = 0; 167 168 ehdr.e_type = ET_CORE; 169 /* XXX This should be the e_machine of the executable. */ 170 ehdr.e_machine = ELFDEFNNAME(MACHDEP_ID); 171 ehdr.e_version = EV_CURRENT; 172 ehdr.e_entry = 0; 173 ehdr.e_flags = 0; 174 ehdr.e_ehsize = sizeof(ehdr); 175 ehdr.e_phentsize = sizeof(Elf_Phdr); 176 if (npsections < PN_XNUM) { 177 ehdr.e_phnum = npsections; 178 ehdr.e_shentsize = 0; 179 ehdr.e_shnum = 0; 180 ehdr.e_shoff = 0; 181 ehdr.e_phoff = sizeof(ehdr); 182 } else { 183 ehdr.e_phnum = PN_XNUM; 184 ehdr.e_shentsize = sizeof(Elf_Shdr); 185 ehdr.e_shnum = 1; 186 ehdr.e_shoff = sizeof(ehdr); 187 ehdr.e_phoff = sizeof(ehdr) + sizeof(shdr); 188 } 189 ehdr.e_shstrndx = 0; 190 191 #ifdef ELF_MD_COREDUMP_SETUP 192 ELF_MD_COREDUMP_SETUP(l, &ehdr); 193 #endif 194 195 /* Write out the ELF header. */ 196 error = coredump_write(cookie, UIO_SYSSPACE, &ehdr, sizeof(ehdr)); 197 if (error) 198 goto out; 199 200 /* Write out sections, if needed */ 201 if (npsections >= PN_XNUM) { 202 memset(&shdr, 0, sizeof(shdr)); 203 shdr.sh_type = SHT_NULL; 204 shdr.sh_info = npsections; 205 error = coredump_write(cookie, UIO_SYSSPACE, &shdr, 206 sizeof(shdr)); 207 if (error) 208 goto out; 209 } 210 211 psectionssize = npsections * sizeof(*psections); 212 notestart = ehdr.e_phoff + psectionssize; 213 214 psections = kmem_zalloc(psectionssize, KM_SLEEP); 215 216 /* Pass 2: now find the P-section headers. */ 217 ws.secoff = notestart + notesize; 218 ws.psections = psections; 219 ws.npsections = npsections - 1; 220 ws.p = l->l_proc; 221 error = uvm_coredump_walkmap(l->l_proc, ELFNAMEEND(coredump_getseghdrs), 222 &ws); 223 if (error) 224 goto out; 225 if (ws.npsections != 0) { 226 /* A section went away */ 227 error = ENOMEM; 228 goto out; 229 } 230 231 /* Add the PT_NOTE header after the P-section headers. */ 232 ws.psections->p_type = PT_NOTE; 233 ws.psections->p_offset = notestart; 234 ws.psections->p_vaddr = 0; 235 ws.psections->p_paddr = 0; 236 ws.psections->p_filesz = notesize; 237 ws.psections->p_memsz = 0; 238 ws.psections->p_flags = PF_R; 239 ws.psections->p_align = ELFROUNDSIZE; 240 241 /* Write the P-section headers followed by the PT_NOTE header */ 242 error = coredump_write(cookie, UIO_SYSSPACE, psections, psectionssize); 243 if (error) 244 goto out; 245 246 #ifdef DIAGNOSTIC 247 if (coredump_offset(cookie) != notestart) 248 panic("coredump: offset %lld != notestart %lld", 249 (long long) coredump_offset(cookie), 250 (long long) notestart); 251 #endif 252 253 /* Write out the notes. */ 254 for (nb = ns.ns_first; nb != NULL; nb = nb->nb_next) { 255 error = coredump_write(cookie, UIO_SYSSPACE, nb->nb_data, 256 nb->nb_next == NULL ? ns.ns_offset : sizeof nb->nb_data); 257 if (error) 258 goto out; 259 } 260 261 /* Finally, write the sections themselves. */ 262 for (i = 0; i < npsections - 1; i++) { 263 if (psections[i].p_filesz == 0) 264 continue; 265 266 #ifdef DIAGNOSTIC 267 if (coredump_offset(cookie) != psections[i].p_offset) 268 panic("coredump: offset %lld != p_offset[%d] %lld", 269 (long long) coredump_offset(cookie), i, 270 (long long) psections[i].p_filesz); 271 #endif 272 273 error = coredump_write(cookie, UIO_USERSPACE, 274 (void *)(vaddr_t)psections[i].p_vaddr, 275 psections[i].p_filesz); 276 if (error) 277 goto out; 278 } 279 280 out: 281 if (psections) 282 kmem_free(psections, psectionssize); 283 while ((nb = ns.ns_first) != NULL) { 284 ns.ns_first = nb->nb_next; 285 kmem_free(nb, sizeof *nb); 286 } 287 return (error); 288 } 289 290 static int 291 ELFNAMEEND(coredump_getseghdrs)(struct uvm_coredump_state *us) 292 { 293 struct writesegs_state *ws = us->cookie; 294 Elf_Phdr phdr; 295 vsize_t size, realsize; 296 vaddr_t end; 297 int error; 298 299 /* Don't overrun if there are more sections */ 300 if (ws->npsections == 0) 301 return ENOMEM; 302 ws->npsections--; 303 304 size = us->end - us->start; 305 realsize = us->realend - us->start; 306 end = us->realend; 307 308 /* Don't bother writing out trailing zeros */ 309 while (realsize > 0) { 310 long buf[1024 / sizeof(long)]; 311 size_t slen = realsize > sizeof(buf) ? sizeof(buf) : realsize; 312 const long *ep; 313 int i; 314 315 end -= slen; 316 if ((error = copyin_proc(ws->p, (void *)end, buf, slen)) != 0) 317 return error; 318 319 ep = (const long *) &buf[slen / sizeof(buf[0])]; 320 for (i = 0, ep--; buf <= ep; ep--, i++) { 321 if (*ep) 322 break; 323 } 324 realsize -= i * sizeof(buf[0]); 325 if (i * sizeof(buf[0]) < slen) 326 break; 327 } 328 329 phdr.p_type = PT_LOAD; 330 phdr.p_offset = ws->secoff; 331 phdr.p_vaddr = us->start; 332 phdr.p_paddr = 0; 333 phdr.p_filesz = realsize; 334 phdr.p_memsz = size; 335 phdr.p_flags = 0; 336 if (us->prot & VM_PROT_READ) 337 phdr.p_flags |= PF_R; 338 if (us->prot & VM_PROT_WRITE) 339 phdr.p_flags |= PF_W; 340 if (us->prot & VM_PROT_EXECUTE) 341 phdr.p_flags |= PF_X; 342 phdr.p_align = PAGE_SIZE; 343 344 ws->secoff += phdr.p_filesz; 345 *ws->psections++ = phdr; 346 347 return (0); 348 } 349 350 static void 351 coredump_note_procinfo(struct lwp *l, struct note_state *ns) 352 { 353 struct proc *p; 354 struct netbsd_elfcore_procinfo cpi; 355 struct lwp *l0; 356 sigset_t ss1, ss2; 357 358 p = l->l_proc; 359 360 /* First, write an elfcore_procinfo. */ 361 cpi.cpi_version = NETBSD_ELFCORE_PROCINFO_VERSION; 362 cpi.cpi_cpisize = sizeof(cpi); 363 cpi.cpi_signo = p->p_sigctx.ps_info._signo; 364 cpi.cpi_sigcode = p->p_sigctx.ps_info._code; 365 cpi.cpi_siglwp = p->p_sigctx.ps_lwp; 366 367 /* 368 * XXX This should be per-LWP. 369 */ 370 ss1 = p->p_sigpend.sp_set; 371 sigemptyset(&ss2); 372 LIST_FOREACH(l0, &p->p_lwps, l_sibling) { 373 sigplusset(&l0->l_sigpend.sp_set, &ss1); 374 sigplusset(&l0->l_sigmask, &ss2); 375 } 376 memcpy(&cpi.cpi_sigpend, &ss1, sizeof(cpi.cpi_sigpend)); 377 memcpy(&cpi.cpi_sigmask, &ss2, sizeof(cpi.cpi_sigmask)); 378 memcpy(&cpi.cpi_sigignore, &p->p_sigctx.ps_sigignore, 379 sizeof(cpi.cpi_sigignore)); 380 memcpy(&cpi.cpi_sigcatch, &p->p_sigctx.ps_sigcatch, 381 sizeof(cpi.cpi_sigcatch)); 382 383 cpi.cpi_pid = p->p_pid; 384 mutex_enter(proc_lock); 385 cpi.cpi_ppid = p->p_pptr->p_pid; 386 cpi.cpi_pgrp = p->p_pgid; 387 cpi.cpi_sid = p->p_session->s_sid; 388 mutex_exit(proc_lock); 389 390 cpi.cpi_ruid = kauth_cred_getuid(l->l_cred); 391 cpi.cpi_euid = kauth_cred_geteuid(l->l_cred); 392 cpi.cpi_svuid = kauth_cred_getsvuid(l->l_cred); 393 394 cpi.cpi_rgid = kauth_cred_getgid(l->l_cred); 395 cpi.cpi_egid = kauth_cred_getegid(l->l_cred); 396 cpi.cpi_svgid = kauth_cred_getsvgid(l->l_cred); 397 398 cpi.cpi_nlwps = p->p_nlwps; 399 (void)strncpy(cpi.cpi_name, p->p_comm, sizeof(cpi.cpi_name)); 400 cpi.cpi_name[sizeof(cpi.cpi_name) - 1] = '\0'; 401 402 ELFNAMEEND(coredump_savenote)(ns, ELF_NOTE_NETBSD_CORE_PROCINFO, 403 ELF_NOTE_NETBSD_CORE_NAME, &cpi, sizeof(cpi)); 404 } 405 406 static int 407 coredump_note_auxv(struct lwp *l, struct note_state *ns) 408 { 409 int error; 410 size_t len; 411 void *kauxv; 412 413 if ((error = proc_getauxv(l->l_proc, &kauxv, &len)) != 0) 414 return error; 415 416 ELFNAMEEND(coredump_savenote)(ns, ELF_NOTE_NETBSD_CORE_AUXV, 417 ELF_NOTE_NETBSD_CORE_NAME, kauxv, len); 418 419 kmem_free(kauxv, len); 420 return 0; 421 } 422 423 static int 424 ELFNAMEEND(coredump_notes)(struct lwp *l, struct note_state *ns) 425 { 426 int error; 427 struct lwp *l0; 428 struct proc *p = l->l_proc; 429 430 coredump_note_procinfo(l, ns); 431 error = coredump_note_auxv(l, ns); 432 if (error) 433 return error; 434 435 /* XXX Add hook for machdep per-proc notes. */ 436 437 /* 438 * Now write the register info for the thread that caused the 439 * coredump. 440 */ 441 error = ELFNAMEEND(coredump_note)(l, ns); 442 if (error) 443 return error; 444 445 /* 446 * Now, for each LWP, write the register info and any other 447 * per-LWP notes. 448 * Lock in case this is a gcore requested dump. 449 */ 450 mutex_enter(p->p_lock); 451 LIST_FOREACH(l0, &p->p_lwps, l_sibling) { 452 if (l0 == l) /* we've taken care of this thread */ 453 continue; 454 error = ELFNAMEEND(coredump_note)(l0, ns); 455 if (error) 456 break; 457 } 458 mutex_exit(p->p_lock); 459 460 return error; 461 } 462 463 static int 464 ELFNAMEEND(coredump_note)(struct lwp *l, struct note_state *ns) 465 { 466 int error; 467 char name[64]; 468 elf_reg intreg; 469 #ifdef PT_GETFPREGS 470 elf_fpreg freg; 471 size_t freglen; 472 #endif 473 474 snprintf(name, sizeof(name), "%s@%d", 475 ELF_NOTE_NETBSD_CORE_NAME, l->l_lid); 476 477 error = elf_process_read_regs(l, &intreg); 478 if (error) 479 return (error); 480 481 ELFNAMEEND(coredump_savenote)(ns, PT_GETREGS, name, &intreg, 482 sizeof(intreg)); 483 484 #ifdef PT_GETFPREGS 485 freglen = sizeof(freg); 486 error = elf_process_read_fpregs(l, &freg, &freglen); 487 if (error) 488 return (error); 489 490 ELFNAMEEND(coredump_savenote)(ns, PT_GETFPREGS, name, &freg, freglen); 491 #endif 492 /* XXX Add hook for machdep per-LWP notes. */ 493 return (0); 494 } 495 496 static void 497 save_note_bytes(struct note_state *ns, const void *data, size_t len) 498 { 499 struct note_buf *nb = ns->ns_last; 500 size_t copylen; 501 unsigned char *wp; 502 503 /* 504 * Just copy the data into a buffer list. 505 * All but the last buffer is full. 506 */ 507 for (;;) { 508 copylen = uimin(len, sizeof(nb->nb_data) - ns->ns_offset); 509 wp = nb->nb_data + ns->ns_offset; 510 memcpy(wp, data, copylen); 511 if (copylen == len) 512 break; 513 nb->nb_next = kmem_alloc(sizeof(*nb->nb_next), KM_SLEEP); 514 nb = nb->nb_next; 515 ns->ns_last = nb; 516 ns->ns_count++; 517 ns->ns_offset = 0; 518 len -= copylen; 519 data = (const unsigned char *)data + copylen; 520 } 521 522 while ((copylen & (ELFROUNDSIZE - 1)) && 523 wp + copylen < nb->nb_data + sizeof(nb->nb_data)) 524 wp[copylen++] = 0; 525 526 ns->ns_offset += copylen; 527 } 528 529 void 530 ELFNAMEEND(coredump_savenote)(struct note_state *ns, unsigned int type, 531 const char *name, void *data, size_t data_len) 532 { 533 Elf_Nhdr nhdr; 534 535 nhdr.n_namesz = strlen(name) + 1; 536 nhdr.n_descsz = data_len; 537 nhdr.n_type = type; 538 539 save_note_bytes(ns, &nhdr, sizeof (nhdr)); 540 save_note_bytes(ns, name, nhdr.n_namesz); 541 save_note_bytes(ns, data, data_len); 542 } 543 544 #else /* COREDUMP */ 545 546 int 547 ELFNAMEEND(coredump)(struct lwp *l, struct coredump_iostate *cookie) 548 { 549 550 return ENOSYS; 551 } 552 553 #endif /* COREDUMP */ 554