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