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> 35e1743d02SSøren Schmidt #include <sys/exec.h> 368c64af4fSJohn Polstra #include <sys/fcntl.h> 37e1743d02SSøren Schmidt #include <sys/imgact.h> 38e1743d02SSøren Schmidt #include <sys/imgact_elf.h> 39e1743d02SSøren Schmidt #include <sys/kernel.h> 40e1743d02SSøren Schmidt #include <sys/malloc.h> 418c64af4fSJohn Polstra #include <sys/mman.h> 42a794e791SBruce Evans #include <sys/namei.h> 438c64af4fSJohn Polstra #include <sys/pioctl.h> 44a794e791SBruce Evans #include <sys/proc.h> 458c64af4fSJohn Polstra #include <sys/procfs.h> 468c64af4fSJohn Polstra #include <sys/resourcevar.h> 4736240ea5SDoug Rabson #include <sys/systm.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> 53a794e791SBruce Evans #include <sys/vnode.h> 54e1743d02SSøren Schmidt 55e1743d02SSøren Schmidt #include <vm/vm.h> 56e1743d02SSøren Schmidt #include <vm/vm_kern.h> 57e1743d02SSøren Schmidt #include <vm/vm_param.h> 58e1743d02SSøren Schmidt #include <vm/pmap.h> 59996c772fSJohn Dyson #include <sys/lock.h> 60e1743d02SSøren Schmidt #include <vm/vm_map.h> 610ff27d31SJohn Polstra #include <vm/vm_object.h> 62e1743d02SSøren Schmidt #include <vm/vm_extern.h> 63e1743d02SSøren Schmidt 6452c24af7SPeter Wemm #include <machine/elf.h> 65e1743d02SSøren Schmidt #include <machine/md_var.h> 66e1743d02SSøren Schmidt 67c815a20cSDavid E. O'Brien #define OLD_EI_BRAND 8 68c815a20cSDavid E. O'Brien 6952c24af7SPeter Wemm __ElfType(Brandinfo); 7052c24af7SPeter Wemm __ElfType(Auxargs); 71ecbb00a2SDoug Rabson 72c33fe779SJohn Polstra static int elf_check_header __P((const Elf_Ehdr *hdr)); 73654f6be1SBruce Evans static int elf_freebsd_fixup __P((register_t **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 86e1743d02SSøren Schmidt static struct sysentvec elf_freebsd_sysvec = { 87e1743d02SSøren Schmidt SYS_MAXSYSCALL, 88e1743d02SSøren Schmidt sysent, 89e1743d02SSøren Schmidt 0, 90e1743d02SSøren Schmidt 0, 91e1743d02SSøren Schmidt 0, 92e1743d02SSøren Schmidt 0, 93e1743d02SSøren Schmidt 0, 94288078beSEivind Eklund 0, 95e1743d02SSøren Schmidt elf_freebsd_fixup, 96e1743d02SSøren Schmidt sendsig, 97e1743d02SSøren Schmidt sigcode, 98e1743d02SSøren Schmidt &szsigcode, 99e1743d02SSøren Schmidt 0, 10022d4b0fbSJohn Polstra "FreeBSD ELF", 10122d4b0fbSJohn Polstra elf_coredump 102e1743d02SSøren Schmidt }; 103e1743d02SSøren Schmidt 104ecbb00a2SDoug Rabson static Elf_Brandinfo freebsd_brand_info = { 105c815a20cSDavid E. O'Brien ELFOSABI_FREEBSD, 106ea5a2b2eSSøren Schmidt "", 107e1743d02SSøren Schmidt "/usr/libexec/ld-elf.so.1", 108ea5a2b2eSSøren Schmidt &elf_freebsd_sysvec 109e1743d02SSøren Schmidt }; 110ecbb00a2SDoug Rabson static Elf_Brandinfo *elf_brand_list[MAX_BRANDS] = { 111ea5a2b2eSSøren Schmidt &freebsd_brand_info, 112e1743d02SSøren Schmidt NULL, NULL, NULL, 113e1743d02SSøren Schmidt NULL, NULL, NULL, NULL 114e1743d02SSøren Schmidt }; 115e1743d02SSøren Schmidt 116e1743d02SSøren Schmidt int 117ecbb00a2SDoug Rabson elf_insert_brand_entry(Elf_Brandinfo *entry) 118e1743d02SSøren Schmidt { 119e1743d02SSøren Schmidt int i; 120e1743d02SSøren Schmidt 121ea5a2b2eSSøren Schmidt for (i=1; i<MAX_BRANDS; i++) { 122ea5a2b2eSSøren Schmidt if (elf_brand_list[i] == NULL) { 123ea5a2b2eSSøren Schmidt elf_brand_list[i] = entry; 124e1743d02SSøren Schmidt break; 125e1743d02SSøren Schmidt } 126e1743d02SSøren Schmidt } 127ea5a2b2eSSøren Schmidt if (i == MAX_BRANDS) 128e1743d02SSøren Schmidt return -1; 129e1743d02SSøren Schmidt return 0; 130e1743d02SSøren Schmidt } 131e1743d02SSøren Schmidt 132e1743d02SSøren Schmidt int 133ecbb00a2SDoug Rabson elf_remove_brand_entry(Elf_Brandinfo *entry) 134e1743d02SSøren Schmidt { 135e1743d02SSøren Schmidt int i; 136e1743d02SSøren Schmidt 137ea5a2b2eSSøren Schmidt for (i=1; i<MAX_BRANDS; i++) { 138ea5a2b2eSSøren Schmidt if (elf_brand_list[i] == entry) { 139ea5a2b2eSSøren Schmidt elf_brand_list[i] = NULL; 140e1743d02SSøren Schmidt break; 141e1743d02SSøren Schmidt } 142e1743d02SSøren Schmidt } 143ea5a2b2eSSøren Schmidt if (i == MAX_BRANDS) 144e1743d02SSøren Schmidt return -1; 145e1743d02SSøren Schmidt return 0; 146e1743d02SSøren Schmidt } 147e1743d02SSøren Schmidt 148096977faSMark Newton int 149096977faSMark Newton elf_brand_inuse(Elf_Brandinfo *entry) 150096977faSMark Newton { 151096977faSMark Newton struct proc *p; 152096977faSMark Newton 1532e3c8fcbSPoul-Henning Kamp LIST_FOREACH(p, &allproc, p_list) { 154096977faSMark Newton if (p->p_sysent == entry->sysvec) 155096977faSMark Newton return TRUE; 156096977faSMark Newton } 157096977faSMark Newton 158096977faSMark Newton return FALSE; 159096977faSMark Newton } 160096977faSMark Newton 161e1743d02SSøren Schmidt static int 162c33fe779SJohn Polstra elf_check_header(const Elf_Ehdr *hdr) 163e1743d02SSøren Schmidt { 16452c24af7SPeter Wemm if (!IS_ELF(*hdr) || 16552c24af7SPeter Wemm hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || 16652c24af7SPeter Wemm hdr->e_ident[EI_DATA] != ELF_TARG_DATA || 16752c24af7SPeter Wemm hdr->e_ident[EI_VERSION] != EV_CURRENT) 168e1743d02SSøren Schmidt return ENOEXEC; 169e1743d02SSøren Schmidt 17052c24af7SPeter Wemm if (!ELF_MACHINE_OK(hdr->e_machine)) 171e1743d02SSøren Schmidt return ENOEXEC; 172e1743d02SSøren Schmidt 173c33fe779SJohn Polstra if (hdr->e_version != ELF_TARG_VER) 174e1743d02SSøren Schmidt return ENOEXEC; 175e1743d02SSøren Schmidt 176e1743d02SSøren Schmidt return 0; 177e1743d02SSøren Schmidt } 178e1743d02SSøren Schmidt 179e1743d02SSøren Schmidt static int 18052c24af7SPeter 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) 181e1743d02SSøren Schmidt { 182e1743d02SSøren Schmidt size_t map_len; 183e1743d02SSøren Schmidt vm_offset_t map_addr; 18452c24af7SPeter Wemm int error, rv; 185e1743d02SSøren Schmidt size_t copy_len; 18652c24af7SPeter Wemm vm_object_t object; 18752c24af7SPeter Wemm vm_offset_t file_addr; 18852c24af7SPeter Wemm vm_offset_t data_buf = 0; 18952c24af7SPeter Wemm 19052c24af7SPeter Wemm object = vp->v_object; 19152c24af7SPeter Wemm error = 0; 192e1743d02SSøren Schmidt 19325ead034SBrian Feldman /* 19425ead034SBrian Feldman * It's necessary to fail if the filsz + offset taken from the 19525ead034SBrian Feldman * header is greater than the actual file pager object's size. 19625ead034SBrian Feldman * If we were to allow this, then the vm_map_find() below would 19725ead034SBrian Feldman * walk right off the end of the file object and into the ether. 19825ead034SBrian Feldman * 19925ead034SBrian Feldman * While I'm here, might as well check for something else that 20025ead034SBrian Feldman * is invalid: filsz cannot be greater than memsz. 20125ead034SBrian Feldman */ 20225ead034SBrian Feldman if ((off_t)filsz + offset > object->un_pager.vnp.vnp_size || 20325ead034SBrian Feldman filsz > memsz) { 20425ead034SBrian Feldman uprintf("elf_load_section: truncated ELF file\n"); 20525ead034SBrian Feldman return (ENOEXEC); 20625ead034SBrian Feldman } 20725ead034SBrian Feldman 2086cde7a16SDavid Greenman map_addr = trunc_page((vm_offset_t)vmaddr); 20952c24af7SPeter Wemm file_addr = trunc_page(offset); 210e1743d02SSøren Schmidt 211e1743d02SSøren Schmidt /* 21252c24af7SPeter Wemm * We have two choices. We can either clear the data in the last page 21352c24af7SPeter Wemm * of an oversized mapping, or we can start the anon mapping a page 21452c24af7SPeter Wemm * early and copy the initialized data into that first page. We 21552c24af7SPeter Wemm * choose the second.. 21652c24af7SPeter Wemm */ 21752c24af7SPeter Wemm if (memsz > filsz) 21852c24af7SPeter Wemm map_len = trunc_page(offset+filsz) - file_addr; 21952c24af7SPeter Wemm else 22052c24af7SPeter Wemm map_len = round_page(offset+filsz) - file_addr; 22152c24af7SPeter Wemm 22252c24af7SPeter Wemm if (map_len != 0) { 22352c24af7SPeter Wemm vm_object_reference(object); 22452c24af7SPeter Wemm vm_map_lock(&vmspace->vm_map); 22552c24af7SPeter Wemm rv = vm_map_insert(&vmspace->vm_map, 22652c24af7SPeter Wemm object, 22752c24af7SPeter Wemm file_addr, /* file offset */ 22852c24af7SPeter Wemm map_addr, /* virtual start */ 22952c24af7SPeter Wemm map_addr + map_len,/* virtual end */ 23052c24af7SPeter Wemm prot, 23152c24af7SPeter Wemm VM_PROT_ALL, 232e972780aSAlan Cox MAP_COPY_ON_WRITE | MAP_PREFAULT); 23352c24af7SPeter Wemm vm_map_unlock(&vmspace->vm_map); 234a3021f91SBoris Popov if (rv != KERN_SUCCESS) { 235a3021f91SBoris Popov vm_object_deallocate(object); 23652c24af7SPeter Wemm return EINVAL; 237a3021f91SBoris Popov } 23852c24af7SPeter Wemm 23952c24af7SPeter Wemm /* we can stop now if we've covered it all */ 24052c24af7SPeter Wemm if (memsz == filsz) 24152c24af7SPeter Wemm return 0; 24252c24af7SPeter Wemm } 24352c24af7SPeter Wemm 24452c24af7SPeter Wemm 24552c24af7SPeter Wemm /* 24652c24af7SPeter Wemm * We have to get the remaining bit of the file into the first part 24752c24af7SPeter Wemm * of the oversized map segment. This is normally because the .data 24852c24af7SPeter Wemm * segment in the file is extended to provide bss. It's a neat idea 24952c24af7SPeter Wemm * to try and save a page, but it's a pain in the behind to implement. 250e1743d02SSøren Schmidt */ 251e1743d02SSøren Schmidt copy_len = (offset + filsz) - trunc_page(offset + filsz); 2526cde7a16SDavid Greenman map_addr = trunc_page((vm_offset_t)vmaddr + filsz); 2536cde7a16SDavid Greenman map_len = round_page((vm_offset_t)vmaddr + memsz) - map_addr; 254e1743d02SSøren Schmidt 25552c24af7SPeter Wemm /* This had damn well better be true! */ 2568191d577SPeter Wemm if (map_len != 0) { 25752c24af7SPeter Wemm vm_map_lock(&vmspace->vm_map); 25852c24af7SPeter Wemm rv = vm_map_insert(&vmspace->vm_map, NULL, 0, 25952c24af7SPeter Wemm map_addr, map_addr + map_len, 26052c24af7SPeter Wemm VM_PROT_ALL, VM_PROT_ALL, 0); 26152c24af7SPeter Wemm vm_map_unlock(&vmspace->vm_map); 26252c24af7SPeter Wemm if (rv != KERN_SUCCESS) 26352c24af7SPeter Wemm return EINVAL; 2648191d577SPeter Wemm } 265e1743d02SSøren Schmidt 26652c24af7SPeter Wemm if (copy_len != 0) { 26752c24af7SPeter Wemm vm_object_reference(object); 26852c24af7SPeter Wemm rv = vm_map_find(exec_map, 26952c24af7SPeter Wemm object, 27052c24af7SPeter Wemm trunc_page(offset + filsz), 27152c24af7SPeter Wemm &data_buf, 272e1743d02SSøren Schmidt PAGE_SIZE, 27352c24af7SPeter Wemm TRUE, 274e1743d02SSøren Schmidt VM_PROT_READ, 27552c24af7SPeter Wemm VM_PROT_ALL, 276e972780aSAlan Cox MAP_COPY_ON_WRITE | MAP_PREFAULT_PARTIAL); 27752c24af7SPeter Wemm if (rv != KERN_SUCCESS) { 27852c24af7SPeter Wemm vm_object_deallocate(object); 27952c24af7SPeter Wemm return EINVAL; 28052c24af7SPeter Wemm } 281e1743d02SSøren Schmidt 28252c24af7SPeter Wemm /* send the page fragment to user space */ 28352c24af7SPeter Wemm error = copyout((caddr_t)data_buf, (caddr_t)map_addr, copy_len); 28452c24af7SPeter Wemm vm_map_remove(exec_map, data_buf, data_buf + PAGE_SIZE); 28552c24af7SPeter Wemm if (error) 28652c24af7SPeter Wemm return (error); 28752c24af7SPeter Wemm } 288e1743d02SSøren Schmidt 289e1743d02SSøren Schmidt /* 2908191d577SPeter Wemm * set it to the specified protection 291e1743d02SSøren Schmidt */ 2928191d577SPeter Wemm vm_map_protect(&vmspace->vm_map, map_addr, map_addr + map_len, prot, 2938191d577SPeter Wemm FALSE); 2948191d577SPeter Wemm 295e1743d02SSøren Schmidt return error; 296e1743d02SSøren Schmidt } 297e1743d02SSøren Schmidt 298c33fe779SJohn Polstra /* 299c33fe779SJohn Polstra * Load the file "file" into memory. It may be either a shared object 300c33fe779SJohn Polstra * or an executable. 301c33fe779SJohn Polstra * 302c33fe779SJohn Polstra * The "addr" reference parameter is in/out. On entry, it specifies 303c33fe779SJohn Polstra * the address where a shared object should be loaded. If the file is 304c33fe779SJohn Polstra * an executable, this value is ignored. On exit, "addr" specifies 305c33fe779SJohn Polstra * where the file was actually loaded. 306c33fe779SJohn Polstra * 307c33fe779SJohn Polstra * The "entry" reference parameter is out only. On exit, it specifies 308c33fe779SJohn Polstra * the entry point for the loaded file. 309c33fe779SJohn Polstra */ 310e1743d02SSøren Schmidt static int 311bdbc8c26SPeter Wemm elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry) 312e1743d02SSøren Schmidt { 313d254af07SMatthew Dillon const Elf_Ehdr *hdr = NULL; 314d254af07SMatthew Dillon const Elf_Phdr *phdr = NULL; 315e1743d02SSøren Schmidt struct nameidata nd; 316e1743d02SSøren Schmidt struct vmspace *vmspace = p->p_vmspace; 317c8a79999SPeter Wemm struct vattr attr; 318c8a79999SPeter Wemm struct image_params image_params, *imgp; 31952c24af7SPeter Wemm vm_prot_t prot; 320c33fe779SJohn Polstra u_long rbase; 321c33fe779SJohn Polstra u_long base_addr = 0; 322c33fe779SJohn Polstra int error, i, numsegs; 323e1743d02SSøren Schmidt 324c8a79999SPeter Wemm imgp = &image_params; 325c8a79999SPeter Wemm /* 326c8a79999SPeter Wemm * Initialize part of the common data 327c8a79999SPeter Wemm */ 328c8a79999SPeter Wemm imgp->proc = p; 329c8a79999SPeter Wemm imgp->uap = NULL; 330c8a79999SPeter Wemm imgp->attr = &attr; 331c8a79999SPeter Wemm imgp->firstpage = NULL; 332c8a79999SPeter Wemm imgp->image_header = (char *)kmem_alloc_wait(exec_map, PAGE_SIZE); 333c8a79999SPeter Wemm 334c8a79999SPeter Wemm if (imgp->image_header == NULL) { 335c8a79999SPeter Wemm nd.ni_vp = NULL; 336c8a79999SPeter Wemm error = ENOMEM; 337c8a79999SPeter Wemm goto fail; 338c8a79999SPeter Wemm } 339c8a79999SPeter Wemm 340e1743d02SSøren Schmidt NDINIT(&nd, LOOKUP, LOCKLEAF|FOLLOW, UIO_SYSSPACE, file, p); 341e1743d02SSøren Schmidt 342d254af07SMatthew Dillon if ((error = namei(&nd)) != 0) { 3431560a9d5SPeter Wemm nd.ni_vp = NULL; 344e1743d02SSøren Schmidt goto fail; 345e1743d02SSøren Schmidt } 346762e6b85SEivind Eklund NDFREE(&nd, NDF_ONLY_PNBUF); 347c8a79999SPeter Wemm imgp->vp = nd.ni_vp; 348c8a79999SPeter Wemm 349e1743d02SSøren Schmidt /* 350e1743d02SSøren Schmidt * Check permissions, modes, uid, etc on the file, and "open" it. 351e1743d02SSøren Schmidt */ 352c8a79999SPeter Wemm error = exec_check_permissions(imgp); 353c8a79999SPeter Wemm if (error) { 354996c772fSJohn Dyson VOP_UNLOCK(nd.ni_vp, 0, p); 355c8a79999SPeter Wemm goto fail; 356c8a79999SPeter Wemm } 357e1743d02SSøren Schmidt 358c8a79999SPeter Wemm error = exec_map_first_page(imgp); 35925ead034SBrian Feldman /* 36025ead034SBrian Feldman * Also make certain that the interpreter stays the same, so set 36125ead034SBrian Feldman * its VTEXT flag, too. 36225ead034SBrian Feldman */ 36325ead034SBrian Feldman if (error == 0) 36425ead034SBrian Feldman nd.ni_vp->v_flag |= VTEXT; 365c8a79999SPeter Wemm VOP_UNLOCK(nd.ni_vp, 0, p); 366e1743d02SSøren Schmidt if (error) 367e1743d02SSøren Schmidt goto fail; 368e1743d02SSøren Schmidt 369d254af07SMatthew Dillon hdr = (const Elf_Ehdr *)imgp->image_header; 370c33fe779SJohn Polstra if ((error = elf_check_header(hdr)) != 0) 371e1743d02SSøren Schmidt goto fail; 372c33fe779SJohn Polstra if (hdr->e_type == ET_DYN) 373c33fe779SJohn Polstra rbase = *addr; 374c33fe779SJohn Polstra else if (hdr->e_type == ET_EXEC) 375c33fe779SJohn Polstra rbase = 0; 376c33fe779SJohn Polstra else { 377c33fe779SJohn Polstra error = ENOEXEC; 378c33fe779SJohn Polstra goto fail; 379c33fe779SJohn Polstra } 380e1743d02SSøren Schmidt 381c8a79999SPeter Wemm /* Only support headers that fit within first page for now */ 38252c24af7SPeter Wemm if ((hdr->e_phoff > PAGE_SIZE) || 38352c24af7SPeter Wemm (hdr->e_phoff + hdr->e_phentsize * hdr->e_phnum) > PAGE_SIZE) { 384c8a79999SPeter Wemm error = ENOEXEC; 385e1743d02SSøren Schmidt goto fail; 386c8a79999SPeter Wemm } 387c8a79999SPeter Wemm 388d254af07SMatthew Dillon phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff); 389e1743d02SSøren Schmidt 390c33fe779SJohn Polstra for (i = 0, numsegs = 0; i < hdr->e_phnum; i++) { 39152c24af7SPeter Wemm if (phdr[i].p_type == PT_LOAD) { /* Loadable segment */ 39252c24af7SPeter Wemm prot = 0; 393e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_X) 394e1743d02SSøren Schmidt prot |= VM_PROT_EXECUTE; 395e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_W) 396e1743d02SSøren Schmidt prot |= VM_PROT_WRITE; 397e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_R) 398e1743d02SSøren Schmidt prot |= VM_PROT_READ; 399e1743d02SSøren Schmidt 400d254af07SMatthew Dillon if ((error = elf_load_section(p, vmspace, nd.ni_vp, 401e1743d02SSøren Schmidt phdr[i].p_offset, 402e1743d02SSøren Schmidt (caddr_t)phdr[i].p_vaddr + 403c33fe779SJohn Polstra rbase, 404e1743d02SSøren Schmidt phdr[i].p_memsz, 405d254af07SMatthew Dillon phdr[i].p_filesz, prot)) != 0) 406e1743d02SSøren Schmidt goto fail; 407e1743d02SSøren Schmidt /* 408c33fe779SJohn Polstra * Establish the base address if this is the 409c33fe779SJohn Polstra * first segment. 410e1743d02SSøren Schmidt */ 411c33fe779SJohn Polstra if (numsegs == 0) 412c33fe779SJohn Polstra base_addr = trunc_page(phdr[i].p_vaddr + rbase); 413c33fe779SJohn Polstra numsegs++; 414e1743d02SSøren Schmidt } 415e1743d02SSøren Schmidt } 416c33fe779SJohn Polstra *addr = base_addr; 417c33fe779SJohn Polstra *entry=(unsigned long)hdr->e_entry + rbase; 418e1743d02SSøren Schmidt 419e1743d02SSøren Schmidt fail: 420c8a79999SPeter Wemm if (imgp->firstpage) 421c8a79999SPeter Wemm exec_unmap_first_page(imgp); 422c8a79999SPeter Wemm if (imgp->image_header) 423c8a79999SPeter Wemm kmem_free_wakeup(exec_map, (vm_offset_t)imgp->image_header, 424c8a79999SPeter Wemm PAGE_SIZE); 4251560a9d5SPeter Wemm if (nd.ni_vp) 4261560a9d5SPeter Wemm vrele(nd.ni_vp); 427e1743d02SSøren Schmidt 428e1743d02SSøren Schmidt return error; 429e1743d02SSøren Schmidt } 430e1743d02SSøren Schmidt 431c815a20cSDavid E. O'Brien static int fallback_elf_brand = ELFOSABI_FREEBSD; 432c815a20cSDavid E. O'Brien SYSCTL_INT(_kern, OID_AUTO, fallback_elf_brand, CTLFLAG_RW, 433c815a20cSDavid E. O'Brien &fallback_elf_brand, ELFOSABI_FREEBSD, 434f8b3601eSMark Newton "ELF brand of last resort"); 435f8b3601eSMark Newton 436303b270bSEivind Eklund static int 437e1743d02SSøren Schmidt exec_elf_imgact(struct image_params *imgp) 438e1743d02SSøren Schmidt { 439ecbb00a2SDoug Rabson const Elf_Ehdr *hdr = (const Elf_Ehdr *) imgp->image_header; 440f5ef029eSPoul-Henning Kamp const Elf_Phdr *phdr; 441ecbb00a2SDoug Rabson Elf_Auxargs *elf_auxargs = NULL; 4425856e12eSJohn Dyson struct vmspace *vmspace; 44352c24af7SPeter Wemm vm_prot_t prot; 444e1743d02SSøren Schmidt u_long text_size = 0, data_size = 0; 445e1743d02SSøren Schmidt u_long text_addr = 0, data_addr = 0; 446e1743d02SSøren Schmidt u_long addr, entry = 0, proghdr = 0; 44752c24af7SPeter Wemm int error, i; 448c8a79999SPeter Wemm const char *interp = NULL; 449d1dbc694SJohn Polstra Elf_Brandinfo *brand_info; 450ea5a2b2eSSøren Schmidt char path[MAXPATHLEN]; 451e1743d02SSøren Schmidt 452e1743d02SSøren Schmidt /* 453e1743d02SSøren Schmidt * Do we have a valid ELF header ? 454e1743d02SSøren Schmidt */ 455c33fe779SJohn Polstra if (elf_check_header(hdr) != 0 || hdr->e_type != ET_EXEC) 456e1743d02SSøren Schmidt return -1; 457e1743d02SSøren Schmidt 458e1743d02SSøren Schmidt /* 459e1743d02SSøren Schmidt * From here on down, we return an errno, not -1, as we've 460e1743d02SSøren Schmidt * detected an ELF file. 461e1743d02SSøren Schmidt */ 462e1743d02SSøren Schmidt 463e1743d02SSøren Schmidt if ((hdr->e_phoff > PAGE_SIZE) || 46452c24af7SPeter Wemm (hdr->e_phoff + hdr->e_phentsize * hdr->e_phnum) > PAGE_SIZE) { 465c8a79999SPeter Wemm /* Only support headers in first page for now */ 466c8a79999SPeter Wemm return ENOEXEC; 467e1743d02SSøren Schmidt } 46852c24af7SPeter Wemm phdr = (const Elf_Phdr*)(imgp->image_header + hdr->e_phoff); 469e1743d02SSøren Schmidt 470e1743d02SSøren Schmidt /* 471e1743d02SSøren Schmidt * From this point on, we may have resources that need to be freed. 472e1743d02SSøren Schmidt */ 47325ead034SBrian Feldman 47425ead034SBrian Feldman /* 47525ead034SBrian Feldman * Yeah, I'm paranoid. There is every reason in the world to get 47625ead034SBrian Feldman * VTEXT now since from here on out, there are places we can have 47725ead034SBrian Feldman * a context switch. Better safe than sorry; I really don't want 47825ead034SBrian Feldman * the file to change while it's being loaded. 47925ead034SBrian Feldman */ 48055af4c7dSBrian Feldman simple_lock(&imgp->vp->v_interlock); 48155af4c7dSBrian Feldman imgp->vp->v_flag |= VTEXT; 48255af4c7dSBrian Feldman simple_unlock(&imgp->vp->v_interlock); 48325ead034SBrian Feldman 484d254af07SMatthew Dillon if ((error = exec_extract_strings(imgp)) != 0) 485e1743d02SSøren Schmidt goto fail; 486e1743d02SSøren Schmidt 487e1743d02SSøren Schmidt exec_new_vmspace(imgp); 488e1743d02SSøren Schmidt 4895856e12eSJohn Dyson vmspace = imgp->proc->p_vmspace; 4905856e12eSJohn Dyson 491e1743d02SSøren Schmidt for (i = 0; i < hdr->e_phnum; i++) { 492e1743d02SSøren Schmidt switch(phdr[i].p_type) { 493e1743d02SSøren Schmidt 494e1743d02SSøren Schmidt case PT_LOAD: /* Loadable segment */ 49552c24af7SPeter Wemm prot = 0; 496e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_X) 497e1743d02SSøren Schmidt prot |= VM_PROT_EXECUTE; 498e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_W) 499e1743d02SSøren Schmidt prot |= VM_PROT_WRITE; 500e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_R) 501e1743d02SSøren Schmidt prot |= VM_PROT_READ; 502e1743d02SSøren Schmidt 503d254af07SMatthew Dillon if ((error = elf_load_section(imgp->proc, 50452c24af7SPeter Wemm vmspace, imgp->vp, 505e1743d02SSøren Schmidt phdr[i].p_offset, 506e1743d02SSøren Schmidt (caddr_t)phdr[i].p_vaddr, 507e1743d02SSøren Schmidt phdr[i].p_memsz, 508d254af07SMatthew Dillon phdr[i].p_filesz, prot)) != 0) 509e1743d02SSøren Schmidt goto fail; 510e1743d02SSøren Schmidt 511e1743d02SSøren Schmidt /* 512e1743d02SSøren Schmidt * Is this .text or .data ?? 513e1743d02SSøren Schmidt * 514e1743d02SSøren Schmidt * We only handle one each of those yet XXX 515e1743d02SSøren Schmidt */ 516e1743d02SSøren Schmidt if (hdr->e_entry >= phdr[i].p_vaddr && 517e1743d02SSøren Schmidt hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) { 518e1743d02SSøren Schmidt text_addr = trunc_page(phdr[i].p_vaddr); 5198191d577SPeter Wemm text_size = round_page(phdr[i].p_memsz + 5208191d577SPeter Wemm phdr[i].p_vaddr - 5218191d577SPeter Wemm text_addr); 522e1743d02SSøren Schmidt entry = (u_long)hdr->e_entry; 523e1743d02SSøren Schmidt } else { 524e1743d02SSøren Schmidt data_addr = trunc_page(phdr[i].p_vaddr); 5258191d577SPeter Wemm data_size = round_page(phdr[i].p_memsz + 5268191d577SPeter Wemm phdr[i].p_vaddr - 5278191d577SPeter Wemm data_addr); 528e1743d02SSøren Schmidt } 529e1743d02SSøren Schmidt break; 530e1743d02SSøren Schmidt case PT_INTERP: /* Path to interpreter */ 531c8a79999SPeter Wemm if (phdr[i].p_filesz > MAXPATHLEN || 532c8a79999SPeter Wemm phdr[i].p_offset + phdr[i].p_filesz > PAGE_SIZE) { 533e1743d02SSøren Schmidt error = ENOEXEC; 534e1743d02SSøren Schmidt goto fail; 535e1743d02SSøren Schmidt } 536c8a79999SPeter Wemm interp = imgp->image_header + phdr[i].p_offset; 537e1743d02SSøren Schmidt break; 538e1743d02SSøren Schmidt case PT_PHDR: /* Program header table info */ 539e1743d02SSøren Schmidt proghdr = phdr[i].p_vaddr; 540e1743d02SSøren Schmidt break; 541e1743d02SSøren Schmidt default: 54252c24af7SPeter Wemm break; 543e1743d02SSøren Schmidt } 544e1743d02SSøren Schmidt } 545e1743d02SSøren Schmidt 546e1743d02SSøren Schmidt vmspace->vm_tsize = text_size >> PAGE_SHIFT; 5477cd99438SBruce Evans vmspace->vm_taddr = (caddr_t)(uintptr_t)text_addr; 548e1743d02SSøren Schmidt vmspace->vm_dsize = data_size >> PAGE_SHIFT; 5497cd99438SBruce Evans vmspace->vm_daddr = (caddr_t)(uintptr_t)data_addr; 550e1743d02SSøren Schmidt 55147633640SJohn Polstra addr = ELF_RTLD_ADDR(vmspace); 552e1743d02SSøren Schmidt 553ea5a2b2eSSøren Schmidt imgp->entry_addr = entry; 554ea5a2b2eSSøren Schmidt 555d1dbc694SJohn Polstra brand_info = NULL; 556c815a20cSDavid E. O'Brien 557c815a20cSDavid E. O'Brien /* XXX For now we look for the magic "FreeBSD" that we used to put 558c815a20cSDavid E. O'Brien * into the ELF header at the EI_ABIVERSION location. If found use 559c815a20cSDavid E. O'Brien * that information rather than figuring out the ABI from proper 560c815a20cSDavid E. O'Brien * branding. This should be removed for 5.0-RELEASE. The Linux caes 561c815a20cSDavid E. O'Brien * can be figured out from the `interp_path' field. 562c815a20cSDavid E. O'Brien */ 563c815a20cSDavid E. O'Brien if (strcmp("FreeBSD", (const char *)&hdr->e_ident[OLD_EI_BRAND]) == 0) 564c815a20cSDavid E. O'Brien brand_info = &freebsd_brand_info; 565c815a20cSDavid E. O'Brien 566c815a20cSDavid E. O'Brien /* If the executable has a brand, search for it in the brand list. */ 567c815a20cSDavid E. O'Brien if (brand_info == NULL) { 568ea5a2b2eSSøren Schmidt for (i = 0; i < MAX_BRANDS; i++) { 569d1dbc694SJohn Polstra Elf_Brandinfo *bi = elf_brand_list[i]; 570d1dbc694SJohn Polstra 571c815a20cSDavid E. O'Brien if (bi != NULL && hdr->e_ident[EI_OSABI] == bi->brand) { 572d1dbc694SJohn Polstra brand_info = bi; 573e1743d02SSøren Schmidt break; 574e1743d02SSøren Schmidt } 575e1743d02SSøren Schmidt } 576e1743d02SSøren Schmidt } 577ea5a2b2eSSøren Schmidt 578d1dbc694SJohn Polstra /* Lacking a known brand, search for a recognized interpreter. */ 579d1dbc694SJohn Polstra if (brand_info == NULL && interp != NULL) { 580ea5a2b2eSSøren Schmidt for (i = 0; i < MAX_BRANDS; i++) { 581d1dbc694SJohn Polstra Elf_Brandinfo *bi = elf_brand_list[i]; 582d1dbc694SJohn Polstra 583d1dbc694SJohn Polstra if (bi != NULL && 584d1dbc694SJohn Polstra strcmp(interp, bi->interp_path) == 0) { 585d1dbc694SJohn Polstra brand_info = bi; 586d672246bSSøren Schmidt break; 587ea5a2b2eSSøren Schmidt } 588ea5a2b2eSSøren Schmidt } 589ea5a2b2eSSøren Schmidt } 590d1dbc694SJohn Polstra 591f8b3601eSMark Newton /* Lacking a recognized interpreter, try the default brand */ 592c815a20cSDavid E. O'Brien if (brand_info == NULL) { 593f8b3601eSMark Newton for (i = 0; i < MAX_BRANDS; i++) { 594f8b3601eSMark Newton Elf_Brandinfo *bi = elf_brand_list[i]; 595f8b3601eSMark Newton 596c815a20cSDavid E. O'Brien if (bi != NULL && fallback_elf_brand == bi->brand) { 597f8b3601eSMark Newton brand_info = bi; 598f8b3601eSMark Newton break; 599f8b3601eSMark Newton } 600f8b3601eSMark Newton } 601f8b3601eSMark Newton } 602f8b3601eSMark Newton 603c815a20cSDavid E. O'Brien /* XXX - Assume FreeBSD after the branding method change. */ 604d1dbc694SJohn Polstra if (brand_info == NULL) 605d1dbc694SJohn Polstra brand_info = &freebsd_brand_info; 606d1dbc694SJohn Polstra 607d1dbc694SJohn Polstra if (brand_info == NULL) { 608c815a20cSDavid E. O'Brien uprintf("ELF binary type \"%u\" not known.\n", 609c815a20cSDavid E. O'Brien hdr->e_ident[EI_OSABI]); 610e1743d02SSøren Schmidt error = ENOEXEC; 611e1743d02SSøren Schmidt goto fail; 612d1dbc694SJohn Polstra } 613d1dbc694SJohn Polstra 614d1dbc694SJohn Polstra imgp->proc->p_sysent = brand_info->sysvec; 615d1dbc694SJohn Polstra if (interp != NULL) { 6162127f260SArchie Cobbs snprintf(path, sizeof(path), "%s%s", 6172127f260SArchie Cobbs brand_info->emul_path, interp); 618d1dbc694SJohn Polstra if ((error = elf_load_file(imgp->proc, path, &addr, 619d1dbc694SJohn Polstra &imgp->entry_addr)) != 0) { 620bdbc8c26SPeter Wemm if ((error = elf_load_file(imgp->proc, interp, &addr, 6217a583b02SMarcel Moolenaar &imgp->entry_addr)) != 0) { 622bdbc8c26SPeter Wemm uprintf("ELF interpreter %s not found\n", path); 623e1743d02SSøren Schmidt goto fail; 624e1743d02SSøren Schmidt } 625e1743d02SSøren Schmidt } 6267a583b02SMarcel Moolenaar } 627ea5a2b2eSSøren Schmidt 628e1743d02SSøren Schmidt /* 629e1743d02SSøren Schmidt * Construct auxargs table (used by the fixup routine) 630e1743d02SSøren Schmidt */ 631ecbb00a2SDoug Rabson elf_auxargs = malloc(sizeof(Elf_Auxargs), M_TEMP, M_WAITOK); 632e1743d02SSøren Schmidt elf_auxargs->execfd = -1; 633e1743d02SSøren Schmidt elf_auxargs->phdr = proghdr; 634e1743d02SSøren Schmidt elf_auxargs->phent = hdr->e_phentsize; 635e1743d02SSøren Schmidt elf_auxargs->phnum = hdr->e_phnum; 636e1743d02SSøren Schmidt elf_auxargs->pagesz = PAGE_SIZE; 637e1743d02SSøren Schmidt elf_auxargs->base = addr; 638e1743d02SSøren Schmidt elf_auxargs->flags = 0; 639e1743d02SSøren Schmidt elf_auxargs->entry = entry; 640e1743d02SSøren Schmidt elf_auxargs->trace = elf_trace; 641e1743d02SSøren Schmidt 642e1743d02SSøren Schmidt imgp->auxargs = elf_auxargs; 643e1743d02SSøren Schmidt imgp->interpreted = 0; 644e1743d02SSøren Schmidt 645e1743d02SSøren Schmidt fail: 646e1743d02SSøren Schmidt return error; 647e1743d02SSøren Schmidt } 648e1743d02SSøren Schmidt 649e1743d02SSøren Schmidt static int 650654f6be1SBruce Evans elf_freebsd_fixup(register_t **stack_base, struct image_params *imgp) 651e1743d02SSøren Schmidt { 652ecbb00a2SDoug Rabson Elf_Auxargs *args = (Elf_Auxargs *)imgp->auxargs; 653654f6be1SBruce Evans register_t *pos; 654e1743d02SSøren Schmidt 655e1743d02SSøren Schmidt pos = *stack_base + (imgp->argc + imgp->envc + 2); 656e1743d02SSøren Schmidt 657e1743d02SSøren Schmidt if (args->trace) { 658e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_DEBUG, 1); 659e1743d02SSøren Schmidt } 660e1743d02SSøren Schmidt if (args->execfd != -1) { 661e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); 662e1743d02SSøren Schmidt } 663e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); 664e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHENT, args->phent); 665e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); 666e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); 667e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); 668e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); 669e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_BASE, args->base); 670e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_NULL, 0); 671e1743d02SSøren Schmidt 672e1743d02SSøren Schmidt free(imgp->auxargs, M_TEMP); 673e1743d02SSøren Schmidt imgp->auxargs = NULL; 674e1743d02SSøren Schmidt 675e1743d02SSøren Schmidt (*stack_base)--; 676216a0f2dSDoug Rabson suword(*stack_base, (long) imgp->argc); 677e1743d02SSøren Schmidt return 0; 678e1743d02SSøren Schmidt } 679e1743d02SSøren Schmidt 680e1743d02SSøren Schmidt /* 6818c64af4fSJohn Polstra * Code for generating ELF core dumps. 6828c64af4fSJohn Polstra */ 6838c64af4fSJohn Polstra 6840ff27d31SJohn Polstra typedef void (*segment_callback) __P((vm_map_entry_t, void *)); 6850ff27d31SJohn Polstra 6860ff27d31SJohn Polstra /* Closure for cb_put_phdr(). */ 6870ff27d31SJohn Polstra struct phdr_closure { 6880ff27d31SJohn Polstra Elf_Phdr *phdr; /* Program header to fill in */ 6890ff27d31SJohn Polstra Elf_Off offset; /* Offset of segment in core file */ 6900ff27d31SJohn Polstra }; 6910ff27d31SJohn Polstra 6920ff27d31SJohn Polstra /* Closure for cb_size_segment(). */ 6930ff27d31SJohn Polstra struct sseg_closure { 6940ff27d31SJohn Polstra int count; /* Count of writable segments. */ 6950ff27d31SJohn Polstra size_t size; /* Total size of all writable segments. */ 6960ff27d31SJohn Polstra }; 6970ff27d31SJohn Polstra 6980ff27d31SJohn Polstra static void cb_put_phdr __P((vm_map_entry_t, void *)); 6990ff27d31SJohn Polstra static void cb_size_segment __P((vm_map_entry_t, void *)); 7000ff27d31SJohn Polstra static void each_writable_segment __P((struct proc *, segment_callback, 7010ff27d31SJohn Polstra void *)); 7020ff27d31SJohn Polstra static int elf_corehdr __P((struct proc *, struct vnode *, struct ucred *, 7030ff27d31SJohn Polstra int, void *, size_t)); 7040ff27d31SJohn Polstra static void elf_puthdr __P((struct proc *, void *, size_t *, 7050ff27d31SJohn Polstra const prstatus_t *, const prfpregset_t *, const prpsinfo_t *, int)); 7060ff27d31SJohn Polstra static void elf_putnote __P((void *, size_t *, const char *, int, 7070ff27d31SJohn Polstra const void *, size_t)); 7088c64af4fSJohn Polstra 7098c64af4fSJohn Polstra extern int osreldate; 7108c64af4fSJohn Polstra 7118c64af4fSJohn Polstra int 712fca666a1SJulian Elischer elf_coredump(p, vp, limit) 7138c64af4fSJohn Polstra register struct proc *p; 7148c64af4fSJohn Polstra register struct vnode *vp; 715fca666a1SJulian Elischer off_t limit; 716fca666a1SJulian Elischer { 717da654d90SPoul-Henning Kamp register struct ucred *cred = p->p_ucred; 718fca666a1SJulian Elischer int error = 0; 7190ff27d31SJohn Polstra struct sseg_closure seginfo; 7200ff27d31SJohn Polstra void *hdr; 7218c64af4fSJohn Polstra size_t hdrsize; 7228c64af4fSJohn Polstra 7230ff27d31SJohn Polstra /* Size the program segments. */ 7240ff27d31SJohn Polstra seginfo.count = 0; 7250ff27d31SJohn Polstra seginfo.size = 0; 7260ff27d31SJohn Polstra each_writable_segment(p, cb_size_segment, &seginfo); 7270ff27d31SJohn Polstra 7280ff27d31SJohn Polstra /* 7290ff27d31SJohn Polstra * Calculate the size of the core file header area by making 7300ff27d31SJohn Polstra * a dry run of generating it. Nothing is written, but the 7310ff27d31SJohn Polstra * size is calculated. 7320ff27d31SJohn Polstra */ 7330ff27d31SJohn Polstra hdrsize = 0; 7340ff27d31SJohn Polstra elf_puthdr((struct proc *)NULL, (void *)NULL, &hdrsize, 7350ff27d31SJohn Polstra (const prstatus_t *)NULL, (const prfpregset_t *)NULL, 7360ff27d31SJohn Polstra (const prpsinfo_t *)NULL, seginfo.count); 7370ff27d31SJohn Polstra 738fca666a1SJulian Elischer if (hdrsize + seginfo.size >= limit) 7398c64af4fSJohn Polstra return (EFAULT); 7400ff27d31SJohn Polstra 7410ff27d31SJohn Polstra /* 7420ff27d31SJohn Polstra * Allocate memory for building the header, fill it up, 7430ff27d31SJohn Polstra * and write it out. 7440ff27d31SJohn Polstra */ 7450ff27d31SJohn Polstra hdr = malloc(hdrsize, M_TEMP, M_WAITOK); 7460ff27d31SJohn Polstra if (hdr == NULL) { 747fca666a1SJulian Elischer return EINVAL; 7480ff27d31SJohn Polstra } 7490ff27d31SJohn Polstra error = elf_corehdr(p, vp, cred, seginfo.count, hdr, hdrsize); 7500ff27d31SJohn Polstra 7510ff27d31SJohn Polstra /* Write the contents of all of the writable segments. */ 7520ff27d31SJohn Polstra if (error == 0) { 7530ff27d31SJohn Polstra Elf_Phdr *php; 7540ff27d31SJohn Polstra off_t offset; 7550ff27d31SJohn Polstra int i; 7560ff27d31SJohn Polstra 7570ff27d31SJohn Polstra php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1; 7580ff27d31SJohn Polstra offset = hdrsize; 7590ff27d31SJohn Polstra for (i = 0; i < seginfo.count; i++) { 7600ff27d31SJohn Polstra error = vn_rdwr(UIO_WRITE, vp, (caddr_t)php->p_vaddr, 7610ff27d31SJohn Polstra php->p_filesz, offset, UIO_USERSPACE, 762dada0278SJohn Polstra IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, p); 7630ff27d31SJohn Polstra if (error != 0) 7640ff27d31SJohn Polstra break; 7650ff27d31SJohn Polstra offset += php->p_filesz; 7660ff27d31SJohn Polstra php++; 7670ff27d31SJohn Polstra } 7680ff27d31SJohn Polstra } 7690ff27d31SJohn Polstra free(hdr, M_TEMP); 7700ff27d31SJohn Polstra 771fca666a1SJulian Elischer return error; 7728c64af4fSJohn Polstra } 7738c64af4fSJohn Polstra 7740ff27d31SJohn Polstra /* 7750ff27d31SJohn Polstra * A callback for each_writable_segment() to write out the segment's 7760ff27d31SJohn Polstra * program header entry. 7770ff27d31SJohn Polstra */ 7780ff27d31SJohn Polstra static void 7790ff27d31SJohn Polstra cb_put_phdr(entry, closure) 7800ff27d31SJohn Polstra vm_map_entry_t entry; 7810ff27d31SJohn Polstra void *closure; 7820ff27d31SJohn Polstra { 7830ff27d31SJohn Polstra struct phdr_closure *phc = (struct phdr_closure *)closure; 7840ff27d31SJohn Polstra Elf_Phdr *phdr = phc->phdr; 7850ff27d31SJohn Polstra 7860ff27d31SJohn Polstra phc->offset = round_page(phc->offset); 7870ff27d31SJohn Polstra 7880ff27d31SJohn Polstra phdr->p_type = PT_LOAD; 7890ff27d31SJohn Polstra phdr->p_offset = phc->offset; 7900ff27d31SJohn Polstra phdr->p_vaddr = entry->start; 7910ff27d31SJohn Polstra phdr->p_paddr = 0; 7920ff27d31SJohn Polstra phdr->p_filesz = phdr->p_memsz = entry->end - entry->start; 7930ff27d31SJohn Polstra phdr->p_align = PAGE_SIZE; 7940ff27d31SJohn Polstra phdr->p_flags = 0; 7950ff27d31SJohn Polstra if (entry->protection & VM_PROT_READ) 7960ff27d31SJohn Polstra phdr->p_flags |= PF_R; 7970ff27d31SJohn Polstra if (entry->protection & VM_PROT_WRITE) 7980ff27d31SJohn Polstra phdr->p_flags |= PF_W; 7990ff27d31SJohn Polstra if (entry->protection & VM_PROT_EXECUTE) 8000ff27d31SJohn Polstra phdr->p_flags |= PF_X; 8010ff27d31SJohn Polstra 8020ff27d31SJohn Polstra phc->offset += phdr->p_filesz; 8030ff27d31SJohn Polstra phc->phdr++; 8040ff27d31SJohn Polstra } 8050ff27d31SJohn Polstra 8060ff27d31SJohn Polstra /* 8070ff27d31SJohn Polstra * A callback for each_writable_segment() to gather information about 8080ff27d31SJohn Polstra * the number of segments and their total size. 8090ff27d31SJohn Polstra */ 8100ff27d31SJohn Polstra static void 8110ff27d31SJohn Polstra cb_size_segment(entry, closure) 8120ff27d31SJohn Polstra vm_map_entry_t entry; 8130ff27d31SJohn Polstra void *closure; 8140ff27d31SJohn Polstra { 8150ff27d31SJohn Polstra struct sseg_closure *ssc = (struct sseg_closure *)closure; 8160ff27d31SJohn Polstra 8170ff27d31SJohn Polstra ssc->count++; 8180ff27d31SJohn Polstra ssc->size += entry->end - entry->start; 8190ff27d31SJohn Polstra } 8200ff27d31SJohn Polstra 8210ff27d31SJohn Polstra /* 8220ff27d31SJohn Polstra * For each writable segment in the process's memory map, call the given 8230ff27d31SJohn Polstra * function with a pointer to the map entry and some arbitrary 8240ff27d31SJohn Polstra * caller-supplied data. 8250ff27d31SJohn Polstra */ 8260ff27d31SJohn Polstra static void 8270ff27d31SJohn Polstra each_writable_segment(p, func, closure) 8280ff27d31SJohn Polstra struct proc *p; 8290ff27d31SJohn Polstra segment_callback func; 8300ff27d31SJohn Polstra void *closure; 8310ff27d31SJohn Polstra { 8320ff27d31SJohn Polstra vm_map_t map = &p->p_vmspace->vm_map; 8330ff27d31SJohn Polstra vm_map_entry_t entry; 8340ff27d31SJohn Polstra 8350ff27d31SJohn Polstra for (entry = map->header.next; entry != &map->header; 8360ff27d31SJohn Polstra entry = entry->next) { 8370ff27d31SJohn Polstra vm_object_t obj; 8380ff27d31SJohn Polstra 8399fdfe602SMatthew Dillon if ((entry->eflags & MAP_ENTRY_IS_SUB_MAP) || 8400ff27d31SJohn Polstra (entry->protection & (VM_PROT_READ|VM_PROT_WRITE)) != 8410ff27d31SJohn Polstra (VM_PROT_READ|VM_PROT_WRITE)) 8420ff27d31SJohn Polstra continue; 8430ff27d31SJohn Polstra 8449730a5daSPaul Saab /* 84577ac690cSPaul Saab ** Dont include memory segment in the coredump if 84677ac690cSPaul Saab ** MAP_NOCORE is set in mmap(2) or MADV_NOCORE in 84777ac690cSPaul Saab ** madvise(2). 8489730a5daSPaul Saab */ 8499730a5daSPaul Saab if (entry->eflags & MAP_ENTRY_NOCOREDUMP) 8509730a5daSPaul Saab continue; 8519730a5daSPaul Saab 8520ff27d31SJohn Polstra if ((obj = entry->object.vm_object) == NULL) 8530ff27d31SJohn Polstra continue; 8540ff27d31SJohn Polstra 8550ff27d31SJohn Polstra /* Find the deepest backing object. */ 8560ff27d31SJohn Polstra while (obj->backing_object != NULL) 8570ff27d31SJohn Polstra obj = obj->backing_object; 8580ff27d31SJohn Polstra 8590ff27d31SJohn Polstra /* Ignore memory-mapped devices and such things. */ 8600ff27d31SJohn Polstra if (obj->type != OBJT_DEFAULT && 8610ff27d31SJohn Polstra obj->type != OBJT_SWAP && 8620ff27d31SJohn Polstra obj->type != OBJT_VNODE) 8630ff27d31SJohn Polstra continue; 8640ff27d31SJohn Polstra 8650ff27d31SJohn Polstra (*func)(entry, closure); 8660ff27d31SJohn Polstra } 8670ff27d31SJohn Polstra } 8680ff27d31SJohn Polstra 8690ff27d31SJohn Polstra /* 8700ff27d31SJohn Polstra * Write the core file header to the file, including padding up to 8710ff27d31SJohn Polstra * the page boundary. 8720ff27d31SJohn Polstra */ 8738c64af4fSJohn Polstra static int 8740ff27d31SJohn Polstra elf_corehdr(p, vp, cred, numsegs, hdr, hdrsize) 8758c64af4fSJohn Polstra struct proc *p; 8768c64af4fSJohn Polstra struct vnode *vp; 8778c64af4fSJohn Polstra struct ucred *cred; 8780ff27d31SJohn Polstra int numsegs; 8790ff27d31SJohn Polstra size_t hdrsize; 8800ff27d31SJohn Polstra void *hdr; 8818c64af4fSJohn Polstra { 8828c64af4fSJohn Polstra size_t off; 8838c64af4fSJohn Polstra prstatus_t status; 8848c64af4fSJohn Polstra prfpregset_t fpregset; 8858c64af4fSJohn Polstra prpsinfo_t psinfo; 8868c64af4fSJohn Polstra 8878c64af4fSJohn Polstra /* Gather the information for the header. */ 8888c64af4fSJohn Polstra bzero(&status, sizeof status); 8898c64af4fSJohn Polstra status.pr_version = PRSTATUS_VERSION; 8908c64af4fSJohn Polstra status.pr_statussz = sizeof(prstatus_t); 8918c64af4fSJohn Polstra status.pr_gregsetsz = sizeof(gregset_t); 8928c64af4fSJohn Polstra status.pr_fpregsetsz = sizeof(fpregset_t); 8938c64af4fSJohn Polstra status.pr_osreldate = osreldate; 8946626c604SJulian Elischer status.pr_cursig = p->p_sig; 8958c64af4fSJohn Polstra status.pr_pid = p->p_pid; 8968c64af4fSJohn Polstra fill_regs(p, &status.pr_reg); 8978c64af4fSJohn Polstra 8988c64af4fSJohn Polstra fill_fpregs(p, &fpregset); 8998c64af4fSJohn Polstra 9008c64af4fSJohn Polstra bzero(&psinfo, sizeof psinfo); 9018c64af4fSJohn Polstra psinfo.pr_version = PRPSINFO_VERSION; 9028c64af4fSJohn Polstra psinfo.pr_psinfosz = sizeof(prpsinfo_t); 9038c64af4fSJohn Polstra strncpy(psinfo.pr_fname, p->p_comm, MAXCOMLEN); 9040ff27d31SJohn Polstra /* XXX - We don't fill in the command line arguments properly yet. */ 9050ff27d31SJohn Polstra strncpy(psinfo.pr_psargs, p->p_comm, PRARGSZ); 9068c64af4fSJohn Polstra 9078c64af4fSJohn Polstra /* Fill in the header. */ 9080ff27d31SJohn Polstra bzero(hdr, hdrsize); 9098c64af4fSJohn Polstra off = 0; 9100ff27d31SJohn Polstra elf_puthdr(p, hdr, &off, &status, &fpregset, &psinfo, numsegs); 9118c64af4fSJohn Polstra 9128c64af4fSJohn Polstra /* Write it to the core file. */ 9130ff27d31SJohn Polstra return vn_rdwr(UIO_WRITE, vp, hdr, hdrsize, (off_t)0, 9148c64af4fSJohn Polstra UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, NULL, p); 915dada0278SJohn Polstra } 916dada0278SJohn Polstra 9178c64af4fSJohn Polstra static void 9180ff27d31SJohn Polstra elf_puthdr(struct proc *p, void *dst, size_t *off, const prstatus_t *status, 9190ff27d31SJohn Polstra const prfpregset_t *fpregset, const prpsinfo_t *psinfo, int numsegs) 9208c64af4fSJohn Polstra { 9218c64af4fSJohn Polstra size_t ehoff; 9228c64af4fSJohn Polstra size_t phoff; 9238c64af4fSJohn Polstra size_t noteoff; 9248c64af4fSJohn Polstra size_t notesz; 9258c64af4fSJohn Polstra 9268c64af4fSJohn Polstra ehoff = *off; 9278c64af4fSJohn Polstra *off += sizeof(Elf_Ehdr); 9288c64af4fSJohn Polstra 9298c64af4fSJohn Polstra phoff = *off; 9300ff27d31SJohn Polstra *off += (numsegs + 1) * sizeof(Elf_Phdr); 9318c64af4fSJohn Polstra 9328c64af4fSJohn Polstra noteoff = *off; 9338c64af4fSJohn Polstra elf_putnote(dst, off, "FreeBSD", NT_PRSTATUS, status, 9348c64af4fSJohn Polstra sizeof *status); 9358c64af4fSJohn Polstra elf_putnote(dst, off, "FreeBSD", NT_FPREGSET, fpregset, 9368c64af4fSJohn Polstra sizeof *fpregset); 9378c64af4fSJohn Polstra elf_putnote(dst, off, "FreeBSD", NT_PRPSINFO, psinfo, 9388c64af4fSJohn Polstra sizeof *psinfo); 9398c64af4fSJohn Polstra notesz = *off - noteoff; 9408c64af4fSJohn Polstra 9410ff27d31SJohn Polstra /* Align up to a page boundary for the program segments. */ 9428c64af4fSJohn Polstra *off = round_page(*off); 9438c64af4fSJohn Polstra 9448c64af4fSJohn Polstra if (dst != NULL) { 9458c64af4fSJohn Polstra Elf_Ehdr *ehdr; 9468c64af4fSJohn Polstra Elf_Phdr *phdr; 9470ff27d31SJohn Polstra struct phdr_closure phc; 9488c64af4fSJohn Polstra 9498c64af4fSJohn Polstra /* 9508c64af4fSJohn Polstra * Fill in the ELF header. 9518c64af4fSJohn Polstra */ 9528c64af4fSJohn Polstra ehdr = (Elf_Ehdr *)((char *)dst + ehoff); 9538c64af4fSJohn Polstra ehdr->e_ident[EI_MAG0] = ELFMAG0; 9548c64af4fSJohn Polstra ehdr->e_ident[EI_MAG1] = ELFMAG1; 9558c64af4fSJohn Polstra ehdr->e_ident[EI_MAG2] = ELFMAG2; 9568c64af4fSJohn Polstra ehdr->e_ident[EI_MAG3] = ELFMAG3; 9578c64af4fSJohn Polstra ehdr->e_ident[EI_CLASS] = ELF_CLASS; 9588c64af4fSJohn Polstra ehdr->e_ident[EI_DATA] = ELF_DATA; 9598c64af4fSJohn Polstra ehdr->e_ident[EI_VERSION] = EV_CURRENT; 960c815a20cSDavid E. O'Brien ehdr->e_ident[EI_OSABI] = ELFOSABI_FREEBSD; 961c815a20cSDavid E. O'Brien ehdr->e_ident[EI_ABIVERSION] = 0; 9628c64af4fSJohn Polstra ehdr->e_ident[EI_PAD] = 0; 9638c64af4fSJohn Polstra ehdr->e_type = ET_CORE; 9648c64af4fSJohn Polstra ehdr->e_machine = ELF_ARCH; 9658c64af4fSJohn Polstra ehdr->e_version = EV_CURRENT; 9668c64af4fSJohn Polstra ehdr->e_entry = 0; 9678c64af4fSJohn Polstra ehdr->e_phoff = phoff; 9688c64af4fSJohn Polstra ehdr->e_flags = 0; 9698c64af4fSJohn Polstra ehdr->e_ehsize = sizeof(Elf_Ehdr); 9708c64af4fSJohn Polstra ehdr->e_phentsize = sizeof(Elf_Phdr); 9710ff27d31SJohn Polstra ehdr->e_phnum = numsegs + 1; 9728c64af4fSJohn Polstra ehdr->e_shentsize = sizeof(Elf_Shdr); 9738c64af4fSJohn Polstra ehdr->e_shnum = 0; 9748c64af4fSJohn Polstra ehdr->e_shstrndx = SHN_UNDEF; 9758c64af4fSJohn Polstra 9768c64af4fSJohn Polstra /* 9778c64af4fSJohn Polstra * Fill in the program header entries. 9788c64af4fSJohn Polstra */ 9798c64af4fSJohn Polstra phdr = (Elf_Phdr *)((char *)dst + phoff); 9808c64af4fSJohn Polstra 9818c64af4fSJohn Polstra /* The note segement. */ 9828c64af4fSJohn Polstra phdr->p_type = PT_NOTE; 9838c64af4fSJohn Polstra phdr->p_offset = noteoff; 9848c64af4fSJohn Polstra phdr->p_vaddr = 0; 9858c64af4fSJohn Polstra phdr->p_paddr = 0; 9868c64af4fSJohn Polstra phdr->p_filesz = notesz; 9878c64af4fSJohn Polstra phdr->p_memsz = 0; 9888c64af4fSJohn Polstra phdr->p_flags = 0; 9898c64af4fSJohn Polstra phdr->p_align = 0; 9908c64af4fSJohn Polstra phdr++; 9918c64af4fSJohn Polstra 9920ff27d31SJohn Polstra /* All the writable segments from the program. */ 9930ff27d31SJohn Polstra phc.phdr = phdr; 9940ff27d31SJohn Polstra phc.offset = *off; 9950ff27d31SJohn Polstra each_writable_segment(p, cb_put_phdr, &phc); 9968c64af4fSJohn Polstra } 9978c64af4fSJohn Polstra } 9988c64af4fSJohn Polstra 9998c64af4fSJohn Polstra static void 10008c64af4fSJohn Polstra elf_putnote(void *dst, size_t *off, const char *name, int type, 10018c64af4fSJohn Polstra const void *desc, size_t descsz) 10028c64af4fSJohn Polstra { 10038c64af4fSJohn Polstra Elf_Note note; 10048c64af4fSJohn Polstra 10058c64af4fSJohn Polstra note.n_namesz = strlen(name) + 1; 10068c64af4fSJohn Polstra note.n_descsz = descsz; 10078c64af4fSJohn Polstra note.n_type = type; 10088c64af4fSJohn Polstra if (dst != NULL) 10098c64af4fSJohn Polstra bcopy(¬e, (char *)dst + *off, sizeof note); 10108c64af4fSJohn Polstra *off += sizeof note; 10118c64af4fSJohn Polstra if (dst != NULL) 10128c64af4fSJohn Polstra bcopy(name, (char *)dst + *off, note.n_namesz); 10138c64af4fSJohn Polstra *off += roundup2(note.n_namesz, sizeof(Elf_Size)); 10148c64af4fSJohn Polstra if (dst != NULL) 10158c64af4fSJohn Polstra bcopy(desc, (char *)dst + *off, note.n_descsz); 10168c64af4fSJohn Polstra *off += roundup2(note.n_descsz, sizeof(Elf_Size)); 10178c64af4fSJohn Polstra } 10188c64af4fSJohn Polstra 10198c64af4fSJohn Polstra /* 1020e1743d02SSøren Schmidt * Tell kern_execve.c about it, with a little help from the linker. 1021e1743d02SSøren Schmidt */ 1022820ca326SMatthew Dillon static struct execsw elf_execsw = {exec_elf_imgact, "ELF"}; 1023aa855a59SPeter Wemm EXEC_SET(elf, elf_execsw); 1024