imgact_elf.c revision 24131
1194140Simp/*- 2194140Simp * Copyright (c) 1995-1996 S�ren Schmidt 3194140Simp * Copyright (c) 1996 Peter Wemm 4194140Simp * All rights reserved. 5194140Simp * 6194140Simp * Redistribution and use in source and binary forms, with or without 7194140Simp * modification, are permitted provided that the following conditions 8194140Simp * are met: 9194140Simp * 1. Redistributions of source code must retain the above copyright 10194140Simp * notice, this list of conditions and the following disclaimer 11194140Simp * in this position and unchanged. 12194140Simp * 2. Redistributions in binary form must reproduce the above copyright 13194140Simp * notice, this list of conditions and the following disclaimer in the 14194140Simp * documentation and/or other materials provided with the distribution. 15194140Simp * 3. The name of the author may not be used to endorse or promote products 16194140Simp * derived from this software withough specific prior written permission 17194140Simp * 18194140Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19194140Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20194140Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21194140Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22194140Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23194140Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24194140Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25194140Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26194140Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27194140Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28194140Simp * 29194140Simp * $Id: imgact_elf.c,v 1.16 1997/02/22 09:38:56 peter Exp $ 30194140Simp */ 31194140Simp 32196262Simp#include "opt_rlimit.h" 33196262Simp 34194140Simp#include <sys/param.h> 35196262Simp#include <sys/systm.h> 36196262Simp#include <sys/resourcevar.h> 37196262Simp#include <sys/exec.h> 38196262Simp#include <sys/mman.h> 39196262Simp#include <sys/imgact.h> 40196262Simp#include <sys/imgact_elf.h> 41196262Simp#include <sys/kernel.h> 42196262Simp#include <sys/sysent.h> 43196262Simp#include <sys/fcntl.h> 44196262Simp#include <sys/malloc.h> 45196262Simp#include <sys/mount.h> 46196262Simp#include <sys/namei.h> 47196262Simp#include <sys/proc.h> 48242302Sjmallett#include <sys/sysproto.h> 49196262Simp#include <sys/syscall.h> 50196262Simp#include <sys/signalvar.h> 51210311Sjmallett#include <sys/sysctl.h> 52210311Sjmallett#include <sys/vnode.h> 53196262Simp 54196262Simp#include <vm/vm.h> 55196262Simp#include <vm/vm_kern.h> 56196262Simp#include <vm/vm_param.h> 57196262Simp#include <vm/pmap.h> 58196262Simp#include <sys/lock.h> 59196262Simp#include <vm/vm_map.h> 60196262Simp#include <vm/vm_prot.h> 61196262Simp#include <vm/vm_extern.h> 62196262Simp 63194140Simp#include <machine/md_var.h> 64194140Simp#include <i386/linux/linux_syscall.h> 65202063Simp#include <i386/linux/linux.h> 66196262Simp 67196262Simp#define MAX_PHDR 32 /* XXX enough ? */ 68196262Simp 69196262Simpstatic int map_pages __P((struct vnode *vp, vm_offset_t offset, vm_offset_t *buf, vm_size_t size)); 70194140Simpstatic void unmap_pages __P((vm_offset_t buf, vm_size_t size)); 71196262Simpstatic int elf_check_permissions __P((struct proc *p, struct vnode *vp)); 72196262Simpstatic int elf_check_header __P((const Elf32_Ehdr *hdr, int type)); 73196262Simpstatic 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)); 74194140Simpstatic int elf_load_file __P((struct proc *p, char *file, u_long *addr, u_long *entry)); 75210311Sjmallettstatic int elf_freebsd_fixup __P((int **stack_base, struct image_params *imgp)); 76210311Sjmallettint exec_elf_imgact __P((struct image_params *imgp)); 77242273Sjmallett 78242342Sjmallettint elf_trace = 0; 79210311SjmallettSYSCTL_INT(_debug, 1, elf_trace, CTLFLAG_RW, &elf_trace, 0, ""); 80210311Sjmallett#define UPRINTF if (elf_trace) uprintf 81210311Sjmallett 82232812Sjmallettstatic struct sysentvec elf_freebsd_sysvec = { 83232812Sjmallett SYS_MAXSYSCALL, 84194140Simp sysent, 85196262Simp 0, 86194140Simp 0, 87196262Simp 0, 88194140Simp 0, 89194140Simp 0, 90210311Sjmallett elf_freebsd_fixup, 91210311Sjmallett sendsig, 92210311Sjmallett sigcode, 93210311Sjmallett &szsigcode, 94210311Sjmallett 0, 95196262Simp "FreeBSD ELF" 96217518Simp}; 97217518Simp 98194140Simpstatic Elf32_Brandinfo freebsd_brand_info = { 99210311Sjmallett "FreeBSD", 100210311Sjmallett "", 101210311Sjmallett "/usr/libexec/ld-elf.so.1", 102210311Sjmallett &elf_freebsd_sysvec 103216069Sjmallett }; 104210311Sjmallettstatic Elf32_Brandinfo *elf_brand_list[MAX_BRANDS] = { 105216069Sjmallett &freebsd_brand_info, 106210311Sjmallett NULL, NULL, NULL, 107210311Sjmallett NULL, NULL, NULL, NULL 108210311Sjmallett }; 109210311Sjmallett 110210311Sjmallettint 111210311Sjmallettelf_insert_brand_entry(Elf32_Brandinfo *entry) 112210311Sjmallett{ 113210311Sjmallett int i; 114210311Sjmallett 115216069Sjmallett for (i=1; i<MAX_BRANDS; i++) { 116232812Sjmallett if (elf_brand_list[i] == NULL) { 117232812Sjmallett elf_brand_list[i] = entry; 118232812Sjmallett break; 119232812Sjmallett } 120232812Sjmallett } 121232812Sjmallett if (i == MAX_BRANDS) 122232812Sjmallett return -1; 123232812Sjmallett return 0; 124232812Sjmallett} 125232812Sjmallett 126210311Sjmallettint 127210311Sjmallettelf_remove_brand_entry(Elf32_Brandinfo *entry) 128210311Sjmallett{ 129210311Sjmallett int i; 130210311Sjmallett 131210311Sjmallett for (i=1; i<MAX_BRANDS; i++) { 132200344Simp if (elf_brand_list[i] == entry) { 133200344Simp elf_brand_list[i] = NULL; 134210311Sjmallett break; 135210311Sjmallett } 136210311Sjmallett } 137210311Sjmallett if (i == MAX_BRANDS) 138210311Sjmallett return -1; 139210311Sjmallett return 0; 140210311Sjmallett} 141210311Sjmallett 142210311Sjmallettstatic int 143198669Srrsmap_pages(struct vnode *vp, vm_offset_t offset, 144198669Srrs vm_offset_t *buf, vm_size_t size) 145198669Srrs{ 146198669Srrs int error; 147198669Srrs vm_offset_t kern_buf; 148196262Simp vm_size_t pageoff; 149194140Simp 150194140Simp /* 151194140Simp * The request may not be aligned, and may even cross several 152196314Simp * page boundaries in the file... 153196314Simp */ 154194140Simp pageoff = (offset & PAGE_MASK); 155210311Sjmallett offset -= pageoff; /* start of first aligned page to map */ 156194140Simp size += pageoff; 157194140Simp size = round_page(size); /* size of aligned pages to map */ 158194140Simp 159194140Simp if (error = vm_mmap(kernel_map, 160194140Simp &kern_buf, 161194140Simp size, 162194140Simp VM_PROT_READ, 163194140Simp VM_PROT_READ, 164201530Simp 0, 165201530Simp (caddr_t)vp, 166194140Simp offset)) 167194140Simp return error; 168194140Simp 169194140Simp *buf = kern_buf + pageoff; 170194140Simp 171194140Simp return 0; 172194140Simp} 173194140Simp 174201530Simpstatic void 175201530Simpunmap_pages(vm_offset_t buf, vm_size_t size) 176194140Simp{ 177233417Sgonzo vm_size_t pageoff; 178233417Sgonzo 179210311Sjmallett pageoff = (buf & PAGE_MASK); 180210311Sjmallett buf -= pageoff; /* start of first aligned page to map */ 181210311Sjmallett size += pageoff; 182210311Sjmallett size = round_page(size);/* size of aligned pages to map */ 183210311Sjmallett 184194140Simp vm_map_remove(kernel_map, buf, buf + size); 185210311Sjmallett} 186210311Sjmallett 187210311Sjmallettstatic int 188232812Sjmallettelf_check_permissions(struct proc *p, struct vnode *vp) 189232812Sjmallett{ 190210311Sjmallett struct vattr attr; 191233417Sgonzo int error; 192233417Sgonzo 193233417Sgonzo /* 194233417Sgonzo * Check number of open-for-writes on the file and deny execution 195233417Sgonzo * if there are any. 196233417Sgonzo */ 197233417Sgonzo if (vp->v_writecount) { 198233417Sgonzo return (ETXTBSY); 199194140Simp } 200194140Simp 201210311Sjmallett /* Get file attributes */ 202210311Sjmallett error = VOP_GETATTR(vp, &attr, p->p_ucred, p); 203194140Simp if (error) 204210311Sjmallett return (error); 205210311Sjmallett 206216318Sgonzo /* 207194140Simp * 1) Check if file execution is disabled for the filesystem that this 208210311Sjmallett * file resides on. 209194140Simp * 2) Insure that at least one execute bit is on - otherwise root 210242346Sjmallett * will always succeed, and we don't want to happen unless the 211210311Sjmallett * file really is executable. 212210311Sjmallett * 3) Insure that the file is a regular file. 213210311Sjmallett */ 214194140Simp if ((vp->v_mount->mnt_flag & MNT_NOEXEC) || 215216318Sgonzo ((attr.va_mode & 0111) == 0) || 216216320Sgonzo (attr.va_type != VREG)) { 217216318Sgonzo return (EACCES); 218210311Sjmallett } 219210311Sjmallett 220201530Simp /* 221194140Simp * Zero length files can't be exec'd 222210311Sjmallett */ 223210311Sjmallett if (attr.va_size == 0) 224210311Sjmallett return (ENOEXEC); 225210311Sjmallett 226210311Sjmallett /* 227210311Sjmallett * Check for execute permission to file based on current credentials. 228216773Sjmallett * Then call filesystem specific open routine (which does nothing 229216773Sjmallett * in the general case). 230216773Sjmallett */ 231216773Sjmallett error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 232216773Sjmallett if (error) 233216773Sjmallett return (error); 234216773Sjmallett 235216773Sjmallett error = VOP_OPEN(vp, FREAD, p->p_ucred, p); 236210311Sjmallett if (error) 237210311Sjmallett return (error); 238210311Sjmallett 239210311Sjmallett return (0); 240194140Simp} 241212842Sjmallett 242212842Sjmallettstatic int 243212842Sjmallettelf_check_header(const Elf32_Ehdr *hdr, int type) 244212842Sjmallett{ 245212842Sjmallett if (!(hdr->e_ident[EI_MAG0] == ELFMAG0 && 246212842Sjmallett hdr->e_ident[EI_MAG1] == ELFMAG1 && 247212842Sjmallett hdr->e_ident[EI_MAG2] == ELFMAG2 && 248212842Sjmallett hdr->e_ident[EI_MAG3] == ELFMAG3)) 249212842Sjmallett return ENOEXEC; 250212842Sjmallett 251212842Sjmallett if (hdr->e_machine != EM_386 && hdr->e_machine != EM_486) 252212842Sjmallett return ENOEXEC; 253210311Sjmallett 254194140Simp if (hdr->e_type != type) 255210311Sjmallett return ENOEXEC; 256210311Sjmallett 257210311Sjmallett return 0; 258210311Sjmallett} 259194140Simp 260210311Sjmallettstatic int 261210311Sjmallettelf_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) 262194140Simp{ 263210311Sjmallett size_t map_len; 264201530Simp vm_offset_t map_addr; 265194140Simp int error; 266216320Sgonzo unsigned char *data_buf = 0; 267216318Sgonzo size_t copy_len; 268216318Sgonzo 269202831Simp map_addr = trunc_page(vmaddr); 270202831Simp 271202831Simp if (memsz > filsz) 272196262Simp map_len = trunc_page(offset+filsz) - trunc_page(offset); 273201530Simp else 274201530Simp map_len = round_page(offset+filsz) - trunc_page(offset); 275196262Simp 276210311Sjmallett if (error = vm_mmap (&vmspace->vm_map, 277196262Simp &map_addr, 278243469Sjmallett map_len, 279194140Simp prot, 280243253Sjmallett VM_PROT_ALL, 281243253Sjmallett MAP_PRIVATE | MAP_FIXED, 282210311Sjmallett (caddr_t)vp, 283243253Sjmallett trunc_page(offset))) 284243253Sjmallett return error; 285210311Sjmallett 286243253Sjmallett if (memsz == filsz) 287210311Sjmallett return 0; 288201845Simp 289201881Simp /* 290243253Sjmallett * We have to map the remaining bit of the file into the kernel's 291243253Sjmallett * memory map, allocate some anonymous memory, and copy that last 292243253Sjmallett * bit into it. The remaining space should be .bss... 293202831Simp */ 294201845Simp copy_len = (offset + filsz) - trunc_page(offset + filsz); 295243253Sjmallett map_addr = trunc_page(vmaddr + filsz); 296243469Sjmallett map_len = round_page(vmaddr + memsz) - map_addr; 297243253Sjmallett 298243469Sjmallett if (map_len != 0) { 299243469Sjmallett if (error = vm_map_find(&vmspace->vm_map, NULL, 0, 300243469Sjmallett &map_addr, map_len, FALSE, 301243469Sjmallett VM_PROT_ALL, VM_PROT_ALL,0)) 302243469Sjmallett return error; 303243469Sjmallett } 304243469Sjmallett 305243253Sjmallett if (error = vm_mmap(kernel_map, 306243253Sjmallett (vm_offset_t *)&data_buf, 307243253Sjmallett PAGE_SIZE, 308243469Sjmallett VM_PROT_READ, 309243469Sjmallett VM_PROT_READ, 310243469Sjmallett 0, 311243253Sjmallett (caddr_t)vp, 312243469Sjmallett trunc_page(offset + filsz))) 313243469Sjmallett return error; 314243469Sjmallett 315243253Sjmallett error = copyout(data_buf, (caddr_t)map_addr, copy_len); 316243253Sjmallett 317243253Sjmallett vm_map_remove(kernel_map, (vm_offset_t)data_buf, 318243253Sjmallett (vm_offset_t)data_buf + PAGE_SIZE); 319243253Sjmallett 320243253Sjmallett /* 321243253Sjmallett * set it to the specified protection 322243253Sjmallett */ 323243253Sjmallett vm_map_protect(&vmspace->vm_map, map_addr, map_addr + map_len, prot, 324243253Sjmallett FALSE); 325243253Sjmallett 326243469Sjmallett UPRINTF("bss size %d (%x)\n", map_len-copy_len, map_len-copy_len); 327243469Sjmallett return error; 328243469Sjmallett} 329243469Sjmallett 330243253Sjmallettstatic int 331243253Sjmallettelf_load_file(struct proc *p, char *file, u_long *addr, u_long *entry) 332243469Sjmallett{ 333243469Sjmallett Elf32_Ehdr *hdr = NULL; 334243469Sjmallett Elf32_Phdr *phdr = NULL; 335243469Sjmallett struct nameidata nd; 336243469Sjmallett struct vmspace *vmspace = p->p_vmspace; 337243469Sjmallett vm_prot_t prot = 0; 338243469Sjmallett unsigned long text_size = 0, data_size = 0; 339243469Sjmallett unsigned long text_addr = 0, data_addr = 0; 340243469Sjmallett int header_size = 0; 341243469Sjmallett int error, i; 342202831Simp 343210311Sjmallett NDINIT(&nd, LOOKUP, LOCKLEAF|FOLLOW, UIO_SYSSPACE, file, p); 344210311Sjmallett 345210311Sjmallett if (error = namei(&nd)) 346210311Sjmallett goto fail; 347210311Sjmallett 348210311Sjmallett if (nd.ni_vp == NULL) { 349196262Simp error = ENOEXEC; 350194140Simp goto fail; 351202831Simp } 352202831Simp 353202831Simp /* 354202831Simp * Check permissions, modes, uid, etc on the file, and "open" it. 355202831Simp */ 356202831Simp error = elf_check_permissions(p, nd.ni_vp); 357202831Simp 358196262Simp /* 359202831Simp * No longer need this, and it prevents demand paging. 360196262Simp */ 361196262Simp VOP_UNLOCK(nd.ni_vp, 0, p); 362196262Simp 363202831Simp if (error) 364202831Simp goto fail; 365196262Simp 366196262Simp /* 367202850Simp * Map in the header 368202850Simp */ 369202850Simp if (error = map_pages(nd.ni_vp, 0, (vm_offset_t *)&hdr, sizeof(hdr))) 370196262Simp goto fail; 371217518Simp 372217518Simp /* 373217518Simp * Do we have a valid ELF header ? 374210311Sjmallett */ 375206721Sjmallett if (error = elf_check_header(hdr, ET_DYN)) 376217518Simp goto fail; 377206721Sjmallett 378206721Sjmallett /* 379206721Sjmallett * ouch, need to bounds check in case user gives us a corrupted 380210311Sjmallett * file with an insane header size 381206721Sjmallett */ 382210311Sjmallett if (hdr->e_phnum > MAX_PHDR) { /* XXX: ever more than this? */ 383206721Sjmallett error = ENOEXEC; 384210311Sjmallett goto fail; 385210311Sjmallett } 386210311Sjmallett 387210311Sjmallett header_size = hdr->e_phentsize * hdr->e_phnum; 388210311Sjmallett 389210311Sjmallett if (error = map_pages(nd.ni_vp, hdr->e_phoff, (vm_offset_t *)&phdr, 390210311Sjmallett header_size)) 391196262Simp goto fail; 392196262Simp 393210311Sjmallett for (i = 0; i < hdr->e_phnum; i++) { 394210311Sjmallett switch(phdr[i].p_type) { 395210311Sjmallett 396210311Sjmallett case PT_NULL: /* NULL section */ 397210311Sjmallett UPRINTF ("ELF(file) PT_NULL section\n"); 398210311Sjmallett break; 399210311Sjmallett case PT_LOAD: /* Loadable segment */ 400210311Sjmallett { 401210311Sjmallett UPRINTF ("ELF(file) PT_LOAD section "); 402210311Sjmallett if (phdr[i].p_flags & PF_X) 403210311Sjmallett prot |= VM_PROT_EXECUTE; 404210311Sjmallett if (phdr[i].p_flags & PF_W) 405210311Sjmallett prot |= VM_PROT_WRITE; 406210311Sjmallett if (phdr[i].p_flags & PF_R) 407210311Sjmallett prot |= VM_PROT_READ; 408242302Sjmallett 409242302Sjmallett if (error = elf_load_section(vmspace, nd.ni_vp, 410242302Sjmallett phdr[i].p_offset, 411242302Sjmallett (caddr_t)phdr[i].p_vaddr + 412242302Sjmallett (*addr), 413242302Sjmallett phdr[i].p_memsz, 414242302Sjmallett phdr[i].p_filesz, prot)) 415242302Sjmallett goto fail; 416242302Sjmallett 417242302Sjmallett /* 418242302Sjmallett * Is this .text or .data ?? 419242302Sjmallett * 420242302Sjmallett * We only handle one each of those yet XXX 421242302Sjmallett */ 422242302Sjmallett if (hdr->e_entry >= phdr[i].p_vaddr && 423242302Sjmallett hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) { 424242302Sjmallett text_addr = trunc_page(phdr[i].p_vaddr+(*addr)); 425242302Sjmallett text_size = round_page(phdr[i].p_memsz + 426242302Sjmallett phdr[i].p_vaddr - 427242302Sjmallett trunc_page(phdr[i].p_vaddr)); 428242302Sjmallett *entry=(unsigned long)hdr->e_entry+(*addr); 429242302Sjmallett UPRINTF(".text <%08x,%08x> entry=%08x\n", 430242302Sjmallett text_addr, text_size, *entry); 431242302Sjmallett } else { 432242302Sjmallett data_addr = trunc_page(phdr[i].p_vaddr+(*addr)); 433242302Sjmallett data_size = round_page(phdr[i].p_memsz + 434242302Sjmallett phdr[i].p_vaddr - 435242302Sjmallett trunc_page(phdr[i].p_vaddr)); 436242302Sjmallett UPRINTF(".data <%08x,%08x>\n", 437242302Sjmallett data_addr, data_size); 438242302Sjmallett } 439242302Sjmallett } 440242302Sjmallett break; 441242302Sjmallett 442242302Sjmallett case PT_DYNAMIC:/* Dynamic link information */ 443242302Sjmallett UPRINTF ("ELF(file) PT_DYNAMIC section\n"); 444242302Sjmallett break; 445242302Sjmallett case PT_INTERP: /* Path to interpreter */ 446242302Sjmallett UPRINTF ("ELF(file) PT_INTERP section\n"); 447242302Sjmallett break; 448243470Sjmallett case PT_NOTE: /* Note section */ 449243470Sjmallett UPRINTF ("ELF(file) PT_NOTE section\n"); 450243470Sjmallett break; 451243470Sjmallett case PT_SHLIB: /* Shared lib section */ 452243470Sjmallett UPRINTF ("ELF(file) PT_SHLIB section\n"); 453243470Sjmallett break; 454243470Sjmallett case PT_PHDR: /* Program header table info */ 455243470Sjmallett UPRINTF ("ELF(file) PT_PHDR section\n"); 456243470Sjmallett break; 457243470Sjmallett default: 458243470Sjmallett UPRINTF ("ELF(file) %d section ??\n", phdr[i].p_type ); 459243470Sjmallett } 460243470Sjmallett } 461243470Sjmallett 462243470Sjmallettfail: 463243470Sjmallett if (phdr) 464243470Sjmallett unmap_pages((vm_offset_t)phdr, header_size); 465243470Sjmallett if (hdr) 466215990Sjmallett unmap_pages((vm_offset_t)hdr, sizeof(hdr)); 467215990Sjmallett 468215990Sjmallett return error; 469215990Sjmallett} 470215990Sjmallett 471215990Sjmallettint 472215990Sjmallettexec_elf_imgact(struct image_params *imgp) 473215990Sjmallett{ 474215990Sjmallett const Elf32_Ehdr *hdr = (const Elf32_Ehdr *) imgp->image_header; 475215990Sjmallett const Elf32_Phdr *phdr, *mapped_phdr = NULL; 476215990Sjmallett Elf32_Auxargs *elf_auxargs = NULL; 477215990Sjmallett struct vmspace *vmspace = imgp->proc->p_vmspace; 478215990Sjmallett vm_prot_t prot = 0; 479215990Sjmallett u_long text_size = 0, data_size = 0; 480215990Sjmallett u_long text_addr = 0, data_addr = 0; 481215990Sjmallett u_long addr, entry = 0, proghdr = 0; 482215990Sjmallett int error, i, header_size = 0, interp_len = 0; 483215990Sjmallett char *interp = NULL; 484215990Sjmallett char *brand = NULL; 485215990Sjmallett char path[MAXPATHLEN]; 486215990Sjmallett 487215990Sjmallett /* 488215990Sjmallett * Do we have a valid ELF header ? 489215990Sjmallett */ 490215990Sjmallett if (elf_check_header(hdr, ET_EXEC)) 491215990Sjmallett return -1; 492215990Sjmallett 493215990Sjmallett /* 494215990Sjmallett * From here on down, we return an errno, not -1, as we've 495215990Sjmallett * detected an ELF file. 496215990Sjmallett */ 497215990Sjmallett 498215990Sjmallett /* 499215990Sjmallett * ouch, need to bounds check in case user gives us a corrupted 500215990Sjmallett * file with an insane header size 501215990Sjmallett */ 502215990Sjmallett if (hdr->e_phnum > MAX_PHDR) { /* XXX: ever more than this? */ 503215990Sjmallett return ENOEXEC; 504215990Sjmallett } 505215990Sjmallett 506215990Sjmallett header_size = hdr->e_phentsize * hdr->e_phnum; 507215990Sjmallett 508215990Sjmallett if ((hdr->e_phoff > PAGE_SIZE) || 509202831Simp (hdr->e_phoff + header_size) > PAGE_SIZE) { 510194140Simp /* 511194140Simp * Ouch ! we only get one page full of header... 512194140Simp * Try to map it in ourselves, and see how we go. 513194140Simp */ 514194140Simp if (error = map_pages(imgp->vp, hdr->e_phoff, 515194140Simp (vm_offset_t *)&mapped_phdr, header_size)) 516194140Simp return (error); 517194140Simp /* 518194140Simp * Save manual mapping for cleanup 519194140Simp */ 520194140Simp phdr = mapped_phdr; 521194140Simp } else { 522194140Simp phdr = (const Elf32_Phdr*) 523194140Simp ((const char *)imgp->image_header + hdr->e_phoff); 524194140Simp } 525194140Simp 526194140Simp /* 527194140Simp * From this point on, we may have resources that need to be freed. 528194140Simp */ 529194140Simp if (error = exec_extract_strings(imgp)) 530194140Simp goto fail; 531194140Simp 532194140Simp exec_new_vmspace(imgp); 533194140Simp 534194140Simp for (i = 0; i < hdr->e_phnum; i++) { 535194140Simp switch(phdr[i].p_type) { 536194140Simp 537194140Simp case PT_NULL: /* NULL section */ 538194140Simp UPRINTF ("ELF PT_NULL section\n"); 539200344Simp break; 540200344Simp case PT_LOAD: /* Loadable segment */ 541200344Simp { 542194140Simp UPRINTF ("ELF PT_LOAD section "); 543200344Simp if (phdr[i].p_flags & PF_X) 544200344Simp prot |= VM_PROT_EXECUTE; 545200344Simp if (phdr[i].p_flags & PF_W) 546200344Simp prot |= VM_PROT_WRITE; 547200344Simp if (phdr[i].p_flags & PF_R) 548200344Simp prot |= VM_PROT_READ; 549194140Simp 550200344Simp if (error = elf_load_section(vmspace, imgp->vp, 551200344Simp phdr[i].p_offset, 552200344Simp (caddr_t)phdr[i].p_vaddr, 553200344Simp phdr[i].p_memsz, 554200344Simp phdr[i].p_filesz, prot)) 555200344Simp goto fail; 556200344Simp 557200344Simp /* 558200344Simp * Is this .text or .data ?? 559200344Simp * 560200344Simp * We only handle one each of those yet XXX 561200344Simp */ 562200344Simp if (hdr->e_entry >= phdr[i].p_vaddr && 563200344Simp hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) { 564200344Simp text_addr = trunc_page(phdr[i].p_vaddr); 565200344Simp text_size = round_page(phdr[i].p_memsz + 566200344Simp phdr[i].p_vaddr - 567200344Simp text_addr); 568200344Simp entry = (u_long)hdr->e_entry; 569200344Simp UPRINTF(".text <%08x,%08x> entry=%08x\n", 570200344Simp text_addr, text_size, entry); 571200344Simp } else { 572200344Simp data_addr = trunc_page(phdr[i].p_vaddr); 573194140Simp data_size = round_page(phdr[i].p_memsz + 574194140Simp phdr[i].p_vaddr - 575243253Sjmallett data_addr); 576243253Sjmallett UPRINTF(".data <%08x,%08x>\n", 577243253Sjmallett data_addr, data_size); 578243253Sjmallett } 579194140Simp } 580200344Simp break; 581200344Simp 582243253Sjmallett case PT_DYNAMIC:/* Dynamic link information */ 583243253Sjmallett UPRINTF ("ELF PT_DYNAMIC section ??\n"); 584243253Sjmallett break; 585243253Sjmallett case PT_INTERP: /* Path to interpreter */ 586243253Sjmallett UPRINTF ("ELF PT_INTERP section "); 587210311Sjmallett if (phdr[i].p_filesz > MAXPATHLEN) { 588243253Sjmallett error = ENOEXEC; 589243253Sjmallett goto fail; 590243253Sjmallett } 591243253Sjmallett interp_len = MAXPATHLEN; 592243253Sjmallett if (error = map_pages(imgp->vp, phdr[i].p_offset, 593243253Sjmallett (vm_offset_t *)&interp, interp_len)) 594243253Sjmallett goto fail; 595194140Simp UPRINTF("<%s>\n", interp); 596215990Sjmallett break; 597210311Sjmallett case PT_NOTE: /* Note section */ 598210311Sjmallett UPRINTF ("ELF PT_NOTE section\n"); 599210311Sjmallett break; 600210311Sjmallett case PT_SHLIB: /* Shared lib section */ 601242276Sjmallett UPRINTF ("ELF PT_SHLIB section\n"); 602242276Sjmallett break; 603228088Sgonzo case PT_PHDR: /* Program header table info */ 604228853Sgonzo UPRINTF ("ELF PT_PHDR section <%x>\n", phdr[i].p_vaddr); 605228853Sgonzo proghdr = phdr[i].p_vaddr; 606228872Sgonzo break; 607228872Sgonzo default: 608232402Sjmallett UPRINTF ("ELF %d section ??\n", phdr[i].p_type); 609242276Sjmallett } 610242276Sjmallett } 611242276Sjmallett 612242276Sjmallett vmspace->vm_tsize = text_size >> PAGE_SHIFT; 613242276Sjmallett vmspace->vm_taddr = (caddr_t)text_addr; 614243253Sjmallett vmspace->vm_dsize = data_size >> PAGE_SHIFT; 615194140Simp vmspace->vm_daddr = (caddr_t)data_addr; 616194140Simp 617200344Simp addr = 2*MAXDSIZ; /* May depend on OS type XXX */ 618200344Simp 619194140Simp imgp->entry_addr = entry; 620243253Sjmallett 621243253Sjmallett /* 622243253Sjmallett * So which kind (brand) of ELF binary do we have at hand 623243253Sjmallett * FreeBSD, Linux, SVR4 or something else ?? 624243253Sjmallett * If its has a interpreter section try that first 625210311Sjmallett */ 626243253Sjmallett if (interp) { 627243253Sjmallett for (i=0; i<MAX_BRANDS; i++) { 628194140Simp if (elf_brand_list[i] != NULL) { 629210311Sjmallett if (!strcmp(interp, elf_brand_list[i]->interp_path)) { 630243253Sjmallett imgp->proc->p_sysent = 631243253Sjmallett elf_brand_list[i]->sysvec; 632243253Sjmallett strcpy(path, elf_brand_list[i]->emul_path); 633243253Sjmallett strcat(path, elf_brand_list[i]->interp_path); 634243253Sjmallett UPRINTF("interpreter=<%s> %s\n", 635243253Sjmallett elf_brand_list[i]->interp_path, 636243253Sjmallett elf_brand_list[i]->emul_path); 637243253Sjmallett break; 638243253Sjmallett } 639210311Sjmallett } 640242273Sjmallett } 641242273Sjmallett } 642242273Sjmallett 643242273Sjmallett /* 644242273Sjmallett * If there is no interpreter, or recognition of it 645242273Sjmallett * failed, se if the binary is branded. 646242273Sjmallett */ 647242273Sjmallett if (!interp || i == MAX_BRANDS) { 648242273Sjmallett brand = (char *)&(hdr->e_ident[EI_BRAND]); 649242273Sjmallett for (i=0; i<MAX_BRANDS; i++) { 650242273Sjmallett if (elf_brand_list[i] != NULL) { 651242273Sjmallett if (!strcmp(brand, elf_brand_list[i]->brand)) { 652243253Sjmallett imgp->proc->p_sysent = elf_brand_list[i]->sysvec; 653243253Sjmallett if (interp) { 654243253Sjmallett strcpy(path, elf_brand_list[i]->emul_path); 655243253Sjmallett strcat(path, elf_brand_list[i]->interp_path); 656215990Sjmallett UPRINTF("interpreter=<%s> %s\n", 657210311Sjmallett elf_brand_list[i]->interp_path, 658242342Sjmallett elf_brand_list[i]->emul_path); 659242342Sjmallett } 660242342Sjmallett break; 661194140Simp } 662202831Simp } 663 } 664 } 665 if (i == MAX_BRANDS) { 666 uprintf("ELF binary type not known\n"); 667 error = ENOEXEC; 668 goto fail; 669 } 670 if (interp) { 671 if (error = elf_load_file(imgp->proc, 672 path, 673 &addr, /* XXX */ 674 &imgp->entry_addr)) { 675 uprintf("ELF interpreter %s not found\n", path); 676 goto fail; 677 } 678 } 679 680 UPRINTF("Executing %s binary\n", elf_brand_list[i]->brand); 681 682 /* 683 * Construct auxargs table (used by the fixup routine) 684 */ 685 elf_auxargs = malloc(sizeof(Elf32_Auxargs), M_TEMP, M_WAITOK); 686 elf_auxargs->execfd = -1; 687 elf_auxargs->phdr = proghdr; 688 elf_auxargs->phent = hdr->e_phentsize; 689 elf_auxargs->phnum = hdr->e_phnum; 690 elf_auxargs->pagesz = PAGE_SIZE; 691 elf_auxargs->base = addr; 692 elf_auxargs->flags = 0; 693 elf_auxargs->entry = entry; 694 elf_auxargs->trace = elf_trace; 695 696 imgp->auxargs = elf_auxargs; 697 imgp->interpreted = 0; 698 699 /* don't allow modifying the file while we run it */ 700 imgp->vp->v_flag |= VTEXT; 701 702fail: 703 if (mapped_phdr) 704 unmap_pages((vm_offset_t)mapped_phdr, header_size); 705 if (interp) 706 unmap_pages((vm_offset_t)interp, interp_len); 707 708 return error; 709} 710 711static int 712elf_freebsd_fixup(int **stack_base, struct image_params *imgp) 713{ 714 Elf32_Auxargs *args = (Elf32_Auxargs *)imgp->auxargs; 715 int *pos; 716 717 pos = *stack_base + (imgp->argc + imgp->envc + 2); 718 719 if (args->trace) { 720 AUXARGS_ENTRY(pos, AT_DEBUG, 1); 721 } 722 if (args->execfd != -1) { 723 AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); 724 } 725 AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); 726 AUXARGS_ENTRY(pos, AT_PHENT, args->phent); 727 AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); 728 AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); 729 AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); 730 AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); 731 AUXARGS_ENTRY(pos, AT_BASE, args->base); 732 AUXARGS_ENTRY(pos, AT_NULL, 0); 733 734 free(imgp->auxargs, M_TEMP); 735 imgp->auxargs = NULL; 736 737 (*stack_base)--; 738 **stack_base = (int)imgp->argc; 739 return 0; 740} 741 742/* 743 * Tell kern_execve.c about it, with a little help from the linker. 744 * Since `const' objects end up in the text segment, TEXT_SET is the 745 * correct directive to use. 746 */ 747const struct execsw elf_execsw = {exec_elf_imgact, "ELF"}; 748TEXT_SET(execsw_set, elf_execsw); 749 750