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 * 29c8a79999SPeter Wemm * $Id: imgact_elf.c,v 1.21 1998/02/09 06:09:21 eivind Exp $ 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/systm.h> 36e1743d02SSøren Schmidt #include <sys/exec.h> 37e1743d02SSøren Schmidt #include <sys/mman.h> 38e1743d02SSøren Schmidt #include <sys/imgact.h> 39e1743d02SSøren Schmidt #include <sys/imgact_elf.h> 40e1743d02SSøren Schmidt #include <sys/kernel.h> 41e1743d02SSøren Schmidt #include <sys/sysent.h> 423ac4d1efSBruce Evans #include <sys/fcntl.h> 43e1743d02SSøren Schmidt #include <sys/malloc.h> 44e1743d02SSøren Schmidt #include <sys/mount.h> 45a794e791SBruce Evans #include <sys/namei.h> 46a794e791SBruce Evans #include <sys/proc.h> 47e1743d02SSøren Schmidt #include <sys/syscall.h> 48e1743d02SSøren Schmidt #include <sys/signalvar.h> 49e1743d02SSøren Schmidt #include <sys/sysctl.h> 50a794e791SBruce Evans #include <sys/vnode.h> 51e1743d02SSøren Schmidt 52e1743d02SSøren Schmidt #include <vm/vm.h> 53e1743d02SSøren Schmidt #include <vm/vm_kern.h> 54e1743d02SSøren Schmidt #include <vm/vm_param.h> 55e1743d02SSøren Schmidt #include <vm/pmap.h> 56996c772fSJohn Dyson #include <sys/lock.h> 57e1743d02SSøren Schmidt #include <vm/vm_map.h> 58e1743d02SSøren Schmidt #include <vm/vm_prot.h> 59e1743d02SSøren Schmidt #include <vm/vm_extern.h> 60e1743d02SSøren Schmidt 61e1743d02SSøren Schmidt #include <machine/md_var.h> 62e1743d02SSøren Schmidt 63e1743d02SSøren Schmidt #define MAX_PHDR 32 /* XXX enough ? */ 64e1743d02SSøren Schmidt 65e0c95ed9SBruce Evans static int elf_check_header __P((const Elf32_Ehdr *hdr, int type)); 66e1743d02SSøren Schmidt static int elf_load_section __P((struct vmspace *vmspace, struct vnode *vp, vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, vm_prot_t prot)); 67e1743d02SSøren Schmidt static int elf_load_file __P((struct proc *p, char *file, u_long *addr, u_long *entry)); 68e1743d02SSøren Schmidt static int elf_freebsd_fixup __P((int **stack_base, struct image_params *imgp)); 69303b270bSEivind Eklund static int exec_elf_imgact __P((struct image_params *imgp)); 70e1743d02SSøren Schmidt 71d8a4f230SBruce Evans static int elf_trace = 0; 72d8a4f230SBruce Evans SYSCTL_INT(_debug, OID_AUTO, elf_trace, CTLFLAG_RW, &elf_trace, 0, ""); 73e1743d02SSøren Schmidt #define UPRINTF if (elf_trace) uprintf 74e1743d02SSøren Schmidt 75e1743d02SSøren Schmidt static struct sysentvec elf_freebsd_sysvec = { 76e1743d02SSøren Schmidt SYS_MAXSYSCALL, 77e1743d02SSøren Schmidt sysent, 78e1743d02SSøren Schmidt 0, 79e1743d02SSøren Schmidt 0, 80e1743d02SSøren Schmidt 0, 81e1743d02SSøren Schmidt 0, 82e1743d02SSøren Schmidt 0, 83e1743d02SSøren Schmidt elf_freebsd_fixup, 84e1743d02SSøren Schmidt sendsig, 85e1743d02SSøren Schmidt sigcode, 86e1743d02SSøren Schmidt &szsigcode, 87e1743d02SSøren Schmidt 0, 886ead3eddSJohn Dyson "FreeBSD ELF" 89e1743d02SSøren Schmidt }; 90e1743d02SSøren Schmidt 91ea5a2b2eSSøren Schmidt static Elf32_Brandinfo freebsd_brand_info = { 92ea5a2b2eSSøren Schmidt "FreeBSD", 93ea5a2b2eSSøren Schmidt "", 94e1743d02SSøren Schmidt "/usr/libexec/ld-elf.so.1", 95ea5a2b2eSSøren Schmidt &elf_freebsd_sysvec 96e1743d02SSøren Schmidt }; 97ea5a2b2eSSøren Schmidt static Elf32_Brandinfo *elf_brand_list[MAX_BRANDS] = { 98ea5a2b2eSSøren Schmidt &freebsd_brand_info, 99e1743d02SSøren Schmidt NULL, NULL, NULL, 100e1743d02SSøren Schmidt NULL, NULL, NULL, NULL 101e1743d02SSøren Schmidt }; 102e1743d02SSøren Schmidt 103e1743d02SSøren Schmidt int 104ea5a2b2eSSøren Schmidt elf_insert_brand_entry(Elf32_Brandinfo *entry) 105e1743d02SSøren Schmidt { 106e1743d02SSøren Schmidt int i; 107e1743d02SSøren Schmidt 108ea5a2b2eSSøren Schmidt for (i=1; i<MAX_BRANDS; i++) { 109ea5a2b2eSSøren Schmidt if (elf_brand_list[i] == NULL) { 110ea5a2b2eSSøren Schmidt elf_brand_list[i] = entry; 111e1743d02SSøren Schmidt break; 112e1743d02SSøren Schmidt } 113e1743d02SSøren Schmidt } 114ea5a2b2eSSøren Schmidt if (i == MAX_BRANDS) 115e1743d02SSøren Schmidt return -1; 116e1743d02SSøren Schmidt return 0; 117e1743d02SSøren Schmidt } 118e1743d02SSøren Schmidt 119e1743d02SSøren Schmidt int 120ea5a2b2eSSøren Schmidt elf_remove_brand_entry(Elf32_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] == entry) { 126ea5a2b2eSSøren Schmidt elf_brand_list[i] = NULL; 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 static int 136e0c95ed9SBruce Evans elf_check_header(const Elf32_Ehdr *hdr, int type) 137e1743d02SSøren Schmidt { 138e1743d02SSøren Schmidt if (!(hdr->e_ident[EI_MAG0] == ELFMAG0 && 139e1743d02SSøren Schmidt hdr->e_ident[EI_MAG1] == ELFMAG1 && 140e1743d02SSøren Schmidt hdr->e_ident[EI_MAG2] == ELFMAG2 && 141e1743d02SSøren Schmidt hdr->e_ident[EI_MAG3] == ELFMAG3)) 142e1743d02SSøren Schmidt return ENOEXEC; 143e1743d02SSøren Schmidt 144e1743d02SSøren Schmidt if (hdr->e_machine != EM_386 && hdr->e_machine != EM_486) 145e1743d02SSøren Schmidt return ENOEXEC; 146e1743d02SSøren Schmidt 147e1743d02SSøren Schmidt if (hdr->e_type != type) 148e1743d02SSøren Schmidt return ENOEXEC; 149e1743d02SSøren Schmidt 150e1743d02SSøren Schmidt return 0; 151e1743d02SSøren Schmidt } 152e1743d02SSøren Schmidt 153e1743d02SSøren Schmidt static int 154e1743d02SSøren Schmidt elf_load_section(struct vmspace *vmspace, struct vnode *vp, vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, vm_prot_t prot) 155e1743d02SSøren Schmidt { 156e1743d02SSøren Schmidt size_t map_len; 157e1743d02SSøren Schmidt vm_offset_t map_addr; 158e1743d02SSøren Schmidt int error; 159e1743d02SSøren Schmidt unsigned char *data_buf = 0; 160e1743d02SSøren Schmidt size_t copy_len; 161e1743d02SSøren Schmidt 162e1743d02SSøren Schmidt map_addr = trunc_page(vmaddr); 163e1743d02SSøren Schmidt 164e1743d02SSøren Schmidt if (memsz > filsz) 165e1743d02SSøren Schmidt map_len = trunc_page(offset+filsz) - trunc_page(offset); 166e1743d02SSøren Schmidt else 167e1743d02SSøren Schmidt map_len = round_page(offset+filsz) - trunc_page(offset); 168e1743d02SSøren Schmidt 169e1743d02SSøren Schmidt if (error = vm_mmap (&vmspace->vm_map, 170e1743d02SSøren Schmidt &map_addr, 171e1743d02SSøren Schmidt map_len, 172e1743d02SSøren Schmidt prot, 173e1743d02SSøren Schmidt VM_PROT_ALL, 17471d7d1b1SPeter Wemm MAP_PRIVATE | MAP_FIXED, 175e1743d02SSøren Schmidt (caddr_t)vp, 176e1743d02SSøren Schmidt trunc_page(offset))) 177e1743d02SSøren Schmidt return error; 178e1743d02SSøren Schmidt 179e1743d02SSøren Schmidt if (memsz == filsz) 180e1743d02SSøren Schmidt return 0; 181e1743d02SSøren Schmidt 182e1743d02SSøren Schmidt /* 183e1743d02SSøren Schmidt * We have to map the remaining bit of the file into the kernel's 184e1743d02SSøren Schmidt * memory map, allocate some anonymous memory, and copy that last 185e1743d02SSøren Schmidt * bit into it. The remaining space should be .bss... 186e1743d02SSøren Schmidt */ 187e1743d02SSøren Schmidt copy_len = (offset + filsz) - trunc_page(offset + filsz); 188e1743d02SSøren Schmidt map_addr = trunc_page(vmaddr + filsz); 189250c11f9SPeter Wemm map_len = round_page(vmaddr + memsz) - map_addr; 190e1743d02SSøren Schmidt 1918191d577SPeter Wemm if (map_len != 0) { 192e1743d02SSøren Schmidt if (error = vm_map_find(&vmspace->vm_map, NULL, 0, 193e1743d02SSøren Schmidt &map_addr, map_len, FALSE, 194e1743d02SSøren Schmidt VM_PROT_ALL, VM_PROT_ALL,0)) 195e1743d02SSøren Schmidt return error; 1968191d577SPeter Wemm } 197e1743d02SSøren Schmidt 198c8a79999SPeter Wemm if (error = vm_mmap(exec_map, 199e1743d02SSøren Schmidt (vm_offset_t *)&data_buf, 200e1743d02SSøren Schmidt PAGE_SIZE, 201e1743d02SSøren Schmidt VM_PROT_READ, 202e1743d02SSøren Schmidt VM_PROT_READ, 20371d7d1b1SPeter Wemm 0, 204e1743d02SSøren Schmidt (caddr_t)vp, 205e1743d02SSøren Schmidt trunc_page(offset + filsz))) 206e1743d02SSøren Schmidt return error; 207e1743d02SSøren Schmidt 208e1743d02SSøren Schmidt error = copyout(data_buf, (caddr_t)map_addr, copy_len); 209e1743d02SSøren Schmidt 210c8a79999SPeter Wemm vm_map_remove(exec_map, (vm_offset_t)data_buf, 211e1743d02SSøren Schmidt (vm_offset_t)data_buf + PAGE_SIZE); 212e1743d02SSøren Schmidt 213e1743d02SSøren Schmidt /* 2148191d577SPeter Wemm * set it to the specified protection 215e1743d02SSøren Schmidt */ 2168191d577SPeter Wemm vm_map_protect(&vmspace->vm_map, map_addr, map_addr + map_len, prot, 2178191d577SPeter Wemm FALSE); 2188191d577SPeter Wemm 219e1743d02SSøren Schmidt UPRINTF("bss size %d (%x)\n", map_len-copy_len, map_len-copy_len); 220e1743d02SSøren Schmidt return error; 221e1743d02SSøren Schmidt } 222e1743d02SSøren Schmidt 223e1743d02SSøren Schmidt static int 224e1743d02SSøren Schmidt elf_load_file(struct proc *p, char *file, u_long *addr, u_long *entry) 225e1743d02SSøren Schmidt { 226e1743d02SSøren Schmidt Elf32_Ehdr *hdr = NULL; 227e1743d02SSøren Schmidt Elf32_Phdr *phdr = NULL; 228e1743d02SSøren Schmidt struct nameidata nd; 229e1743d02SSøren Schmidt struct vmspace *vmspace = p->p_vmspace; 230c8a79999SPeter Wemm struct vattr attr; 231c8a79999SPeter Wemm struct image_params image_params, *imgp; 232e1743d02SSøren Schmidt vm_prot_t prot = 0; 233e1743d02SSøren Schmidt unsigned long text_size = 0, data_size = 0; 234e1743d02SSøren Schmidt unsigned long text_addr = 0, data_addr = 0; 235e1743d02SSøren Schmidt int header_size = 0; 236e1743d02SSøren Schmidt int error, i; 237e1743d02SSøren Schmidt 238c8a79999SPeter Wemm imgp = &image_params; 239c8a79999SPeter Wemm /* 240c8a79999SPeter Wemm * Initialize part of the common data 241c8a79999SPeter Wemm */ 242c8a79999SPeter Wemm imgp->proc = p; 243c8a79999SPeter Wemm imgp->uap = NULL; 244c8a79999SPeter Wemm imgp->attr = &attr; 245c8a79999SPeter Wemm imgp->firstpage = NULL; 246c8a79999SPeter Wemm imgp->image_header = (char *)kmem_alloc_wait(exec_map, PAGE_SIZE); 247c8a79999SPeter Wemm 248c8a79999SPeter Wemm if (imgp->image_header == NULL) { 249c8a79999SPeter Wemm nd.ni_vp = NULL; 250c8a79999SPeter Wemm error = ENOMEM; 251c8a79999SPeter Wemm goto fail; 252c8a79999SPeter Wemm } 253c8a79999SPeter Wemm 254e1743d02SSøren Schmidt NDINIT(&nd, LOOKUP, LOCKLEAF|FOLLOW, UIO_SYSSPACE, file, p); 255e1743d02SSøren Schmidt 2561560a9d5SPeter Wemm if (error = namei(&nd)) { 2571560a9d5SPeter Wemm nd.ni_vp = NULL; 258e1743d02SSøren Schmidt goto fail; 259e1743d02SSøren Schmidt } 260e1743d02SSøren Schmidt 261c8a79999SPeter Wemm imgp->vp = nd.ni_vp; 262c8a79999SPeter Wemm 263e1743d02SSøren Schmidt /* 264e1743d02SSøren Schmidt * Check permissions, modes, uid, etc on the file, and "open" it. 265e1743d02SSøren Schmidt */ 266c8a79999SPeter Wemm error = exec_check_permissions(imgp); 267c8a79999SPeter Wemm if (error) { 268996c772fSJohn Dyson VOP_UNLOCK(nd.ni_vp, 0, p); 269c8a79999SPeter Wemm goto fail; 270c8a79999SPeter Wemm } 271e1743d02SSøren Schmidt 272c8a79999SPeter Wemm error = exec_map_first_page(imgp); 273c8a79999SPeter Wemm VOP_UNLOCK(nd.ni_vp, 0, p); 274e1743d02SSøren Schmidt if (error) 275e1743d02SSøren Schmidt goto fail; 276e1743d02SSøren Schmidt 277c8a79999SPeter Wemm hdr = (Elf32_Ehdr *)imgp->image_header; 278e1743d02SSøren Schmidt if (error = elf_check_header(hdr, ET_DYN)) 279e1743d02SSøren Schmidt goto fail; 280e1743d02SSøren Schmidt 281e1743d02SSøren Schmidt /* 282e1743d02SSøren Schmidt * ouch, need to bounds check in case user gives us a corrupted 283e1743d02SSøren Schmidt * file with an insane header size 284e1743d02SSøren Schmidt */ 285e1743d02SSøren Schmidt if (hdr->e_phnum > MAX_PHDR) { /* XXX: ever more than this? */ 286e1743d02SSøren Schmidt error = ENOEXEC; 287e1743d02SSøren Schmidt goto fail; 288e1743d02SSøren Schmidt } 289e1743d02SSøren Schmidt 290e1743d02SSøren Schmidt header_size = hdr->e_phentsize * hdr->e_phnum; 291e1743d02SSøren Schmidt 292c8a79999SPeter Wemm /* Only support headers that fit within first page for now */ 293c8a79999SPeter Wemm if (header_size + hdr->e_phoff > PAGE_SIZE) { 294c8a79999SPeter Wemm error = ENOEXEC; 295e1743d02SSøren Schmidt goto fail; 296c8a79999SPeter Wemm } 297c8a79999SPeter Wemm 298c8a79999SPeter Wemm phdr = (Elf32_Phdr *)(imgp->image_header + hdr->e_phoff); 299e1743d02SSøren Schmidt 300e1743d02SSøren Schmidt for (i = 0; i < hdr->e_phnum; i++) { 301e1743d02SSøren Schmidt switch(phdr[i].p_type) { 302e1743d02SSøren Schmidt 303e1743d02SSøren Schmidt case PT_NULL: /* NULL section */ 304e1743d02SSøren Schmidt UPRINTF ("ELF(file) PT_NULL section\n"); 305e1743d02SSøren Schmidt break; 306e1743d02SSøren Schmidt case PT_LOAD: /* Loadable segment */ 307e1743d02SSøren Schmidt { 308e1743d02SSøren Schmidt UPRINTF ("ELF(file) PT_LOAD section "); 309e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_X) 310e1743d02SSøren Schmidt prot |= VM_PROT_EXECUTE; 311e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_W) 312e1743d02SSøren Schmidt prot |= VM_PROT_WRITE; 313e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_R) 314e1743d02SSøren Schmidt prot |= VM_PROT_READ; 315e1743d02SSøren Schmidt 316e1743d02SSøren Schmidt if (error = elf_load_section(vmspace, nd.ni_vp, 317e1743d02SSøren Schmidt phdr[i].p_offset, 318e1743d02SSøren Schmidt (caddr_t)phdr[i].p_vaddr + 319e1743d02SSøren Schmidt (*addr), 320e1743d02SSøren Schmidt phdr[i].p_memsz, 321e1743d02SSøren Schmidt phdr[i].p_filesz, prot)) 322e1743d02SSøren Schmidt goto fail; 323e1743d02SSøren Schmidt 324e1743d02SSøren Schmidt /* 325e1743d02SSøren Schmidt * Is this .text or .data ?? 326e1743d02SSøren Schmidt * 327e1743d02SSøren Schmidt * We only handle one each of those yet XXX 328e1743d02SSøren Schmidt */ 329e1743d02SSøren Schmidt if (hdr->e_entry >= phdr[i].p_vaddr && 330e1743d02SSøren Schmidt hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) { 331e1743d02SSøren Schmidt text_addr = trunc_page(phdr[i].p_vaddr+(*addr)); 3328191d577SPeter Wemm text_size = round_page(phdr[i].p_memsz + 3338191d577SPeter Wemm phdr[i].p_vaddr - 3348191d577SPeter Wemm trunc_page(phdr[i].p_vaddr)); 335e1743d02SSøren Schmidt *entry=(unsigned long)hdr->e_entry+(*addr); 336e1743d02SSøren Schmidt UPRINTF(".text <%08x,%08x> entry=%08x\n", 337e1743d02SSøren Schmidt text_addr, text_size, *entry); 338e1743d02SSøren Schmidt } else { 339e1743d02SSøren Schmidt data_addr = trunc_page(phdr[i].p_vaddr+(*addr)); 3408191d577SPeter Wemm data_size = round_page(phdr[i].p_memsz + 3418191d577SPeter Wemm phdr[i].p_vaddr - 3428191d577SPeter Wemm trunc_page(phdr[i].p_vaddr)); 343e1743d02SSøren Schmidt UPRINTF(".data <%08x,%08x>\n", 344e1743d02SSøren Schmidt data_addr, data_size); 345e1743d02SSøren Schmidt } 346e1743d02SSøren Schmidt } 347e1743d02SSøren Schmidt break; 348e1743d02SSøren Schmidt 349e1743d02SSøren Schmidt case PT_DYNAMIC:/* Dynamic link information */ 350e1743d02SSøren Schmidt UPRINTF ("ELF(file) PT_DYNAMIC section\n"); 351e1743d02SSøren Schmidt break; 352e1743d02SSøren Schmidt case PT_INTERP: /* Path to interpreter */ 353e1743d02SSøren Schmidt UPRINTF ("ELF(file) PT_INTERP section\n"); 354e1743d02SSøren Schmidt break; 355e1743d02SSøren Schmidt case PT_NOTE: /* Note section */ 356e1743d02SSøren Schmidt UPRINTF ("ELF(file) PT_NOTE section\n"); 357e1743d02SSøren Schmidt break; 358e1743d02SSøren Schmidt case PT_SHLIB: /* Shared lib section */ 359e1743d02SSøren Schmidt UPRINTF ("ELF(file) PT_SHLIB section\n"); 360e1743d02SSøren Schmidt break; 361e1743d02SSøren Schmidt case PT_PHDR: /* Program header table info */ 362e1743d02SSøren Schmidt UPRINTF ("ELF(file) PT_PHDR section\n"); 363e1743d02SSøren Schmidt break; 364e1743d02SSøren Schmidt default: 365e1743d02SSøren Schmidt UPRINTF ("ELF(file) %d section ??\n", phdr[i].p_type ); 366e1743d02SSøren Schmidt } 367e1743d02SSøren Schmidt } 368e1743d02SSøren Schmidt 369e1743d02SSøren Schmidt fail: 370c8a79999SPeter Wemm if (imgp->firstpage) 371c8a79999SPeter Wemm exec_unmap_first_page(imgp); 372c8a79999SPeter Wemm if (imgp->image_header) 373c8a79999SPeter Wemm kmem_free_wakeup(exec_map, (vm_offset_t)imgp->image_header, 374c8a79999SPeter Wemm PAGE_SIZE); 3751560a9d5SPeter Wemm if (nd.ni_vp) 3761560a9d5SPeter Wemm vrele(nd.ni_vp); 377e1743d02SSøren Schmidt 378e1743d02SSøren Schmidt return error; 379e1743d02SSøren Schmidt } 380e1743d02SSøren Schmidt 381303b270bSEivind Eklund static int 382e1743d02SSøren Schmidt exec_elf_imgact(struct image_params *imgp) 383e1743d02SSøren Schmidt { 384e0c95ed9SBruce Evans const Elf32_Ehdr *hdr = (const Elf32_Ehdr *) imgp->image_header; 385e0c95ed9SBruce Evans const Elf32_Phdr *phdr, *mapped_phdr = NULL; 386e1743d02SSøren Schmidt Elf32_Auxargs *elf_auxargs = NULL; 3875856e12eSJohn Dyson struct vmspace *vmspace; 388e1743d02SSøren Schmidt vm_prot_t prot = 0; 389e1743d02SSøren Schmidt u_long text_size = 0, data_size = 0; 390e1743d02SSøren Schmidt u_long text_addr = 0, data_addr = 0; 391e1743d02SSøren Schmidt u_long addr, entry = 0, proghdr = 0; 392c8a79999SPeter Wemm int error, i, header_size = 0; 393c8a79999SPeter Wemm const char *interp = NULL; 394ea5a2b2eSSøren Schmidt char *brand = NULL; 395ea5a2b2eSSøren Schmidt char path[MAXPATHLEN]; 396e1743d02SSøren Schmidt 397e1743d02SSøren Schmidt /* 398e1743d02SSøren Schmidt * Do we have a valid ELF header ? 399e1743d02SSøren Schmidt */ 400e1743d02SSøren Schmidt if (elf_check_header(hdr, ET_EXEC)) 401e1743d02SSøren Schmidt return -1; 402e1743d02SSøren Schmidt 403e1743d02SSøren Schmidt /* 404e1743d02SSøren Schmidt * From here on down, we return an errno, not -1, as we've 405e1743d02SSøren Schmidt * detected an ELF file. 406e1743d02SSøren Schmidt */ 407e1743d02SSøren Schmidt 408e1743d02SSøren Schmidt /* 409e1743d02SSøren Schmidt * ouch, need to bounds check in case user gives us a corrupted 410e1743d02SSøren Schmidt * file with an insane header size 411e1743d02SSøren Schmidt */ 412e1743d02SSøren Schmidt if (hdr->e_phnum > MAX_PHDR) { /* XXX: ever more than this? */ 413e1743d02SSøren Schmidt return ENOEXEC; 414e1743d02SSøren Schmidt } 415e1743d02SSøren Schmidt 416e1743d02SSøren Schmidt header_size = hdr->e_phentsize * hdr->e_phnum; 417e1743d02SSøren Schmidt 418e1743d02SSøren Schmidt if ((hdr->e_phoff > PAGE_SIZE) || 419e1743d02SSøren Schmidt (hdr->e_phoff + header_size) > PAGE_SIZE) { 420c8a79999SPeter Wemm /* Only support headers in first page for now */ 421c8a79999SPeter Wemm return ENOEXEC; 422e1743d02SSøren Schmidt } else { 423e0c95ed9SBruce Evans phdr = (const Elf32_Phdr*) 424e0c95ed9SBruce Evans ((const char *)imgp->image_header + hdr->e_phoff); 425e1743d02SSøren Schmidt } 426e1743d02SSøren Schmidt 427e1743d02SSøren Schmidt /* 428e1743d02SSøren Schmidt * From this point on, we may have resources that need to be freed. 429e1743d02SSøren Schmidt */ 430e1743d02SSøren Schmidt if (error = exec_extract_strings(imgp)) 431e1743d02SSøren Schmidt goto fail; 432e1743d02SSøren Schmidt 433e1743d02SSøren Schmidt exec_new_vmspace(imgp); 434e1743d02SSøren Schmidt 4355856e12eSJohn Dyson vmspace = imgp->proc->p_vmspace; 4365856e12eSJohn Dyson 437e1743d02SSøren Schmidt for (i = 0; i < hdr->e_phnum; i++) { 438e1743d02SSøren Schmidt switch(phdr[i].p_type) { 439e1743d02SSøren Schmidt 440e1743d02SSøren Schmidt case PT_NULL: /* NULL section */ 441e1743d02SSøren Schmidt UPRINTF ("ELF PT_NULL section\n"); 442e1743d02SSøren Schmidt break; 443e1743d02SSøren Schmidt case PT_LOAD: /* Loadable segment */ 444e1743d02SSøren Schmidt { 445e1743d02SSøren Schmidt UPRINTF ("ELF PT_LOAD section "); 446e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_X) 447e1743d02SSøren Schmidt prot |= VM_PROT_EXECUTE; 448e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_W) 449e1743d02SSøren Schmidt prot |= VM_PROT_WRITE; 450e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_R) 451e1743d02SSøren Schmidt prot |= VM_PROT_READ; 452e1743d02SSøren Schmidt 453e1743d02SSøren Schmidt if (error = elf_load_section(vmspace, imgp->vp, 454e1743d02SSøren Schmidt phdr[i].p_offset, 455e1743d02SSøren Schmidt (caddr_t)phdr[i].p_vaddr, 456e1743d02SSøren Schmidt phdr[i].p_memsz, 457e1743d02SSøren Schmidt phdr[i].p_filesz, prot)) 458e1743d02SSøren Schmidt goto fail; 459e1743d02SSøren Schmidt 460e1743d02SSøren Schmidt /* 461e1743d02SSøren Schmidt * Is this .text or .data ?? 462e1743d02SSøren Schmidt * 463e1743d02SSøren Schmidt * We only handle one each of those yet XXX 464e1743d02SSøren Schmidt */ 465e1743d02SSøren Schmidt if (hdr->e_entry >= phdr[i].p_vaddr && 466e1743d02SSøren Schmidt hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) { 467e1743d02SSøren Schmidt text_addr = trunc_page(phdr[i].p_vaddr); 4688191d577SPeter Wemm text_size = round_page(phdr[i].p_memsz + 4698191d577SPeter Wemm phdr[i].p_vaddr - 4708191d577SPeter Wemm text_addr); 471e1743d02SSøren Schmidt entry = (u_long)hdr->e_entry; 472e1743d02SSøren Schmidt UPRINTF(".text <%08x,%08x> entry=%08x\n", 473e1743d02SSøren Schmidt text_addr, text_size, entry); 474e1743d02SSøren Schmidt } else { 475e1743d02SSøren Schmidt data_addr = trunc_page(phdr[i].p_vaddr); 4768191d577SPeter Wemm data_size = round_page(phdr[i].p_memsz + 4778191d577SPeter Wemm phdr[i].p_vaddr - 4788191d577SPeter Wemm data_addr); 479e1743d02SSøren Schmidt UPRINTF(".data <%08x,%08x>\n", 480e1743d02SSøren Schmidt data_addr, data_size); 481e1743d02SSøren Schmidt } 482e1743d02SSøren Schmidt } 483e1743d02SSøren Schmidt break; 484e1743d02SSøren Schmidt 485e1743d02SSøren Schmidt case PT_DYNAMIC:/* Dynamic link information */ 486e1743d02SSøren Schmidt UPRINTF ("ELF PT_DYNAMIC section ??\n"); 487e1743d02SSøren Schmidt break; 488e1743d02SSøren Schmidt case PT_INTERP: /* Path to interpreter */ 489e1743d02SSøren Schmidt UPRINTF ("ELF PT_INTERP section "); 490c8a79999SPeter Wemm if (phdr[i].p_filesz > MAXPATHLEN || 491c8a79999SPeter Wemm phdr[i].p_offset + phdr[i].p_filesz > PAGE_SIZE) { 492e1743d02SSøren Schmidt error = ENOEXEC; 493e1743d02SSøren Schmidt goto fail; 494e1743d02SSøren Schmidt } 495c8a79999SPeter Wemm interp = imgp->image_header + phdr[i].p_offset; 496e1743d02SSøren Schmidt UPRINTF("<%s>\n", interp); 497e1743d02SSøren Schmidt break; 498e1743d02SSøren Schmidt case PT_NOTE: /* Note section */ 499e1743d02SSøren Schmidt UPRINTF ("ELF PT_NOTE section\n"); 500e1743d02SSøren Schmidt break; 501e1743d02SSøren Schmidt case PT_SHLIB: /* Shared lib section */ 502e1743d02SSøren Schmidt UPRINTF ("ELF PT_SHLIB section\n"); 503e1743d02SSøren Schmidt break; 504e1743d02SSøren Schmidt case PT_PHDR: /* Program header table info */ 505e1743d02SSøren Schmidt UPRINTF ("ELF PT_PHDR section <%x>\n", phdr[i].p_vaddr); 506e1743d02SSøren Schmidt proghdr = phdr[i].p_vaddr; 507e1743d02SSøren Schmidt break; 508e1743d02SSøren Schmidt default: 509e1743d02SSøren Schmidt UPRINTF ("ELF %d section ??\n", phdr[i].p_type); 510e1743d02SSøren Schmidt } 511e1743d02SSøren Schmidt } 512e1743d02SSøren Schmidt 513e1743d02SSøren Schmidt vmspace->vm_tsize = text_size >> PAGE_SHIFT; 514e1743d02SSøren Schmidt vmspace->vm_taddr = (caddr_t)text_addr; 515e1743d02SSøren Schmidt vmspace->vm_dsize = data_size >> PAGE_SHIFT; 516e1743d02SSøren Schmidt vmspace->vm_daddr = (caddr_t)data_addr; 517e1743d02SSøren Schmidt 518e1743d02SSøren Schmidt addr = 2*MAXDSIZ; /* May depend on OS type XXX */ 519e1743d02SSøren Schmidt 520ea5a2b2eSSøren Schmidt imgp->entry_addr = entry; 521ea5a2b2eSSøren Schmidt 522e1743d02SSøren Schmidt /* 523ea5a2b2eSSøren Schmidt * So which kind (brand) of ELF binary do we have at hand 524ea5a2b2eSSøren Schmidt * FreeBSD, Linux, SVR4 or something else ?? 525ea5a2b2eSSøren Schmidt * If its has a interpreter section try that first 526e1743d02SSøren Schmidt */ 527ea5a2b2eSSøren Schmidt if (interp) { 528ea5a2b2eSSøren Schmidt for (i=0; i<MAX_BRANDS; i++) { 529ea5a2b2eSSøren Schmidt if (elf_brand_list[i] != NULL) { 530ea5a2b2eSSøren Schmidt if (!strcmp(interp, elf_brand_list[i]->interp_path)) { 531e1743d02SSøren Schmidt imgp->proc->p_sysent = 532ea5a2b2eSSøren Schmidt elf_brand_list[i]->sysvec; 533ea5a2b2eSSøren Schmidt strcpy(path, elf_brand_list[i]->emul_path); 534ea5a2b2eSSøren Schmidt strcat(path, elf_brand_list[i]->interp_path); 535e1743d02SSøren Schmidt UPRINTF("interpreter=<%s> %s\n", 536ea5a2b2eSSøren Schmidt elf_brand_list[i]->interp_path, 537ea5a2b2eSSøren Schmidt elf_brand_list[i]->emul_path); 538e1743d02SSøren Schmidt break; 539e1743d02SSøren Schmidt } 540e1743d02SSøren Schmidt } 541e1743d02SSøren Schmidt } 542ea5a2b2eSSøren Schmidt } 543ea5a2b2eSSøren Schmidt 544ea5a2b2eSSøren Schmidt /* 545ea5a2b2eSSøren Schmidt * If there is no interpreter, or recognition of it 546ea5a2b2eSSøren Schmidt * failed, se if the binary is branded. 547ea5a2b2eSSøren Schmidt */ 548ea5a2b2eSSøren Schmidt if (!interp || i == MAX_BRANDS) { 549ea5a2b2eSSøren Schmidt brand = (char *)&(hdr->e_ident[EI_BRAND]); 550ea5a2b2eSSøren Schmidt for (i=0; i<MAX_BRANDS; i++) { 551ea5a2b2eSSøren Schmidt if (elf_brand_list[i] != NULL) { 552ea5a2b2eSSøren Schmidt if (!strcmp(brand, elf_brand_list[i]->brand)) { 553ea5a2b2eSSøren Schmidt imgp->proc->p_sysent = elf_brand_list[i]->sysvec; 554ea5a2b2eSSøren Schmidt if (interp) { 555ea5a2b2eSSøren Schmidt strcpy(path, elf_brand_list[i]->emul_path); 556ea5a2b2eSSøren Schmidt strcat(path, elf_brand_list[i]->interp_path); 557ea5a2b2eSSøren Schmidt UPRINTF("interpreter=<%s> %s\n", 558ea5a2b2eSSøren Schmidt elf_brand_list[i]->interp_path, 559ea5a2b2eSSøren Schmidt elf_brand_list[i]->emul_path); 560ea5a2b2eSSøren Schmidt } 561d672246bSSøren Schmidt break; 562ea5a2b2eSSøren Schmidt } 563ea5a2b2eSSøren Schmidt } 564ea5a2b2eSSøren Schmidt } 565ea5a2b2eSSøren Schmidt } 566ea5a2b2eSSøren Schmidt if (i == MAX_BRANDS) { 567ea5a2b2eSSøren Schmidt uprintf("ELF binary type not known\n"); 568e1743d02SSøren Schmidt error = ENOEXEC; 569e1743d02SSøren Schmidt goto fail; 570e1743d02SSøren Schmidt } 571ea5a2b2eSSøren Schmidt if (interp) { 572e1743d02SSøren Schmidt if (error = elf_load_file(imgp->proc, 573e1743d02SSøren Schmidt path, 574e1743d02SSøren Schmidt &addr, /* XXX */ 575e1743d02SSøren Schmidt &imgp->entry_addr)) { 576e1743d02SSøren Schmidt uprintf("ELF interpreter %s not found\n", path); 577e1743d02SSøren Schmidt goto fail; 578e1743d02SSøren Schmidt } 579e1743d02SSøren Schmidt } 580ea5a2b2eSSøren Schmidt 581717fb679SSøren Schmidt UPRINTF("Executing %s binary\n", elf_brand_list[i]->brand); 582e1743d02SSøren Schmidt 583e1743d02SSøren Schmidt /* 584e1743d02SSøren Schmidt * Construct auxargs table (used by the fixup routine) 585e1743d02SSøren Schmidt */ 586e1743d02SSøren Schmidt elf_auxargs = malloc(sizeof(Elf32_Auxargs), M_TEMP, M_WAITOK); 587e1743d02SSøren Schmidt elf_auxargs->execfd = -1; 588e1743d02SSøren Schmidt elf_auxargs->phdr = proghdr; 589e1743d02SSøren Schmidt elf_auxargs->phent = hdr->e_phentsize; 590e1743d02SSøren Schmidt elf_auxargs->phnum = hdr->e_phnum; 591e1743d02SSøren Schmidt elf_auxargs->pagesz = PAGE_SIZE; 592e1743d02SSøren Schmidt elf_auxargs->base = addr; 593e1743d02SSøren Schmidt elf_auxargs->flags = 0; 594e1743d02SSøren Schmidt elf_auxargs->entry = entry; 595e1743d02SSøren Schmidt elf_auxargs->trace = elf_trace; 596e1743d02SSøren Schmidt 597e1743d02SSøren Schmidt imgp->auxargs = elf_auxargs; 598e1743d02SSøren Schmidt imgp->interpreted = 0; 599e1743d02SSøren Schmidt 600e1743d02SSøren Schmidt /* don't allow modifying the file while we run it */ 601e1743d02SSøren Schmidt imgp->vp->v_flag |= VTEXT; 602e1743d02SSøren Schmidt 603e1743d02SSøren Schmidt fail: 604e1743d02SSøren Schmidt return error; 605e1743d02SSøren Schmidt } 606e1743d02SSøren Schmidt 607e1743d02SSøren Schmidt static int 608e1743d02SSøren Schmidt elf_freebsd_fixup(int **stack_base, struct image_params *imgp) 609e1743d02SSøren Schmidt { 610e1743d02SSøren Schmidt Elf32_Auxargs *args = (Elf32_Auxargs *)imgp->auxargs; 611e1743d02SSøren Schmidt int *pos; 612e1743d02SSøren Schmidt 613e1743d02SSøren Schmidt pos = *stack_base + (imgp->argc + imgp->envc + 2); 614e1743d02SSøren Schmidt 615e1743d02SSøren Schmidt if (args->trace) { 616e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_DEBUG, 1); 617e1743d02SSøren Schmidt } 618e1743d02SSøren Schmidt if (args->execfd != -1) { 619e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); 620e1743d02SSøren Schmidt } 621e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); 622e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHENT, args->phent); 623e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); 624e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); 625e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); 626e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); 627e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_BASE, args->base); 628e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_NULL, 0); 629e1743d02SSøren Schmidt 630e1743d02SSøren Schmidt free(imgp->auxargs, M_TEMP); 631e1743d02SSøren Schmidt imgp->auxargs = NULL; 632e1743d02SSøren Schmidt 633e1743d02SSøren Schmidt (*stack_base)--; 634e1743d02SSøren Schmidt **stack_base = (int)imgp->argc; 635e1743d02SSøren Schmidt return 0; 636e1743d02SSøren Schmidt } 637e1743d02SSøren Schmidt 638e1743d02SSøren Schmidt /* 639e1743d02SSøren Schmidt * Tell kern_execve.c about it, with a little help from the linker. 640e1743d02SSøren Schmidt * Since `const' objects end up in the text segment, TEXT_SET is the 641e1743d02SSøren Schmidt * correct directive to use. 642e1743d02SSøren Schmidt */ 643d8a4f230SBruce Evans static const struct execsw elf_execsw = {exec_elf_imgact, "ELF"}; 644e1743d02SSøren Schmidt TEXT_SET(execsw_set, elf_execsw); 645e1743d02SSøren Schmidt 646