imgact_elf.c revision 40435
1/*- 2 * Copyright (c) 1995-1996 S�ren Schmidt 3 * Copyright (c) 1996 Peter Wemm 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer 11 * in this position and unchanged. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software withough specific prior written permission 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 * $Id: imgact_elf.c,v 1.39 1998/10/15 09:52:19 dfr Exp $ 30 */ 31 32#include "opt_rlimit.h" 33 34#include <sys/param.h> 35#include <sys/acct.h> 36#include <sys/exec.h> 37#include <sys/fcntl.h> 38#include <sys/imgact.h> 39#include <sys/imgact_elf.h> 40#include <sys/kernel.h> 41#include <sys/malloc.h> 42#include <sys/mman.h> 43#include <sys/namei.h> 44#include <sys/pioctl.h> 45#include <sys/proc.h> 46#include <sys/procfs.h> 47#include <sys/resourcevar.h> 48#include <sys/signalvar.h> 49#include <sys/stat.h> 50#include <sys/syscall.h> 51#include <sys/sysctl.h> 52#include <sys/sysent.h> 53#include <sys/systm.h> 54#include <sys/vnode.h> 55 56#include <vm/vm.h> 57#include <vm/vm_kern.h> 58#include <vm/vm_param.h> 59#include <vm/pmap.h> 60#include <sys/lock.h> 61#include <vm/vm_map.h> 62#include <vm/vm_object.h> 63#include <vm/vm_prot.h> 64#include <vm/vm_extern.h> 65 66#include <machine/md_var.h> 67 68#define MAX_PHDR 32 /* XXX enough ? */ 69 70#if ELF_TARG_CLASS == ELFCLASS32 71 72#define Elf_Ehdr Elf32_Ehdr 73#define Elf_Phdr Elf32_Phdr 74#define Elf_Auxargs Elf32_Auxargs 75#define Elf_Brandinfo Elf32_Brandinfo 76 77#else 78 79#define Elf_Ehdr Elf64_Ehdr 80#define Elf_Phdr Elf64_Phdr 81#define Elf_Auxargs Elf64_Auxargs 82#define Elf_Brandinfo Elf64_Brandinfo 83 84#endif 85 86 87static int elf_check_header __P((const Elf_Ehdr *hdr, int type)); 88static int elf_freebsd_fixup __P((long **stack_base, 89 struct image_params *imgp)); 90static int elf_load_file __P((struct proc *p, char *file, u_long *addr, 91 u_long *entry)); 92static int elf_load_section __P((struct vmspace *vmspace, struct vnode *vp, 93 vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, 94 vm_prot_t prot)); 95static int exec_elf_imgact __P((struct image_params *imgp)); 96 97static int elf_trace = 0; 98SYSCTL_INT(_debug, OID_AUTO, elf_trace, CTLFLAG_RW, &elf_trace, 0, ""); 99#define UPRINTF if (elf_trace) uprintf 100 101static struct sysentvec elf_freebsd_sysvec = { 102 SYS_MAXSYSCALL, 103 sysent, 104 0, 105 0, 106 0, 107 0, 108 0, 109 0, 110 elf_freebsd_fixup, 111 sendsig, 112 sigcode, 113 &szsigcode, 114 0, 115 "FreeBSD ELF", 116 elf_coredump 117}; 118 119static Elf_Brandinfo freebsd_brand_info = { 120 "FreeBSD", 121 "", 122 "/usr/libexec/ld-elf.so.1", 123 &elf_freebsd_sysvec 124 }; 125static Elf_Brandinfo *elf_brand_list[MAX_BRANDS] = { 126 &freebsd_brand_info, 127 NULL, NULL, NULL, 128 NULL, NULL, NULL, NULL 129 }; 130 131int 132elf_insert_brand_entry(Elf_Brandinfo *entry) 133{ 134 int i; 135 136 for (i=1; i<MAX_BRANDS; i++) { 137 if (elf_brand_list[i] == NULL) { 138 elf_brand_list[i] = entry; 139 break; 140 } 141 } 142 if (i == MAX_BRANDS) 143 return -1; 144 return 0; 145} 146 147int 148elf_remove_brand_entry(Elf_Brandinfo *entry) 149{ 150 int i; 151 152 for (i=1; i<MAX_BRANDS; i++) { 153 if (elf_brand_list[i] == entry) { 154 elf_brand_list[i] = NULL; 155 break; 156 } 157 } 158 if (i == MAX_BRANDS) 159 return -1; 160 return 0; 161} 162 163static int 164elf_check_header(const Elf_Ehdr *hdr, int type) 165{ 166 if (!(hdr->e_ident[EI_MAG0] == ELFMAG0 && 167 hdr->e_ident[EI_MAG1] == ELFMAG1 && 168 hdr->e_ident[EI_MAG2] == ELFMAG2 && 169 hdr->e_ident[EI_MAG3] == ELFMAG3)) 170 return ENOEXEC; 171 172#ifdef __i386__ 173 if (hdr->e_machine != EM_386 && hdr->e_machine != EM_486) 174#endif 175#ifdef __alpha__ 176 if (hdr->e_machine != EM_ALPHA) 177#endif 178 return ENOEXEC; 179 180 181 if (hdr->e_type != type) 182 return ENOEXEC; 183 184 return 0; 185} 186 187static int 188elf_load_section(struct vmspace *vmspace, struct vnode *vp, vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, vm_prot_t prot) 189{ 190 size_t map_len; 191 vm_offset_t map_addr; 192 int error; 193 unsigned char *data_buf = 0; 194 size_t copy_len; 195 196 map_addr = trunc_page((vm_offset_t)vmaddr); 197 198 if (memsz > filsz) 199 map_len = trunc_page(offset+filsz) - trunc_page(offset); 200 else 201 map_len = round_page(offset+filsz) - trunc_page(offset); 202 203 if (error = vm_mmap (&vmspace->vm_map, 204 &map_addr, 205 map_len, 206 prot, 207 VM_PROT_ALL, 208 MAP_PRIVATE | MAP_FIXED, 209 (caddr_t)vp, 210 trunc_page(offset))) 211 return error; 212 213 if (memsz == filsz) 214 return 0; 215 216 /* 217 * We have to map the remaining bit of the file into the kernel's 218 * memory map, allocate some anonymous memory, and copy that last 219 * bit into it. The remaining space should be .bss... 220 */ 221 copy_len = (offset + filsz) - trunc_page(offset + filsz); 222 map_addr = trunc_page((vm_offset_t)vmaddr + filsz); 223 map_len = round_page((vm_offset_t)vmaddr + memsz) - map_addr; 224 225 if (map_len != 0) { 226 if (error = vm_map_find(&vmspace->vm_map, NULL, 0, 227 &map_addr, map_len, FALSE, 228 VM_PROT_ALL, VM_PROT_ALL,0)) 229 return error; 230 } 231 232 if (error = vm_mmap(exec_map, 233 (vm_offset_t *)&data_buf, 234 PAGE_SIZE, 235 VM_PROT_READ, 236 VM_PROT_READ, 237 0, 238 (caddr_t)vp, 239 trunc_page(offset + filsz))) 240 return error; 241 242 error = copyout(data_buf, (caddr_t)map_addr, copy_len); 243 244 vm_map_remove(exec_map, (vm_offset_t)data_buf, 245 (vm_offset_t)data_buf + PAGE_SIZE); 246 247 /* 248 * set it to the specified protection 249 */ 250 vm_map_protect(&vmspace->vm_map, map_addr, map_addr + map_len, prot, 251 FALSE); 252 253 UPRINTF("bss size %d (%x)\n", map_len-copy_len, map_len-copy_len); 254 return error; 255} 256 257static int 258elf_load_file(struct proc *p, char *file, u_long *addr, u_long *entry) 259{ 260 Elf_Ehdr *hdr = NULL; 261 Elf_Phdr *phdr = NULL; 262 struct nameidata nd; 263 struct vmspace *vmspace = p->p_vmspace; 264 struct vattr attr; 265 struct image_params image_params, *imgp; 266 vm_prot_t prot = 0; 267 unsigned long text_size = 0, data_size = 0; 268 unsigned long text_addr = 0, data_addr = 0; 269 int header_size = 0; 270 int error, i; 271 272 imgp = &image_params; 273 /* 274 * Initialize part of the common data 275 */ 276 imgp->proc = p; 277 imgp->uap = NULL; 278 imgp->attr = &attr; 279 imgp->firstpage = NULL; 280 imgp->image_header = (char *)kmem_alloc_wait(exec_map, PAGE_SIZE); 281 282 if (imgp->image_header == NULL) { 283 nd.ni_vp = NULL; 284 error = ENOMEM; 285 goto fail; 286 } 287 288 NDINIT(&nd, LOOKUP, LOCKLEAF|FOLLOW, UIO_SYSSPACE, file, p); 289 290 if (error = namei(&nd)) { 291 nd.ni_vp = NULL; 292 goto fail; 293 } 294 295 imgp->vp = nd.ni_vp; 296 297 /* 298 * Check permissions, modes, uid, etc on the file, and "open" it. 299 */ 300 error = exec_check_permissions(imgp); 301 if (error) { 302 VOP_UNLOCK(nd.ni_vp, 0, p); 303 goto fail; 304 } 305 306 error = exec_map_first_page(imgp); 307 VOP_UNLOCK(nd.ni_vp, 0, p); 308 if (error) 309 goto fail; 310 311 hdr = (Elf_Ehdr *)imgp->image_header; 312 if (error = elf_check_header(hdr, ET_DYN)) 313 goto fail; 314 315 /* 316 * ouch, need to bounds check in case user gives us a corrupted 317 * file with an insane header size 318 */ 319 if (hdr->e_phnum > MAX_PHDR) { /* XXX: ever more than this? */ 320 error = ENOEXEC; 321 goto fail; 322 } 323 324 header_size = hdr->e_phentsize * hdr->e_phnum; 325 326 /* Only support headers that fit within first page for now */ 327 if (header_size + hdr->e_phoff > PAGE_SIZE) { 328 error = ENOEXEC; 329 goto fail; 330 } 331 332 phdr = (Elf_Phdr *)(imgp->image_header + hdr->e_phoff); 333 334 for (i = 0; i < hdr->e_phnum; i++) { 335 switch(phdr[i].p_type) { 336 337 case PT_NULL: /* NULL section */ 338 UPRINTF ("ELF(file) PT_NULL section\n"); 339 break; 340 case PT_LOAD: /* Loadable segment */ 341 { 342 UPRINTF ("ELF(file) PT_LOAD section "); 343 if (phdr[i].p_flags & PF_X) 344 prot |= VM_PROT_EXECUTE; 345 if (phdr[i].p_flags & PF_W) 346 prot |= VM_PROT_WRITE; 347 if (phdr[i].p_flags & PF_R) 348 prot |= VM_PROT_READ; 349 350 if (error = elf_load_section(vmspace, nd.ni_vp, 351 phdr[i].p_offset, 352 (caddr_t)phdr[i].p_vaddr + 353 (*addr), 354 phdr[i].p_memsz, 355 phdr[i].p_filesz, prot)) 356 goto fail; 357 358 /* 359 * Is this .text or .data ?? 360 * 361 * We only handle one each of those yet XXX 362 */ 363 if (hdr->e_entry >= phdr[i].p_vaddr && 364 hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) { 365 text_addr = trunc_page(phdr[i].p_vaddr+(*addr)); 366 text_size = round_page(phdr[i].p_memsz + 367 phdr[i].p_vaddr - 368 trunc_page(phdr[i].p_vaddr)); 369 *entry=(unsigned long)hdr->e_entry+(*addr); 370 UPRINTF(".text <%08lx,%08lx> entry=%08lx\n", 371 text_addr, text_size, *entry); 372 } else { 373 data_addr = trunc_page(phdr[i].p_vaddr+(*addr)); 374 data_size = round_page(phdr[i].p_memsz + 375 phdr[i].p_vaddr - 376 trunc_page(phdr[i].p_vaddr)); 377 UPRINTF(".data <%08lx,%08lx>\n", 378 data_addr, data_size); 379 } 380 } 381 break; 382 383 case PT_DYNAMIC:/* Dynamic link information */ 384 UPRINTF ("ELF(file) PT_DYNAMIC section\n"); 385 break; 386 case PT_INTERP: /* Path to interpreter */ 387 UPRINTF ("ELF(file) PT_INTERP section\n"); 388 break; 389 case PT_NOTE: /* Note section */ 390 UPRINTF ("ELF(file) PT_NOTE section\n"); 391 break; 392 case PT_SHLIB: /* Shared lib section */ 393 UPRINTF ("ELF(file) PT_SHLIB section\n"); 394 break; 395 case PT_PHDR: /* Program header table info */ 396 UPRINTF ("ELF(file) PT_PHDR section\n"); 397 break; 398 default: 399 UPRINTF ("ELF(file) %d section ??\n", phdr[i].p_type ); 400 } 401 } 402 403fail: 404 if (imgp->firstpage) 405 exec_unmap_first_page(imgp); 406 if (imgp->image_header) 407 kmem_free_wakeup(exec_map, (vm_offset_t)imgp->image_header, 408 PAGE_SIZE); 409 if (nd.ni_vp) 410 vrele(nd.ni_vp); 411 412 return error; 413} 414 415static int 416exec_elf_imgact(struct image_params *imgp) 417{ 418 const Elf_Ehdr *hdr = (const Elf_Ehdr *) imgp->image_header; 419 const Elf_Phdr *phdr, *mapped_phdr = NULL; 420 Elf_Auxargs *elf_auxargs = NULL; 421 struct vmspace *vmspace; 422 vm_prot_t prot = 0; 423 u_long text_size = 0, data_size = 0; 424 u_long text_addr = 0, data_addr = 0; 425 u_long addr, entry = 0, proghdr = 0; 426 int error, i, header_size = 0; 427 const char *interp = NULL; 428 Elf_Brandinfo *brand_info; 429 char *brand; 430 char path[MAXPATHLEN]; 431 432 /* 433 * Do we have a valid ELF header ? 434 */ 435 if (elf_check_header(hdr, ET_EXEC)) 436 return -1; 437 438 /* 439 * From here on down, we return an errno, not -1, as we've 440 * detected an ELF file. 441 */ 442 443 /* 444 * ouch, need to bounds check in case user gives us a corrupted 445 * file with an insane header size 446 */ 447 if (hdr->e_phnum > MAX_PHDR) { /* XXX: ever more than this? */ 448 return ENOEXEC; 449 } 450 451 header_size = hdr->e_phentsize * hdr->e_phnum; 452 453 if ((hdr->e_phoff > PAGE_SIZE) || 454 (hdr->e_phoff + header_size) > PAGE_SIZE) { 455 /* Only support headers in first page for now */ 456 return ENOEXEC; 457 } else { 458 phdr = (const Elf_Phdr*) 459 ((const char *)imgp->image_header + hdr->e_phoff); 460 } 461 462 /* 463 * From this point on, we may have resources that need to be freed. 464 */ 465 if (error = exec_extract_strings(imgp)) 466 goto fail; 467 468 exec_new_vmspace(imgp); 469 470 vmspace = imgp->proc->p_vmspace; 471 472 for (i = 0; i < hdr->e_phnum; i++) { 473 switch(phdr[i].p_type) { 474 475 case PT_NULL: /* NULL section */ 476 UPRINTF ("ELF PT_NULL section\n"); 477 break; 478 case PT_LOAD: /* Loadable segment */ 479 { 480 UPRINTF ("ELF PT_LOAD section "); 481 if (phdr[i].p_flags & PF_X) 482 prot |= VM_PROT_EXECUTE; 483 if (phdr[i].p_flags & PF_W) 484 prot |= VM_PROT_WRITE; 485 if (phdr[i].p_flags & PF_R) 486 prot |= VM_PROT_READ; 487 488 if (error = elf_load_section(vmspace, imgp->vp, 489 phdr[i].p_offset, 490 (caddr_t)phdr[i].p_vaddr, 491 phdr[i].p_memsz, 492 phdr[i].p_filesz, prot)) 493 goto fail; 494 495 /* 496 * Is this .text or .data ?? 497 * 498 * We only handle one each of those yet XXX 499 */ 500 if (hdr->e_entry >= phdr[i].p_vaddr && 501 hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) { 502 text_addr = trunc_page(phdr[i].p_vaddr); 503 text_size = round_page(phdr[i].p_memsz + 504 phdr[i].p_vaddr - 505 text_addr); 506 entry = (u_long)hdr->e_entry; 507 UPRINTF(".text <%08lx,%08lx> entry=%08lx\n", 508 text_addr, text_size, entry); 509 } else { 510 data_addr = trunc_page(phdr[i].p_vaddr); 511 data_size = round_page(phdr[i].p_memsz + 512 phdr[i].p_vaddr - 513 data_addr); 514 UPRINTF(".data <%08lx,%08lx>\n", 515 data_addr, data_size); 516 } 517 } 518 break; 519 520 case PT_DYNAMIC:/* Dynamic link information */ 521 UPRINTF ("ELF PT_DYNAMIC section ??\n"); 522 break; 523 case PT_INTERP: /* Path to interpreter */ 524 UPRINTF ("ELF PT_INTERP section "); 525 if (phdr[i].p_filesz > MAXPATHLEN || 526 phdr[i].p_offset + phdr[i].p_filesz > PAGE_SIZE) { 527 error = ENOEXEC; 528 goto fail; 529 } 530 interp = imgp->image_header + phdr[i].p_offset; 531 UPRINTF("<%s>\n", interp); 532 break; 533 case PT_NOTE: /* Note section */ 534 UPRINTF ("ELF PT_NOTE section\n"); 535 break; 536 case PT_SHLIB: /* Shared lib section */ 537 UPRINTF ("ELF PT_SHLIB section\n"); 538 break; 539 case PT_PHDR: /* Program header table info */ 540 UPRINTF ("ELF PT_PHDR section <%x>\n", phdr[i].p_vaddr); 541 proghdr = phdr[i].p_vaddr; 542 break; 543 default: 544 UPRINTF ("ELF %d section ??\n", phdr[i].p_type); 545 } 546 } 547 548 vmspace->vm_tsize = text_size >> PAGE_SHIFT; 549 vmspace->vm_taddr = (caddr_t)(uintptr_t)text_addr; 550 vmspace->vm_dsize = data_size >> PAGE_SHIFT; 551 vmspace->vm_daddr = (caddr_t)(uintptr_t)data_addr; 552 553 addr = 2L*MAXDSIZ; /* May depend on OS type XXX */ 554 555 imgp->entry_addr = entry; 556 557 /* If the executable has a brand, search for it in the brand list. */ 558 brand_info = NULL; 559 brand = (char *)&hdr->e_ident[EI_BRAND]; 560 if (brand[0] != '\0') { 561 for (i = 0; i < MAX_BRANDS; i++) { 562 Elf_Brandinfo *bi = elf_brand_list[i]; 563 564 if (bi != NULL && strcmp(brand, bi->brand) == 0) { 565 brand_info = bi; 566 break; 567 } 568 } 569 } 570 571 /* Lacking a known brand, search for a recognized interpreter. */ 572 if (brand_info == NULL && interp != NULL) { 573 for (i = 0; i < MAX_BRANDS; i++) { 574 Elf_Brandinfo *bi = elf_brand_list[i]; 575 576 if (bi != NULL && 577 strcmp(interp, bi->interp_path) == 0) { 578 brand_info = bi; 579 break; 580 } 581 } 582 } 583 584#ifdef __alpha__ 585 /* XXX - Assume FreeBSD on the alpha. */ 586 if (brand_info == NULL) 587 brand_info = &freebsd_brand_info; 588#endif 589 590 if (brand_info == NULL) { 591 if (brand[0] == 0) 592 uprintf("ELF binary type not known." 593 " Use \"brandelf\" to brand it.\n"); 594 else 595 uprintf("ELF binary type \"%.*s\" not known.\n", 596 EI_NIDENT - EI_BRAND, brand); 597 error = ENOEXEC; 598 goto fail; 599 } 600 601 imgp->proc->p_sysent = brand_info->sysvec; 602 if (interp != NULL) { 603 strcpy(path, brand_info->emul_path); 604 strcat(path, interp); 605 UPRINTF("interpreter=<%s> %s\n", interp, brand_info->emul_path); 606 if ((error = elf_load_file(imgp->proc, path, &addr, 607 &imgp->entry_addr)) != 0) { 608 uprintf("ELF interpreter %s not found\n", path); 609 goto fail; 610 } 611 } 612 613 UPRINTF("Executing %s binary\n", brand_info->brand); 614 615 /* 616 * Construct auxargs table (used by the fixup routine) 617 */ 618 elf_auxargs = malloc(sizeof(Elf_Auxargs), M_TEMP, M_WAITOK); 619 elf_auxargs->execfd = -1; 620 elf_auxargs->phdr = proghdr; 621 elf_auxargs->phent = hdr->e_phentsize; 622 elf_auxargs->phnum = hdr->e_phnum; 623 elf_auxargs->pagesz = PAGE_SIZE; 624 elf_auxargs->base = addr; 625 elf_auxargs->flags = 0; 626 elf_auxargs->entry = entry; 627 elf_auxargs->trace = elf_trace; 628 629 imgp->auxargs = elf_auxargs; 630 imgp->interpreted = 0; 631 632 /* don't allow modifying the file while we run it */ 633 imgp->vp->v_flag |= VTEXT; 634 635fail: 636 return error; 637} 638 639static int 640elf_freebsd_fixup(long **stack_base, struct image_params *imgp) 641{ 642 Elf_Auxargs *args = (Elf_Auxargs *)imgp->auxargs; 643 long *pos; 644 645 pos = *stack_base + (imgp->argc + imgp->envc + 2); 646 647 if (args->trace) { 648 AUXARGS_ENTRY(pos, AT_DEBUG, 1); 649 } 650 if (args->execfd != -1) { 651 AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); 652 } 653 AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); 654 AUXARGS_ENTRY(pos, AT_PHENT, args->phent); 655 AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); 656 AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); 657 AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); 658 AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); 659 AUXARGS_ENTRY(pos, AT_BASE, args->base); 660 AUXARGS_ENTRY(pos, AT_NULL, 0); 661 662 free(imgp->auxargs, M_TEMP); 663 imgp->auxargs = NULL; 664 665 (*stack_base)--; 666 suword(*stack_base, (long) imgp->argc); 667 return 0; 668} 669 670/* 671 * Code for generating ELF core dumps. 672 */ 673 674typedef void (*segment_callback) __P((vm_map_entry_t, void *)); 675 676/* Closure for cb_put_phdr(). */ 677struct phdr_closure { 678 Elf_Phdr *phdr; /* Program header to fill in */ 679 Elf_Off offset; /* Offset of segment in core file */ 680}; 681 682/* Closure for cb_size_segment(). */ 683struct sseg_closure { 684 int count; /* Count of writable segments. */ 685 size_t size; /* Total size of all writable segments. */ 686}; 687 688static void cb_put_phdr __P((vm_map_entry_t, void *)); 689static void cb_size_segment __P((vm_map_entry_t, void *)); 690static void each_writable_segment __P((struct proc *, segment_callback, 691 void *)); 692static int elf_corehdr __P((struct proc *, struct vnode *, struct ucred *, 693 int, void *, size_t)); 694static void elf_puthdr __P((struct proc *, void *, size_t *, 695 const prstatus_t *, const prfpregset_t *, const prpsinfo_t *, int)); 696static void elf_putnote __P((void *, size_t *, const char *, int, 697 const void *, size_t)); 698 699extern int osreldate; 700 701int 702elf_coredump(p) 703 register struct proc *p; 704{ 705 register struct vnode *vp; 706 register struct ucred *cred = p->p_cred->pc_ucred; 707 register struct vmspace *vm = p->p_vmspace; 708 struct nameidata nd; 709 struct vattr vattr; 710 int error, error1; 711 char *name; /* name of corefile */ 712 struct sseg_closure seginfo; 713 void *hdr; 714 size_t hdrsize; 715 716 STOPEVENT(p, S_CORE, 0); 717 718 if (sugid_coredump == 0 && p->p_flag & P_SUGID) 719 return (EFAULT); 720 721 /* Size the program segments. */ 722 seginfo.count = 0; 723 seginfo.size = 0; 724 each_writable_segment(p, cb_size_segment, &seginfo); 725 726 /* 727 * Calculate the size of the core file header area by making 728 * a dry run of generating it. Nothing is written, but the 729 * size is calculated. 730 */ 731 hdrsize = 0; 732 elf_puthdr((struct proc *)NULL, (void *)NULL, &hdrsize, 733 (const prstatus_t *)NULL, (const prfpregset_t *)NULL, 734 (const prpsinfo_t *)NULL, seginfo.count); 735 736 if (hdrsize + seginfo.size >= p->p_rlimit[RLIMIT_CORE].rlim_cur) 737 return (EFAULT); 738 name = expand_name(p->p_comm, p->p_ucred->cr_uid, p->p_pid); 739 if (name == NULL) 740 return (EFAULT); /* XXX -- not the best error */ 741 742 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, name, p); 743 error = vn_open(&nd, O_CREAT | FWRITE, S_IRUSR | S_IWUSR); 744 free(name, M_TEMP); 745 if (error) 746 return (error); 747 vp = nd.ni_vp; 748 749 /* Don't dump to non-regular files or files with links. */ 750 if (vp->v_type != VREG || 751 VOP_GETATTR(vp, &vattr, cred, p) || vattr.va_nlink != 1) { 752 error = EFAULT; 753 goto out; 754 } 755 VATTR_NULL(&vattr); 756 vattr.va_size = 0; 757 VOP_LEASE(vp, p, cred, LEASE_WRITE); 758 VOP_SETATTR(vp, &vattr, cred, p); 759 p->p_acflag |= ACORE; 760 761 762 /* 763 * Allocate memory for building the header, fill it up, 764 * and write it out. 765 */ 766 hdr = malloc(hdrsize, M_TEMP, M_WAITOK); 767 if (hdr == NULL) { 768 error = EINVAL; 769 goto out; 770 } 771 error = elf_corehdr(p, vp, cred, seginfo.count, hdr, hdrsize); 772 773 /* Write the contents of all of the writable segments. */ 774 if (error == 0) { 775 Elf_Phdr *php; 776 off_t offset; 777 int i; 778 779 php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1; 780 offset = hdrsize; 781 for (i = 0; i < seginfo.count; i++) { 782 error = vn_rdwr(UIO_WRITE, vp, (caddr_t)php->p_vaddr, 783 php->p_filesz, offset, UIO_USERSPACE, 784 IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, p); 785 if (error != 0) 786 break; 787 offset += php->p_filesz; 788 php++; 789 } 790 } 791 free(hdr, M_TEMP); 792 793out: 794 VOP_UNLOCK(vp, 0, p); 795 error1 = vn_close(vp, FWRITE, cred, p); 796 if (error == 0) 797 error = error1; 798 return (error); 799} 800 801/* 802 * A callback for each_writable_segment() to write out the segment's 803 * program header entry. 804 */ 805static void 806cb_put_phdr(entry, closure) 807 vm_map_entry_t entry; 808 void *closure; 809{ 810 struct phdr_closure *phc = (struct phdr_closure *)closure; 811 Elf_Phdr *phdr = phc->phdr; 812 813 phc->offset = round_page(phc->offset); 814 815 phdr->p_type = PT_LOAD; 816 phdr->p_offset = phc->offset; 817 phdr->p_vaddr = entry->start; 818 phdr->p_paddr = 0; 819 phdr->p_filesz = phdr->p_memsz = entry->end - entry->start; 820 phdr->p_align = PAGE_SIZE; 821 phdr->p_flags = 0; 822 if (entry->protection & VM_PROT_READ) 823 phdr->p_flags |= PF_R; 824 if (entry->protection & VM_PROT_WRITE) 825 phdr->p_flags |= PF_W; 826 if (entry->protection & VM_PROT_EXECUTE) 827 phdr->p_flags |= PF_X; 828 829 phc->offset += phdr->p_filesz; 830 phc->phdr++; 831} 832 833/* 834 * A callback for each_writable_segment() to gather information about 835 * the number of segments and their total size. 836 */ 837static void 838cb_size_segment(entry, closure) 839 vm_map_entry_t entry; 840 void *closure; 841{ 842 struct sseg_closure *ssc = (struct sseg_closure *)closure; 843 844 ssc->count++; 845 ssc->size += entry->end - entry->start; 846} 847 848/* 849 * For each writable segment in the process's memory map, call the given 850 * function with a pointer to the map entry and some arbitrary 851 * caller-supplied data. 852 */ 853static void 854each_writable_segment(p, func, closure) 855 struct proc *p; 856 segment_callback func; 857 void *closure; 858{ 859 vm_map_t map = &p->p_vmspace->vm_map; 860 vm_map_entry_t entry; 861 862 for (entry = map->header.next; entry != &map->header; 863 entry = entry->next) { 864 vm_object_t obj; 865 866 if (entry->eflags & (MAP_ENTRY_IS_A_MAP|MAP_ENTRY_IS_SUB_MAP) || 867 (entry->protection & (VM_PROT_READ|VM_PROT_WRITE)) != 868 (VM_PROT_READ|VM_PROT_WRITE)) 869 continue; 870 871 if ((obj = entry->object.vm_object) == NULL) 872 continue; 873 874 /* Find the deepest backing object. */ 875 while (obj->backing_object != NULL) 876 obj = obj->backing_object; 877 878 /* Ignore memory-mapped devices and such things. */ 879 if (obj->type != OBJT_DEFAULT && 880 obj->type != OBJT_SWAP && 881 obj->type != OBJT_VNODE) 882 continue; 883 884 (*func)(entry, closure); 885 } 886} 887 888/* 889 * Write the core file header to the file, including padding up to 890 * the page boundary. 891 */ 892static int 893elf_corehdr(p, vp, cred, numsegs, hdr, hdrsize) 894 struct proc *p; 895 struct vnode *vp; 896 struct ucred *cred; 897 int numsegs; 898 size_t hdrsize; 899 void *hdr; 900{ 901 struct vmspace *vm = p->p_vmspace; 902 size_t off; 903 prstatus_t status; 904 prfpregset_t fpregset; 905 prpsinfo_t psinfo; 906 907 /* Gather the information for the header. */ 908 bzero(&status, sizeof status); 909 status.pr_version = PRSTATUS_VERSION; 910 status.pr_statussz = sizeof(prstatus_t); 911 status.pr_gregsetsz = sizeof(gregset_t); 912 status.pr_fpregsetsz = sizeof(fpregset_t); 913 status.pr_osreldate = osreldate; 914 status.pr_cursig = p->p_sigacts->ps_sig; 915 status.pr_pid = p->p_pid; 916 fill_regs(p, &status.pr_reg); 917 918 fill_fpregs(p, &fpregset); 919 920 bzero(&psinfo, sizeof psinfo); 921 psinfo.pr_version = PRPSINFO_VERSION; 922 psinfo.pr_psinfosz = sizeof(prpsinfo_t); 923 strncpy(psinfo.pr_fname, p->p_comm, MAXCOMLEN); 924 /* XXX - We don't fill in the command line arguments properly yet. */ 925 strncpy(psinfo.pr_psargs, p->p_comm, PRARGSZ); 926 927 /* Fill in the header. */ 928 bzero(hdr, hdrsize); 929 off = 0; 930 elf_puthdr(p, hdr, &off, &status, &fpregset, &psinfo, numsegs); 931 932 /* Write it to the core file. */ 933 return vn_rdwr(UIO_WRITE, vp, hdr, hdrsize, (off_t)0, 934 UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, NULL, p); 935} 936 937static void 938elf_puthdr(struct proc *p, void *dst, size_t *off, const prstatus_t *status, 939 const prfpregset_t *fpregset, const prpsinfo_t *psinfo, int numsegs) 940{ 941 size_t ehoff; 942 size_t phoff; 943 size_t noteoff; 944 size_t notesz; 945 946 ehoff = *off; 947 *off += sizeof(Elf_Ehdr); 948 949 phoff = *off; 950 *off += (numsegs + 1) * sizeof(Elf_Phdr); 951 952 noteoff = *off; 953 elf_putnote(dst, off, "FreeBSD", NT_PRSTATUS, status, 954 sizeof *status); 955 elf_putnote(dst, off, "FreeBSD", NT_FPREGSET, fpregset, 956 sizeof *fpregset); 957 elf_putnote(dst, off, "FreeBSD", NT_PRPSINFO, psinfo, 958 sizeof *psinfo); 959 notesz = *off - noteoff; 960 961 /* Align up to a page boundary for the program segments. */ 962 *off = round_page(*off); 963 964 if (dst != NULL) { 965 Elf_Ehdr *ehdr; 966 Elf_Phdr *phdr; 967 struct phdr_closure phc; 968 969 /* 970 * Fill in the ELF header. 971 */ 972 ehdr = (Elf_Ehdr *)((char *)dst + ehoff); 973 ehdr->e_ident[EI_MAG0] = ELFMAG0; 974 ehdr->e_ident[EI_MAG1] = ELFMAG1; 975 ehdr->e_ident[EI_MAG2] = ELFMAG2; 976 ehdr->e_ident[EI_MAG3] = ELFMAG3; 977 ehdr->e_ident[EI_CLASS] = ELF_CLASS; 978 ehdr->e_ident[EI_DATA] = ELF_DATA; 979 ehdr->e_ident[EI_VERSION] = EV_CURRENT; 980 ehdr->e_ident[EI_PAD] = 0; 981 strncpy(ehdr->e_ident + EI_BRAND, "FreeBSD", 982 EI_NIDENT - EI_BRAND); 983 ehdr->e_type = ET_CORE; 984 ehdr->e_machine = ELF_ARCH; 985 ehdr->e_version = EV_CURRENT; 986 ehdr->e_entry = 0; 987 ehdr->e_phoff = phoff; 988 ehdr->e_flags = 0; 989 ehdr->e_ehsize = sizeof(Elf_Ehdr); 990 ehdr->e_phentsize = sizeof(Elf_Phdr); 991 ehdr->e_phnum = numsegs + 1; 992 ehdr->e_shentsize = sizeof(Elf_Shdr); 993 ehdr->e_shnum = 0; 994 ehdr->e_shstrndx = SHN_UNDEF; 995 996 /* 997 * Fill in the program header entries. 998 */ 999 phdr = (Elf_Phdr *)((char *)dst + phoff); 1000 1001 /* The note segement. */ 1002 phdr->p_type = PT_NOTE; 1003 phdr->p_offset = noteoff; 1004 phdr->p_vaddr = 0; 1005 phdr->p_paddr = 0; 1006 phdr->p_filesz = notesz; 1007 phdr->p_memsz = 0; 1008 phdr->p_flags = 0; 1009 phdr->p_align = 0; 1010 phdr++; 1011 1012 /* All the writable segments from the program. */ 1013 phc.phdr = phdr; 1014 phc.offset = *off; 1015 each_writable_segment(p, cb_put_phdr, &phc); 1016 } 1017} 1018 1019static void 1020elf_putnote(void *dst, size_t *off, const char *name, int type, 1021 const void *desc, size_t descsz) 1022{ 1023 Elf_Note note; 1024 1025 note.n_namesz = strlen(name) + 1; 1026 note.n_descsz = descsz; 1027 note.n_type = type; 1028 if (dst != NULL) 1029 bcopy(¬e, (char *)dst + *off, sizeof note); 1030 *off += sizeof note; 1031 if (dst != NULL) 1032 bcopy(name, (char *)dst + *off, note.n_namesz); 1033 *off += roundup2(note.n_namesz, sizeof(Elf_Size)); 1034 if (dst != NULL) 1035 bcopy(desc, (char *)dst + *off, note.n_descsz); 1036 *off += roundup2(note.n_descsz, sizeof(Elf_Size)); 1037} 1038 1039/* 1040 * Tell kern_execve.c about it, with a little help from the linker. 1041 * Since `const' objects end up in the text segment, TEXT_SET is the 1042 * correct directive to use. 1043 */ 1044static const struct execsw elf_execsw = {exec_elf_imgact, "ELF"}; 1045EXEC_SET(elf, elf_execsw); 1046