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> 4135e0e5b3SJohn Baldwin #include <sys/mutex.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> 4836240ea5SDoug Rabson #include <sys/systm.h> 49e1743d02SSøren Schmidt #include <sys/signalvar.h> 508c64af4fSJohn Polstra #include <sys/stat.h> 518c64af4fSJohn Polstra #include <sys/syscall.h> 52e1743d02SSøren Schmidt #include <sys/sysctl.h> 538c64af4fSJohn Polstra #include <sys/sysent.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_extern.h> 64e1743d02SSøren Schmidt 6552c24af7SPeter Wemm #include <machine/elf.h> 66e1743d02SSøren Schmidt #include <machine/md_var.h> 67e1743d02SSøren Schmidt 68c815a20cSDavid E. O'Brien #define OLD_EI_BRAND 8 69c815a20cSDavid E. O'Brien 7052c24af7SPeter Wemm __ElfType(Brandinfo); 7152c24af7SPeter Wemm __ElfType(Auxargs); 72ecbb00a2SDoug Rabson 73c33fe779SJohn Polstra static int elf_check_header __P((const Elf_Ehdr *hdr)); 74654f6be1SBruce Evans static int elf_freebsd_fixup __P((register_t **stack_base, 758c64af4fSJohn Polstra struct image_params *imgp)); 76bdbc8c26SPeter Wemm static int elf_load_file __P((struct proc *p, const char *file, u_long *addr, 778c64af4fSJohn Polstra u_long *entry)); 7852c24af7SPeter Wemm static int elf_load_section __P((struct proc *p, 7952c24af7SPeter Wemm struct vmspace *vmspace, struct vnode *vp, 808c64af4fSJohn Polstra vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, 818c64af4fSJohn Polstra vm_prot_t prot)); 82303b270bSEivind Eklund static int exec_elf_imgact __P((struct image_params *imgp)); 83e1743d02SSøren Schmidt 84d8a4f230SBruce Evans static int elf_trace = 0; 85d8a4f230SBruce Evans SYSCTL_INT(_debug, OID_AUTO, elf_trace, CTLFLAG_RW, &elf_trace, 0, ""); 86e1743d02SSøren Schmidt 8700910f28SDavid E. O'Brien struct sysentvec elf_freebsd_sysvec = { 88e1743d02SSøren Schmidt SYS_MAXSYSCALL, 89e1743d02SSøren Schmidt sysent, 90e1743d02SSøren Schmidt 0, 91e1743d02SSøren Schmidt 0, 92e1743d02SSøren Schmidt 0, 93e1743d02SSøren Schmidt 0, 94e1743d02SSøren Schmidt 0, 95288078beSEivind Eklund 0, 96e1743d02SSøren Schmidt elf_freebsd_fixup, 97e1743d02SSøren Schmidt sendsig, 98e1743d02SSøren Schmidt sigcode, 99e1743d02SSøren Schmidt &szsigcode, 100e1743d02SSøren Schmidt 0, 10122d4b0fbSJohn Polstra "FreeBSD ELF", 102806d7daaSMarcel Moolenaar elf_coredump, 103806d7daaSMarcel Moolenaar NULL, 104806d7daaSMarcel Moolenaar MINSIGSTKSZ 105e1743d02SSøren Schmidt }; 106e1743d02SSøren Schmidt 107ecbb00a2SDoug Rabson static Elf_Brandinfo freebsd_brand_info = { 108c815a20cSDavid E. O'Brien ELFOSABI_FREEBSD, 109ea5a2b2eSSøren Schmidt "", 110e1743d02SSøren Schmidt "/usr/libexec/ld-elf.so.1", 111ea5a2b2eSSøren Schmidt &elf_freebsd_sysvec 112e1743d02SSøren Schmidt }; 113ecbb00a2SDoug Rabson static Elf_Brandinfo *elf_brand_list[MAX_BRANDS] = { 114ea5a2b2eSSøren Schmidt &freebsd_brand_info, 115e1743d02SSøren Schmidt NULL, NULL, NULL, 116e1743d02SSøren Schmidt NULL, NULL, NULL, NULL 117e1743d02SSøren Schmidt }; 118e1743d02SSøren Schmidt 119e1743d02SSøren Schmidt int 120ecbb00a2SDoug Rabson elf_insert_brand_entry(Elf_Brandinfo *entry) 121e1743d02SSøren Schmidt { 122e1743d02SSøren Schmidt int i; 123e1743d02SSøren Schmidt 124ea5a2b2eSSøren Schmidt for (i=1; i<MAX_BRANDS; i++) { 125ea5a2b2eSSøren Schmidt if (elf_brand_list[i] == NULL) { 126ea5a2b2eSSøren Schmidt elf_brand_list[i] = entry; 127e1743d02SSøren Schmidt break; 128e1743d02SSøren Schmidt } 129e1743d02SSøren Schmidt } 130ea5a2b2eSSøren Schmidt if (i == MAX_BRANDS) 131e1743d02SSøren Schmidt return -1; 132e1743d02SSøren Schmidt return 0; 133e1743d02SSøren Schmidt } 134e1743d02SSøren Schmidt 135e1743d02SSøren Schmidt int 136ecbb00a2SDoug Rabson elf_remove_brand_entry(Elf_Brandinfo *entry) 137e1743d02SSøren Schmidt { 138e1743d02SSøren Schmidt int i; 139e1743d02SSøren Schmidt 140ea5a2b2eSSøren Schmidt for (i=1; i<MAX_BRANDS; i++) { 141ea5a2b2eSSøren Schmidt if (elf_brand_list[i] == entry) { 142ea5a2b2eSSøren Schmidt elf_brand_list[i] = NULL; 143e1743d02SSøren Schmidt break; 144e1743d02SSøren Schmidt } 145e1743d02SSøren Schmidt } 146ea5a2b2eSSøren Schmidt if (i == MAX_BRANDS) 147e1743d02SSøren Schmidt return -1; 148e1743d02SSøren Schmidt return 0; 149e1743d02SSøren Schmidt } 150e1743d02SSøren Schmidt 151096977faSMark Newton int 152096977faSMark Newton elf_brand_inuse(Elf_Brandinfo *entry) 153096977faSMark Newton { 154096977faSMark Newton struct proc *p; 155553629ebSJake Burkholder int rval = FALSE; 156096977faSMark Newton 157553629ebSJake Burkholder lockmgr(&allproc_lock, LK_SHARED, NULL, CURPROC); 1582e3c8fcbSPoul-Henning Kamp LIST_FOREACH(p, &allproc, p_list) { 159553629ebSJake Burkholder if (p->p_sysent == entry->sysvec) { 160553629ebSJake Burkholder rval = TRUE; 161553629ebSJake Burkholder break; 162096977faSMark Newton } 163553629ebSJake Burkholder } 164553629ebSJake Burkholder lockmgr(&allproc_lock, LK_RELEASE, NULL, CURPROC); 165096977faSMark Newton 166553629ebSJake Burkholder return (rval); 167096977faSMark Newton } 168096977faSMark Newton 169e1743d02SSøren Schmidt static int 170c33fe779SJohn Polstra elf_check_header(const Elf_Ehdr *hdr) 171e1743d02SSøren Schmidt { 17252c24af7SPeter Wemm if (!IS_ELF(*hdr) || 17352c24af7SPeter Wemm hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || 17452c24af7SPeter Wemm hdr->e_ident[EI_DATA] != ELF_TARG_DATA || 17552c24af7SPeter Wemm hdr->e_ident[EI_VERSION] != EV_CURRENT) 176e1743d02SSøren Schmidt return ENOEXEC; 177e1743d02SSøren Schmidt 17852c24af7SPeter Wemm if (!ELF_MACHINE_OK(hdr->e_machine)) 179e1743d02SSøren Schmidt return ENOEXEC; 180e1743d02SSøren Schmidt 181c33fe779SJohn Polstra if (hdr->e_version != ELF_TARG_VER) 182e1743d02SSøren Schmidt return ENOEXEC; 183e1743d02SSøren Schmidt 184e1743d02SSøren Schmidt return 0; 185e1743d02SSøren Schmidt } 186e1743d02SSøren Schmidt 187e1743d02SSøren Schmidt static int 18852c24af7SPeter 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) 189e1743d02SSøren Schmidt { 190e1743d02SSøren Schmidt size_t map_len; 191e1743d02SSøren Schmidt vm_offset_t map_addr; 19252c24af7SPeter Wemm int error, rv; 193e1743d02SSøren Schmidt size_t copy_len; 19452c24af7SPeter Wemm vm_object_t object; 19552c24af7SPeter Wemm vm_offset_t file_addr; 19652c24af7SPeter Wemm vm_offset_t data_buf = 0; 19752c24af7SPeter Wemm 1989ff5ce6bSBoris Popov VOP_GETVOBJECT(vp, &object); 19952c24af7SPeter Wemm error = 0; 200e1743d02SSøren Schmidt 20125ead034SBrian Feldman /* 20225ead034SBrian Feldman * It's necessary to fail if the filsz + offset taken from the 20325ead034SBrian Feldman * header is greater than the actual file pager object's size. 20425ead034SBrian Feldman * If we were to allow this, then the vm_map_find() below would 20525ead034SBrian Feldman * walk right off the end of the file object and into the ether. 20625ead034SBrian Feldman * 20725ead034SBrian Feldman * While I'm here, might as well check for something else that 20825ead034SBrian Feldman * is invalid: filsz cannot be greater than memsz. 20925ead034SBrian Feldman */ 21025ead034SBrian Feldman if ((off_t)filsz + offset > object->un_pager.vnp.vnp_size || 21125ead034SBrian Feldman filsz > memsz) { 21225ead034SBrian Feldman uprintf("elf_load_section: truncated ELF file\n"); 21325ead034SBrian Feldman return (ENOEXEC); 21425ead034SBrian Feldman } 21525ead034SBrian Feldman 2166cde7a16SDavid Greenman map_addr = trunc_page((vm_offset_t)vmaddr); 21752c24af7SPeter Wemm file_addr = trunc_page(offset); 218e1743d02SSøren Schmidt 219e1743d02SSøren Schmidt /* 22052c24af7SPeter Wemm * We have two choices. We can either clear the data in the last page 22152c24af7SPeter Wemm * of an oversized mapping, or we can start the anon mapping a page 22252c24af7SPeter Wemm * early and copy the initialized data into that first page. We 22352c24af7SPeter Wemm * choose the second.. 22452c24af7SPeter Wemm */ 22552c24af7SPeter Wemm if (memsz > filsz) 22652c24af7SPeter Wemm map_len = trunc_page(offset+filsz) - file_addr; 22752c24af7SPeter Wemm else 22852c24af7SPeter Wemm map_len = round_page(offset+filsz) - file_addr; 22952c24af7SPeter Wemm 23052c24af7SPeter Wemm if (map_len != 0) { 23152c24af7SPeter Wemm vm_object_reference(object); 23252c24af7SPeter Wemm vm_map_lock(&vmspace->vm_map); 23352c24af7SPeter Wemm rv = vm_map_insert(&vmspace->vm_map, 23452c24af7SPeter Wemm object, 23552c24af7SPeter Wemm file_addr, /* file offset */ 23652c24af7SPeter Wemm map_addr, /* virtual start */ 23752c24af7SPeter Wemm map_addr + map_len,/* virtual end */ 23852c24af7SPeter Wemm prot, 23952c24af7SPeter Wemm VM_PROT_ALL, 240e972780aSAlan Cox MAP_COPY_ON_WRITE | MAP_PREFAULT); 24152c24af7SPeter Wemm vm_map_unlock(&vmspace->vm_map); 242a3021f91SBoris Popov if (rv != KERN_SUCCESS) { 243a3021f91SBoris Popov vm_object_deallocate(object); 24452c24af7SPeter Wemm return EINVAL; 245a3021f91SBoris Popov } 24652c24af7SPeter Wemm 24752c24af7SPeter Wemm /* we can stop now if we've covered it all */ 24852c24af7SPeter Wemm if (memsz == filsz) 24952c24af7SPeter Wemm return 0; 25052c24af7SPeter Wemm } 25152c24af7SPeter Wemm 25252c24af7SPeter Wemm 25352c24af7SPeter Wemm /* 25452c24af7SPeter Wemm * We have to get the remaining bit of the file into the first part 25552c24af7SPeter Wemm * of the oversized map segment. This is normally because the .data 25652c24af7SPeter Wemm * segment in the file is extended to provide bss. It's a neat idea 25752c24af7SPeter Wemm * to try and save a page, but it's a pain in the behind to implement. 258e1743d02SSøren Schmidt */ 259e1743d02SSøren Schmidt copy_len = (offset + filsz) - trunc_page(offset + filsz); 2606cde7a16SDavid Greenman map_addr = trunc_page((vm_offset_t)vmaddr + filsz); 2616cde7a16SDavid Greenman map_len = round_page((vm_offset_t)vmaddr + memsz) - map_addr; 262e1743d02SSøren Schmidt 26352c24af7SPeter Wemm /* This had damn well better be true! */ 2648191d577SPeter Wemm if (map_len != 0) { 26552c24af7SPeter Wemm vm_map_lock(&vmspace->vm_map); 26652c24af7SPeter Wemm rv = vm_map_insert(&vmspace->vm_map, NULL, 0, 26752c24af7SPeter Wemm map_addr, map_addr + map_len, 26852c24af7SPeter Wemm VM_PROT_ALL, VM_PROT_ALL, 0); 26952c24af7SPeter Wemm vm_map_unlock(&vmspace->vm_map); 27052c24af7SPeter Wemm if (rv != KERN_SUCCESS) 27152c24af7SPeter Wemm return EINVAL; 2728191d577SPeter Wemm } 273e1743d02SSøren Schmidt 27452c24af7SPeter Wemm if (copy_len != 0) { 27552c24af7SPeter Wemm vm_object_reference(object); 27652c24af7SPeter Wemm rv = vm_map_find(exec_map, 27752c24af7SPeter Wemm object, 27852c24af7SPeter Wemm trunc_page(offset + filsz), 27952c24af7SPeter Wemm &data_buf, 280e1743d02SSøren Schmidt PAGE_SIZE, 28152c24af7SPeter Wemm TRUE, 282e1743d02SSøren Schmidt VM_PROT_READ, 28352c24af7SPeter Wemm VM_PROT_ALL, 284e972780aSAlan Cox MAP_COPY_ON_WRITE | MAP_PREFAULT_PARTIAL); 28552c24af7SPeter Wemm if (rv != KERN_SUCCESS) { 28652c24af7SPeter Wemm vm_object_deallocate(object); 28752c24af7SPeter Wemm return EINVAL; 28852c24af7SPeter Wemm } 289e1743d02SSøren Schmidt 29052c24af7SPeter Wemm /* send the page fragment to user space */ 29152c24af7SPeter Wemm error = copyout((caddr_t)data_buf, (caddr_t)map_addr, copy_len); 29252c24af7SPeter Wemm vm_map_remove(exec_map, data_buf, data_buf + PAGE_SIZE); 29352c24af7SPeter Wemm if (error) 29452c24af7SPeter Wemm return (error); 29552c24af7SPeter Wemm } 296e1743d02SSøren Schmidt 297e1743d02SSøren Schmidt /* 2988191d577SPeter Wemm * set it to the specified protection 299e1743d02SSøren Schmidt */ 3008191d577SPeter Wemm vm_map_protect(&vmspace->vm_map, map_addr, map_addr + map_len, prot, 3018191d577SPeter Wemm FALSE); 3028191d577SPeter Wemm 303e1743d02SSøren Schmidt return error; 304e1743d02SSøren Schmidt } 305e1743d02SSøren Schmidt 306c33fe779SJohn Polstra /* 307c33fe779SJohn Polstra * Load the file "file" into memory. It may be either a shared object 308c33fe779SJohn Polstra * or an executable. 309c33fe779SJohn Polstra * 310c33fe779SJohn Polstra * The "addr" reference parameter is in/out. On entry, it specifies 311c33fe779SJohn Polstra * the address where a shared object should be loaded. If the file is 312c33fe779SJohn Polstra * an executable, this value is ignored. On exit, "addr" specifies 313c33fe779SJohn Polstra * where the file was actually loaded. 314c33fe779SJohn Polstra * 315c33fe779SJohn Polstra * The "entry" reference parameter is out only. On exit, it specifies 316c33fe779SJohn Polstra * the entry point for the loaded file. 317c33fe779SJohn Polstra */ 318e1743d02SSøren Schmidt static int 319bdbc8c26SPeter Wemm elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry) 320e1743d02SSøren Schmidt { 321d254af07SMatthew Dillon const Elf_Ehdr *hdr = NULL; 322d254af07SMatthew Dillon const Elf_Phdr *phdr = NULL; 323e1743d02SSøren Schmidt struct nameidata nd; 324e1743d02SSøren Schmidt struct vmspace *vmspace = p->p_vmspace; 325c8a79999SPeter Wemm struct vattr attr; 326c8a79999SPeter Wemm struct image_params image_params, *imgp; 32752c24af7SPeter Wemm vm_prot_t prot; 328c33fe779SJohn Polstra u_long rbase; 329c33fe779SJohn Polstra u_long base_addr = 0; 330c33fe779SJohn Polstra int error, i, numsegs; 331e1743d02SSøren Schmidt 332c8a79999SPeter Wemm imgp = &image_params; 333c8a79999SPeter Wemm /* 334c8a79999SPeter Wemm * Initialize part of the common data 335c8a79999SPeter Wemm */ 336c8a79999SPeter Wemm imgp->proc = p; 337c8a79999SPeter Wemm imgp->uap = NULL; 338c8a79999SPeter Wemm imgp->attr = &attr; 339c8a79999SPeter Wemm imgp->firstpage = NULL; 340c8a79999SPeter Wemm imgp->image_header = (char *)kmem_alloc_wait(exec_map, PAGE_SIZE); 341c8a79999SPeter Wemm 342c8a79999SPeter Wemm if (imgp->image_header == NULL) { 343c8a79999SPeter Wemm nd.ni_vp = NULL; 344c8a79999SPeter Wemm error = ENOMEM; 345c8a79999SPeter Wemm goto fail; 346c8a79999SPeter Wemm } 347c8a79999SPeter Wemm 348e1743d02SSøren Schmidt NDINIT(&nd, LOOKUP, LOCKLEAF|FOLLOW, UIO_SYSSPACE, file, p); 349e1743d02SSøren Schmidt 350d254af07SMatthew Dillon if ((error = namei(&nd)) != 0) { 3511560a9d5SPeter Wemm nd.ni_vp = NULL; 352e1743d02SSøren Schmidt goto fail; 353e1743d02SSøren Schmidt } 354762e6b85SEivind Eklund NDFREE(&nd, NDF_ONLY_PNBUF); 355c8a79999SPeter Wemm imgp->vp = nd.ni_vp; 356c8a79999SPeter Wemm 357e1743d02SSøren Schmidt /* 358e1743d02SSøren Schmidt * Check permissions, modes, uid, etc on the file, and "open" it. 359e1743d02SSøren Schmidt */ 360c8a79999SPeter Wemm error = exec_check_permissions(imgp); 361c8a79999SPeter Wemm if (error) { 362996c772fSJohn Dyson VOP_UNLOCK(nd.ni_vp, 0, p); 363c8a79999SPeter Wemm goto fail; 364c8a79999SPeter Wemm } 365e1743d02SSøren Schmidt 366c8a79999SPeter Wemm error = exec_map_first_page(imgp); 36725ead034SBrian Feldman /* 36825ead034SBrian Feldman * Also make certain that the interpreter stays the same, so set 36925ead034SBrian Feldman * its VTEXT flag, too. 37025ead034SBrian Feldman */ 37125ead034SBrian Feldman if (error == 0) 37225ead034SBrian Feldman nd.ni_vp->v_flag |= VTEXT; 373c8a79999SPeter Wemm VOP_UNLOCK(nd.ni_vp, 0, p); 374e1743d02SSøren Schmidt if (error) 375e1743d02SSøren Schmidt goto fail; 376e1743d02SSøren Schmidt 377d254af07SMatthew Dillon hdr = (const Elf_Ehdr *)imgp->image_header; 378c33fe779SJohn Polstra if ((error = elf_check_header(hdr)) != 0) 379e1743d02SSøren Schmidt goto fail; 380c33fe779SJohn Polstra if (hdr->e_type == ET_DYN) 381c33fe779SJohn Polstra rbase = *addr; 382c33fe779SJohn Polstra else if (hdr->e_type == ET_EXEC) 383c33fe779SJohn Polstra rbase = 0; 384c33fe779SJohn Polstra else { 385c33fe779SJohn Polstra error = ENOEXEC; 386c33fe779SJohn Polstra goto fail; 387c33fe779SJohn Polstra } 388e1743d02SSøren Schmidt 389c8a79999SPeter Wemm /* Only support headers that fit within first page for now */ 39052c24af7SPeter Wemm if ((hdr->e_phoff > PAGE_SIZE) || 39152c24af7SPeter Wemm (hdr->e_phoff + hdr->e_phentsize * hdr->e_phnum) > PAGE_SIZE) { 392c8a79999SPeter Wemm error = ENOEXEC; 393e1743d02SSøren Schmidt goto fail; 394c8a79999SPeter Wemm } 395c8a79999SPeter Wemm 396d254af07SMatthew Dillon phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff); 397e1743d02SSøren Schmidt 398c33fe779SJohn Polstra for (i = 0, numsegs = 0; i < hdr->e_phnum; i++) { 39952c24af7SPeter Wemm if (phdr[i].p_type == PT_LOAD) { /* Loadable segment */ 40052c24af7SPeter Wemm prot = 0; 401e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_X) 402e1743d02SSøren Schmidt prot |= VM_PROT_EXECUTE; 403e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_W) 404e1743d02SSøren Schmidt prot |= VM_PROT_WRITE; 405e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_R) 406e1743d02SSøren Schmidt prot |= VM_PROT_READ; 407e1743d02SSøren Schmidt 408d254af07SMatthew Dillon if ((error = elf_load_section(p, vmspace, nd.ni_vp, 409e1743d02SSøren Schmidt phdr[i].p_offset, 410e1743d02SSøren Schmidt (caddr_t)phdr[i].p_vaddr + 411c33fe779SJohn Polstra rbase, 412e1743d02SSøren Schmidt phdr[i].p_memsz, 413d254af07SMatthew Dillon phdr[i].p_filesz, prot)) != 0) 414e1743d02SSøren Schmidt goto fail; 415e1743d02SSøren Schmidt /* 416c33fe779SJohn Polstra * Establish the base address if this is the 417c33fe779SJohn Polstra * first segment. 418e1743d02SSøren Schmidt */ 419c33fe779SJohn Polstra if (numsegs == 0) 420c33fe779SJohn Polstra base_addr = trunc_page(phdr[i].p_vaddr + rbase); 421c33fe779SJohn Polstra numsegs++; 422e1743d02SSøren Schmidt } 423e1743d02SSøren Schmidt } 424c33fe779SJohn Polstra *addr = base_addr; 425c33fe779SJohn Polstra *entry=(unsigned long)hdr->e_entry + rbase; 426e1743d02SSøren Schmidt 427e1743d02SSøren Schmidt fail: 428c8a79999SPeter Wemm if (imgp->firstpage) 429c8a79999SPeter Wemm exec_unmap_first_page(imgp); 430c8a79999SPeter Wemm if (imgp->image_header) 431c8a79999SPeter Wemm kmem_free_wakeup(exec_map, (vm_offset_t)imgp->image_header, 432c8a79999SPeter Wemm PAGE_SIZE); 4331560a9d5SPeter Wemm if (nd.ni_vp) 4341560a9d5SPeter Wemm vrele(nd.ni_vp); 435e1743d02SSøren Schmidt 436e1743d02SSøren Schmidt return error; 437e1743d02SSøren Schmidt } 438e1743d02SSøren Schmidt 439c815a20cSDavid E. O'Brien static int fallback_elf_brand = ELFOSABI_FREEBSD; 440c815a20cSDavid E. O'Brien SYSCTL_INT(_kern, OID_AUTO, fallback_elf_brand, CTLFLAG_RW, 441c815a20cSDavid E. O'Brien &fallback_elf_brand, ELFOSABI_FREEBSD, 442f8b3601eSMark Newton "ELF brand of last resort"); 443f8b3601eSMark Newton 444303b270bSEivind Eklund static int 445e1743d02SSøren Schmidt exec_elf_imgact(struct image_params *imgp) 446e1743d02SSøren Schmidt { 447ecbb00a2SDoug Rabson const Elf_Ehdr *hdr = (const Elf_Ehdr *) imgp->image_header; 448f5ef029eSPoul-Henning Kamp const Elf_Phdr *phdr; 449ecbb00a2SDoug Rabson Elf_Auxargs *elf_auxargs = NULL; 4505856e12eSJohn Dyson struct vmspace *vmspace; 45152c24af7SPeter Wemm vm_prot_t prot; 452e1743d02SSøren Schmidt u_long text_size = 0, data_size = 0; 453e1743d02SSøren Schmidt u_long text_addr = 0, data_addr = 0; 454e1743d02SSøren Schmidt u_long addr, entry = 0, proghdr = 0; 45552c24af7SPeter Wemm int error, i; 456c8a79999SPeter Wemm const char *interp = NULL; 457d1dbc694SJohn Polstra Elf_Brandinfo *brand_info; 458ea5a2b2eSSøren Schmidt char path[MAXPATHLEN]; 459e1743d02SSøren Schmidt 460e1743d02SSøren Schmidt /* 461e1743d02SSøren Schmidt * Do we have a valid ELF header ? 462e1743d02SSøren Schmidt */ 463c33fe779SJohn Polstra if (elf_check_header(hdr) != 0 || hdr->e_type != ET_EXEC) 464e1743d02SSøren Schmidt return -1; 465e1743d02SSøren Schmidt 466e1743d02SSøren Schmidt /* 467e1743d02SSøren Schmidt * From here on down, we return an errno, not -1, as we've 468e1743d02SSøren Schmidt * detected an ELF file. 469e1743d02SSøren Schmidt */ 470e1743d02SSøren Schmidt 471e1743d02SSøren Schmidt if ((hdr->e_phoff > PAGE_SIZE) || 47252c24af7SPeter Wemm (hdr->e_phoff + hdr->e_phentsize * hdr->e_phnum) > PAGE_SIZE) { 473c8a79999SPeter Wemm /* Only support headers in first page for now */ 474c8a79999SPeter Wemm return ENOEXEC; 475e1743d02SSøren Schmidt } 47652c24af7SPeter Wemm phdr = (const Elf_Phdr*)(imgp->image_header + hdr->e_phoff); 477e1743d02SSøren Schmidt 478e1743d02SSøren Schmidt /* 479e1743d02SSøren Schmidt * From this point on, we may have resources that need to be freed. 480e1743d02SSøren Schmidt */ 48125ead034SBrian Feldman 48225ead034SBrian Feldman /* 48325ead034SBrian Feldman * Yeah, I'm paranoid. There is every reason in the world to get 48425ead034SBrian Feldman * VTEXT now since from here on out, there are places we can have 48525ead034SBrian Feldman * a context switch. Better safe than sorry; I really don't want 48625ead034SBrian Feldman * the file to change while it's being loaded. 48725ead034SBrian Feldman */ 488a18b1f1dSJason Evans mtx_enter(&imgp->vp->v_interlock, MTX_DEF); 48955af4c7dSBrian Feldman imgp->vp->v_flag |= VTEXT; 490a18b1f1dSJason Evans mtx_exit(&imgp->vp->v_interlock, MTX_DEF); 49125ead034SBrian Feldman 492d254af07SMatthew Dillon if ((error = exec_extract_strings(imgp)) != 0) 493e1743d02SSøren Schmidt goto fail; 494e1743d02SSøren Schmidt 495e1743d02SSøren Schmidt exec_new_vmspace(imgp); 496e1743d02SSøren Schmidt 4975856e12eSJohn Dyson vmspace = imgp->proc->p_vmspace; 4985856e12eSJohn Dyson 499e1743d02SSøren Schmidt for (i = 0; i < hdr->e_phnum; i++) { 500e1743d02SSøren Schmidt switch(phdr[i].p_type) { 501e1743d02SSøren Schmidt 502e1743d02SSøren Schmidt case PT_LOAD: /* Loadable segment */ 50352c24af7SPeter Wemm prot = 0; 504e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_X) 505e1743d02SSøren Schmidt prot |= VM_PROT_EXECUTE; 506e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_W) 507e1743d02SSøren Schmidt prot |= VM_PROT_WRITE; 508e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_R) 509e1743d02SSøren Schmidt prot |= VM_PROT_READ; 510e1743d02SSøren Schmidt 511d254af07SMatthew Dillon if ((error = elf_load_section(imgp->proc, 51252c24af7SPeter Wemm vmspace, imgp->vp, 513e1743d02SSøren Schmidt phdr[i].p_offset, 514e1743d02SSøren Schmidt (caddr_t)phdr[i].p_vaddr, 515e1743d02SSøren Schmidt phdr[i].p_memsz, 516d254af07SMatthew Dillon phdr[i].p_filesz, prot)) != 0) 517e1743d02SSøren Schmidt goto fail; 518e1743d02SSøren Schmidt 519e1743d02SSøren Schmidt /* 520e1743d02SSøren Schmidt * Is this .text or .data ?? 521e1743d02SSøren Schmidt * 522e1743d02SSøren Schmidt * We only handle one each of those yet XXX 523e1743d02SSøren Schmidt */ 524e1743d02SSøren Schmidt if (hdr->e_entry >= phdr[i].p_vaddr && 525e1743d02SSøren Schmidt hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) { 526e1743d02SSøren Schmidt text_addr = trunc_page(phdr[i].p_vaddr); 5278191d577SPeter Wemm text_size = round_page(phdr[i].p_memsz + 5288191d577SPeter Wemm phdr[i].p_vaddr - 5298191d577SPeter Wemm text_addr); 530e1743d02SSøren Schmidt entry = (u_long)hdr->e_entry; 531e1743d02SSøren Schmidt } else { 532e1743d02SSøren Schmidt data_addr = trunc_page(phdr[i].p_vaddr); 5338191d577SPeter Wemm data_size = round_page(phdr[i].p_memsz + 5348191d577SPeter Wemm phdr[i].p_vaddr - 5358191d577SPeter Wemm data_addr); 536e1743d02SSøren Schmidt } 537e1743d02SSøren Schmidt break; 538e1743d02SSøren Schmidt case PT_INTERP: /* Path to interpreter */ 539c8a79999SPeter Wemm if (phdr[i].p_filesz > MAXPATHLEN || 540c8a79999SPeter Wemm phdr[i].p_offset + phdr[i].p_filesz > PAGE_SIZE) { 541e1743d02SSøren Schmidt error = ENOEXEC; 542e1743d02SSøren Schmidt goto fail; 543e1743d02SSøren Schmidt } 544c8a79999SPeter Wemm interp = imgp->image_header + phdr[i].p_offset; 545e1743d02SSøren Schmidt break; 546e1743d02SSøren Schmidt case PT_PHDR: /* Program header table info */ 547e1743d02SSøren Schmidt proghdr = phdr[i].p_vaddr; 548e1743d02SSøren Schmidt break; 549e1743d02SSøren Schmidt default: 55052c24af7SPeter Wemm break; 551e1743d02SSøren Schmidt } 552e1743d02SSøren Schmidt } 553e1743d02SSøren Schmidt 554e1743d02SSøren Schmidt vmspace->vm_tsize = text_size >> PAGE_SHIFT; 5557cd99438SBruce Evans vmspace->vm_taddr = (caddr_t)(uintptr_t)text_addr; 556e1743d02SSøren Schmidt vmspace->vm_dsize = data_size >> PAGE_SHIFT; 5577cd99438SBruce Evans vmspace->vm_daddr = (caddr_t)(uintptr_t)data_addr; 558e1743d02SSøren Schmidt 55947633640SJohn Polstra addr = ELF_RTLD_ADDR(vmspace); 560e1743d02SSøren Schmidt 561ea5a2b2eSSøren Schmidt imgp->entry_addr = entry; 562ea5a2b2eSSøren Schmidt 563d1dbc694SJohn Polstra brand_info = NULL; 564c815a20cSDavid E. O'Brien 565c815a20cSDavid E. O'Brien /* XXX For now we look for the magic "FreeBSD" that we used to put 566c815a20cSDavid E. O'Brien * into the ELF header at the EI_ABIVERSION location. If found use 567c815a20cSDavid E. O'Brien * that information rather than figuring out the ABI from proper 568c815a20cSDavid E. O'Brien * branding. This should be removed for 5.0-RELEASE. The Linux caes 569c815a20cSDavid E. O'Brien * can be figured out from the `interp_path' field. 570c815a20cSDavid E. O'Brien */ 571c815a20cSDavid E. O'Brien if (strcmp("FreeBSD", (const char *)&hdr->e_ident[OLD_EI_BRAND]) == 0) 572c815a20cSDavid E. O'Brien brand_info = &freebsd_brand_info; 573c815a20cSDavid E. O'Brien 574c815a20cSDavid E. O'Brien /* If the executable has a brand, search for it in the brand list. */ 575c815a20cSDavid E. O'Brien if (brand_info == NULL) { 576ea5a2b2eSSøren Schmidt for (i = 0; i < MAX_BRANDS; i++) { 577d1dbc694SJohn Polstra Elf_Brandinfo *bi = elf_brand_list[i]; 578d1dbc694SJohn Polstra 579c815a20cSDavid E. O'Brien if (bi != NULL && hdr->e_ident[EI_OSABI] == bi->brand) { 580d1dbc694SJohn Polstra brand_info = bi; 581e1743d02SSøren Schmidt break; 582e1743d02SSøren Schmidt } 583e1743d02SSøren Schmidt } 584e1743d02SSøren Schmidt } 585ea5a2b2eSSøren Schmidt 586d1dbc694SJohn Polstra /* Lacking a known brand, search for a recognized interpreter. */ 587d1dbc694SJohn Polstra if (brand_info == NULL && interp != NULL) { 588ea5a2b2eSSøren Schmidt for (i = 0; i < MAX_BRANDS; i++) { 589d1dbc694SJohn Polstra Elf_Brandinfo *bi = elf_brand_list[i]; 590d1dbc694SJohn Polstra 591d1dbc694SJohn Polstra if (bi != NULL && 592d1dbc694SJohn Polstra strcmp(interp, bi->interp_path) == 0) { 593d1dbc694SJohn Polstra brand_info = bi; 594d672246bSSøren Schmidt break; 595ea5a2b2eSSøren Schmidt } 596ea5a2b2eSSøren Schmidt } 597ea5a2b2eSSøren Schmidt } 598d1dbc694SJohn Polstra 599f8b3601eSMark Newton /* Lacking a recognized interpreter, try the default brand */ 600c815a20cSDavid E. O'Brien if (brand_info == NULL) { 601f8b3601eSMark Newton for (i = 0; i < MAX_BRANDS; i++) { 602f8b3601eSMark Newton Elf_Brandinfo *bi = elf_brand_list[i]; 603f8b3601eSMark Newton 604c815a20cSDavid E. O'Brien if (bi != NULL && fallback_elf_brand == bi->brand) { 605f8b3601eSMark Newton brand_info = bi; 606f8b3601eSMark Newton break; 607f8b3601eSMark Newton } 608f8b3601eSMark Newton } 609f8b3601eSMark Newton } 610f8b3601eSMark Newton 611c815a20cSDavid E. O'Brien /* XXX - Assume FreeBSD after the branding method change. */ 612d1dbc694SJohn Polstra if (brand_info == NULL) 613d1dbc694SJohn Polstra brand_info = &freebsd_brand_info; 614d1dbc694SJohn Polstra 615d1dbc694SJohn Polstra if (brand_info == NULL) { 616c815a20cSDavid E. O'Brien uprintf("ELF binary type \"%u\" not known.\n", 617c815a20cSDavid E. O'Brien hdr->e_ident[EI_OSABI]); 618e1743d02SSøren Schmidt error = ENOEXEC; 619e1743d02SSøren Schmidt goto fail; 620d1dbc694SJohn Polstra } 621d1dbc694SJohn Polstra 622d1dbc694SJohn Polstra imgp->proc->p_sysent = brand_info->sysvec; 623d1dbc694SJohn Polstra if (interp != NULL) { 6242127f260SArchie Cobbs snprintf(path, sizeof(path), "%s%s", 6252127f260SArchie Cobbs brand_info->emul_path, interp); 626d1dbc694SJohn Polstra if ((error = elf_load_file(imgp->proc, path, &addr, 627d1dbc694SJohn Polstra &imgp->entry_addr)) != 0) { 628bdbc8c26SPeter Wemm if ((error = elf_load_file(imgp->proc, interp, &addr, 6297a583b02SMarcel Moolenaar &imgp->entry_addr)) != 0) { 630bdbc8c26SPeter Wemm uprintf("ELF interpreter %s not found\n", path); 631e1743d02SSøren Schmidt goto fail; 632e1743d02SSøren Schmidt } 633e1743d02SSøren Schmidt } 6347a583b02SMarcel Moolenaar } 635ea5a2b2eSSøren Schmidt 636e1743d02SSøren Schmidt /* 637e1743d02SSøren Schmidt * Construct auxargs table (used by the fixup routine) 638e1743d02SSøren Schmidt */ 639ecbb00a2SDoug Rabson elf_auxargs = malloc(sizeof(Elf_Auxargs), M_TEMP, M_WAITOK); 640e1743d02SSøren Schmidt elf_auxargs->execfd = -1; 641e1743d02SSøren Schmidt elf_auxargs->phdr = proghdr; 642e1743d02SSøren Schmidt elf_auxargs->phent = hdr->e_phentsize; 643e1743d02SSøren Schmidt elf_auxargs->phnum = hdr->e_phnum; 644e1743d02SSøren Schmidt elf_auxargs->pagesz = PAGE_SIZE; 645e1743d02SSøren Schmidt elf_auxargs->base = addr; 646e1743d02SSøren Schmidt elf_auxargs->flags = 0; 647e1743d02SSøren Schmidt elf_auxargs->entry = entry; 648e1743d02SSøren Schmidt elf_auxargs->trace = elf_trace; 649e1743d02SSøren Schmidt 650e1743d02SSøren Schmidt imgp->auxargs = elf_auxargs; 651e1743d02SSøren Schmidt imgp->interpreted = 0; 652e1743d02SSøren Schmidt 653e1743d02SSøren Schmidt fail: 654e1743d02SSøren Schmidt return error; 655e1743d02SSøren Schmidt } 656e1743d02SSøren Schmidt 657e1743d02SSøren Schmidt static int 658654f6be1SBruce Evans elf_freebsd_fixup(register_t **stack_base, struct image_params *imgp) 659e1743d02SSøren Schmidt { 660ecbb00a2SDoug Rabson Elf_Auxargs *args = (Elf_Auxargs *)imgp->auxargs; 661654f6be1SBruce Evans register_t *pos; 662e1743d02SSøren Schmidt 663e1743d02SSøren Schmidt pos = *stack_base + (imgp->argc + imgp->envc + 2); 664e1743d02SSøren Schmidt 665e1743d02SSøren Schmidt if (args->trace) { 666e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_DEBUG, 1); 667e1743d02SSøren Schmidt } 668e1743d02SSøren Schmidt if (args->execfd != -1) { 669e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); 670e1743d02SSøren Schmidt } 671e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); 672e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHENT, args->phent); 673e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); 674e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); 675e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); 676e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); 677e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_BASE, args->base); 678e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_NULL, 0); 679e1743d02SSøren Schmidt 680e1743d02SSøren Schmidt free(imgp->auxargs, M_TEMP); 681e1743d02SSøren Schmidt imgp->auxargs = NULL; 682e1743d02SSøren Schmidt 683e1743d02SSøren Schmidt (*stack_base)--; 684216a0f2dSDoug Rabson suword(*stack_base, (long) imgp->argc); 685e1743d02SSøren Schmidt return 0; 686e1743d02SSøren Schmidt } 687e1743d02SSøren Schmidt 688e1743d02SSøren Schmidt /* 6898c64af4fSJohn Polstra * Code for generating ELF core dumps. 6908c64af4fSJohn Polstra */ 6918c64af4fSJohn Polstra 6920ff27d31SJohn Polstra typedef void (*segment_callback) __P((vm_map_entry_t, void *)); 6930ff27d31SJohn Polstra 6940ff27d31SJohn Polstra /* Closure for cb_put_phdr(). */ 6950ff27d31SJohn Polstra struct phdr_closure { 6960ff27d31SJohn Polstra Elf_Phdr *phdr; /* Program header to fill in */ 6970ff27d31SJohn Polstra Elf_Off offset; /* Offset of segment in core file */ 6980ff27d31SJohn Polstra }; 6990ff27d31SJohn Polstra 7000ff27d31SJohn Polstra /* Closure for cb_size_segment(). */ 7010ff27d31SJohn Polstra struct sseg_closure { 7020ff27d31SJohn Polstra int count; /* Count of writable segments. */ 7030ff27d31SJohn Polstra size_t size; /* Total size of all writable segments. */ 7040ff27d31SJohn Polstra }; 7050ff27d31SJohn Polstra 7060ff27d31SJohn Polstra static void cb_put_phdr __P((vm_map_entry_t, void *)); 7070ff27d31SJohn Polstra static void cb_size_segment __P((vm_map_entry_t, void *)); 7080ff27d31SJohn Polstra static void each_writable_segment __P((struct proc *, segment_callback, 7090ff27d31SJohn Polstra void *)); 7100ff27d31SJohn Polstra static int elf_corehdr __P((struct proc *, struct vnode *, struct ucred *, 7110ff27d31SJohn Polstra int, void *, size_t)); 7120ff27d31SJohn Polstra static void elf_puthdr __P((struct proc *, void *, size_t *, 7130ff27d31SJohn Polstra const prstatus_t *, const prfpregset_t *, const prpsinfo_t *, int)); 7140ff27d31SJohn Polstra static void elf_putnote __P((void *, size_t *, const char *, int, 7150ff27d31SJohn Polstra const void *, size_t)); 7168c64af4fSJohn Polstra 7178c64af4fSJohn Polstra extern int osreldate; 7188c64af4fSJohn Polstra 7198c64af4fSJohn Polstra int 720fca666a1SJulian Elischer elf_coredump(p, vp, limit) 7218c64af4fSJohn Polstra register struct proc *p; 7228c64af4fSJohn Polstra register struct vnode *vp; 723fca666a1SJulian Elischer off_t limit; 724fca666a1SJulian Elischer { 725da654d90SPoul-Henning Kamp register struct ucred *cred = p->p_ucred; 726fca666a1SJulian Elischer int error = 0; 7270ff27d31SJohn Polstra struct sseg_closure seginfo; 7280ff27d31SJohn Polstra void *hdr; 7298c64af4fSJohn Polstra size_t hdrsize; 7308c64af4fSJohn Polstra 7310ff27d31SJohn Polstra /* Size the program segments. */ 7320ff27d31SJohn Polstra seginfo.count = 0; 7330ff27d31SJohn Polstra seginfo.size = 0; 7340ff27d31SJohn Polstra each_writable_segment(p, cb_size_segment, &seginfo); 7350ff27d31SJohn Polstra 7360ff27d31SJohn Polstra /* 7370ff27d31SJohn Polstra * Calculate the size of the core file header area by making 7380ff27d31SJohn Polstra * a dry run of generating it. Nothing is written, but the 7390ff27d31SJohn Polstra * size is calculated. 7400ff27d31SJohn Polstra */ 7410ff27d31SJohn Polstra hdrsize = 0; 7420ff27d31SJohn Polstra elf_puthdr((struct proc *)NULL, (void *)NULL, &hdrsize, 7430ff27d31SJohn Polstra (const prstatus_t *)NULL, (const prfpregset_t *)NULL, 7440ff27d31SJohn Polstra (const prpsinfo_t *)NULL, seginfo.count); 7450ff27d31SJohn Polstra 746fca666a1SJulian Elischer if (hdrsize + seginfo.size >= limit) 7478c64af4fSJohn Polstra return (EFAULT); 7480ff27d31SJohn Polstra 7490ff27d31SJohn Polstra /* 7500ff27d31SJohn Polstra * Allocate memory for building the header, fill it up, 7510ff27d31SJohn Polstra * and write it out. 7520ff27d31SJohn Polstra */ 7530ff27d31SJohn Polstra hdr = malloc(hdrsize, M_TEMP, M_WAITOK); 7540ff27d31SJohn Polstra if (hdr == NULL) { 755fca666a1SJulian Elischer return EINVAL; 7560ff27d31SJohn Polstra } 7570ff27d31SJohn Polstra error = elf_corehdr(p, vp, cred, seginfo.count, hdr, hdrsize); 7580ff27d31SJohn Polstra 7590ff27d31SJohn Polstra /* Write the contents of all of the writable segments. */ 7600ff27d31SJohn Polstra if (error == 0) { 7610ff27d31SJohn Polstra Elf_Phdr *php; 7620ff27d31SJohn Polstra off_t offset; 7630ff27d31SJohn Polstra int i; 7640ff27d31SJohn Polstra 7650ff27d31SJohn Polstra php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1; 7660ff27d31SJohn Polstra offset = hdrsize; 7670ff27d31SJohn Polstra for (i = 0; i < seginfo.count; i++) { 7680ff27d31SJohn Polstra error = vn_rdwr(UIO_WRITE, vp, (caddr_t)php->p_vaddr, 7690ff27d31SJohn Polstra php->p_filesz, offset, UIO_USERSPACE, 770dada0278SJohn Polstra IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, p); 7710ff27d31SJohn Polstra if (error != 0) 7720ff27d31SJohn Polstra break; 7730ff27d31SJohn Polstra offset += php->p_filesz; 7740ff27d31SJohn Polstra php++; 7750ff27d31SJohn Polstra } 7760ff27d31SJohn Polstra } 7770ff27d31SJohn Polstra free(hdr, M_TEMP); 7780ff27d31SJohn Polstra 779fca666a1SJulian Elischer return error; 7808c64af4fSJohn Polstra } 7818c64af4fSJohn Polstra 7820ff27d31SJohn Polstra /* 7830ff27d31SJohn Polstra * A callback for each_writable_segment() to write out the segment's 7840ff27d31SJohn Polstra * program header entry. 7850ff27d31SJohn Polstra */ 7860ff27d31SJohn Polstra static void 7870ff27d31SJohn Polstra cb_put_phdr(entry, closure) 7880ff27d31SJohn Polstra vm_map_entry_t entry; 7890ff27d31SJohn Polstra void *closure; 7900ff27d31SJohn Polstra { 7910ff27d31SJohn Polstra struct phdr_closure *phc = (struct phdr_closure *)closure; 7920ff27d31SJohn Polstra Elf_Phdr *phdr = phc->phdr; 7930ff27d31SJohn Polstra 7940ff27d31SJohn Polstra phc->offset = round_page(phc->offset); 7950ff27d31SJohn Polstra 7960ff27d31SJohn Polstra phdr->p_type = PT_LOAD; 7970ff27d31SJohn Polstra phdr->p_offset = phc->offset; 7980ff27d31SJohn Polstra phdr->p_vaddr = entry->start; 7990ff27d31SJohn Polstra phdr->p_paddr = 0; 8000ff27d31SJohn Polstra phdr->p_filesz = phdr->p_memsz = entry->end - entry->start; 8010ff27d31SJohn Polstra phdr->p_align = PAGE_SIZE; 8020ff27d31SJohn Polstra phdr->p_flags = 0; 8030ff27d31SJohn Polstra if (entry->protection & VM_PROT_READ) 8040ff27d31SJohn Polstra phdr->p_flags |= PF_R; 8050ff27d31SJohn Polstra if (entry->protection & VM_PROT_WRITE) 8060ff27d31SJohn Polstra phdr->p_flags |= PF_W; 8070ff27d31SJohn Polstra if (entry->protection & VM_PROT_EXECUTE) 8080ff27d31SJohn Polstra phdr->p_flags |= PF_X; 8090ff27d31SJohn Polstra 8100ff27d31SJohn Polstra phc->offset += phdr->p_filesz; 8110ff27d31SJohn Polstra phc->phdr++; 8120ff27d31SJohn Polstra } 8130ff27d31SJohn Polstra 8140ff27d31SJohn Polstra /* 8150ff27d31SJohn Polstra * A callback for each_writable_segment() to gather information about 8160ff27d31SJohn Polstra * the number of segments and their total size. 8170ff27d31SJohn Polstra */ 8180ff27d31SJohn Polstra static void 8190ff27d31SJohn Polstra cb_size_segment(entry, closure) 8200ff27d31SJohn Polstra vm_map_entry_t entry; 8210ff27d31SJohn Polstra void *closure; 8220ff27d31SJohn Polstra { 8230ff27d31SJohn Polstra struct sseg_closure *ssc = (struct sseg_closure *)closure; 8240ff27d31SJohn Polstra 8250ff27d31SJohn Polstra ssc->count++; 8260ff27d31SJohn Polstra ssc->size += entry->end - entry->start; 8270ff27d31SJohn Polstra } 8280ff27d31SJohn Polstra 8290ff27d31SJohn Polstra /* 8300ff27d31SJohn Polstra * For each writable segment in the process's memory map, call the given 8310ff27d31SJohn Polstra * function with a pointer to the map entry and some arbitrary 8320ff27d31SJohn Polstra * caller-supplied data. 8330ff27d31SJohn Polstra */ 8340ff27d31SJohn Polstra static void 8350ff27d31SJohn Polstra each_writable_segment(p, func, closure) 8360ff27d31SJohn Polstra struct proc *p; 8370ff27d31SJohn Polstra segment_callback func; 8380ff27d31SJohn Polstra void *closure; 8390ff27d31SJohn Polstra { 8400ff27d31SJohn Polstra vm_map_t map = &p->p_vmspace->vm_map; 8410ff27d31SJohn Polstra vm_map_entry_t entry; 8420ff27d31SJohn Polstra 8430ff27d31SJohn Polstra for (entry = map->header.next; entry != &map->header; 8440ff27d31SJohn Polstra entry = entry->next) { 8450ff27d31SJohn Polstra vm_object_t obj; 8460ff27d31SJohn Polstra 8479fdfe602SMatthew Dillon if ((entry->eflags & MAP_ENTRY_IS_SUB_MAP) || 8480ff27d31SJohn Polstra (entry->protection & (VM_PROT_READ|VM_PROT_WRITE)) != 8490ff27d31SJohn Polstra (VM_PROT_READ|VM_PROT_WRITE)) 8500ff27d31SJohn Polstra continue; 8510ff27d31SJohn Polstra 8529730a5daSPaul Saab /* 85377ac690cSPaul Saab ** Dont include memory segment in the coredump if 85477ac690cSPaul Saab ** MAP_NOCORE is set in mmap(2) or MADV_NOCORE in 85577ac690cSPaul Saab ** madvise(2). 8569730a5daSPaul Saab */ 8579730a5daSPaul Saab if (entry->eflags & MAP_ENTRY_NOCOREDUMP) 8589730a5daSPaul Saab continue; 8599730a5daSPaul Saab 8600ff27d31SJohn Polstra if ((obj = entry->object.vm_object) == NULL) 8610ff27d31SJohn Polstra continue; 8620ff27d31SJohn Polstra 8630ff27d31SJohn Polstra /* Find the deepest backing object. */ 8640ff27d31SJohn Polstra while (obj->backing_object != NULL) 8650ff27d31SJohn Polstra obj = obj->backing_object; 8660ff27d31SJohn Polstra 8670ff27d31SJohn Polstra /* Ignore memory-mapped devices and such things. */ 8680ff27d31SJohn Polstra if (obj->type != OBJT_DEFAULT && 8690ff27d31SJohn Polstra obj->type != OBJT_SWAP && 8700ff27d31SJohn Polstra obj->type != OBJT_VNODE) 8710ff27d31SJohn Polstra continue; 8720ff27d31SJohn Polstra 8730ff27d31SJohn Polstra (*func)(entry, closure); 8740ff27d31SJohn Polstra } 8750ff27d31SJohn Polstra } 8760ff27d31SJohn Polstra 8770ff27d31SJohn Polstra /* 8780ff27d31SJohn Polstra * Write the core file header to the file, including padding up to 8790ff27d31SJohn Polstra * the page boundary. 8800ff27d31SJohn Polstra */ 8818c64af4fSJohn Polstra static int 8820ff27d31SJohn Polstra elf_corehdr(p, vp, cred, numsegs, hdr, hdrsize) 8838c64af4fSJohn Polstra struct proc *p; 8848c64af4fSJohn Polstra struct vnode *vp; 8858c64af4fSJohn Polstra struct ucred *cred; 8860ff27d31SJohn Polstra int numsegs; 8870ff27d31SJohn Polstra size_t hdrsize; 8880ff27d31SJohn Polstra void *hdr; 8898c64af4fSJohn Polstra { 8908c64af4fSJohn Polstra size_t off; 8918c64af4fSJohn Polstra prstatus_t status; 8928c64af4fSJohn Polstra prfpregset_t fpregset; 8938c64af4fSJohn Polstra prpsinfo_t psinfo; 8948c64af4fSJohn Polstra 8958c64af4fSJohn Polstra /* Gather the information for the header. */ 8968c64af4fSJohn Polstra bzero(&status, sizeof status); 8978c64af4fSJohn Polstra status.pr_version = PRSTATUS_VERSION; 8988c64af4fSJohn Polstra status.pr_statussz = sizeof(prstatus_t); 8998c64af4fSJohn Polstra status.pr_gregsetsz = sizeof(gregset_t); 9008c64af4fSJohn Polstra status.pr_fpregsetsz = sizeof(fpregset_t); 9018c64af4fSJohn Polstra status.pr_osreldate = osreldate; 9026626c604SJulian Elischer status.pr_cursig = p->p_sig; 9038c64af4fSJohn Polstra status.pr_pid = p->p_pid; 9048c64af4fSJohn Polstra fill_regs(p, &status.pr_reg); 9058c64af4fSJohn Polstra 9068c64af4fSJohn Polstra fill_fpregs(p, &fpregset); 9078c64af4fSJohn Polstra 9088c64af4fSJohn Polstra bzero(&psinfo, sizeof psinfo); 9098c64af4fSJohn Polstra psinfo.pr_version = PRPSINFO_VERSION; 9108c64af4fSJohn Polstra psinfo.pr_psinfosz = sizeof(prpsinfo_t); 9118c64af4fSJohn Polstra strncpy(psinfo.pr_fname, p->p_comm, MAXCOMLEN); 9120ff27d31SJohn Polstra /* XXX - We don't fill in the command line arguments properly yet. */ 9130ff27d31SJohn Polstra strncpy(psinfo.pr_psargs, p->p_comm, PRARGSZ); 9148c64af4fSJohn Polstra 9158c64af4fSJohn Polstra /* Fill in the header. */ 9160ff27d31SJohn Polstra bzero(hdr, hdrsize); 9178c64af4fSJohn Polstra off = 0; 9180ff27d31SJohn Polstra elf_puthdr(p, hdr, &off, &status, &fpregset, &psinfo, numsegs); 9198c64af4fSJohn Polstra 9208c64af4fSJohn Polstra /* Write it to the core file. */ 9210ff27d31SJohn Polstra return vn_rdwr(UIO_WRITE, vp, hdr, hdrsize, (off_t)0, 9228c64af4fSJohn Polstra UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, NULL, p); 923dada0278SJohn Polstra } 924dada0278SJohn Polstra 9258c64af4fSJohn Polstra static void 9260ff27d31SJohn Polstra elf_puthdr(struct proc *p, void *dst, size_t *off, const prstatus_t *status, 9270ff27d31SJohn Polstra const prfpregset_t *fpregset, const prpsinfo_t *psinfo, int numsegs) 9288c64af4fSJohn Polstra { 9298c64af4fSJohn Polstra size_t ehoff; 9308c64af4fSJohn Polstra size_t phoff; 9318c64af4fSJohn Polstra size_t noteoff; 9328c64af4fSJohn Polstra size_t notesz; 9338c64af4fSJohn Polstra 9348c64af4fSJohn Polstra ehoff = *off; 9358c64af4fSJohn Polstra *off += sizeof(Elf_Ehdr); 9368c64af4fSJohn Polstra 9378c64af4fSJohn Polstra phoff = *off; 9380ff27d31SJohn Polstra *off += (numsegs + 1) * sizeof(Elf_Phdr); 9398c64af4fSJohn Polstra 9408c64af4fSJohn Polstra noteoff = *off; 9418c64af4fSJohn Polstra elf_putnote(dst, off, "FreeBSD", NT_PRSTATUS, status, 9428c64af4fSJohn Polstra sizeof *status); 9438c64af4fSJohn Polstra elf_putnote(dst, off, "FreeBSD", NT_FPREGSET, fpregset, 9448c64af4fSJohn Polstra sizeof *fpregset); 9458c64af4fSJohn Polstra elf_putnote(dst, off, "FreeBSD", NT_PRPSINFO, psinfo, 9468c64af4fSJohn Polstra sizeof *psinfo); 9478c64af4fSJohn Polstra notesz = *off - noteoff; 9488c64af4fSJohn Polstra 9490ff27d31SJohn Polstra /* Align up to a page boundary for the program segments. */ 9508c64af4fSJohn Polstra *off = round_page(*off); 9518c64af4fSJohn Polstra 9528c64af4fSJohn Polstra if (dst != NULL) { 9538c64af4fSJohn Polstra Elf_Ehdr *ehdr; 9548c64af4fSJohn Polstra Elf_Phdr *phdr; 9550ff27d31SJohn Polstra struct phdr_closure phc; 9568c64af4fSJohn Polstra 9578c64af4fSJohn Polstra /* 9588c64af4fSJohn Polstra * Fill in the ELF header. 9598c64af4fSJohn Polstra */ 9608c64af4fSJohn Polstra ehdr = (Elf_Ehdr *)((char *)dst + ehoff); 9618c64af4fSJohn Polstra ehdr->e_ident[EI_MAG0] = ELFMAG0; 9628c64af4fSJohn Polstra ehdr->e_ident[EI_MAG1] = ELFMAG1; 9638c64af4fSJohn Polstra ehdr->e_ident[EI_MAG2] = ELFMAG2; 9648c64af4fSJohn Polstra ehdr->e_ident[EI_MAG3] = ELFMAG3; 9658c64af4fSJohn Polstra ehdr->e_ident[EI_CLASS] = ELF_CLASS; 9668c64af4fSJohn Polstra ehdr->e_ident[EI_DATA] = ELF_DATA; 9678c64af4fSJohn Polstra ehdr->e_ident[EI_VERSION] = EV_CURRENT; 968c815a20cSDavid E. O'Brien ehdr->e_ident[EI_OSABI] = ELFOSABI_FREEBSD; 969c815a20cSDavid E. O'Brien ehdr->e_ident[EI_ABIVERSION] = 0; 9708c64af4fSJohn Polstra ehdr->e_ident[EI_PAD] = 0; 9718c64af4fSJohn Polstra ehdr->e_type = ET_CORE; 9728c64af4fSJohn Polstra ehdr->e_machine = ELF_ARCH; 9738c64af4fSJohn Polstra ehdr->e_version = EV_CURRENT; 9748c64af4fSJohn Polstra ehdr->e_entry = 0; 9758c64af4fSJohn Polstra ehdr->e_phoff = phoff; 9768c64af4fSJohn Polstra ehdr->e_flags = 0; 9778c64af4fSJohn Polstra ehdr->e_ehsize = sizeof(Elf_Ehdr); 9788c64af4fSJohn Polstra ehdr->e_phentsize = sizeof(Elf_Phdr); 9790ff27d31SJohn Polstra ehdr->e_phnum = numsegs + 1; 9808c64af4fSJohn Polstra ehdr->e_shentsize = sizeof(Elf_Shdr); 9818c64af4fSJohn Polstra ehdr->e_shnum = 0; 9828c64af4fSJohn Polstra ehdr->e_shstrndx = SHN_UNDEF; 9838c64af4fSJohn Polstra 9848c64af4fSJohn Polstra /* 9858c64af4fSJohn Polstra * Fill in the program header entries. 9868c64af4fSJohn Polstra */ 9878c64af4fSJohn Polstra phdr = (Elf_Phdr *)((char *)dst + phoff); 9888c64af4fSJohn Polstra 9898c64af4fSJohn Polstra /* The note segement. */ 9908c64af4fSJohn Polstra phdr->p_type = PT_NOTE; 9918c64af4fSJohn Polstra phdr->p_offset = noteoff; 9928c64af4fSJohn Polstra phdr->p_vaddr = 0; 9938c64af4fSJohn Polstra phdr->p_paddr = 0; 9948c64af4fSJohn Polstra phdr->p_filesz = notesz; 9958c64af4fSJohn Polstra phdr->p_memsz = 0; 9968c64af4fSJohn Polstra phdr->p_flags = 0; 9978c64af4fSJohn Polstra phdr->p_align = 0; 9988c64af4fSJohn Polstra phdr++; 9998c64af4fSJohn Polstra 10000ff27d31SJohn Polstra /* All the writable segments from the program. */ 10010ff27d31SJohn Polstra phc.phdr = phdr; 10020ff27d31SJohn Polstra phc.offset = *off; 10030ff27d31SJohn Polstra each_writable_segment(p, cb_put_phdr, &phc); 10048c64af4fSJohn Polstra } 10058c64af4fSJohn Polstra } 10068c64af4fSJohn Polstra 10078c64af4fSJohn Polstra static void 10088c64af4fSJohn Polstra elf_putnote(void *dst, size_t *off, const char *name, int type, 10098c64af4fSJohn Polstra const void *desc, size_t descsz) 10108c64af4fSJohn Polstra { 10118c64af4fSJohn Polstra Elf_Note note; 10128c64af4fSJohn Polstra 10138c64af4fSJohn Polstra note.n_namesz = strlen(name) + 1; 10148c64af4fSJohn Polstra note.n_descsz = descsz; 10158c64af4fSJohn Polstra note.n_type = type; 10168c64af4fSJohn Polstra if (dst != NULL) 10178c64af4fSJohn Polstra bcopy(¬e, (char *)dst + *off, sizeof note); 10188c64af4fSJohn Polstra *off += sizeof note; 10198c64af4fSJohn Polstra if (dst != NULL) 10208c64af4fSJohn Polstra bcopy(name, (char *)dst + *off, note.n_namesz); 10218c64af4fSJohn Polstra *off += roundup2(note.n_namesz, sizeof(Elf_Size)); 10228c64af4fSJohn Polstra if (dst != NULL) 10238c64af4fSJohn Polstra bcopy(desc, (char *)dst + *off, note.n_descsz); 10248c64af4fSJohn Polstra *off += roundup2(note.n_descsz, sizeof(Elf_Size)); 10258c64af4fSJohn Polstra } 10268c64af4fSJohn Polstra 10278c64af4fSJohn Polstra /* 1028e1743d02SSøren Schmidt * Tell kern_execve.c about it, with a little help from the linker. 1029e1743d02SSøren Schmidt */ 1030820ca326SMatthew Dillon static struct execsw elf_execsw = {exec_elf_imgact, "ELF"}; 1031aa855a59SPeter Wemm EXEC_SET(elf, elf_execsw); 1032