1e1743d02SSøren Schmidt /*- 2e1743d02SSøren Schmidt * Copyright (c) 1995-1996 S�ren Schmidt 3e1743d02SSøren Schmidt * Copyright (c) 1996 Peter Wemm 4e1743d02SSøren Schmidt * All rights reserved. 5e1743d02SSøren Schmidt * 6e1743d02SSøren Schmidt * Redistribution and use in source and binary forms, with or without 7e1743d02SSøren Schmidt * modification, are permitted provided that the following conditions 8e1743d02SSøren Schmidt * are met: 9e1743d02SSøren Schmidt * 1. Redistributions of source code must retain the above copyright 10e1743d02SSøren Schmidt * notice, this list of conditions and the following disclaimer 11e1743d02SSøren Schmidt * in this position and unchanged. 12e1743d02SSøren Schmidt * 2. Redistributions in binary form must reproduce the above copyright 13e1743d02SSøren Schmidt * notice, this list of conditions and the following disclaimer in the 14e1743d02SSøren Schmidt * documentation and/or other materials provided with the distribution. 15e1743d02SSøren Schmidt * 3. The name of the author may not be used to endorse or promote products 16e1743d02SSøren Schmidt * derived from this software withough specific prior written permission 17e1743d02SSøren Schmidt * 18e1743d02SSøren Schmidt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19e1743d02SSøren Schmidt * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20e1743d02SSøren Schmidt * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21e1743d02SSøren Schmidt * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22e1743d02SSøren Schmidt * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23e1743d02SSøren Schmidt * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24e1743d02SSøren Schmidt * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25e1743d02SSøren Schmidt * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26e1743d02SSøren Schmidt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27e1743d02SSøren Schmidt * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28e1743d02SSøren Schmidt * 29c3aac50fSPeter Wemm * $FreeBSD$ 30e1743d02SSøren Schmidt */ 31e1743d02SSøren Schmidt 32e9822d92SJoerg Wunsch #include "opt_rlimit.h" 33e9822d92SJoerg Wunsch 34e1743d02SSøren Schmidt #include <sys/param.h> 358c64af4fSJohn Polstra #include <sys/acct.h> 36e1743d02SSøren Schmidt #include <sys/exec.h> 378c64af4fSJohn Polstra #include <sys/fcntl.h> 38e1743d02SSøren Schmidt #include <sys/imgact.h> 39e1743d02SSøren Schmidt #include <sys/imgact_elf.h> 40e1743d02SSøren Schmidt #include <sys/kernel.h> 41e1743d02SSøren Schmidt #include <sys/malloc.h> 428c64af4fSJohn Polstra #include <sys/mman.h> 43a794e791SBruce Evans #include <sys/namei.h> 448c64af4fSJohn Polstra #include <sys/pioctl.h> 45a794e791SBruce Evans #include <sys/proc.h> 468c64af4fSJohn Polstra #include <sys/procfs.h> 478c64af4fSJohn Polstra #include <sys/resourcevar.h> 48e1743d02SSøren Schmidt #include <sys/signalvar.h> 498c64af4fSJohn Polstra #include <sys/stat.h> 508c64af4fSJohn Polstra #include <sys/syscall.h> 51e1743d02SSøren Schmidt #include <sys/sysctl.h> 528c64af4fSJohn Polstra #include <sys/sysent.h> 538c64af4fSJohn Polstra #include <sys/systm.h> 54a794e791SBruce Evans #include <sys/vnode.h> 55e1743d02SSøren Schmidt 56e1743d02SSøren Schmidt #include <vm/vm.h> 57e1743d02SSøren Schmidt #include <vm/vm_kern.h> 58e1743d02SSøren Schmidt #include <vm/vm_param.h> 59e1743d02SSøren Schmidt #include <vm/pmap.h> 60996c772fSJohn Dyson #include <sys/lock.h> 61e1743d02SSøren Schmidt #include <vm/vm_map.h> 620ff27d31SJohn Polstra #include <vm/vm_object.h> 63e1743d02SSøren Schmidt #include <vm/vm_prot.h> 64e1743d02SSøren Schmidt #include <vm/vm_extern.h> 65e1743d02SSøren Schmidt 6652c24af7SPeter Wemm #include <machine/elf.h> 67e1743d02SSøren Schmidt #include <machine/md_var.h> 68e1743d02SSøren Schmidt 6952c24af7SPeter Wemm __ElfType(Brandinfo); 7052c24af7SPeter Wemm __ElfType(Auxargs); 71ecbb00a2SDoug Rabson 72c33fe779SJohn Polstra static int elf_check_header __P((const Elf_Ehdr *hdr)); 738c64af4fSJohn Polstra static int elf_freebsd_fixup __P((long **stack_base, 748c64af4fSJohn Polstra struct image_params *imgp)); 75bdbc8c26SPeter Wemm static int elf_load_file __P((struct proc *p, const char *file, u_long *addr, 768c64af4fSJohn Polstra u_long *entry)); 7752c24af7SPeter Wemm static int elf_load_section __P((struct proc *p, 7852c24af7SPeter Wemm struct vmspace *vmspace, struct vnode *vp, 798c64af4fSJohn Polstra vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, 808c64af4fSJohn Polstra vm_prot_t prot)); 81303b270bSEivind Eklund static int exec_elf_imgact __P((struct image_params *imgp)); 82e1743d02SSøren Schmidt 83d8a4f230SBruce Evans static int elf_trace = 0; 84d8a4f230SBruce Evans SYSCTL_INT(_debug, OID_AUTO, elf_trace, CTLFLAG_RW, &elf_trace, 0, ""); 85e1743d02SSøren Schmidt 86f8b3601eSMark Newton /* 87f8b3601eSMark Newton * XXX Maximum length of an ELF brand (sysctl wants a statically-allocated 88f8b3601eSMark Newton * buffer). 89f8b3601eSMark Newton */ 90f8b3601eSMark Newton #define MAXBRANDLEN 16 91f8b3601eSMark Newton 92e1743d02SSøren Schmidt static struct sysentvec elf_freebsd_sysvec = { 93e1743d02SSøren Schmidt SYS_MAXSYSCALL, 94e1743d02SSøren Schmidt sysent, 95e1743d02SSøren Schmidt 0, 96e1743d02SSøren Schmidt 0, 97e1743d02SSøren Schmidt 0, 98e1743d02SSøren Schmidt 0, 99e1743d02SSøren Schmidt 0, 100288078beSEivind Eklund 0, 101e1743d02SSøren Schmidt elf_freebsd_fixup, 102e1743d02SSøren Schmidt sendsig, 103e1743d02SSøren Schmidt sigcode, 104e1743d02SSøren Schmidt &szsigcode, 105e1743d02SSøren Schmidt 0, 10622d4b0fbSJohn Polstra "FreeBSD ELF", 10722d4b0fbSJohn Polstra elf_coredump 108e1743d02SSøren Schmidt }; 109e1743d02SSøren Schmidt 110ecbb00a2SDoug Rabson static Elf_Brandinfo freebsd_brand_info = { 111ea5a2b2eSSøren Schmidt "FreeBSD", 112ea5a2b2eSSøren Schmidt "", 113e1743d02SSøren Schmidt "/usr/libexec/ld-elf.so.1", 114ea5a2b2eSSøren Schmidt &elf_freebsd_sysvec 115e1743d02SSøren Schmidt }; 116ecbb00a2SDoug Rabson static Elf_Brandinfo *elf_brand_list[MAX_BRANDS] = { 117ea5a2b2eSSøren Schmidt &freebsd_brand_info, 118e1743d02SSøren Schmidt NULL, NULL, NULL, 119e1743d02SSøren Schmidt NULL, NULL, NULL, NULL 120e1743d02SSøren Schmidt }; 121e1743d02SSøren Schmidt 122e1743d02SSøren Schmidt int 123ecbb00a2SDoug Rabson elf_insert_brand_entry(Elf_Brandinfo *entry) 124e1743d02SSøren Schmidt { 125e1743d02SSøren Schmidt int i; 126e1743d02SSøren Schmidt 127ea5a2b2eSSøren Schmidt for (i=1; i<MAX_BRANDS; i++) { 128ea5a2b2eSSøren Schmidt if (elf_brand_list[i] == NULL) { 129ea5a2b2eSSøren Schmidt elf_brand_list[i] = entry; 130e1743d02SSøren Schmidt break; 131e1743d02SSøren Schmidt } 132e1743d02SSøren Schmidt } 133ea5a2b2eSSøren Schmidt if (i == MAX_BRANDS) 134e1743d02SSøren Schmidt return -1; 135e1743d02SSøren Schmidt return 0; 136e1743d02SSøren Schmidt } 137e1743d02SSøren Schmidt 138e1743d02SSøren Schmidt int 139ecbb00a2SDoug Rabson elf_remove_brand_entry(Elf_Brandinfo *entry) 140e1743d02SSøren Schmidt { 141e1743d02SSøren Schmidt int i; 142e1743d02SSøren Schmidt 143ea5a2b2eSSøren Schmidt for (i=1; i<MAX_BRANDS; i++) { 144ea5a2b2eSSøren Schmidt if (elf_brand_list[i] == entry) { 145ea5a2b2eSSøren Schmidt elf_brand_list[i] = NULL; 146e1743d02SSøren Schmidt break; 147e1743d02SSøren Schmidt } 148e1743d02SSøren Schmidt } 149ea5a2b2eSSøren Schmidt if (i == MAX_BRANDS) 150e1743d02SSøren Schmidt return -1; 151e1743d02SSøren Schmidt return 0; 152e1743d02SSøren Schmidt } 153e1743d02SSøren Schmidt 154096977faSMark Newton int 155096977faSMark Newton elf_brand_inuse(Elf_Brandinfo *entry) 156096977faSMark Newton { 157096977faSMark Newton struct proc *p; 158096977faSMark Newton 159096977faSMark Newton for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { 160096977faSMark Newton if (p->p_sysent == entry->sysvec) 161096977faSMark Newton return TRUE; 162096977faSMark Newton } 163096977faSMark Newton 164096977faSMark Newton return FALSE; 165096977faSMark Newton } 166096977faSMark Newton 167e1743d02SSøren Schmidt static int 168c33fe779SJohn Polstra elf_check_header(const Elf_Ehdr *hdr) 169e1743d02SSøren Schmidt { 17052c24af7SPeter Wemm if (!IS_ELF(*hdr) || 17152c24af7SPeter Wemm hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || 17252c24af7SPeter Wemm hdr->e_ident[EI_DATA] != ELF_TARG_DATA || 17352c24af7SPeter Wemm hdr->e_ident[EI_VERSION] != EV_CURRENT) 174e1743d02SSøren Schmidt return ENOEXEC; 175e1743d02SSøren Schmidt 17652c24af7SPeter Wemm if (!ELF_MACHINE_OK(hdr->e_machine)) 177e1743d02SSøren Schmidt return ENOEXEC; 178e1743d02SSøren Schmidt 179c33fe779SJohn Polstra if (hdr->e_version != ELF_TARG_VER) 180e1743d02SSøren Schmidt return ENOEXEC; 181e1743d02SSøren Schmidt 182e1743d02SSøren Schmidt return 0; 183e1743d02SSøren Schmidt } 184e1743d02SSøren Schmidt 185e1743d02SSøren Schmidt static int 18652c24af7SPeter Wemm elf_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) 187e1743d02SSøren Schmidt { 188e1743d02SSøren Schmidt size_t map_len; 189e1743d02SSøren Schmidt vm_offset_t map_addr; 19052c24af7SPeter Wemm int error, rv; 191e1743d02SSøren Schmidt size_t copy_len; 19252c24af7SPeter Wemm vm_object_t object; 19352c24af7SPeter Wemm vm_offset_t file_addr; 19452c24af7SPeter Wemm vm_offset_t data_buf = 0; 19552c24af7SPeter Wemm 19652c24af7SPeter Wemm object = vp->v_object; 19752c24af7SPeter Wemm error = 0; 198e1743d02SSøren Schmidt 1996cde7a16SDavid Greenman map_addr = trunc_page((vm_offset_t)vmaddr); 20052c24af7SPeter Wemm file_addr = trunc_page(offset); 201e1743d02SSøren Schmidt 202e1743d02SSøren Schmidt /* 20352c24af7SPeter Wemm * We have two choices. We can either clear the data in the last page 20452c24af7SPeter Wemm * of an oversized mapping, or we can start the anon mapping a page 20552c24af7SPeter Wemm * early and copy the initialized data into that first page. We 20652c24af7SPeter Wemm * choose the second.. 20752c24af7SPeter Wemm */ 20852c24af7SPeter Wemm if (memsz > filsz) 20952c24af7SPeter Wemm map_len = trunc_page(offset+filsz) - file_addr; 21052c24af7SPeter Wemm else 21152c24af7SPeter Wemm map_len = round_page(offset+filsz) - file_addr; 21252c24af7SPeter Wemm 21352c24af7SPeter Wemm if (map_len != 0) { 21452c24af7SPeter Wemm vm_object_reference(object); 21552c24af7SPeter Wemm vm_map_lock(&vmspace->vm_map); 21652c24af7SPeter Wemm rv = vm_map_insert(&vmspace->vm_map, 21752c24af7SPeter Wemm object, 21852c24af7SPeter Wemm file_addr, /* file offset */ 21952c24af7SPeter Wemm map_addr, /* virtual start */ 22052c24af7SPeter Wemm map_addr + map_len,/* virtual end */ 22152c24af7SPeter Wemm prot, 22252c24af7SPeter Wemm VM_PROT_ALL, 223e972780aSAlan Cox MAP_COPY_ON_WRITE | MAP_PREFAULT); 22452c24af7SPeter Wemm vm_map_unlock(&vmspace->vm_map); 22552c24af7SPeter Wemm if (rv != KERN_SUCCESS) 22652c24af7SPeter Wemm return EINVAL; 22752c24af7SPeter Wemm 22852c24af7SPeter Wemm /* we can stop now if we've covered it all */ 22952c24af7SPeter Wemm if (memsz == filsz) 23052c24af7SPeter Wemm return 0; 23152c24af7SPeter Wemm } 23252c24af7SPeter Wemm 23352c24af7SPeter Wemm 23452c24af7SPeter Wemm /* 23552c24af7SPeter Wemm * We have to get the remaining bit of the file into the first part 23652c24af7SPeter Wemm * of the oversized map segment. This is normally because the .data 23752c24af7SPeter Wemm * segment in the file is extended to provide bss. It's a neat idea 23852c24af7SPeter Wemm * to try and save a page, but it's a pain in the behind to implement. 239e1743d02SSøren Schmidt */ 240e1743d02SSøren Schmidt copy_len = (offset + filsz) - trunc_page(offset + filsz); 2416cde7a16SDavid Greenman map_addr = trunc_page((vm_offset_t)vmaddr + filsz); 2426cde7a16SDavid Greenman map_len = round_page((vm_offset_t)vmaddr + memsz) - map_addr; 243e1743d02SSøren Schmidt 24452c24af7SPeter Wemm /* This had damn well better be true! */ 2458191d577SPeter Wemm if (map_len != 0) { 24652c24af7SPeter Wemm vm_map_lock(&vmspace->vm_map); 24752c24af7SPeter Wemm rv = vm_map_insert(&vmspace->vm_map, NULL, 0, 24852c24af7SPeter Wemm map_addr, map_addr + map_len, 24952c24af7SPeter Wemm VM_PROT_ALL, VM_PROT_ALL, 0); 25052c24af7SPeter Wemm vm_map_unlock(&vmspace->vm_map); 25152c24af7SPeter Wemm if (rv != KERN_SUCCESS) 25252c24af7SPeter Wemm return EINVAL; 2538191d577SPeter Wemm } 254e1743d02SSøren Schmidt 25552c24af7SPeter Wemm if (copy_len != 0) { 25652c24af7SPeter Wemm vm_object_reference(object); 25752c24af7SPeter Wemm rv = vm_map_find(exec_map, 25852c24af7SPeter Wemm object, 25952c24af7SPeter Wemm trunc_page(offset + filsz), 26052c24af7SPeter Wemm &data_buf, 261e1743d02SSøren Schmidt PAGE_SIZE, 26252c24af7SPeter Wemm TRUE, 263e1743d02SSøren Schmidt VM_PROT_READ, 26452c24af7SPeter Wemm VM_PROT_ALL, 265e972780aSAlan Cox MAP_COPY_ON_WRITE | MAP_PREFAULT_PARTIAL); 26652c24af7SPeter Wemm if (rv != KERN_SUCCESS) { 26752c24af7SPeter Wemm vm_object_deallocate(object); 26852c24af7SPeter Wemm return EINVAL; 26952c24af7SPeter Wemm } 270e1743d02SSøren Schmidt 27152c24af7SPeter Wemm /* send the page fragment to user space */ 27252c24af7SPeter Wemm error = copyout((caddr_t)data_buf, (caddr_t)map_addr, copy_len); 27352c24af7SPeter Wemm vm_map_remove(exec_map, data_buf, data_buf + PAGE_SIZE); 27452c24af7SPeter Wemm if (error) 27552c24af7SPeter Wemm return (error); 27652c24af7SPeter Wemm } 277e1743d02SSøren Schmidt 278e1743d02SSøren Schmidt /* 2798191d577SPeter Wemm * set it to the specified protection 280e1743d02SSøren Schmidt */ 2818191d577SPeter Wemm vm_map_protect(&vmspace->vm_map, map_addr, map_addr + map_len, prot, 2828191d577SPeter Wemm FALSE); 2838191d577SPeter Wemm 284e1743d02SSøren Schmidt return error; 285e1743d02SSøren Schmidt } 286e1743d02SSøren Schmidt 287c33fe779SJohn Polstra /* 288c33fe779SJohn Polstra * Load the file "file" into memory. It may be either a shared object 289c33fe779SJohn Polstra * or an executable. 290c33fe779SJohn Polstra * 291c33fe779SJohn Polstra * The "addr" reference parameter is in/out. On entry, it specifies 292c33fe779SJohn Polstra * the address where a shared object should be loaded. If the file is 293c33fe779SJohn Polstra * an executable, this value is ignored. On exit, "addr" specifies 294c33fe779SJohn Polstra * where the file was actually loaded. 295c33fe779SJohn Polstra * 296c33fe779SJohn Polstra * The "entry" reference parameter is out only. On exit, it specifies 297c33fe779SJohn Polstra * the entry point for the loaded file. 298c33fe779SJohn Polstra */ 299e1743d02SSøren Schmidt static int 300bdbc8c26SPeter Wemm elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry) 301e1743d02SSøren Schmidt { 302d254af07SMatthew Dillon const Elf_Ehdr *hdr = NULL; 303d254af07SMatthew Dillon const Elf_Phdr *phdr = NULL; 304e1743d02SSøren Schmidt struct nameidata nd; 305e1743d02SSøren Schmidt struct vmspace *vmspace = p->p_vmspace; 306c8a79999SPeter Wemm struct vattr attr; 307c8a79999SPeter Wemm struct image_params image_params, *imgp; 30852c24af7SPeter Wemm vm_prot_t prot; 309c33fe779SJohn Polstra u_long rbase; 310c33fe779SJohn Polstra u_long base_addr = 0; 311c33fe779SJohn Polstra int error, i, numsegs; 312e1743d02SSøren Schmidt 313c8a79999SPeter Wemm imgp = &image_params; 314c8a79999SPeter Wemm /* 315c8a79999SPeter Wemm * Initialize part of the common data 316c8a79999SPeter Wemm */ 317c8a79999SPeter Wemm imgp->proc = p; 318c8a79999SPeter Wemm imgp->uap = NULL; 319c8a79999SPeter Wemm imgp->attr = &attr; 320c8a79999SPeter Wemm imgp->firstpage = NULL; 321c8a79999SPeter Wemm imgp->image_header = (char *)kmem_alloc_wait(exec_map, PAGE_SIZE); 322c8a79999SPeter Wemm 323c8a79999SPeter Wemm if (imgp->image_header == NULL) { 324c8a79999SPeter Wemm nd.ni_vp = NULL; 325c8a79999SPeter Wemm error = ENOMEM; 326c8a79999SPeter Wemm goto fail; 327c8a79999SPeter Wemm } 328c8a79999SPeter Wemm 329e1743d02SSøren Schmidt NDINIT(&nd, LOOKUP, LOCKLEAF|FOLLOW, UIO_SYSSPACE, file, p); 330e1743d02SSøren Schmidt 331d254af07SMatthew Dillon if ((error = namei(&nd)) != 0) { 3321560a9d5SPeter Wemm nd.ni_vp = NULL; 333e1743d02SSøren Schmidt goto fail; 334e1743d02SSøren Schmidt } 335e1743d02SSøren Schmidt 336c8a79999SPeter Wemm imgp->vp = nd.ni_vp; 337c8a79999SPeter Wemm 338e1743d02SSøren Schmidt /* 339e1743d02SSøren Schmidt * Check permissions, modes, uid, etc on the file, and "open" it. 340e1743d02SSøren Schmidt */ 341c8a79999SPeter Wemm error = exec_check_permissions(imgp); 342c8a79999SPeter Wemm if (error) { 343996c772fSJohn Dyson VOP_UNLOCK(nd.ni_vp, 0, p); 344c8a79999SPeter Wemm goto fail; 345c8a79999SPeter Wemm } 346e1743d02SSøren Schmidt 347c8a79999SPeter Wemm error = exec_map_first_page(imgp); 348c8a79999SPeter Wemm VOP_UNLOCK(nd.ni_vp, 0, p); 349e1743d02SSøren Schmidt if (error) 350e1743d02SSøren Schmidt goto fail; 351e1743d02SSøren Schmidt 352d254af07SMatthew Dillon hdr = (const Elf_Ehdr *)imgp->image_header; 353c33fe779SJohn Polstra if ((error = elf_check_header(hdr)) != 0) 354e1743d02SSøren Schmidt goto fail; 355c33fe779SJohn Polstra if (hdr->e_type == ET_DYN) 356c33fe779SJohn Polstra rbase = *addr; 357c33fe779SJohn Polstra else if (hdr->e_type == ET_EXEC) 358c33fe779SJohn Polstra rbase = 0; 359c33fe779SJohn Polstra else { 360c33fe779SJohn Polstra error = ENOEXEC; 361c33fe779SJohn Polstra goto fail; 362c33fe779SJohn Polstra } 363e1743d02SSøren Schmidt 364c8a79999SPeter Wemm /* Only support headers that fit within first page for now */ 36552c24af7SPeter Wemm if ((hdr->e_phoff > PAGE_SIZE) || 36652c24af7SPeter Wemm (hdr->e_phoff + hdr->e_phentsize * hdr->e_phnum) > PAGE_SIZE) { 367c8a79999SPeter Wemm error = ENOEXEC; 368e1743d02SSøren Schmidt goto fail; 369c8a79999SPeter Wemm } 370c8a79999SPeter Wemm 371d254af07SMatthew Dillon phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff); 372e1743d02SSøren Schmidt 373c33fe779SJohn Polstra for (i = 0, numsegs = 0; i < hdr->e_phnum; i++) { 37452c24af7SPeter Wemm if (phdr[i].p_type == PT_LOAD) { /* Loadable segment */ 37552c24af7SPeter Wemm prot = 0; 376e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_X) 377e1743d02SSøren Schmidt prot |= VM_PROT_EXECUTE; 378e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_W) 379e1743d02SSøren Schmidt prot |= VM_PROT_WRITE; 380e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_R) 381e1743d02SSøren Schmidt prot |= VM_PROT_READ; 382e1743d02SSøren Schmidt 383d254af07SMatthew Dillon if ((error = elf_load_section(p, vmspace, nd.ni_vp, 384e1743d02SSøren Schmidt phdr[i].p_offset, 385e1743d02SSøren Schmidt (caddr_t)phdr[i].p_vaddr + 386c33fe779SJohn Polstra rbase, 387e1743d02SSøren Schmidt phdr[i].p_memsz, 388d254af07SMatthew Dillon phdr[i].p_filesz, prot)) != 0) 389e1743d02SSøren Schmidt goto fail; 390e1743d02SSøren Schmidt /* 391c33fe779SJohn Polstra * Establish the base address if this is the 392c33fe779SJohn Polstra * first segment. 393e1743d02SSøren Schmidt */ 394c33fe779SJohn Polstra if (numsegs == 0) 395c33fe779SJohn Polstra base_addr = trunc_page(phdr[i].p_vaddr + rbase); 396c33fe779SJohn Polstra numsegs++; 397e1743d02SSøren Schmidt } 398e1743d02SSøren Schmidt } 399c33fe779SJohn Polstra *addr = base_addr; 400c33fe779SJohn Polstra *entry=(unsigned long)hdr->e_entry + rbase; 401e1743d02SSøren Schmidt 402e1743d02SSøren Schmidt fail: 403c8a79999SPeter Wemm if (imgp->firstpage) 404c8a79999SPeter Wemm exec_unmap_first_page(imgp); 405c8a79999SPeter Wemm if (imgp->image_header) 406c8a79999SPeter Wemm kmem_free_wakeup(exec_map, (vm_offset_t)imgp->image_header, 407c8a79999SPeter Wemm PAGE_SIZE); 4081560a9d5SPeter Wemm if (nd.ni_vp) 4091560a9d5SPeter Wemm vrele(nd.ni_vp); 410e1743d02SSøren Schmidt 411e1743d02SSøren Schmidt return error; 412e1743d02SSøren Schmidt } 413e1743d02SSøren Schmidt 414f8b3601eSMark Newton static char fallback_elf_brand[MAXBRANDLEN+1] = { "none" }; 415f8b3601eSMark Newton SYSCTL_STRING(_kern, OID_AUTO, fallback_elf_brand, CTLFLAG_RW, 416f8b3601eSMark Newton fallback_elf_brand, sizeof(fallback_elf_brand), 417f8b3601eSMark Newton "ELF brand of last resort"); 418f8b3601eSMark Newton 419303b270bSEivind Eklund static int 420e1743d02SSøren Schmidt exec_elf_imgact(struct image_params *imgp) 421e1743d02SSøren Schmidt { 422ecbb00a2SDoug Rabson const Elf_Ehdr *hdr = (const Elf_Ehdr *) imgp->image_header; 423f5ef029eSPoul-Henning Kamp const Elf_Phdr *phdr; 424ecbb00a2SDoug Rabson Elf_Auxargs *elf_auxargs = NULL; 4255856e12eSJohn Dyson struct vmspace *vmspace; 42652c24af7SPeter Wemm vm_prot_t prot; 427e1743d02SSøren Schmidt u_long text_size = 0, data_size = 0; 428e1743d02SSøren Schmidt u_long text_addr = 0, data_addr = 0; 429e1743d02SSøren Schmidt u_long addr, entry = 0, proghdr = 0; 43052c24af7SPeter Wemm int error, i; 431c8a79999SPeter Wemm const char *interp = NULL; 432d1dbc694SJohn Polstra Elf_Brandinfo *brand_info; 433d254af07SMatthew Dillon const char *brand; 434ea5a2b2eSSøren Schmidt char path[MAXPATHLEN]; 435e1743d02SSøren Schmidt 436e1743d02SSøren Schmidt /* 437e1743d02SSøren Schmidt * Do we have a valid ELF header ? 438e1743d02SSøren Schmidt */ 439c33fe779SJohn Polstra if (elf_check_header(hdr) != 0 || hdr->e_type != ET_EXEC) 440e1743d02SSøren Schmidt return -1; 441e1743d02SSøren Schmidt 442e1743d02SSøren Schmidt /* 443e1743d02SSøren Schmidt * From here on down, we return an errno, not -1, as we've 444e1743d02SSøren Schmidt * detected an ELF file. 445e1743d02SSøren Schmidt */ 446e1743d02SSøren Schmidt 447e1743d02SSøren Schmidt if ((hdr->e_phoff > PAGE_SIZE) || 44852c24af7SPeter Wemm (hdr->e_phoff + hdr->e_phentsize * hdr->e_phnum) > PAGE_SIZE) { 449c8a79999SPeter Wemm /* Only support headers in first page for now */ 450c8a79999SPeter Wemm return ENOEXEC; 451e1743d02SSøren Schmidt } 45252c24af7SPeter Wemm phdr = (const Elf_Phdr*)(imgp->image_header + hdr->e_phoff); 453e1743d02SSøren Schmidt 454e1743d02SSøren Schmidt /* 455e1743d02SSøren Schmidt * From this point on, we may have resources that need to be freed. 456e1743d02SSøren Schmidt */ 457d254af07SMatthew Dillon if ((error = exec_extract_strings(imgp)) != 0) 458e1743d02SSøren Schmidt goto fail; 459e1743d02SSøren Schmidt 460e1743d02SSøren Schmidt exec_new_vmspace(imgp); 461e1743d02SSøren Schmidt 4625856e12eSJohn Dyson vmspace = imgp->proc->p_vmspace; 4635856e12eSJohn Dyson 464e1743d02SSøren Schmidt for (i = 0; i < hdr->e_phnum; i++) { 465e1743d02SSøren Schmidt switch(phdr[i].p_type) { 466e1743d02SSøren Schmidt 467e1743d02SSøren Schmidt case PT_LOAD: /* Loadable segment */ 46852c24af7SPeter Wemm prot = 0; 469e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_X) 470e1743d02SSøren Schmidt prot |= VM_PROT_EXECUTE; 471e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_W) 472e1743d02SSøren Schmidt prot |= VM_PROT_WRITE; 473e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_R) 474e1743d02SSøren Schmidt prot |= VM_PROT_READ; 475e1743d02SSøren Schmidt 476d254af07SMatthew Dillon if ((error = elf_load_section(imgp->proc, 47752c24af7SPeter Wemm vmspace, imgp->vp, 478e1743d02SSøren Schmidt phdr[i].p_offset, 479e1743d02SSøren Schmidt (caddr_t)phdr[i].p_vaddr, 480e1743d02SSøren Schmidt phdr[i].p_memsz, 481d254af07SMatthew Dillon phdr[i].p_filesz, prot)) != 0) 482e1743d02SSøren Schmidt goto fail; 483e1743d02SSøren Schmidt 484e1743d02SSøren Schmidt /* 485e1743d02SSøren Schmidt * Is this .text or .data ?? 486e1743d02SSøren Schmidt * 487e1743d02SSøren Schmidt * We only handle one each of those yet XXX 488e1743d02SSøren Schmidt */ 489e1743d02SSøren Schmidt if (hdr->e_entry >= phdr[i].p_vaddr && 490e1743d02SSøren Schmidt hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) { 491e1743d02SSøren Schmidt text_addr = trunc_page(phdr[i].p_vaddr); 4928191d577SPeter Wemm text_size = round_page(phdr[i].p_memsz + 4938191d577SPeter Wemm phdr[i].p_vaddr - 4948191d577SPeter Wemm text_addr); 495e1743d02SSøren Schmidt entry = (u_long)hdr->e_entry; 496e1743d02SSøren Schmidt } else { 497e1743d02SSøren Schmidt data_addr = trunc_page(phdr[i].p_vaddr); 4988191d577SPeter Wemm data_size = round_page(phdr[i].p_memsz + 4998191d577SPeter Wemm phdr[i].p_vaddr - 5008191d577SPeter Wemm data_addr); 501e1743d02SSøren Schmidt } 502e1743d02SSøren Schmidt break; 503e1743d02SSøren Schmidt case PT_INTERP: /* Path to interpreter */ 504c8a79999SPeter Wemm if (phdr[i].p_filesz > MAXPATHLEN || 505c8a79999SPeter Wemm phdr[i].p_offset + phdr[i].p_filesz > PAGE_SIZE) { 506e1743d02SSøren Schmidt error = ENOEXEC; 507e1743d02SSøren Schmidt goto fail; 508e1743d02SSøren Schmidt } 509c8a79999SPeter Wemm interp = imgp->image_header + phdr[i].p_offset; 510e1743d02SSøren Schmidt break; 511e1743d02SSøren Schmidt case PT_PHDR: /* Program header table info */ 512e1743d02SSøren Schmidt proghdr = phdr[i].p_vaddr; 513e1743d02SSøren Schmidt break; 514e1743d02SSøren Schmidt default: 51552c24af7SPeter Wemm break; 516e1743d02SSøren Schmidt } 517e1743d02SSøren Schmidt } 518e1743d02SSøren Schmidt 519e1743d02SSøren Schmidt vmspace->vm_tsize = text_size >> PAGE_SHIFT; 5207cd99438SBruce Evans vmspace->vm_taddr = (caddr_t)(uintptr_t)text_addr; 521e1743d02SSøren Schmidt vmspace->vm_dsize = data_size >> PAGE_SHIFT; 5227cd99438SBruce Evans vmspace->vm_daddr = (caddr_t)(uintptr_t)data_addr; 523e1743d02SSøren Schmidt 52447633640SJohn Polstra addr = ELF_RTLD_ADDR(vmspace); 525e1743d02SSøren Schmidt 526ea5a2b2eSSøren Schmidt imgp->entry_addr = entry; 527ea5a2b2eSSøren Schmidt 528d1dbc694SJohn Polstra /* If the executable has a brand, search for it in the brand list. */ 529d1dbc694SJohn Polstra brand_info = NULL; 530d254af07SMatthew Dillon brand = (const char *)&hdr->e_ident[EI_BRAND]; 531d1dbc694SJohn Polstra if (brand[0] != '\0') { 532ea5a2b2eSSøren Schmidt for (i = 0; i < MAX_BRANDS; i++) { 533d1dbc694SJohn Polstra Elf_Brandinfo *bi = elf_brand_list[i]; 534d1dbc694SJohn Polstra 535d1dbc694SJohn Polstra if (bi != NULL && strcmp(brand, bi->brand) == 0) { 536d1dbc694SJohn Polstra brand_info = bi; 537e1743d02SSøren Schmidt break; 538e1743d02SSøren Schmidt } 539e1743d02SSøren Schmidt } 540e1743d02SSøren Schmidt } 541ea5a2b2eSSøren Schmidt 542d1dbc694SJohn Polstra /* Lacking a known brand, search for a recognized interpreter. */ 543d1dbc694SJohn Polstra if (brand_info == NULL && interp != NULL) { 544ea5a2b2eSSøren Schmidt for (i = 0; i < MAX_BRANDS; i++) { 545d1dbc694SJohn Polstra Elf_Brandinfo *bi = elf_brand_list[i]; 546d1dbc694SJohn Polstra 547d1dbc694SJohn Polstra if (bi != NULL && 548d1dbc694SJohn Polstra strcmp(interp, bi->interp_path) == 0) { 549d1dbc694SJohn Polstra brand_info = bi; 550d672246bSSøren Schmidt break; 551ea5a2b2eSSøren Schmidt } 552ea5a2b2eSSøren Schmidt } 553ea5a2b2eSSøren Schmidt } 554d1dbc694SJohn Polstra 555f8b3601eSMark Newton /* Lacking a recognized interpreter, try the default brand */ 5566f8126faSJohn Polstra if (brand_info == NULL && fallback_elf_brand[0] != '\0') { 557f8b3601eSMark Newton for (i = 0; i < MAX_BRANDS; i++) { 558f8b3601eSMark Newton Elf_Brandinfo *bi = elf_brand_list[i]; 559f8b3601eSMark Newton 560f8b3601eSMark Newton if (bi != NULL 561f8b3601eSMark Newton && strcmp(fallback_elf_brand, bi->brand) == 0) { 562f8b3601eSMark Newton brand_info = bi; 563f8b3601eSMark Newton break; 564f8b3601eSMark Newton } 565f8b3601eSMark Newton } 566f8b3601eSMark Newton } 567f8b3601eSMark Newton 568d1dbc694SJohn Polstra #ifdef __alpha__ 569d1dbc694SJohn Polstra /* XXX - Assume FreeBSD on the alpha. */ 570d1dbc694SJohn Polstra if (brand_info == NULL) 571d1dbc694SJohn Polstra brand_info = &freebsd_brand_info; 572d1dbc694SJohn Polstra #endif 573d1dbc694SJohn Polstra 574d1dbc694SJohn Polstra if (brand_info == NULL) { 575d1dbc694SJohn Polstra if (brand[0] == 0) 576d1dbc694SJohn Polstra uprintf("ELF binary type not known." 577d1dbc694SJohn Polstra " Use \"brandelf\" to brand it.\n"); 578d1dbc694SJohn Polstra else 579d1dbc694SJohn Polstra uprintf("ELF binary type \"%.*s\" not known.\n", 580d1dbc694SJohn Polstra EI_NIDENT - EI_BRAND, brand); 581e1743d02SSøren Schmidt error = ENOEXEC; 582e1743d02SSøren Schmidt goto fail; 583d1dbc694SJohn Polstra } 584d1dbc694SJohn Polstra 585d1dbc694SJohn Polstra imgp->proc->p_sysent = brand_info->sysvec; 586d1dbc694SJohn Polstra if (interp != NULL) { 5872127f260SArchie Cobbs snprintf(path, sizeof(path), "%s%s", 5882127f260SArchie Cobbs brand_info->emul_path, interp); 589d1dbc694SJohn Polstra if ((error = elf_load_file(imgp->proc, path, &addr, 590d1dbc694SJohn Polstra &imgp->entry_addr)) != 0) { 591bdbc8c26SPeter Wemm if ((error = elf_load_file(imgp->proc, interp, &addr, 5927a583b02SMarcel Moolenaar &imgp->entry_addr)) != 0) { 593bdbc8c26SPeter Wemm uprintf("ELF interpreter %s not found\n", path); 594e1743d02SSøren Schmidt goto fail; 595e1743d02SSøren Schmidt } 596e1743d02SSøren Schmidt } 5977a583b02SMarcel Moolenaar } 598ea5a2b2eSSøren Schmidt 599e1743d02SSøren Schmidt /* 600e1743d02SSøren Schmidt * Construct auxargs table (used by the fixup routine) 601e1743d02SSøren Schmidt */ 602ecbb00a2SDoug Rabson elf_auxargs = malloc(sizeof(Elf_Auxargs), M_TEMP, M_WAITOK); 603e1743d02SSøren Schmidt elf_auxargs->execfd = -1; 604e1743d02SSøren Schmidt elf_auxargs->phdr = proghdr; 605e1743d02SSøren Schmidt elf_auxargs->phent = hdr->e_phentsize; 606e1743d02SSøren Schmidt elf_auxargs->phnum = hdr->e_phnum; 607e1743d02SSøren Schmidt elf_auxargs->pagesz = PAGE_SIZE; 608e1743d02SSøren Schmidt elf_auxargs->base = addr; 609e1743d02SSøren Schmidt elf_auxargs->flags = 0; 610e1743d02SSøren Schmidt elf_auxargs->entry = entry; 611e1743d02SSøren Schmidt elf_auxargs->trace = elf_trace; 612e1743d02SSøren Schmidt 613e1743d02SSøren Schmidt imgp->auxargs = elf_auxargs; 614e1743d02SSøren Schmidt imgp->interpreted = 0; 615e1743d02SSøren Schmidt 616e1743d02SSøren Schmidt /* don't allow modifying the file while we run it */ 617e1743d02SSøren Schmidt imgp->vp->v_flag |= VTEXT; 618e1743d02SSøren Schmidt 619e1743d02SSøren Schmidt fail: 620e1743d02SSøren Schmidt return error; 621e1743d02SSøren Schmidt } 622e1743d02SSøren Schmidt 623e1743d02SSøren Schmidt static int 624ecbb00a2SDoug Rabson elf_freebsd_fixup(long **stack_base, struct image_params *imgp) 625e1743d02SSøren Schmidt { 626ecbb00a2SDoug Rabson Elf_Auxargs *args = (Elf_Auxargs *)imgp->auxargs; 627ecbb00a2SDoug Rabson long *pos; 628e1743d02SSøren Schmidt 629e1743d02SSøren Schmidt pos = *stack_base + (imgp->argc + imgp->envc + 2); 630e1743d02SSøren Schmidt 631e1743d02SSøren Schmidt if (args->trace) { 632e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_DEBUG, 1); 633e1743d02SSøren Schmidt } 634e1743d02SSøren Schmidt if (args->execfd != -1) { 635e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); 636e1743d02SSøren Schmidt } 637e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); 638e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHENT, args->phent); 639e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); 640e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); 641e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); 642e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); 643e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_BASE, args->base); 644e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_NULL, 0); 645e1743d02SSøren Schmidt 646e1743d02SSøren Schmidt free(imgp->auxargs, M_TEMP); 647e1743d02SSøren Schmidt imgp->auxargs = NULL; 648e1743d02SSøren Schmidt 649e1743d02SSøren Schmidt (*stack_base)--; 650216a0f2dSDoug Rabson suword(*stack_base, (long) imgp->argc); 651e1743d02SSøren Schmidt return 0; 652e1743d02SSøren Schmidt } 653e1743d02SSøren Schmidt 654e1743d02SSøren Schmidt /* 6558c64af4fSJohn Polstra * Code for generating ELF core dumps. 6568c64af4fSJohn Polstra */ 6578c64af4fSJohn Polstra 6580ff27d31SJohn Polstra typedef void (*segment_callback) __P((vm_map_entry_t, void *)); 6590ff27d31SJohn Polstra 6600ff27d31SJohn Polstra /* Closure for cb_put_phdr(). */ 6610ff27d31SJohn Polstra struct phdr_closure { 6620ff27d31SJohn Polstra Elf_Phdr *phdr; /* Program header to fill in */ 6630ff27d31SJohn Polstra Elf_Off offset; /* Offset of segment in core file */ 6640ff27d31SJohn Polstra }; 6650ff27d31SJohn Polstra 6660ff27d31SJohn Polstra /* Closure for cb_size_segment(). */ 6670ff27d31SJohn Polstra struct sseg_closure { 6680ff27d31SJohn Polstra int count; /* Count of writable segments. */ 6690ff27d31SJohn Polstra size_t size; /* Total size of all writable segments. */ 6700ff27d31SJohn Polstra }; 6710ff27d31SJohn Polstra 6720ff27d31SJohn Polstra static void cb_put_phdr __P((vm_map_entry_t, void *)); 6730ff27d31SJohn Polstra static void cb_size_segment __P((vm_map_entry_t, void *)); 6740ff27d31SJohn Polstra static void each_writable_segment __P((struct proc *, segment_callback, 6750ff27d31SJohn Polstra void *)); 6760ff27d31SJohn Polstra static int elf_corehdr __P((struct proc *, struct vnode *, struct ucred *, 6770ff27d31SJohn Polstra int, void *, size_t)); 6780ff27d31SJohn Polstra static void elf_puthdr __P((struct proc *, void *, size_t *, 6790ff27d31SJohn Polstra const prstatus_t *, const prfpregset_t *, const prpsinfo_t *, int)); 6800ff27d31SJohn Polstra static void elf_putnote __P((void *, size_t *, const char *, int, 6810ff27d31SJohn Polstra const void *, size_t)); 6828c64af4fSJohn Polstra 6838c64af4fSJohn Polstra extern int osreldate; 6848c64af4fSJohn Polstra 6858c64af4fSJohn Polstra int 686fca666a1SJulian Elischer elf_coredump(p, vp, limit) 6878c64af4fSJohn Polstra register struct proc *p; 6888c64af4fSJohn Polstra register struct vnode *vp; 689fca666a1SJulian Elischer off_t limit; 690fca666a1SJulian Elischer { 6918c64af4fSJohn Polstra register struct ucred *cred = p->p_cred->pc_ucred; 692fca666a1SJulian Elischer int error = 0; 6930ff27d31SJohn Polstra struct sseg_closure seginfo; 6940ff27d31SJohn Polstra void *hdr; 6958c64af4fSJohn Polstra size_t hdrsize; 6968c64af4fSJohn Polstra 6970ff27d31SJohn Polstra /* Size the program segments. */ 6980ff27d31SJohn Polstra seginfo.count = 0; 6990ff27d31SJohn Polstra seginfo.size = 0; 7000ff27d31SJohn Polstra each_writable_segment(p, cb_size_segment, &seginfo); 7010ff27d31SJohn Polstra 7020ff27d31SJohn Polstra /* 7030ff27d31SJohn Polstra * Calculate the size of the core file header area by making 7040ff27d31SJohn Polstra * a dry run of generating it. Nothing is written, but the 7050ff27d31SJohn Polstra * size is calculated. 7060ff27d31SJohn Polstra */ 7070ff27d31SJohn Polstra hdrsize = 0; 7080ff27d31SJohn Polstra elf_puthdr((struct proc *)NULL, (void *)NULL, &hdrsize, 7090ff27d31SJohn Polstra (const prstatus_t *)NULL, (const prfpregset_t *)NULL, 7100ff27d31SJohn Polstra (const prpsinfo_t *)NULL, seginfo.count); 7110ff27d31SJohn Polstra 712fca666a1SJulian Elischer if (hdrsize + seginfo.size >= limit) 7138c64af4fSJohn Polstra return (EFAULT); 7140ff27d31SJohn Polstra 7150ff27d31SJohn Polstra /* 7160ff27d31SJohn Polstra * Allocate memory for building the header, fill it up, 7170ff27d31SJohn Polstra * and write it out. 7180ff27d31SJohn Polstra */ 7190ff27d31SJohn Polstra hdr = malloc(hdrsize, M_TEMP, M_WAITOK); 7200ff27d31SJohn Polstra if (hdr == NULL) { 721fca666a1SJulian Elischer return EINVAL; 7220ff27d31SJohn Polstra } 7230ff27d31SJohn Polstra error = elf_corehdr(p, vp, cred, seginfo.count, hdr, hdrsize); 7240ff27d31SJohn Polstra 7250ff27d31SJohn Polstra /* Write the contents of all of the writable segments. */ 7260ff27d31SJohn Polstra if (error == 0) { 7270ff27d31SJohn Polstra Elf_Phdr *php; 7280ff27d31SJohn Polstra off_t offset; 7290ff27d31SJohn Polstra int i; 7300ff27d31SJohn Polstra 7310ff27d31SJohn Polstra php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1; 7320ff27d31SJohn Polstra offset = hdrsize; 7330ff27d31SJohn Polstra for (i = 0; i < seginfo.count; i++) { 7340ff27d31SJohn Polstra error = vn_rdwr(UIO_WRITE, vp, (caddr_t)php->p_vaddr, 7350ff27d31SJohn Polstra php->p_filesz, offset, UIO_USERSPACE, 736dada0278SJohn Polstra IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, p); 7370ff27d31SJohn Polstra if (error != 0) 7380ff27d31SJohn Polstra break; 7390ff27d31SJohn Polstra offset += php->p_filesz; 7400ff27d31SJohn Polstra php++; 7410ff27d31SJohn Polstra } 7420ff27d31SJohn Polstra } 7430ff27d31SJohn Polstra free(hdr, M_TEMP); 7440ff27d31SJohn Polstra 745fca666a1SJulian Elischer return error; 7468c64af4fSJohn Polstra } 7478c64af4fSJohn Polstra 7480ff27d31SJohn Polstra /* 7490ff27d31SJohn Polstra * A callback for each_writable_segment() to write out the segment's 7500ff27d31SJohn Polstra * program header entry. 7510ff27d31SJohn Polstra */ 7520ff27d31SJohn Polstra static void 7530ff27d31SJohn Polstra cb_put_phdr(entry, closure) 7540ff27d31SJohn Polstra vm_map_entry_t entry; 7550ff27d31SJohn Polstra void *closure; 7560ff27d31SJohn Polstra { 7570ff27d31SJohn Polstra struct phdr_closure *phc = (struct phdr_closure *)closure; 7580ff27d31SJohn Polstra Elf_Phdr *phdr = phc->phdr; 7590ff27d31SJohn Polstra 7600ff27d31SJohn Polstra phc->offset = round_page(phc->offset); 7610ff27d31SJohn Polstra 7620ff27d31SJohn Polstra phdr->p_type = PT_LOAD; 7630ff27d31SJohn Polstra phdr->p_offset = phc->offset; 7640ff27d31SJohn Polstra phdr->p_vaddr = entry->start; 7650ff27d31SJohn Polstra phdr->p_paddr = 0; 7660ff27d31SJohn Polstra phdr->p_filesz = phdr->p_memsz = entry->end - entry->start; 7670ff27d31SJohn Polstra phdr->p_align = PAGE_SIZE; 7680ff27d31SJohn Polstra phdr->p_flags = 0; 7690ff27d31SJohn Polstra if (entry->protection & VM_PROT_READ) 7700ff27d31SJohn Polstra phdr->p_flags |= PF_R; 7710ff27d31SJohn Polstra if (entry->protection & VM_PROT_WRITE) 7720ff27d31SJohn Polstra phdr->p_flags |= PF_W; 7730ff27d31SJohn Polstra if (entry->protection & VM_PROT_EXECUTE) 7740ff27d31SJohn Polstra phdr->p_flags |= PF_X; 7750ff27d31SJohn Polstra 7760ff27d31SJohn Polstra phc->offset += phdr->p_filesz; 7770ff27d31SJohn Polstra phc->phdr++; 7780ff27d31SJohn Polstra } 7790ff27d31SJohn Polstra 7800ff27d31SJohn Polstra /* 7810ff27d31SJohn Polstra * A callback for each_writable_segment() to gather information about 7820ff27d31SJohn Polstra * the number of segments and their total size. 7830ff27d31SJohn Polstra */ 7840ff27d31SJohn Polstra static void 7850ff27d31SJohn Polstra cb_size_segment(entry, closure) 7860ff27d31SJohn Polstra vm_map_entry_t entry; 7870ff27d31SJohn Polstra void *closure; 7880ff27d31SJohn Polstra { 7890ff27d31SJohn Polstra struct sseg_closure *ssc = (struct sseg_closure *)closure; 7900ff27d31SJohn Polstra 7910ff27d31SJohn Polstra ssc->count++; 7920ff27d31SJohn Polstra ssc->size += entry->end - entry->start; 7930ff27d31SJohn Polstra } 7940ff27d31SJohn Polstra 7950ff27d31SJohn Polstra /* 7960ff27d31SJohn Polstra * For each writable segment in the process's memory map, call the given 7970ff27d31SJohn Polstra * function with a pointer to the map entry and some arbitrary 7980ff27d31SJohn Polstra * caller-supplied data. 7990ff27d31SJohn Polstra */ 8000ff27d31SJohn Polstra static void 8010ff27d31SJohn Polstra each_writable_segment(p, func, closure) 8020ff27d31SJohn Polstra struct proc *p; 8030ff27d31SJohn Polstra segment_callback func; 8040ff27d31SJohn Polstra void *closure; 8050ff27d31SJohn Polstra { 8060ff27d31SJohn Polstra vm_map_t map = &p->p_vmspace->vm_map; 8070ff27d31SJohn Polstra vm_map_entry_t entry; 8080ff27d31SJohn Polstra 8090ff27d31SJohn Polstra for (entry = map->header.next; entry != &map->header; 8100ff27d31SJohn Polstra entry = entry->next) { 8110ff27d31SJohn Polstra vm_object_t obj; 8120ff27d31SJohn Polstra 8139fdfe602SMatthew Dillon if ((entry->eflags & MAP_ENTRY_IS_SUB_MAP) || 8140ff27d31SJohn Polstra (entry->protection & (VM_PROT_READ|VM_PROT_WRITE)) != 8150ff27d31SJohn Polstra (VM_PROT_READ|VM_PROT_WRITE)) 8160ff27d31SJohn Polstra continue; 8170ff27d31SJohn Polstra 8180ff27d31SJohn Polstra if ((obj = entry->object.vm_object) == NULL) 8190ff27d31SJohn Polstra continue; 8200ff27d31SJohn Polstra 8210ff27d31SJohn Polstra /* Find the deepest backing object. */ 8220ff27d31SJohn Polstra while (obj->backing_object != NULL) 8230ff27d31SJohn Polstra obj = obj->backing_object; 8240ff27d31SJohn Polstra 8250ff27d31SJohn Polstra /* Ignore memory-mapped devices and such things. */ 8260ff27d31SJohn Polstra if (obj->type != OBJT_DEFAULT && 8270ff27d31SJohn Polstra obj->type != OBJT_SWAP && 8280ff27d31SJohn Polstra obj->type != OBJT_VNODE) 8290ff27d31SJohn Polstra continue; 8300ff27d31SJohn Polstra 8310ff27d31SJohn Polstra (*func)(entry, closure); 8320ff27d31SJohn Polstra } 8330ff27d31SJohn Polstra } 8340ff27d31SJohn Polstra 8350ff27d31SJohn Polstra /* 8360ff27d31SJohn Polstra * Write the core file header to the file, including padding up to 8370ff27d31SJohn Polstra * the page boundary. 8380ff27d31SJohn Polstra */ 8398c64af4fSJohn Polstra static int 8400ff27d31SJohn Polstra elf_corehdr(p, vp, cred, numsegs, hdr, hdrsize) 8418c64af4fSJohn Polstra struct proc *p; 8428c64af4fSJohn Polstra struct vnode *vp; 8438c64af4fSJohn Polstra struct ucred *cred; 8440ff27d31SJohn Polstra int numsegs; 8450ff27d31SJohn Polstra size_t hdrsize; 8460ff27d31SJohn Polstra void *hdr; 8478c64af4fSJohn Polstra { 8488c64af4fSJohn Polstra size_t off; 8498c64af4fSJohn Polstra prstatus_t status; 8508c64af4fSJohn Polstra prfpregset_t fpregset; 8518c64af4fSJohn Polstra prpsinfo_t psinfo; 8528c64af4fSJohn Polstra 8538c64af4fSJohn Polstra /* Gather the information for the header. */ 8548c64af4fSJohn Polstra bzero(&status, sizeof status); 8558c64af4fSJohn Polstra status.pr_version = PRSTATUS_VERSION; 8568c64af4fSJohn Polstra status.pr_statussz = sizeof(prstatus_t); 8578c64af4fSJohn Polstra status.pr_gregsetsz = sizeof(gregset_t); 8588c64af4fSJohn Polstra status.pr_fpregsetsz = sizeof(fpregset_t); 8598c64af4fSJohn Polstra status.pr_osreldate = osreldate; 8606626c604SJulian Elischer status.pr_cursig = p->p_sig; 8618c64af4fSJohn Polstra status.pr_pid = p->p_pid; 8628c64af4fSJohn Polstra fill_regs(p, &status.pr_reg); 8638c64af4fSJohn Polstra 8648c64af4fSJohn Polstra fill_fpregs(p, &fpregset); 8658c64af4fSJohn Polstra 8668c64af4fSJohn Polstra bzero(&psinfo, sizeof psinfo); 8678c64af4fSJohn Polstra psinfo.pr_version = PRPSINFO_VERSION; 8688c64af4fSJohn Polstra psinfo.pr_psinfosz = sizeof(prpsinfo_t); 8698c64af4fSJohn Polstra strncpy(psinfo.pr_fname, p->p_comm, MAXCOMLEN); 8700ff27d31SJohn Polstra /* XXX - We don't fill in the command line arguments properly yet. */ 8710ff27d31SJohn Polstra strncpy(psinfo.pr_psargs, p->p_comm, PRARGSZ); 8728c64af4fSJohn Polstra 8738c64af4fSJohn Polstra /* Fill in the header. */ 8740ff27d31SJohn Polstra bzero(hdr, hdrsize); 8758c64af4fSJohn Polstra off = 0; 8760ff27d31SJohn Polstra elf_puthdr(p, hdr, &off, &status, &fpregset, &psinfo, numsegs); 8778c64af4fSJohn Polstra 8788c64af4fSJohn Polstra /* Write it to the core file. */ 8790ff27d31SJohn Polstra return vn_rdwr(UIO_WRITE, vp, hdr, hdrsize, (off_t)0, 8808c64af4fSJohn Polstra UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, NULL, p); 881dada0278SJohn Polstra } 882dada0278SJohn Polstra 8838c64af4fSJohn Polstra static void 8840ff27d31SJohn Polstra elf_puthdr(struct proc *p, void *dst, size_t *off, const prstatus_t *status, 8850ff27d31SJohn Polstra const prfpregset_t *fpregset, const prpsinfo_t *psinfo, int numsegs) 8868c64af4fSJohn Polstra { 8878c64af4fSJohn Polstra size_t ehoff; 8888c64af4fSJohn Polstra size_t phoff; 8898c64af4fSJohn Polstra size_t noteoff; 8908c64af4fSJohn Polstra size_t notesz; 8918c64af4fSJohn Polstra 8928c64af4fSJohn Polstra ehoff = *off; 8938c64af4fSJohn Polstra *off += sizeof(Elf_Ehdr); 8948c64af4fSJohn Polstra 8958c64af4fSJohn Polstra phoff = *off; 8960ff27d31SJohn Polstra *off += (numsegs + 1) * sizeof(Elf_Phdr); 8978c64af4fSJohn Polstra 8988c64af4fSJohn Polstra noteoff = *off; 8998c64af4fSJohn Polstra elf_putnote(dst, off, "FreeBSD", NT_PRSTATUS, status, 9008c64af4fSJohn Polstra sizeof *status); 9018c64af4fSJohn Polstra elf_putnote(dst, off, "FreeBSD", NT_FPREGSET, fpregset, 9028c64af4fSJohn Polstra sizeof *fpregset); 9038c64af4fSJohn Polstra elf_putnote(dst, off, "FreeBSD", NT_PRPSINFO, psinfo, 9048c64af4fSJohn Polstra sizeof *psinfo); 9058c64af4fSJohn Polstra notesz = *off - noteoff; 9068c64af4fSJohn Polstra 9070ff27d31SJohn Polstra /* Align up to a page boundary for the program segments. */ 9088c64af4fSJohn Polstra *off = round_page(*off); 9098c64af4fSJohn Polstra 9108c64af4fSJohn Polstra if (dst != NULL) { 9118c64af4fSJohn Polstra Elf_Ehdr *ehdr; 9128c64af4fSJohn Polstra Elf_Phdr *phdr; 9130ff27d31SJohn Polstra struct phdr_closure phc; 9148c64af4fSJohn Polstra 9158c64af4fSJohn Polstra /* 9168c64af4fSJohn Polstra * Fill in the ELF header. 9178c64af4fSJohn Polstra */ 9188c64af4fSJohn Polstra ehdr = (Elf_Ehdr *)((char *)dst + ehoff); 9198c64af4fSJohn Polstra ehdr->e_ident[EI_MAG0] = ELFMAG0; 9208c64af4fSJohn Polstra ehdr->e_ident[EI_MAG1] = ELFMAG1; 9218c64af4fSJohn Polstra ehdr->e_ident[EI_MAG2] = ELFMAG2; 9228c64af4fSJohn Polstra ehdr->e_ident[EI_MAG3] = ELFMAG3; 9238c64af4fSJohn Polstra ehdr->e_ident[EI_CLASS] = ELF_CLASS; 9248c64af4fSJohn Polstra ehdr->e_ident[EI_DATA] = ELF_DATA; 9258c64af4fSJohn Polstra ehdr->e_ident[EI_VERSION] = EV_CURRENT; 9268c64af4fSJohn Polstra ehdr->e_ident[EI_PAD] = 0; 9278c64af4fSJohn Polstra strncpy(ehdr->e_ident + EI_BRAND, "FreeBSD", 9288c64af4fSJohn Polstra EI_NIDENT - EI_BRAND); 9298c64af4fSJohn Polstra ehdr->e_type = ET_CORE; 9308c64af4fSJohn Polstra ehdr->e_machine = ELF_ARCH; 9318c64af4fSJohn Polstra ehdr->e_version = EV_CURRENT; 9328c64af4fSJohn Polstra ehdr->e_entry = 0; 9338c64af4fSJohn Polstra ehdr->e_phoff = phoff; 9348c64af4fSJohn Polstra ehdr->e_flags = 0; 9358c64af4fSJohn Polstra ehdr->e_ehsize = sizeof(Elf_Ehdr); 9368c64af4fSJohn Polstra ehdr->e_phentsize = sizeof(Elf_Phdr); 9370ff27d31SJohn Polstra ehdr->e_phnum = numsegs + 1; 9388c64af4fSJohn Polstra ehdr->e_shentsize = sizeof(Elf_Shdr); 9398c64af4fSJohn Polstra ehdr->e_shnum = 0; 9408c64af4fSJohn Polstra ehdr->e_shstrndx = SHN_UNDEF; 9418c64af4fSJohn Polstra 9428c64af4fSJohn Polstra /* 9438c64af4fSJohn Polstra * Fill in the program header entries. 9448c64af4fSJohn Polstra */ 9458c64af4fSJohn Polstra phdr = (Elf_Phdr *)((char *)dst + phoff); 9468c64af4fSJohn Polstra 9478c64af4fSJohn Polstra /* The note segement. */ 9488c64af4fSJohn Polstra phdr->p_type = PT_NOTE; 9498c64af4fSJohn Polstra phdr->p_offset = noteoff; 9508c64af4fSJohn Polstra phdr->p_vaddr = 0; 9518c64af4fSJohn Polstra phdr->p_paddr = 0; 9528c64af4fSJohn Polstra phdr->p_filesz = notesz; 9538c64af4fSJohn Polstra phdr->p_memsz = 0; 9548c64af4fSJohn Polstra phdr->p_flags = 0; 9558c64af4fSJohn Polstra phdr->p_align = 0; 9568c64af4fSJohn Polstra phdr++; 9578c64af4fSJohn Polstra 9580ff27d31SJohn Polstra /* All the writable segments from the program. */ 9590ff27d31SJohn Polstra phc.phdr = phdr; 9600ff27d31SJohn Polstra phc.offset = *off; 9610ff27d31SJohn Polstra each_writable_segment(p, cb_put_phdr, &phc); 9628c64af4fSJohn Polstra } 9638c64af4fSJohn Polstra } 9648c64af4fSJohn Polstra 9658c64af4fSJohn Polstra static void 9668c64af4fSJohn Polstra elf_putnote(void *dst, size_t *off, const char *name, int type, 9678c64af4fSJohn Polstra const void *desc, size_t descsz) 9688c64af4fSJohn Polstra { 9698c64af4fSJohn Polstra Elf_Note note; 9708c64af4fSJohn Polstra 9718c64af4fSJohn Polstra note.n_namesz = strlen(name) + 1; 9728c64af4fSJohn Polstra note.n_descsz = descsz; 9738c64af4fSJohn Polstra note.n_type = type; 9748c64af4fSJohn Polstra if (dst != NULL) 9758c64af4fSJohn Polstra bcopy(¬e, (char *)dst + *off, sizeof note); 9768c64af4fSJohn Polstra *off += sizeof note; 9778c64af4fSJohn Polstra if (dst != NULL) 9788c64af4fSJohn Polstra bcopy(name, (char *)dst + *off, note.n_namesz); 9798c64af4fSJohn Polstra *off += roundup2(note.n_namesz, sizeof(Elf_Size)); 9808c64af4fSJohn Polstra if (dst != NULL) 9818c64af4fSJohn Polstra bcopy(desc, (char *)dst + *off, note.n_descsz); 9828c64af4fSJohn Polstra *off += roundup2(note.n_descsz, sizeof(Elf_Size)); 9838c64af4fSJohn Polstra } 9848c64af4fSJohn Polstra 9858c64af4fSJohn Polstra /* 986e1743d02SSøren Schmidt * Tell kern_execve.c about it, with a little help from the linker. 987e1743d02SSøren Schmidt */ 988820ca326SMatthew Dillon static struct execsw elf_execsw = {exec_elf_imgact, "ELF"}; 989aa855a59SPeter Wemm EXEC_SET(elf, elf_execsw); 990