imgact_elf.c revision 48594
1327952Sdim/*- 2311116Sdim * Copyright (c) 1995-1996 S�ren Schmidt 3353358Sdim * Copyright (c) 1996 Peter Wemm 4353358Sdim * All rights reserved. 5353358Sdim * 6311116Sdim * Redistribution and use in source and binary forms, with or without 7327952Sdim * modification, are permitted provided that the following conditions 8327952Sdim * are met: 9311116Sdim * 1. Redistributions of source code must retain the above copyright 10311116Sdim * notice, this list of conditions and the following disclaimer 11311116Sdim * in this position and unchanged. 12311116Sdim * 2. Redistributions in binary form must reproduce the above copyright 13327952Sdim * notice, this list of conditions and the following disclaimer in the 14327952Sdim * documentation and/or other materials provided with the distribution. 15311116Sdim * 3. The name of the author may not be used to endorse or promote products 16311116Sdim * derived from this software withough specific prior written permission 17327952Sdim * 18327952Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19327952Sdim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20321369Sdim * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21327952Sdim * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22327952Sdim * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23327952Sdim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24327952Sdim * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25327952Sdim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26327952Sdim * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27327952Sdim * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28327952Sdim * 29327952Sdim * $Id: imgact_elf.c,v 1.58 1999/05/17 00:53:38 alc Exp $ 30327952Sdim */ 31341825Sdim 32327952Sdim#include "opt_rlimit.h" 33327952Sdim 34327952Sdim#include <sys/param.h> 35327952Sdim#include <sys/acct.h> 36311116Sdim#include <sys/exec.h> 37311116Sdim#include <sys/fcntl.h> 38311116Sdim#include <sys/imgact.h> 39321369Sdim#include <sys/imgact_elf.h> 40327952Sdim#include <sys/kernel.h> 41341825Sdim#include <sys/malloc.h> 42311116Sdim#include <sys/mman.h> 43311116Sdim#include <sys/namei.h> 44311116Sdim#include <sys/pioctl.h> 45311116Sdim#include <sys/proc.h> 46311116Sdim#include <sys/procfs.h> 47311116Sdim#include <sys/resourcevar.h> 48311116Sdim#include <sys/signalvar.h> 49311116Sdim#include <sys/stat.h> 50341825Sdim#include <sys/syscall.h> 51311116Sdim#include <sys/sysctl.h> 52311116Sdim#include <sys/sysent.h> 53311116Sdim#include <sys/systm.h> 54341825Sdim#include <sys/vnode.h> 55311116Sdim 56311116Sdim#include <vm/vm.h> 57341825Sdim#include <vm/vm_kern.h> 58311116Sdim#include <vm/vm_param.h> 59311116Sdim#include <vm/pmap.h> 60341825Sdim#include <sys/lock.h> 61311116Sdim#include <vm/vm_map.h> 62311116Sdim#include <vm/vm_object.h> 63341825Sdim#include <vm/vm_prot.h> 64311116Sdim#include <vm/vm_extern.h> 65311116Sdim 66311116Sdim#include <machine/elf.h> 67311116Sdim#include <machine/md_var.h> 68311116Sdim 69311116Sdim__ElfType(Brandinfo); 70341825Sdim__ElfType(Auxargs); 71321369Sdim 72321369Sdimstatic int elf_check_header __P((const Elf_Ehdr *hdr)); 73311116Sdimstatic int elf_freebsd_fixup __P((long **stack_base, 74311116Sdim struct image_params *imgp)); 75341825Sdimstatic int elf_load_file __P((struct proc *p, char *file, u_long *addr, 76311116Sdim u_long *entry)); 77311116Sdimstatic int elf_load_section __P((struct proc *p, 78311116Sdim struct vmspace *vmspace, struct vnode *vp, 79311116Sdim vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, 80311116Sdim vm_prot_t prot)); 81311116Sdimstatic int exec_elf_imgact __P((struct image_params *imgp)); 82311116Sdim 83311116Sdimstatic int elf_trace = 0; 84311116SdimSYSCTL_INT(_debug, OID_AUTO, elf_trace, CTLFLAG_RW, &elf_trace, 0, ""); 85311116Sdim 86311116Sdim/* 87311116Sdim * XXX Maximum length of an ELF brand (sysctl wants a statically-allocated 88311116Sdim * buffer). 89327952Sdim */ 90327952Sdim#define MAXBRANDLEN 16 91327952Sdim 92327952Sdimstatic struct sysentvec elf_freebsd_sysvec = { 93327952Sdim SYS_MAXSYSCALL, 94327952Sdim sysent, 95327952Sdim 0, 96327952Sdim 0, 97327952Sdim 0, 98327952Sdim 0, 99327952Sdim 0, 100327952Sdim 0, 101311116Sdim elf_freebsd_fixup, 102311116Sdim sendsig, 103311116Sdim sigcode, 104311116Sdim &szsigcode, 105311116Sdim 0, 106311116Sdim "FreeBSD ELF", 107311116Sdim elf_coredump 108311116Sdim}; 109311116Sdim 110311116Sdimstatic Elf_Brandinfo freebsd_brand_info = { 111321369Sdim "FreeBSD", 112311116Sdim "", 113311116Sdim "/usr/libexec/ld-elf.so.1", 114311116Sdim &elf_freebsd_sysvec 115311116Sdim }; 116311116Sdimstatic Elf_Brandinfo *elf_brand_list[MAX_BRANDS] = { 117341825Sdim &freebsd_brand_info, 118311116Sdim NULL, NULL, NULL, 119311116Sdim NULL, NULL, NULL, NULL 120311116Sdim }; 121341825Sdim 122311116Sdimint 123311116Sdimelf_insert_brand_entry(Elf_Brandinfo *entry) 124311116Sdim{ 125327952Sdim int i; 126321369Sdim 127311116Sdim for (i=1; i<MAX_BRANDS; i++) { 128311116Sdim if (elf_brand_list[i] == NULL) { 129311116Sdim elf_brand_list[i] = entry; 130311116Sdim break; 131327952Sdim } 132327952Sdim } 133311116Sdim if (i == MAX_BRANDS) 134327952Sdim return -1; 135327952Sdim return 0; 136327952Sdim} 137327952Sdim 138327952Sdimint 139327952Sdimelf_remove_brand_entry(Elf_Brandinfo *entry) 140327952Sdim{ 141311116Sdim int i; 142311116Sdim 143327952Sdim for (i=1; i<MAX_BRANDS; i++) { 144327952Sdim if (elf_brand_list[i] == entry) { 145327952Sdim elf_brand_list[i] = NULL; 146327952Sdim break; 147327952Sdim } 148327952Sdim } 149327952Sdim if (i == MAX_BRANDS) 150327952Sdim return -1; 151327952Sdim return 0; 152327952Sdim} 153327952Sdim 154327952Sdimint 155327952Sdimelf_brand_inuse(Elf_Brandinfo *entry) 156327952Sdim{ 157327952Sdim struct proc *p; 158327952Sdim 159327952Sdim for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { 160327952Sdim if (p->p_sysent == entry->sysvec) 161327952Sdim return TRUE; 162327952Sdim } 163327952Sdim 164327952Sdim return FALSE; 165311116Sdim} 166311116Sdim 167321369Sdimstatic int 168311116Sdimelf_check_header(const Elf_Ehdr *hdr) 169311116Sdim{ 170321369Sdim if (!IS_ELF(*hdr) || 171321369Sdim hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || 172321369Sdim hdr->e_ident[EI_DATA] != ELF_TARG_DATA || 173327952Sdim hdr->e_ident[EI_VERSION] != EV_CURRENT) 174327952Sdim return ENOEXEC; 175327952Sdim 176327952Sdim if (!ELF_MACHINE_OK(hdr->e_machine)) 177311116Sdim return ENOEXEC; 178311116Sdim 179311116Sdim if (hdr->e_version != ELF_TARG_VER) 180321369Sdim return ENOEXEC; 181321369Sdim 182321369Sdim return 0; 183311116Sdim} 184321369Sdim 185321369Sdimstatic int 186321369Sdimelf_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) 187321369Sdim{ 188327952Sdim size_t map_len; 189327952Sdim vm_offset_t map_addr; 190327952Sdim int error, rv; 191321369Sdim size_t copy_len; 192321369Sdim vm_object_t object; 193321369Sdim vm_offset_t file_addr; 194321369Sdim vm_offset_t data_buf = 0; 195311116Sdim 196353358Sdim object = vp->v_object; 197327952Sdim error = 0; 198327952Sdim 199327952Sdim map_addr = trunc_page((vm_offset_t)vmaddr); 200327952Sdim file_addr = trunc_page(offset); 201327952Sdim 202327952Sdim /* 203327952Sdim * We have two choices. We can either clear the data in the last page 204353358Sdim * of an oversized mapping, or we can start the anon mapping a page 205353358Sdim * early and copy the initialized data into that first page. We 206353358Sdim * choose the second.. 207327952Sdim */ 208353358Sdim if (memsz > filsz) 209353358Sdim map_len = trunc_page(offset+filsz) - file_addr; 210353358Sdim else 211327952Sdim map_len = round_page(offset+filsz) - file_addr; 212353358Sdim 213321369Sdim if (map_len != 0) { 214327952Sdim vm_object_reference(object); 215321369Sdim vm_map_lock(&vmspace->vm_map); 216353358Sdim rv = vm_map_insert(&vmspace->vm_map, 217353358Sdim object, 218311116Sdim file_addr, /* file offset */ 219353358Sdim map_addr, /* virtual start */ 220311116Sdim map_addr + map_len,/* virtual end */ 221311116Sdim prot, 222311116Sdim VM_PROT_ALL, 223311116Sdim MAP_COPY_ON_WRITE | MAP_PREFAULT); 224327952Sdim vm_map_unlock(&vmspace->vm_map); 225327952Sdim if (rv != KERN_SUCCESS) 226327952Sdim return EINVAL; 227327952Sdim 228327952Sdim /* we can stop now if we've covered it all */ 229327952Sdim if (memsz == filsz) 230327952Sdim return 0; 231327952Sdim } 232327952Sdim 233327952Sdim 234327952Sdim /* 235327952Sdim * We have to get the remaining bit of the file into the first part 236327952Sdim * of the oversized map segment. This is normally because the .data 237327952Sdim * segment in the file is extended to provide bss. It's a neat idea 238327952Sdim * to try and save a page, but it's a pain in the behind to implement. 239327952Sdim */ 240327952Sdim copy_len = (offset + filsz) - trunc_page(offset + filsz); 241327952Sdim map_addr = trunc_page((vm_offset_t)vmaddr + filsz); 242327952Sdim map_len = round_page((vm_offset_t)vmaddr + memsz) - map_addr; 243327952Sdim 244327952Sdim /* This had damn well better be true! */ 245327952Sdim if (map_len != 0) { 246327952Sdim vm_map_lock(&vmspace->vm_map); 247327952Sdim rv = vm_map_insert(&vmspace->vm_map, NULL, 0, 248327952Sdim map_addr, map_addr + map_len, 249327952Sdim VM_PROT_ALL, VM_PROT_ALL, 0); 250327952Sdim vm_map_unlock(&vmspace->vm_map); 251327952Sdim if (rv != KERN_SUCCESS) 252327952Sdim return EINVAL; 253327952Sdim } 254327952Sdim 255327952Sdim if (copy_len != 0) { 256327952Sdim vm_object_reference(object); 257327952Sdim rv = vm_map_find(exec_map, 258327952Sdim object, 259327952Sdim trunc_page(offset + filsz), 260327952Sdim &data_buf, 261327952Sdim PAGE_SIZE, 262327952Sdim TRUE, 263327952Sdim VM_PROT_READ, 264327952Sdim VM_PROT_ALL, 265327952Sdim MAP_COPY_ON_WRITE | MAP_PREFAULT_PARTIAL); 266327952Sdim if (rv != KERN_SUCCESS) { 267327952Sdim vm_object_deallocate(object); 268327952Sdim return EINVAL; 269327952Sdim } 270327952Sdim 271327952Sdim /* send the page fragment to user space */ 272327952Sdim error = copyout((caddr_t)data_buf, (caddr_t)map_addr, copy_len); 273327952Sdim vm_map_remove(exec_map, data_buf, data_buf + PAGE_SIZE); 274327952Sdim if (error) 275327952Sdim return (error); 276327952Sdim } 277327952Sdim 278327952Sdim /* 279327952Sdim * set it to the specified protection 280327952Sdim */ 281327952Sdim vm_map_protect(&vmspace->vm_map, map_addr, map_addr + map_len, prot, 282327952Sdim FALSE); 283327952Sdim 284327952Sdim return error; 285327952Sdim} 286327952Sdim 287327952Sdim/* 288327952Sdim * Load the file "file" into memory. It may be either a shared object 289327952Sdim * or an executable. 290327952Sdim * 291327952Sdim * The "addr" reference parameter is in/out. On entry, it specifies 292327952Sdim * the address where a shared object should be loaded. If the file is 293327952Sdim * an executable, this value is ignored. On exit, "addr" specifies 294327952Sdim * where the file was actually loaded. 295327952Sdim * 296327952Sdim * The "entry" reference parameter is out only. On exit, it specifies 297327952Sdim * the entry point for the loaded file. 298327952Sdim */ 299327952Sdimstatic int 300327952Sdimelf_load_file(struct proc *p, char *file, u_long *addr, u_long *entry) 301327952Sdim{ 302327952Sdim const Elf_Ehdr *hdr = NULL; 303327952Sdim const Elf_Phdr *phdr = NULL; 304327952Sdim struct nameidata nd; 305327952Sdim struct vmspace *vmspace = p->p_vmspace; 306327952Sdim struct vattr attr; 307327952Sdim struct image_params image_params, *imgp; 308327952Sdim vm_prot_t prot; 309327952Sdim u_long rbase; 310327952Sdim u_long base_addr = 0; 311327952Sdim int error, i, numsegs; 312327952Sdim 313327952Sdim imgp = &image_params; 314327952Sdim /* 315327952Sdim * Initialize part of the common data 316327952Sdim */ 317327952Sdim imgp->proc = p; 318327952Sdim imgp->uap = NULL; 319327952Sdim imgp->attr = &attr; 320327952Sdim imgp->firstpage = NULL; 321327952Sdim imgp->image_header = (char *)kmem_alloc_wait(exec_map, PAGE_SIZE); 322327952Sdim 323327952Sdim if (imgp->image_header == NULL) { 324327952Sdim nd.ni_vp = NULL; 325327952Sdim error = ENOMEM; 326327952Sdim goto fail; 327327952Sdim } 328327952Sdim 329327952Sdim NDINIT(&nd, LOOKUP, LOCKLEAF|FOLLOW, UIO_SYSSPACE, file, p); 330327952Sdim 331327952Sdim if ((error = namei(&nd)) != 0) { 332327952Sdim nd.ni_vp = NULL; 333327952Sdim goto fail; 334327952Sdim } 335327952Sdim 336327952Sdim imgp->vp = nd.ni_vp; 337327952Sdim 338327952Sdim /* 339327952Sdim * Check permissions, modes, uid, etc on the file, and "open" it. 340327952Sdim */ 341327952Sdim error = exec_check_permissions(imgp); 342327952Sdim if (error) { 343327952Sdim VOP_UNLOCK(nd.ni_vp, 0, p); 344327952Sdim goto fail; 345327952Sdim } 346327952Sdim 347327952Sdim error = exec_map_first_page(imgp); 348327952Sdim VOP_UNLOCK(nd.ni_vp, 0, p); 349327952Sdim if (error) 350327952Sdim goto fail; 351327952Sdim 352327952Sdim hdr = (const Elf_Ehdr *)imgp->image_header; 353327952Sdim if ((error = elf_check_header(hdr)) != 0) 354327952Sdim goto fail; 355327952Sdim if (hdr->e_type == ET_DYN) 356327952Sdim rbase = *addr; 357327952Sdim else if (hdr->e_type == ET_EXEC) 358327952Sdim rbase = 0; 359327952Sdim else { 360327952Sdim error = ENOEXEC; 361327952Sdim goto fail; 362327952Sdim } 363327952Sdim 364327952Sdim /* Only support headers that fit within first page for now */ 365327952Sdim if ((hdr->e_phoff > PAGE_SIZE) || 366327952Sdim (hdr->e_phoff + hdr->e_phentsize * hdr->e_phnum) > PAGE_SIZE) { 367327952Sdim error = ENOEXEC; 368327952Sdim goto fail; 369327952Sdim } 370327952Sdim 371327952Sdim phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff); 372327952Sdim 373327952Sdim for (i = 0, numsegs = 0; i < hdr->e_phnum; i++) { 374327952Sdim if (phdr[i].p_type == PT_LOAD) { /* Loadable segment */ 375327952Sdim prot = 0; 376327952Sdim if (phdr[i].p_flags & PF_X) 377327952Sdim prot |= VM_PROT_EXECUTE; 378327952Sdim if (phdr[i].p_flags & PF_W) 379327952Sdim prot |= VM_PROT_WRITE; 380327952Sdim if (phdr[i].p_flags & PF_R) 381327952Sdim prot |= VM_PROT_READ; 382327952Sdim 383327952Sdim if ((error = elf_load_section(p, vmspace, nd.ni_vp, 384327952Sdim phdr[i].p_offset, 385327952Sdim (caddr_t)phdr[i].p_vaddr + 386327952Sdim rbase, 387327952Sdim phdr[i].p_memsz, 388327952Sdim phdr[i].p_filesz, prot)) != 0) 389327952Sdim goto fail; 390327952Sdim /* 391327952Sdim * Establish the base address if this is the 392327952Sdim * first segment. 393327952Sdim */ 394327952Sdim if (numsegs == 0) 395327952Sdim base_addr = trunc_page(phdr[i].p_vaddr + rbase); 396327952Sdim numsegs++; 397327952Sdim } 398327952Sdim } 399327952Sdim *addr = base_addr; 400327952Sdim *entry=(unsigned long)hdr->e_entry + rbase; 401327952Sdim 402327952Sdimfail: 403327952Sdim if (imgp->firstpage) 404327952Sdim exec_unmap_first_page(imgp); 405327952Sdim if (imgp->image_header) 406327952Sdim kmem_free_wakeup(exec_map, (vm_offset_t)imgp->image_header, 407327952Sdim PAGE_SIZE); 408327952Sdim if (nd.ni_vp) 409327952Sdim vrele(nd.ni_vp); 410327952Sdim 411327952Sdim return error; 412327952Sdim} 413327952Sdim 414327952Sdimstatic char fallback_elf_brand[MAXBRANDLEN+1] = { "none" }; 415327952SdimSYSCTL_STRING(_kern, OID_AUTO, fallback_elf_brand, CTLFLAG_RW, 416327952Sdim fallback_elf_brand, sizeof(fallback_elf_brand), 417327952Sdim "ELF brand of last resort"); 418327952Sdim 419327952Sdimstatic int 420327952Sdimexec_elf_imgact(struct image_params *imgp) 421327952Sdim{ 422353358Sdim const Elf_Ehdr *hdr = (const Elf_Ehdr *) imgp->image_header; 423327952Sdim const Elf_Phdr *phdr; 424327952Sdim Elf_Auxargs *elf_auxargs = NULL; 425327952Sdim struct vmspace *vmspace; 426327952Sdim vm_prot_t prot; 427327952Sdim u_long text_size = 0, data_size = 0; 428327952Sdim u_long text_addr = 0, data_addr = 0; 429327952Sdim u_long addr, entry = 0, proghdr = 0; 430327952Sdim int error, i; 431327952Sdim const char *interp = NULL; 432327952Sdim Elf_Brandinfo *brand_info; 433327952Sdim const char *brand; 434327952Sdim char path[MAXPATHLEN]; 435327952Sdim 436327952Sdim /* 437327952Sdim * Do we have a valid ELF header ? 438327952Sdim */ 439327952Sdim if (elf_check_header(hdr) != 0 || hdr->e_type != ET_EXEC) 440327952Sdim return -1; 441327952Sdim 442327952Sdim /* 443327952Sdim * From here on down, we return an errno, not -1, as we've 444327952Sdim * detected an ELF file. 445327952Sdim */ 446327952Sdim 447327952Sdim if ((hdr->e_phoff > PAGE_SIZE) || 448327952Sdim (hdr->e_phoff + hdr->e_phentsize * hdr->e_phnum) > PAGE_SIZE) { 449327952Sdim /* Only support headers in first page for now */ 450327952Sdim return ENOEXEC; 451327952Sdim } 452327952Sdim phdr = (const Elf_Phdr*)(imgp->image_header + hdr->e_phoff); 453327952Sdim 454327952Sdim /* 455327952Sdim * From this point on, we may have resources that need to be freed. 456327952Sdim */ 457327952Sdim if ((error = exec_extract_strings(imgp)) != 0) 458327952Sdim goto fail; 459327952Sdim 460327952Sdim exec_new_vmspace(imgp); 461327952Sdim 462327952Sdim vmspace = imgp->proc->p_vmspace; 463327952Sdim 464327952Sdim for (i = 0; i < hdr->e_phnum; i++) { 465327952Sdim switch(phdr[i].p_type) { 466327952Sdim 467327952Sdim case PT_LOAD: /* Loadable segment */ 468327952Sdim prot = 0; 469344779Sdim if (phdr[i].p_flags & PF_X) 470327952Sdim prot |= VM_PROT_EXECUTE; 471327952Sdim if (phdr[i].p_flags & PF_W) 472327952Sdim prot |= VM_PROT_WRITE; 473327952Sdim if (phdr[i].p_flags & PF_R) 474327952Sdim prot |= VM_PROT_READ; 475327952Sdim 476327952Sdim if ((error = elf_load_section(imgp->proc, 477327952Sdim vmspace, imgp->vp, 478327952Sdim phdr[i].p_offset, 479327952Sdim (caddr_t)phdr[i].p_vaddr, 480327952Sdim phdr[i].p_memsz, 481327952Sdim phdr[i].p_filesz, prot)) != 0) 482327952Sdim goto fail; 483327952Sdim 484327952Sdim /* 485327952Sdim * Is this .text or .data ?? 486327952Sdim * 487327952Sdim * We only handle one each of those yet XXX 488327952Sdim */ 489327952Sdim if (hdr->e_entry >= phdr[i].p_vaddr && 490327952Sdim hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) { 491327952Sdim text_addr = trunc_page(phdr[i].p_vaddr); 492327952Sdim text_size = round_page(phdr[i].p_memsz + 493327952Sdim phdr[i].p_vaddr - 494327952Sdim text_addr); 495327952Sdim entry = (u_long)hdr->e_entry; 496327952Sdim } else { 497327952Sdim data_addr = trunc_page(phdr[i].p_vaddr); 498327952Sdim data_size = round_page(phdr[i].p_memsz + 499327952Sdim phdr[i].p_vaddr - 500327952Sdim data_addr); 501327952Sdim } 502327952Sdim break; 503327952Sdim case PT_INTERP: /* Path to interpreter */ 504327952Sdim if (phdr[i].p_filesz > MAXPATHLEN || 505327952Sdim phdr[i].p_offset + phdr[i].p_filesz > PAGE_SIZE) { 506327952Sdim error = ENOEXEC; 507327952Sdim goto fail; 508327952Sdim } 509327952Sdim interp = imgp->image_header + phdr[i].p_offset; 510327952Sdim break; 511327952Sdim case PT_PHDR: /* Program header table info */ 512327952Sdim proghdr = phdr[i].p_vaddr; 513327952Sdim break; 514327952Sdim default: 515327952Sdim break; 516327952Sdim } 517327952Sdim } 518327952Sdim 519327952Sdim vmspace->vm_tsize = text_size >> PAGE_SHIFT; 520327952Sdim vmspace->vm_taddr = (caddr_t)(uintptr_t)text_addr; 521327952Sdim vmspace->vm_dsize = data_size >> PAGE_SHIFT; 522327952Sdim vmspace->vm_daddr = (caddr_t)(uintptr_t)data_addr; 523327952Sdim 524327952Sdim addr = ELF_RTLD_ADDR(vmspace); 525327952Sdim 526327952Sdim imgp->entry_addr = entry; 527327952Sdim 528327952Sdim /* If the executable has a brand, search for it in the brand list. */ 529327952Sdim brand_info = NULL; 530327952Sdim brand = (const char *)&hdr->e_ident[EI_BRAND]; 531327952Sdim if (brand[0] != '\0') { 532327952Sdim for (i = 0; i < MAX_BRANDS; i++) { 533327952Sdim Elf_Brandinfo *bi = elf_brand_list[i]; 534327952Sdim 535327952Sdim if (bi != NULL && strcmp(brand, bi->brand) == 0) { 536327952Sdim brand_info = bi; 537327952Sdim break; 538327952Sdim } 539327952Sdim } 540327952Sdim } 541327952Sdim 542327952Sdim /* Lacking a known brand, search for a recognized interpreter. */ 543327952Sdim if (brand_info == NULL && interp != NULL) { 544327952Sdim for (i = 0; i < MAX_BRANDS; i++) { 545327952Sdim Elf_Brandinfo *bi = elf_brand_list[i]; 546327952Sdim 547327952Sdim if (bi != NULL && 548327952Sdim strcmp(interp, bi->interp_path) == 0) { 549327952Sdim brand_info = bi; 550327952Sdim break; 551327952Sdim } 552327952Sdim } 553327952Sdim } 554327952Sdim 555327952Sdim /* Lacking a recognized interpreter, try the default brand */ 556327952Sdim if (brand_info == NULL && fallback_elf_brand[0] != '\0') { 557327952Sdim for (i = 0; i < MAX_BRANDS; i++) { 558327952Sdim Elf_Brandinfo *bi = elf_brand_list[i]; 559327952Sdim 560327952Sdim if (bi != NULL 561327952Sdim && strcmp(fallback_elf_brand, bi->brand) == 0) { 562327952Sdim brand_info = bi; 563327952Sdim break; 564327952Sdim } 565327952Sdim } 566327952Sdim } 567327952Sdim 568327952Sdim#ifdef __alpha__ 569327952Sdim /* XXX - Assume FreeBSD on the alpha. */ 570327952Sdim if (brand_info == NULL) 571327952Sdim brand_info = &freebsd_brand_info; 572327952Sdim#endif 573327952Sdim 574327952Sdim if (brand_info == NULL) { 575327952Sdim if (brand[0] == 0) 576327952Sdim uprintf("ELF binary type not known." 577327952Sdim " Use \"brandelf\" to brand it.\n"); 578327952Sdim else 579327952Sdim uprintf("ELF binary type \"%.*s\" not known.\n", 580327952Sdim EI_NIDENT - EI_BRAND, brand); 581327952Sdim error = ENOEXEC; 582327952Sdim goto fail; 583327952Sdim } 584327952Sdim 585327952Sdim imgp->proc->p_sysent = brand_info->sysvec; 586327952Sdim if (interp != NULL) { 587327952Sdim snprintf(path, sizeof(path), "%s%s", 588327952Sdim brand_info->emul_path, interp); 589327952Sdim if ((error = elf_load_file(imgp->proc, path, &addr, 590327952Sdim &imgp->entry_addr)) != 0) { 591327952Sdim if ((error = elf_load_file(imgp->proc, interp, &addr, 592327952Sdim &imgp->entry_addr)) != 0) { 593327952Sdim uprintf("ELF interpreter %s not found\n", 594327952Sdim path); 595327952Sdim goto fail; 596327952Sdim } 597327952Sdim } 598327952Sdim } 599327952Sdim 600327952Sdim /* 601327952Sdim * Construct auxargs table (used by the fixup routine) 602327952Sdim */ 603327952Sdim elf_auxargs = malloc(sizeof(Elf_Auxargs), M_TEMP, M_WAITOK); 604327952Sdim elf_auxargs->execfd = -1; 605327952Sdim elf_auxargs->phdr = proghdr; 606327952Sdim elf_auxargs->phent = hdr->e_phentsize; 607327952Sdim elf_auxargs->phnum = hdr->e_phnum; 608327952Sdim elf_auxargs->pagesz = PAGE_SIZE; 609327952Sdim elf_auxargs->base = addr; 610327952Sdim elf_auxargs->flags = 0; 611327952Sdim elf_auxargs->entry = entry; 612327952Sdim elf_auxargs->trace = elf_trace; 613327952Sdim 614327952Sdim imgp->auxargs = elf_auxargs; 615327952Sdim imgp->interpreted = 0; 616327952Sdim 617327952Sdim /* don't allow modifying the file while we run it */ 618327952Sdim imgp->vp->v_flag |= VTEXT; 619327952Sdim 620327952Sdimfail: 621327952Sdim return error; 622327952Sdim} 623327952Sdim 624327952Sdimstatic int 625327952Sdimelf_freebsd_fixup(long **stack_base, struct image_params *imgp) 626327952Sdim{ 627327952Sdim Elf_Auxargs *args = (Elf_Auxargs *)imgp->auxargs; 628327952Sdim long *pos; 629327952Sdim 630327952Sdim pos = *stack_base + (imgp->argc + imgp->envc + 2); 631327952Sdim 632327952Sdim if (args->trace) { 633327952Sdim AUXARGS_ENTRY(pos, AT_DEBUG, 1); 634327952Sdim } 635327952Sdim if (args->execfd != -1) { 636327952Sdim AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); 637327952Sdim } 638327952Sdim AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); 639327952Sdim AUXARGS_ENTRY(pos, AT_PHENT, args->phent); 640327952Sdim AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); 641327952Sdim AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); 642327952Sdim AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); 643327952Sdim AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); 644327952Sdim AUXARGS_ENTRY(pos, AT_BASE, args->base); 645327952Sdim AUXARGS_ENTRY(pos, AT_NULL, 0); 646327952Sdim 647327952Sdim free(imgp->auxargs, M_TEMP); 648327952Sdim imgp->auxargs = NULL; 649327952Sdim 650327952Sdim (*stack_base)--; 651327952Sdim suword(*stack_base, (long) imgp->argc); 652327952Sdim return 0; 653327952Sdim} 654327952Sdim 655327952Sdim/* 656327952Sdim * Code for generating ELF core dumps. 657327952Sdim */ 658327952Sdim 659327952Sdimtypedef void (*segment_callback) __P((vm_map_entry_t, void *)); 660327952Sdim 661327952Sdim/* Closure for cb_put_phdr(). */ 662327952Sdimstruct phdr_closure { 663327952Sdim Elf_Phdr *phdr; /* Program header to fill in */ 664327952Sdim Elf_Off offset; /* Offset of segment in core file */ 665327952Sdim}; 666327952Sdim 667327952Sdim/* Closure for cb_size_segment(). */ 668327952Sdimstruct sseg_closure { 669327952Sdim int count; /* Count of writable segments. */ 670327952Sdim size_t size; /* Total size of all writable segments. */ 671327952Sdim}; 672327952Sdim 673327952Sdimstatic void cb_put_phdr __P((vm_map_entry_t, void *)); 674327952Sdimstatic void cb_size_segment __P((vm_map_entry_t, void *)); 675327952Sdimstatic void each_writable_segment __P((struct proc *, segment_callback, 676327952Sdim void *)); 677327952Sdimstatic int elf_corehdr __P((struct proc *, struct vnode *, struct ucred *, 678327952Sdim int, void *, size_t)); 679327952Sdimstatic void elf_puthdr __P((struct proc *, void *, size_t *, 680327952Sdim const prstatus_t *, const prfpregset_t *, const prpsinfo_t *, int)); 681327952Sdimstatic void elf_putnote __P((void *, size_t *, const char *, int, 682327952Sdim const void *, size_t)); 683327952Sdim 684327952Sdimextern int osreldate; 685327952Sdim 686327952Sdimint 687327952Sdimelf_coredump(p) 688311116Sdim register struct proc *p; 689311116Sdim{ 690311116Sdim register struct vnode *vp; 691311116Sdim register struct ucred *cred = p->p_cred->pc_ucred; 692311116Sdim struct nameidata nd; 693311116Sdim struct vattr vattr; 694311116Sdim int error, error1; 695311116Sdim char *name; /* name of corefile */ 696311116Sdim struct sseg_closure seginfo; 697311116Sdim void *hdr; 698311116Sdim size_t hdrsize; 699311116Sdim 700311116Sdim STOPEVENT(p, S_CORE, 0); 701311116Sdim 702311116Sdim if (sugid_coredump == 0 && p->p_flag & P_SUGID) 703311116Sdim return (EFAULT); 704311116Sdim 705311116Sdim /* Size the program segments. */ 706311116Sdim seginfo.count = 0; 707311116Sdim seginfo.size = 0; 708311116Sdim each_writable_segment(p, cb_size_segment, &seginfo); 709311116Sdim 710311116Sdim /* 711311116Sdim * Calculate the size of the core file header area by making 712311116Sdim * a dry run of generating it. Nothing is written, but the 713311116Sdim * size is calculated. 714311116Sdim */ 715311116Sdim hdrsize = 0; 716311116Sdim elf_puthdr((struct proc *)NULL, (void *)NULL, &hdrsize, 717311116Sdim (const prstatus_t *)NULL, (const prfpregset_t *)NULL, 718311116Sdim (const prpsinfo_t *)NULL, seginfo.count); 719311116Sdim 720311116Sdim if (hdrsize + seginfo.size >= p->p_rlimit[RLIMIT_CORE].rlim_cur) 721311116Sdim return (EFAULT); 722311116Sdim name = expand_name(p->p_comm, p->p_ucred->cr_uid, p->p_pid); 723321369Sdim if (name == NULL) 724321369Sdim return (EFAULT); /* XXX -- not the best error */ 725311116Sdim 726321369Sdim NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, name, p); 727321369Sdim error = vn_open(&nd, O_CREAT | FWRITE, S_IRUSR | S_IWUSR); 728321369Sdim free(name, M_TEMP); 729321369Sdim if (error) 730327952Sdim return (error); 731327952Sdim vp = nd.ni_vp; 732321369Sdim 733321369Sdim /* Don't dump to non-regular files or files with links. */ 734321369Sdim if (vp->v_type != VREG || 735321369Sdim VOP_GETATTR(vp, &vattr, cred, p) || vattr.va_nlink != 1) { 736327952Sdim error = EFAULT; 737327952Sdim goto out; 738327952Sdim } 739327952Sdim VATTR_NULL(&vattr); 740327952Sdim vattr.va_size = 0; 741327952Sdim VOP_LEASE(vp, p, cred, LEASE_WRITE); 742327952Sdim VOP_SETATTR(vp, &vattr, cred, p); 743327952Sdim p->p_acflag |= ACORE; 744327952Sdim 745327952Sdim 746327952Sdim /* 747327952Sdim * Allocate memory for building the header, fill it up, 748327952Sdim * and write it out. 749327952Sdim */ 750327952Sdim hdr = malloc(hdrsize, M_TEMP, M_WAITOK); 751321369Sdim if (hdr == NULL) { 752321369Sdim error = EINVAL; 753321369Sdim goto out; 754321369Sdim } 755321369Sdim error = elf_corehdr(p, vp, cred, seginfo.count, hdr, hdrsize); 756321369Sdim 757321369Sdim /* Write the contents of all of the writable segments. */ 758321369Sdim if (error == 0) { 759321369Sdim Elf_Phdr *php; 760321369Sdim off_t offset; 761321369Sdim int i; 762321369Sdim 763321369Sdim php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1; 764321369Sdim offset = hdrsize; 765327952Sdim for (i = 0; i < seginfo.count; i++) { 766327952Sdim error = vn_rdwr(UIO_WRITE, vp, (caddr_t)php->p_vaddr, 767321369Sdim php->p_filesz, offset, UIO_USERSPACE, 768321369Sdim IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, p); 769321369Sdim if (error != 0) 770327952Sdim break; 771327952Sdim offset += php->p_filesz; 772327952Sdim php++; 773327952Sdim } 774327952Sdim } 775327952Sdim free(hdr, M_TEMP); 776327952Sdim 777327952Sdimout: 778327952Sdim VOP_UNLOCK(vp, 0, p); 779327952Sdim error1 = vn_close(vp, FWRITE, cred, p); 780327952Sdim if (error == 0) 781327952Sdim error = error1; 782327952Sdim return (error); 783327952Sdim} 784327952Sdim 785327952Sdim/* 786327952Sdim * A callback for each_writable_segment() to write out the segment's 787327952Sdim * program header entry. 788327952Sdim */ 789327952Sdimstatic void 790311116Sdimcb_put_phdr(entry, closure) 791321369Sdim vm_map_entry_t entry; 792321369Sdim void *closure; 793311116Sdim{ 794321369Sdim struct phdr_closure *phc = (struct phdr_closure *)closure; 795321369Sdim Elf_Phdr *phdr = phc->phdr; 796321369Sdim 797321369Sdim phc->offset = round_page(phc->offset); 798321369Sdim 799311116Sdim phdr->p_type = PT_LOAD; 800311116Sdim phdr->p_offset = phc->offset; 801311116Sdim phdr->p_vaddr = entry->start; 802311116Sdim phdr->p_paddr = 0; 803311116Sdim phdr->p_filesz = phdr->p_memsz = entry->end - entry->start; 804311116Sdim phdr->p_align = PAGE_SIZE; 805311116Sdim phdr->p_flags = 0; 806311116Sdim if (entry->protection & VM_PROT_READ) 807311116Sdim phdr->p_flags |= PF_R; 808311116Sdim if (entry->protection & VM_PROT_WRITE) 809311116Sdim phdr->p_flags |= PF_W; 810311116Sdim if (entry->protection & VM_PROT_EXECUTE) 811311116Sdim phdr->p_flags |= PF_X; 812311116Sdim 813311116Sdim phc->offset += phdr->p_filesz; 814311116Sdim phc->phdr++; 815311116Sdim} 816311116Sdim 817311116Sdim/* 818311116Sdim * A callback for each_writable_segment() to gather information about 819311116Sdim * the number of segments and their total size. 820311116Sdim */ 821311116Sdimstatic void 822321369Sdimcb_size_segment(entry, closure) 823321369Sdim vm_map_entry_t entry; 824321369Sdim void *closure; 825321369Sdim{ 826321369Sdim struct sseg_closure *ssc = (struct sseg_closure *)closure; 827321369Sdim 828321369Sdim ssc->count++; 829321369Sdim ssc->size += entry->end - entry->start; 830321369Sdim} 831321369Sdim 832321369Sdim/* 833321369Sdim * For each writable segment in the process's memory map, call the given 834321369Sdim * function with a pointer to the map entry and some arbitrary 835321369Sdim * caller-supplied data. 836321369Sdim */ 837321369Sdimstatic void 838321369Sdimeach_writable_segment(p, func, closure) 839321369Sdim struct proc *p; 840321369Sdim segment_callback func; 841321369Sdim void *closure; 842321369Sdim{ 843321369Sdim vm_map_t map = &p->p_vmspace->vm_map; 844321369Sdim vm_map_entry_t entry; 845321369Sdim 846321369Sdim for (entry = map->header.next; entry != &map->header; 847321369Sdim entry = entry->next) { 848 vm_object_t obj; 849 850 if ((entry->eflags & MAP_ENTRY_IS_SUB_MAP) || 851 (entry->protection & (VM_PROT_READ|VM_PROT_WRITE)) != 852 (VM_PROT_READ|VM_PROT_WRITE)) 853 continue; 854 855 if ((obj = entry->object.vm_object) == NULL) 856 continue; 857 858 /* Find the deepest backing object. */ 859 while (obj->backing_object != NULL) 860 obj = obj->backing_object; 861 862 /* Ignore memory-mapped devices and such things. */ 863 if (obj->type != OBJT_DEFAULT && 864 obj->type != OBJT_SWAP && 865 obj->type != OBJT_VNODE) 866 continue; 867 868 (*func)(entry, closure); 869 } 870} 871 872/* 873 * Write the core file header to the file, including padding up to 874 * the page boundary. 875 */ 876static int 877elf_corehdr(p, vp, cred, numsegs, hdr, hdrsize) 878 struct proc *p; 879 struct vnode *vp; 880 struct ucred *cred; 881 int numsegs; 882 size_t hdrsize; 883 void *hdr; 884{ 885 size_t off; 886 prstatus_t status; 887 prfpregset_t fpregset; 888 prpsinfo_t psinfo; 889 890 /* Gather the information for the header. */ 891 bzero(&status, sizeof status); 892 status.pr_version = PRSTATUS_VERSION; 893 status.pr_statussz = sizeof(prstatus_t); 894 status.pr_gregsetsz = sizeof(gregset_t); 895 status.pr_fpregsetsz = sizeof(fpregset_t); 896 status.pr_osreldate = osreldate; 897 status.pr_cursig = p->p_sig; 898 status.pr_pid = p->p_pid; 899 fill_regs(p, &status.pr_reg); 900 901 fill_fpregs(p, &fpregset); 902 903 bzero(&psinfo, sizeof psinfo); 904 psinfo.pr_version = PRPSINFO_VERSION; 905 psinfo.pr_psinfosz = sizeof(prpsinfo_t); 906 strncpy(psinfo.pr_fname, p->p_comm, MAXCOMLEN); 907 /* XXX - We don't fill in the command line arguments properly yet. */ 908 strncpy(psinfo.pr_psargs, p->p_comm, PRARGSZ); 909 910 /* Fill in the header. */ 911 bzero(hdr, hdrsize); 912 off = 0; 913 elf_puthdr(p, hdr, &off, &status, &fpregset, &psinfo, numsegs); 914 915 /* Write it to the core file. */ 916 return vn_rdwr(UIO_WRITE, vp, hdr, hdrsize, (off_t)0, 917 UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, NULL, p); 918} 919 920static void 921elf_puthdr(struct proc *p, void *dst, size_t *off, const prstatus_t *status, 922 const prfpregset_t *fpregset, const prpsinfo_t *psinfo, int numsegs) 923{ 924 size_t ehoff; 925 size_t phoff; 926 size_t noteoff; 927 size_t notesz; 928 929 ehoff = *off; 930 *off += sizeof(Elf_Ehdr); 931 932 phoff = *off; 933 *off += (numsegs + 1) * sizeof(Elf_Phdr); 934 935 noteoff = *off; 936 elf_putnote(dst, off, "FreeBSD", NT_PRSTATUS, status, 937 sizeof *status); 938 elf_putnote(dst, off, "FreeBSD", NT_FPREGSET, fpregset, 939 sizeof *fpregset); 940 elf_putnote(dst, off, "FreeBSD", NT_PRPSINFO, psinfo, 941 sizeof *psinfo); 942 notesz = *off - noteoff; 943 944 /* Align up to a page boundary for the program segments. */ 945 *off = round_page(*off); 946 947 if (dst != NULL) { 948 Elf_Ehdr *ehdr; 949 Elf_Phdr *phdr; 950 struct phdr_closure phc; 951 952 /* 953 * Fill in the ELF header. 954 */ 955 ehdr = (Elf_Ehdr *)((char *)dst + ehoff); 956 ehdr->e_ident[EI_MAG0] = ELFMAG0; 957 ehdr->e_ident[EI_MAG1] = ELFMAG1; 958 ehdr->e_ident[EI_MAG2] = ELFMAG2; 959 ehdr->e_ident[EI_MAG3] = ELFMAG3; 960 ehdr->e_ident[EI_CLASS] = ELF_CLASS; 961 ehdr->e_ident[EI_DATA] = ELF_DATA; 962 ehdr->e_ident[EI_VERSION] = EV_CURRENT; 963 ehdr->e_ident[EI_PAD] = 0; 964 strncpy(ehdr->e_ident + EI_BRAND, "FreeBSD", 965 EI_NIDENT - EI_BRAND); 966 ehdr->e_type = ET_CORE; 967 ehdr->e_machine = ELF_ARCH; 968 ehdr->e_version = EV_CURRENT; 969 ehdr->e_entry = 0; 970 ehdr->e_phoff = phoff; 971 ehdr->e_flags = 0; 972 ehdr->e_ehsize = sizeof(Elf_Ehdr); 973 ehdr->e_phentsize = sizeof(Elf_Phdr); 974 ehdr->e_phnum = numsegs + 1; 975 ehdr->e_shentsize = sizeof(Elf_Shdr); 976 ehdr->e_shnum = 0; 977 ehdr->e_shstrndx = SHN_UNDEF; 978 979 /* 980 * Fill in the program header entries. 981 */ 982 phdr = (Elf_Phdr *)((char *)dst + phoff); 983 984 /* The note segement. */ 985 phdr->p_type = PT_NOTE; 986 phdr->p_offset = noteoff; 987 phdr->p_vaddr = 0; 988 phdr->p_paddr = 0; 989 phdr->p_filesz = notesz; 990 phdr->p_memsz = 0; 991 phdr->p_flags = 0; 992 phdr->p_align = 0; 993 phdr++; 994 995 /* All the writable segments from the program. */ 996 phc.phdr = phdr; 997 phc.offset = *off; 998 each_writable_segment(p, cb_put_phdr, &phc); 999 } 1000} 1001 1002static void 1003elf_putnote(void *dst, size_t *off, const char *name, int type, 1004 const void *desc, size_t descsz) 1005{ 1006 Elf_Note note; 1007 1008 note.n_namesz = strlen(name) + 1; 1009 note.n_descsz = descsz; 1010 note.n_type = type; 1011 if (dst != NULL) 1012 bcopy(¬e, (char *)dst + *off, sizeof note); 1013 *off += sizeof note; 1014 if (dst != NULL) 1015 bcopy(name, (char *)dst + *off, note.n_namesz); 1016 *off += roundup2(note.n_namesz, sizeof(Elf_Size)); 1017 if (dst != NULL) 1018 bcopy(desc, (char *)dst + *off, note.n_descsz); 1019 *off += roundup2(note.n_descsz, sizeof(Elf_Size)); 1020} 1021 1022/* 1023 * Tell kern_execve.c about it, with a little help from the linker. 1024 */ 1025static struct execsw elf_execsw = {exec_elf_imgact, "ELF"}; 1026EXEC_SET(elf, elf_execsw); 1027