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 * 290ff27d31SJohn Polstra * $Id: imgact_elf.c,v 1.33 1998/09/15 22:07:20 jdp Exp $ 30e1743d02SSøren Schmidt */ 31e1743d02SSøren Schmidt 32e9822d92SJoerg Wunsch #include "opt_rlimit.h" 33e9822d92SJoerg Wunsch 34e1743d02SSøren Schmidt #include <sys/param.h> 358c64af4fSJohn Polstra #include <sys/acct.h> 36e1743d02SSøren Schmidt #include <sys/exec.h> 378c64af4fSJohn Polstra #include <sys/fcntl.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/malloc.h> 428c64af4fSJohn Polstra #include <sys/mman.h> 43a794e791SBruce Evans #include <sys/namei.h> 448c64af4fSJohn Polstra #include <sys/pioctl.h> 45a794e791SBruce Evans #include <sys/proc.h> 468c64af4fSJohn Polstra #include <sys/procfs.h> 478c64af4fSJohn Polstra #include <sys/resourcevar.h> 48e1743d02SSøren Schmidt #include <sys/signalvar.h> 498c64af4fSJohn Polstra #include <sys/stat.h> 508c64af4fSJohn Polstra #include <sys/syscall.h> 51e1743d02SSøren Schmidt #include <sys/sysctl.h> 528c64af4fSJohn Polstra #include <sys/sysent.h> 538c64af4fSJohn Polstra #include <sys/systm.h> 54a794e791SBruce Evans #include <sys/vnode.h> 55e1743d02SSøren Schmidt 56e1743d02SSøren Schmidt #include <vm/vm.h> 57e1743d02SSøren Schmidt #include <vm/vm_kern.h> 58e1743d02SSøren Schmidt #include <vm/vm_param.h> 59e1743d02SSøren Schmidt #include <vm/pmap.h> 60996c772fSJohn Dyson #include <sys/lock.h> 61e1743d02SSøren Schmidt #include <vm/vm_map.h> 620ff27d31SJohn Polstra #include <vm/vm_object.h> 63e1743d02SSøren Schmidt #include <vm/vm_prot.h> 64e1743d02SSøren Schmidt #include <vm/vm_extern.h> 65e1743d02SSøren Schmidt 66e1743d02SSøren Schmidt #include <machine/md_var.h> 67e1743d02SSøren Schmidt 68e1743d02SSøren Schmidt #define MAX_PHDR 32 /* XXX enough ? */ 69e1743d02SSøren Schmidt 70ecbb00a2SDoug Rabson #if ELF_TARG_CLASS == ELFCLASS32 71ecbb00a2SDoug Rabson 72ecbb00a2SDoug Rabson #define Elf_Ehdr Elf32_Ehdr 73ecbb00a2SDoug Rabson #define Elf_Phdr Elf32_Phdr 74ecbb00a2SDoug Rabson #define Elf_Auxargs Elf32_Auxargs 75ecbb00a2SDoug Rabson #define Elf_Brandinfo Elf32_Brandinfo 76ecbb00a2SDoug Rabson 77ecbb00a2SDoug Rabson #else 78ecbb00a2SDoug Rabson 79ecbb00a2SDoug Rabson #define Elf_Ehdr Elf64_Ehdr 80ecbb00a2SDoug Rabson #define Elf_Phdr Elf64_Phdr 81ecbb00a2SDoug Rabson #define Elf_Auxargs Elf64_Auxargs 82ecbb00a2SDoug Rabson #define Elf_Brandinfo Elf64_Brandinfo 83ecbb00a2SDoug Rabson 84ecbb00a2SDoug Rabson #endif 85ecbb00a2SDoug Rabson 86ecbb00a2SDoug Rabson 87ecbb00a2SDoug Rabson static int elf_check_header __P((const Elf_Ehdr *hdr, int type)); 888c64af4fSJohn Polstra static int elf_freebsd_fixup __P((long **stack_base, 898c64af4fSJohn Polstra struct image_params *imgp)); 908c64af4fSJohn Polstra static int elf_load_file __P((struct proc *p, char *file, u_long *addr, 918c64af4fSJohn Polstra u_long *entry)); 928c64af4fSJohn Polstra static int elf_load_section __P((struct vmspace *vmspace, struct vnode *vp, 938c64af4fSJohn Polstra vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, 948c64af4fSJohn Polstra vm_prot_t prot)); 95303b270bSEivind Eklund static int exec_elf_imgact __P((struct image_params *imgp)); 96e1743d02SSøren Schmidt 97d8a4f230SBruce Evans static int elf_trace = 0; 98d8a4f230SBruce Evans SYSCTL_INT(_debug, OID_AUTO, elf_trace, CTLFLAG_RW, &elf_trace, 0, ""); 99e1743d02SSøren Schmidt #define UPRINTF if (elf_trace) uprintf 100e1743d02SSøren Schmidt 101e1743d02SSøren Schmidt static struct sysentvec elf_freebsd_sysvec = { 102e1743d02SSøren Schmidt SYS_MAXSYSCALL, 103e1743d02SSøren Schmidt sysent, 104e1743d02SSøren Schmidt 0, 105e1743d02SSøren Schmidt 0, 106e1743d02SSøren Schmidt 0, 107e1743d02SSøren Schmidt 0, 108e1743d02SSøren Schmidt 0, 109288078beSEivind Eklund 0, 110e1743d02SSøren Schmidt elf_freebsd_fixup, 111e1743d02SSøren Schmidt sendsig, 112e1743d02SSøren Schmidt sigcode, 113e1743d02SSøren Schmidt &szsigcode, 114e1743d02SSøren Schmidt 0, 11522d4b0fbSJohn Polstra "FreeBSD ELF", 11622d4b0fbSJohn Polstra elf_coredump 117e1743d02SSøren Schmidt }; 118e1743d02SSøren Schmidt 119ecbb00a2SDoug Rabson static Elf_Brandinfo freebsd_brand_info = { 120ea5a2b2eSSøren Schmidt "FreeBSD", 121ea5a2b2eSSøren Schmidt "", 122e1743d02SSøren Schmidt "/usr/libexec/ld-elf.so.1", 123ea5a2b2eSSøren Schmidt &elf_freebsd_sysvec 124e1743d02SSøren Schmidt }; 125ecbb00a2SDoug Rabson static Elf_Brandinfo *elf_brand_list[MAX_BRANDS] = { 126ea5a2b2eSSøren Schmidt &freebsd_brand_info, 127e1743d02SSøren Schmidt NULL, NULL, NULL, 128e1743d02SSøren Schmidt NULL, NULL, NULL, NULL 129e1743d02SSøren Schmidt }; 130e1743d02SSøren Schmidt 131e1743d02SSøren Schmidt int 132ecbb00a2SDoug Rabson elf_insert_brand_entry(Elf_Brandinfo *entry) 133e1743d02SSøren Schmidt { 134e1743d02SSøren Schmidt int i; 135e1743d02SSøren Schmidt 136ea5a2b2eSSøren Schmidt for (i=1; i<MAX_BRANDS; i++) { 137ea5a2b2eSSøren Schmidt if (elf_brand_list[i] == NULL) { 138ea5a2b2eSSøren Schmidt elf_brand_list[i] = entry; 139e1743d02SSøren Schmidt break; 140e1743d02SSøren Schmidt } 141e1743d02SSøren Schmidt } 142ea5a2b2eSSøren Schmidt if (i == MAX_BRANDS) 143e1743d02SSøren Schmidt return -1; 144e1743d02SSøren Schmidt return 0; 145e1743d02SSøren Schmidt } 146e1743d02SSøren Schmidt 147e1743d02SSøren Schmidt int 148ecbb00a2SDoug Rabson elf_remove_brand_entry(Elf_Brandinfo *entry) 149e1743d02SSøren Schmidt { 150e1743d02SSøren Schmidt int i; 151e1743d02SSøren Schmidt 152ea5a2b2eSSøren Schmidt for (i=1; i<MAX_BRANDS; i++) { 153ea5a2b2eSSøren Schmidt if (elf_brand_list[i] == entry) { 154ea5a2b2eSSøren Schmidt elf_brand_list[i] = NULL; 155e1743d02SSøren Schmidt break; 156e1743d02SSøren Schmidt } 157e1743d02SSøren Schmidt } 158ea5a2b2eSSøren Schmidt if (i == MAX_BRANDS) 159e1743d02SSøren Schmidt return -1; 160e1743d02SSøren Schmidt return 0; 161e1743d02SSøren Schmidt } 162e1743d02SSøren Schmidt 163e1743d02SSøren Schmidt static int 164ecbb00a2SDoug Rabson elf_check_header(const Elf_Ehdr *hdr, int type) 165e1743d02SSøren Schmidt { 166e1743d02SSøren Schmidt if (!(hdr->e_ident[EI_MAG0] == ELFMAG0 && 167e1743d02SSøren Schmidt hdr->e_ident[EI_MAG1] == ELFMAG1 && 168e1743d02SSøren Schmidt hdr->e_ident[EI_MAG2] == ELFMAG2 && 169e1743d02SSøren Schmidt hdr->e_ident[EI_MAG3] == ELFMAG3)) 170e1743d02SSøren Schmidt return ENOEXEC; 171e1743d02SSøren Schmidt 1722e91d07aSDoug Rabson #ifdef __i386__ 173e1743d02SSøren Schmidt if (hdr->e_machine != EM_386 && hdr->e_machine != EM_486) 174ecbb00a2SDoug Rabson #endif 175ecbb00a2SDoug Rabson #ifdef __alpha__ 176ecbb00a2SDoug Rabson if (hdr->e_machine != EM_ALPHA) 177ecbb00a2SDoug Rabson #endif 178e1743d02SSøren Schmidt return ENOEXEC; 179e1743d02SSøren Schmidt 180ecbb00a2SDoug Rabson 181e1743d02SSøren Schmidt if (hdr->e_type != type) 182e1743d02SSøren Schmidt return ENOEXEC; 183e1743d02SSøren Schmidt 184e1743d02SSøren Schmidt return 0; 185e1743d02SSøren Schmidt } 186e1743d02SSøren Schmidt 187e1743d02SSøren Schmidt static int 188e1743d02SSø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) 189e1743d02SSøren Schmidt { 190e1743d02SSøren Schmidt size_t map_len; 191e1743d02SSøren Schmidt vm_offset_t map_addr; 192e1743d02SSøren Schmidt int error; 193e1743d02SSøren Schmidt unsigned char *data_buf = 0; 194e1743d02SSøren Schmidt size_t copy_len; 195e1743d02SSøren Schmidt 196e1743d02SSøren Schmidt map_addr = trunc_page(vmaddr); 197e1743d02SSøren Schmidt 198e1743d02SSøren Schmidt if (memsz > filsz) 199e1743d02SSøren Schmidt map_len = trunc_page(offset+filsz) - trunc_page(offset); 200e1743d02SSøren Schmidt else 201e1743d02SSøren Schmidt map_len = round_page(offset+filsz) - trunc_page(offset); 202e1743d02SSøren Schmidt 203e1743d02SSøren Schmidt if (error = vm_mmap (&vmspace->vm_map, 204e1743d02SSøren Schmidt &map_addr, 205e1743d02SSøren Schmidt map_len, 206e1743d02SSøren Schmidt prot, 207e1743d02SSøren Schmidt VM_PROT_ALL, 20871d7d1b1SPeter Wemm MAP_PRIVATE | MAP_FIXED, 209e1743d02SSøren Schmidt (caddr_t)vp, 210e1743d02SSøren Schmidt trunc_page(offset))) 211e1743d02SSøren Schmidt return error; 212e1743d02SSøren Schmidt 213e1743d02SSøren Schmidt if (memsz == filsz) 214e1743d02SSøren Schmidt return 0; 215e1743d02SSøren Schmidt 216e1743d02SSøren Schmidt /* 217e1743d02SSøren Schmidt * We have to map the remaining bit of the file into the kernel's 218e1743d02SSøren Schmidt * memory map, allocate some anonymous memory, and copy that last 219e1743d02SSøren Schmidt * bit into it. The remaining space should be .bss... 220e1743d02SSøren Schmidt */ 221e1743d02SSøren Schmidt copy_len = (offset + filsz) - trunc_page(offset + filsz); 222e1743d02SSøren Schmidt map_addr = trunc_page(vmaddr + filsz); 223250c11f9SPeter Wemm map_len = round_page(vmaddr + memsz) - map_addr; 224e1743d02SSøren Schmidt 2258191d577SPeter Wemm if (map_len != 0) { 226e1743d02SSøren Schmidt if (error = vm_map_find(&vmspace->vm_map, NULL, 0, 227e1743d02SSøren Schmidt &map_addr, map_len, FALSE, 228e1743d02SSøren Schmidt VM_PROT_ALL, VM_PROT_ALL,0)) 229e1743d02SSøren Schmidt return error; 2308191d577SPeter Wemm } 231e1743d02SSøren Schmidt 232c8a79999SPeter Wemm if (error = vm_mmap(exec_map, 233e1743d02SSøren Schmidt (vm_offset_t *)&data_buf, 234e1743d02SSøren Schmidt PAGE_SIZE, 235e1743d02SSøren Schmidt VM_PROT_READ, 236e1743d02SSøren Schmidt VM_PROT_READ, 23771d7d1b1SPeter Wemm 0, 238e1743d02SSøren Schmidt (caddr_t)vp, 239e1743d02SSøren Schmidt trunc_page(offset + filsz))) 240e1743d02SSøren Schmidt return error; 241e1743d02SSøren Schmidt 242e1743d02SSøren Schmidt error = copyout(data_buf, (caddr_t)map_addr, copy_len); 243e1743d02SSøren Schmidt 244c8a79999SPeter Wemm vm_map_remove(exec_map, (vm_offset_t)data_buf, 245e1743d02SSøren Schmidt (vm_offset_t)data_buf + PAGE_SIZE); 246e1743d02SSøren Schmidt 247e1743d02SSøren Schmidt /* 2488191d577SPeter Wemm * set it to the specified protection 249e1743d02SSøren Schmidt */ 2508191d577SPeter Wemm vm_map_protect(&vmspace->vm_map, map_addr, map_addr + map_len, prot, 2518191d577SPeter Wemm FALSE); 2528191d577SPeter Wemm 253e1743d02SSøren Schmidt UPRINTF("bss size %d (%x)\n", map_len-copy_len, map_len-copy_len); 254e1743d02SSøren Schmidt return error; 255e1743d02SSøren Schmidt } 256e1743d02SSøren Schmidt 257e1743d02SSøren Schmidt static int 258e1743d02SSøren Schmidt elf_load_file(struct proc *p, char *file, u_long *addr, u_long *entry) 259e1743d02SSøren Schmidt { 260ecbb00a2SDoug Rabson Elf_Ehdr *hdr = NULL; 261ecbb00a2SDoug Rabson Elf_Phdr *phdr = NULL; 262e1743d02SSøren Schmidt struct nameidata nd; 263e1743d02SSøren Schmidt struct vmspace *vmspace = p->p_vmspace; 264c8a79999SPeter Wemm struct vattr attr; 265c8a79999SPeter Wemm struct image_params image_params, *imgp; 266e1743d02SSøren Schmidt vm_prot_t prot = 0; 267e1743d02SSøren Schmidt unsigned long text_size = 0, data_size = 0; 268e1743d02SSøren Schmidt unsigned long text_addr = 0, data_addr = 0; 269e1743d02SSøren Schmidt int header_size = 0; 270e1743d02SSøren Schmidt int error, i; 271e1743d02SSøren Schmidt 272c8a79999SPeter Wemm imgp = &image_params; 273c8a79999SPeter Wemm /* 274c8a79999SPeter Wemm * Initialize part of the common data 275c8a79999SPeter Wemm */ 276c8a79999SPeter Wemm imgp->proc = p; 277c8a79999SPeter Wemm imgp->uap = NULL; 278c8a79999SPeter Wemm imgp->attr = &attr; 279c8a79999SPeter Wemm imgp->firstpage = NULL; 280c8a79999SPeter Wemm imgp->image_header = (char *)kmem_alloc_wait(exec_map, PAGE_SIZE); 281c8a79999SPeter Wemm 282c8a79999SPeter Wemm if (imgp->image_header == NULL) { 283c8a79999SPeter Wemm nd.ni_vp = NULL; 284c8a79999SPeter Wemm error = ENOMEM; 285c8a79999SPeter Wemm goto fail; 286c8a79999SPeter Wemm } 287c8a79999SPeter Wemm 288e1743d02SSøren Schmidt NDINIT(&nd, LOOKUP, LOCKLEAF|FOLLOW, UIO_SYSSPACE, file, p); 289e1743d02SSøren Schmidt 2901560a9d5SPeter Wemm if (error = namei(&nd)) { 2911560a9d5SPeter Wemm nd.ni_vp = NULL; 292e1743d02SSøren Schmidt goto fail; 293e1743d02SSøren Schmidt } 294e1743d02SSøren Schmidt 295c8a79999SPeter Wemm imgp->vp = nd.ni_vp; 296c8a79999SPeter Wemm 297e1743d02SSøren Schmidt /* 298e1743d02SSøren Schmidt * Check permissions, modes, uid, etc on the file, and "open" it. 299e1743d02SSøren Schmidt */ 300c8a79999SPeter Wemm error = exec_check_permissions(imgp); 301c8a79999SPeter Wemm if (error) { 302996c772fSJohn Dyson VOP_UNLOCK(nd.ni_vp, 0, p); 303c8a79999SPeter Wemm goto fail; 304c8a79999SPeter Wemm } 305e1743d02SSøren Schmidt 306c8a79999SPeter Wemm error = exec_map_first_page(imgp); 307c8a79999SPeter Wemm VOP_UNLOCK(nd.ni_vp, 0, p); 308e1743d02SSøren Schmidt if (error) 309e1743d02SSøren Schmidt goto fail; 310e1743d02SSøren Schmidt 311ecbb00a2SDoug Rabson hdr = (Elf_Ehdr *)imgp->image_header; 312e1743d02SSøren Schmidt if (error = elf_check_header(hdr, ET_DYN)) 313e1743d02SSøren Schmidt goto fail; 314e1743d02SSøren Schmidt 315e1743d02SSøren Schmidt /* 316e1743d02SSøren Schmidt * ouch, need to bounds check in case user gives us a corrupted 317e1743d02SSøren Schmidt * file with an insane header size 318e1743d02SSøren Schmidt */ 319e1743d02SSøren Schmidt if (hdr->e_phnum > MAX_PHDR) { /* XXX: ever more than this? */ 320e1743d02SSøren Schmidt error = ENOEXEC; 321e1743d02SSøren Schmidt goto fail; 322e1743d02SSøren Schmidt } 323e1743d02SSøren Schmidt 324e1743d02SSøren Schmidt header_size = hdr->e_phentsize * hdr->e_phnum; 325e1743d02SSøren Schmidt 326c8a79999SPeter Wemm /* Only support headers that fit within first page for now */ 327c8a79999SPeter Wemm if (header_size + hdr->e_phoff > PAGE_SIZE) { 328c8a79999SPeter Wemm error = ENOEXEC; 329e1743d02SSøren Schmidt goto fail; 330c8a79999SPeter Wemm } 331c8a79999SPeter Wemm 332ecbb00a2SDoug Rabson phdr = (Elf_Phdr *)(imgp->image_header + hdr->e_phoff); 333e1743d02SSøren Schmidt 334e1743d02SSøren Schmidt for (i = 0; i < hdr->e_phnum; i++) { 335e1743d02SSøren Schmidt switch(phdr[i].p_type) { 336e1743d02SSøren Schmidt 337e1743d02SSøren Schmidt case PT_NULL: /* NULL section */ 338e1743d02SSøren Schmidt UPRINTF ("ELF(file) PT_NULL section\n"); 339e1743d02SSøren Schmidt break; 340e1743d02SSøren Schmidt case PT_LOAD: /* Loadable segment */ 341e1743d02SSøren Schmidt { 342e1743d02SSøren Schmidt UPRINTF ("ELF(file) PT_LOAD section "); 343e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_X) 344e1743d02SSøren Schmidt prot |= VM_PROT_EXECUTE; 345e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_W) 346e1743d02SSøren Schmidt prot |= VM_PROT_WRITE; 347e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_R) 348e1743d02SSøren Schmidt prot |= VM_PROT_READ; 349e1743d02SSøren Schmidt 350e1743d02SSøren Schmidt if (error = elf_load_section(vmspace, nd.ni_vp, 351e1743d02SSøren Schmidt phdr[i].p_offset, 352e1743d02SSøren Schmidt (caddr_t)phdr[i].p_vaddr + 353e1743d02SSøren Schmidt (*addr), 354e1743d02SSøren Schmidt phdr[i].p_memsz, 355e1743d02SSøren Schmidt phdr[i].p_filesz, prot)) 356e1743d02SSøren Schmidt goto fail; 357e1743d02SSøren Schmidt 358e1743d02SSøren Schmidt /* 359e1743d02SSøren Schmidt * Is this .text or .data ?? 360e1743d02SSøren Schmidt * 361e1743d02SSøren Schmidt * We only handle one each of those yet XXX 362e1743d02SSøren Schmidt */ 363e1743d02SSøren Schmidt if (hdr->e_entry >= phdr[i].p_vaddr && 364e1743d02SSøren Schmidt hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) { 365e1743d02SSøren Schmidt text_addr = trunc_page(phdr[i].p_vaddr+(*addr)); 3668191d577SPeter Wemm text_size = round_page(phdr[i].p_memsz + 3678191d577SPeter Wemm phdr[i].p_vaddr - 3688191d577SPeter Wemm trunc_page(phdr[i].p_vaddr)); 369e1743d02SSøren Schmidt *entry=(unsigned long)hdr->e_entry+(*addr); 370ed62fb52SBruce Evans UPRINTF(".text <%08lx,%08lx> entry=%08lx\n", 371e1743d02SSøren Schmidt text_addr, text_size, *entry); 372e1743d02SSøren Schmidt } else { 373e1743d02SSøren Schmidt data_addr = trunc_page(phdr[i].p_vaddr+(*addr)); 3748191d577SPeter Wemm data_size = round_page(phdr[i].p_memsz + 3758191d577SPeter Wemm phdr[i].p_vaddr - 3768191d577SPeter Wemm trunc_page(phdr[i].p_vaddr)); 377ed62fb52SBruce Evans UPRINTF(".data <%08lx,%08lx>\n", 378e1743d02SSøren Schmidt data_addr, data_size); 379e1743d02SSøren Schmidt } 380e1743d02SSøren Schmidt } 381e1743d02SSøren Schmidt break; 382e1743d02SSøren Schmidt 383e1743d02SSøren Schmidt case PT_DYNAMIC:/* Dynamic link information */ 384e1743d02SSøren Schmidt UPRINTF ("ELF(file) PT_DYNAMIC section\n"); 385e1743d02SSøren Schmidt break; 386e1743d02SSøren Schmidt case PT_INTERP: /* Path to interpreter */ 387e1743d02SSøren Schmidt UPRINTF ("ELF(file) PT_INTERP section\n"); 388e1743d02SSøren Schmidt break; 389e1743d02SSøren Schmidt case PT_NOTE: /* Note section */ 390e1743d02SSøren Schmidt UPRINTF ("ELF(file) PT_NOTE section\n"); 391e1743d02SSøren Schmidt break; 392e1743d02SSøren Schmidt case PT_SHLIB: /* Shared lib section */ 393e1743d02SSøren Schmidt UPRINTF ("ELF(file) PT_SHLIB section\n"); 394e1743d02SSøren Schmidt break; 395e1743d02SSøren Schmidt case PT_PHDR: /* Program header table info */ 396e1743d02SSøren Schmidt UPRINTF ("ELF(file) PT_PHDR section\n"); 397e1743d02SSøren Schmidt break; 398e1743d02SSøren Schmidt default: 399e1743d02SSøren Schmidt UPRINTF ("ELF(file) %d section ??\n", phdr[i].p_type ); 400e1743d02SSøren Schmidt } 401e1743d02SSøren Schmidt } 402e1743d02SSøren Schmidt 403e1743d02SSøren Schmidt fail: 404c8a79999SPeter Wemm if (imgp->firstpage) 405c8a79999SPeter Wemm exec_unmap_first_page(imgp); 406c8a79999SPeter Wemm if (imgp->image_header) 407c8a79999SPeter Wemm kmem_free_wakeup(exec_map, (vm_offset_t)imgp->image_header, 408c8a79999SPeter Wemm PAGE_SIZE); 4091560a9d5SPeter Wemm if (nd.ni_vp) 4101560a9d5SPeter Wemm vrele(nd.ni_vp); 411e1743d02SSøren Schmidt 412e1743d02SSøren Schmidt return error; 413e1743d02SSøren Schmidt } 414e1743d02SSøren Schmidt 415303b270bSEivind Eklund static int 416e1743d02SSøren Schmidt exec_elf_imgact(struct image_params *imgp) 417e1743d02SSøren Schmidt { 418ecbb00a2SDoug Rabson const Elf_Ehdr *hdr = (const Elf_Ehdr *) imgp->image_header; 419ecbb00a2SDoug Rabson const Elf_Phdr *phdr, *mapped_phdr = NULL; 420ecbb00a2SDoug Rabson Elf_Auxargs *elf_auxargs = NULL; 4215856e12eSJohn Dyson struct vmspace *vmspace; 422e1743d02SSøren Schmidt vm_prot_t prot = 0; 423e1743d02SSøren Schmidt u_long text_size = 0, data_size = 0; 424e1743d02SSøren Schmidt u_long text_addr = 0, data_addr = 0; 425e1743d02SSøren Schmidt u_long addr, entry = 0, proghdr = 0; 426c8a79999SPeter Wemm int error, i, header_size = 0; 427c8a79999SPeter Wemm const char *interp = NULL; 428ea5a2b2eSSøren Schmidt char *brand = NULL; 429ea5a2b2eSSøren Schmidt char path[MAXPATHLEN]; 430e1743d02SSøren Schmidt 431e1743d02SSøren Schmidt /* 432e1743d02SSøren Schmidt * Do we have a valid ELF header ? 433e1743d02SSøren Schmidt */ 434e1743d02SSøren Schmidt if (elf_check_header(hdr, ET_EXEC)) 435e1743d02SSøren Schmidt return -1; 436e1743d02SSøren Schmidt 437e1743d02SSøren Schmidt /* 438e1743d02SSøren Schmidt * From here on down, we return an errno, not -1, as we've 439e1743d02SSøren Schmidt * detected an ELF file. 440e1743d02SSøren Schmidt */ 441e1743d02SSøren Schmidt 442e1743d02SSøren Schmidt /* 443e1743d02SSøren Schmidt * ouch, need to bounds check in case user gives us a corrupted 444e1743d02SSøren Schmidt * file with an insane header size 445e1743d02SSøren Schmidt */ 446e1743d02SSøren Schmidt if (hdr->e_phnum > MAX_PHDR) { /* XXX: ever more than this? */ 447e1743d02SSøren Schmidt return ENOEXEC; 448e1743d02SSøren Schmidt } 449e1743d02SSøren Schmidt 450e1743d02SSøren Schmidt header_size = hdr->e_phentsize * hdr->e_phnum; 451e1743d02SSøren Schmidt 452e1743d02SSøren Schmidt if ((hdr->e_phoff > PAGE_SIZE) || 453e1743d02SSøren Schmidt (hdr->e_phoff + header_size) > PAGE_SIZE) { 454c8a79999SPeter Wemm /* Only support headers in first page for now */ 455c8a79999SPeter Wemm return ENOEXEC; 456e1743d02SSøren Schmidt } else { 457ecbb00a2SDoug Rabson phdr = (const Elf_Phdr*) 458e0c95ed9SBruce Evans ((const char *)imgp->image_header + hdr->e_phoff); 459e1743d02SSøren Schmidt } 460e1743d02SSøren Schmidt 461e1743d02SSøren Schmidt /* 462e1743d02SSøren Schmidt * From this point on, we may have resources that need to be freed. 463e1743d02SSøren Schmidt */ 464e1743d02SSøren Schmidt if (error = exec_extract_strings(imgp)) 465e1743d02SSøren Schmidt goto fail; 466e1743d02SSøren Schmidt 467e1743d02SSøren Schmidt exec_new_vmspace(imgp); 468e1743d02SSøren Schmidt 4695856e12eSJohn Dyson vmspace = imgp->proc->p_vmspace; 4705856e12eSJohn Dyson 471e1743d02SSøren Schmidt for (i = 0; i < hdr->e_phnum; i++) { 472e1743d02SSøren Schmidt switch(phdr[i].p_type) { 473e1743d02SSøren Schmidt 474e1743d02SSøren Schmidt case PT_NULL: /* NULL section */ 475e1743d02SSøren Schmidt UPRINTF ("ELF PT_NULL section\n"); 476e1743d02SSøren Schmidt break; 477e1743d02SSøren Schmidt case PT_LOAD: /* Loadable segment */ 478e1743d02SSøren Schmidt { 479e1743d02SSøren Schmidt UPRINTF ("ELF PT_LOAD section "); 480e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_X) 481e1743d02SSøren Schmidt prot |= VM_PROT_EXECUTE; 482e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_W) 483e1743d02SSøren Schmidt prot |= VM_PROT_WRITE; 484e1743d02SSøren Schmidt if (phdr[i].p_flags & PF_R) 485e1743d02SSøren Schmidt prot |= VM_PROT_READ; 486e1743d02SSøren Schmidt 487e1743d02SSøren Schmidt if (error = elf_load_section(vmspace, imgp->vp, 488e1743d02SSøren Schmidt phdr[i].p_offset, 489e1743d02SSøren Schmidt (caddr_t)phdr[i].p_vaddr, 490e1743d02SSøren Schmidt phdr[i].p_memsz, 491e1743d02SSøren Schmidt phdr[i].p_filesz, prot)) 492e1743d02SSøren Schmidt goto fail; 493e1743d02SSøren Schmidt 494e1743d02SSøren Schmidt /* 495e1743d02SSøren Schmidt * Is this .text or .data ?? 496e1743d02SSøren Schmidt * 497e1743d02SSøren Schmidt * We only handle one each of those yet XXX 498e1743d02SSøren Schmidt */ 499e1743d02SSøren Schmidt if (hdr->e_entry >= phdr[i].p_vaddr && 500e1743d02SSøren Schmidt hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) { 501e1743d02SSøren Schmidt text_addr = trunc_page(phdr[i].p_vaddr); 5028191d577SPeter Wemm text_size = round_page(phdr[i].p_memsz + 5038191d577SPeter Wemm phdr[i].p_vaddr - 5048191d577SPeter Wemm text_addr); 505e1743d02SSøren Schmidt entry = (u_long)hdr->e_entry; 506ed62fb52SBruce Evans UPRINTF(".text <%08lx,%08lx> entry=%08lx\n", 507e1743d02SSøren Schmidt text_addr, text_size, entry); 508e1743d02SSøren Schmidt } else { 509e1743d02SSøren Schmidt data_addr = trunc_page(phdr[i].p_vaddr); 5108191d577SPeter Wemm data_size = round_page(phdr[i].p_memsz + 5118191d577SPeter Wemm phdr[i].p_vaddr - 5128191d577SPeter Wemm data_addr); 513ed62fb52SBruce Evans UPRINTF(".data <%08lx,%08lx>\n", 514e1743d02SSøren Schmidt data_addr, data_size); 515e1743d02SSøren Schmidt } 516e1743d02SSøren Schmidt } 517e1743d02SSøren Schmidt break; 518e1743d02SSøren Schmidt 519e1743d02SSøren Schmidt case PT_DYNAMIC:/* Dynamic link information */ 520e1743d02SSøren Schmidt UPRINTF ("ELF PT_DYNAMIC section ??\n"); 521e1743d02SSøren Schmidt break; 522e1743d02SSøren Schmidt case PT_INTERP: /* Path to interpreter */ 523e1743d02SSøren Schmidt UPRINTF ("ELF PT_INTERP section "); 524c8a79999SPeter Wemm if (phdr[i].p_filesz > MAXPATHLEN || 525c8a79999SPeter Wemm phdr[i].p_offset + phdr[i].p_filesz > PAGE_SIZE) { 526e1743d02SSøren Schmidt error = ENOEXEC; 527e1743d02SSøren Schmidt goto fail; 528e1743d02SSøren Schmidt } 529c8a79999SPeter Wemm interp = imgp->image_header + phdr[i].p_offset; 530e1743d02SSøren Schmidt UPRINTF("<%s>\n", interp); 531e1743d02SSøren Schmidt break; 532e1743d02SSøren Schmidt case PT_NOTE: /* Note section */ 533e1743d02SSøren Schmidt UPRINTF ("ELF PT_NOTE section\n"); 534e1743d02SSøren Schmidt break; 535e1743d02SSøren Schmidt case PT_SHLIB: /* Shared lib section */ 536e1743d02SSøren Schmidt UPRINTF ("ELF PT_SHLIB section\n"); 537e1743d02SSøren Schmidt break; 538e1743d02SSøren Schmidt case PT_PHDR: /* Program header table info */ 539e1743d02SSøren Schmidt UPRINTF ("ELF PT_PHDR section <%x>\n", phdr[i].p_vaddr); 540e1743d02SSøren Schmidt proghdr = phdr[i].p_vaddr; 541e1743d02SSøren Schmidt break; 542e1743d02SSøren Schmidt default: 543e1743d02SSøren Schmidt UPRINTF ("ELF %d section ??\n", phdr[i].p_type); 544e1743d02SSøren Schmidt } 545e1743d02SSøren Schmidt } 546e1743d02SSøren Schmidt 547e1743d02SSøren Schmidt vmspace->vm_tsize = text_size >> PAGE_SHIFT; 5487cd99438SBruce Evans vmspace->vm_taddr = (caddr_t)(uintptr_t)text_addr; 549e1743d02SSøren Schmidt vmspace->vm_dsize = data_size >> PAGE_SHIFT; 5507cd99438SBruce Evans vmspace->vm_daddr = (caddr_t)(uintptr_t)data_addr; 551e1743d02SSøren Schmidt 552ecbb00a2SDoug Rabson addr = 2L*MAXDSIZ; /* May depend on OS type XXX */ 553e1743d02SSøren Schmidt 554ea5a2b2eSSøren Schmidt imgp->entry_addr = entry; 555ea5a2b2eSSøren Schmidt 556e1743d02SSøren Schmidt /* 557ea5a2b2eSSøren Schmidt * So which kind (brand) of ELF binary do we have at hand 558ea5a2b2eSSøren Schmidt * FreeBSD, Linux, SVR4 or something else ?? 559ea5a2b2eSSøren Schmidt * If its has a interpreter section try that first 560e1743d02SSøren Schmidt */ 561ea5a2b2eSSøren Schmidt if (interp) { 562ea5a2b2eSSøren Schmidt for (i=0; i<MAX_BRANDS; i++) { 563ea5a2b2eSSøren Schmidt if (elf_brand_list[i] != NULL) { 564ea5a2b2eSSøren Schmidt if (!strcmp(interp, elf_brand_list[i]->interp_path)) { 565e1743d02SSøren Schmidt imgp->proc->p_sysent = 566ea5a2b2eSSøren Schmidt elf_brand_list[i]->sysvec; 567ea5a2b2eSSøren Schmidt strcpy(path, elf_brand_list[i]->emul_path); 568ea5a2b2eSSøren Schmidt strcat(path, elf_brand_list[i]->interp_path); 569e1743d02SSøren Schmidt UPRINTF("interpreter=<%s> %s\n", 570ea5a2b2eSSøren Schmidt elf_brand_list[i]->interp_path, 571ea5a2b2eSSøren Schmidt elf_brand_list[i]->emul_path); 572e1743d02SSøren Schmidt break; 573e1743d02SSøren Schmidt } 574e1743d02SSøren Schmidt } 575e1743d02SSøren Schmidt } 576ea5a2b2eSSøren Schmidt } 577ea5a2b2eSSøren Schmidt 578ea5a2b2eSSøren Schmidt /* 579ea5a2b2eSSøren Schmidt * If there is no interpreter, or recognition of it 580ea5a2b2eSSøren Schmidt * failed, se if the binary is branded. 581ea5a2b2eSSøren Schmidt */ 582ea5a2b2eSSøren Schmidt if (!interp || i == MAX_BRANDS) { 583ea5a2b2eSSøren Schmidt brand = (char *)&(hdr->e_ident[EI_BRAND]); 584ea5a2b2eSSøren Schmidt for (i=0; i<MAX_BRANDS; i++) { 585ea5a2b2eSSøren Schmidt if (elf_brand_list[i] != NULL) { 586ea5a2b2eSSøren Schmidt if (!strcmp(brand, elf_brand_list[i]->brand)) { 587ea5a2b2eSSøren Schmidt imgp->proc->p_sysent = elf_brand_list[i]->sysvec; 588ea5a2b2eSSøren Schmidt if (interp) { 589ea5a2b2eSSøren Schmidt strcpy(path, elf_brand_list[i]->emul_path); 590ea5a2b2eSSøren Schmidt strcat(path, elf_brand_list[i]->interp_path); 591ea5a2b2eSSøren Schmidt UPRINTF("interpreter=<%s> %s\n", 592ea5a2b2eSSøren Schmidt elf_brand_list[i]->interp_path, 593ea5a2b2eSSøren Schmidt elf_brand_list[i]->emul_path); 594ea5a2b2eSSøren Schmidt } 595d672246bSSøren Schmidt break; 596ea5a2b2eSSøren Schmidt } 597ea5a2b2eSSøren Schmidt } 598ea5a2b2eSSøren Schmidt } 599ea5a2b2eSSøren Schmidt } 600ea5a2b2eSSøren Schmidt if (i == MAX_BRANDS) { 601a9d81f7cSDoug Rabson #ifndef __alpha__ 602ea5a2b2eSSøren Schmidt uprintf("ELF binary type not known\n"); 603e1743d02SSøren Schmidt error = ENOEXEC; 604e1743d02SSøren Schmidt goto fail; 605a9d81f7cSDoug Rabson #else 606a9d81f7cSDoug Rabson i = 0; /* assume freebsd */ 607a9d81f7cSDoug Rabson imgp->proc->p_sysent = elf_brand_list[i]->sysvec; 608a9d81f7cSDoug Rabson if (interp) { 609a9d81f7cSDoug Rabson strcpy(path, elf_brand_list[i]->emul_path); 610a9d81f7cSDoug Rabson strcat(path, elf_brand_list[i]->interp_path); 611a9d81f7cSDoug Rabson UPRINTF("interpreter=<%s> %s\n", 612a9d81f7cSDoug Rabson elf_brand_list[i]->interp_path, 613a9d81f7cSDoug Rabson elf_brand_list[i]->emul_path); 614a9d81f7cSDoug Rabson } 615ecbb00a2SDoug Rabson #endif 616e1743d02SSøren Schmidt } 617ea5a2b2eSSøren Schmidt if (interp) { 618e1743d02SSøren Schmidt if (error = elf_load_file(imgp->proc, 619e1743d02SSøren Schmidt path, 620e1743d02SSøren Schmidt &addr, /* XXX */ 621e1743d02SSøren Schmidt &imgp->entry_addr)) { 622e1743d02SSøren Schmidt uprintf("ELF interpreter %s not found\n", path); 623e1743d02SSøren Schmidt goto fail; 624e1743d02SSøren Schmidt } 625e1743d02SSøren Schmidt } 626ea5a2b2eSSøren Schmidt 627717fb679SSøren Schmidt UPRINTF("Executing %s binary\n", elf_brand_list[i]->brand); 628e1743d02SSøren Schmidt 629e1743d02SSøren Schmidt /* 630e1743d02SSøren Schmidt * Construct auxargs table (used by the fixup routine) 631e1743d02SSøren Schmidt */ 632ecbb00a2SDoug Rabson elf_auxargs = malloc(sizeof(Elf_Auxargs), M_TEMP, M_WAITOK); 633e1743d02SSøren Schmidt elf_auxargs->execfd = -1; 634e1743d02SSøren Schmidt elf_auxargs->phdr = proghdr; 635e1743d02SSøren Schmidt elf_auxargs->phent = hdr->e_phentsize; 636e1743d02SSøren Schmidt elf_auxargs->phnum = hdr->e_phnum; 637e1743d02SSøren Schmidt elf_auxargs->pagesz = PAGE_SIZE; 638e1743d02SSøren Schmidt elf_auxargs->base = addr; 639e1743d02SSøren Schmidt elf_auxargs->flags = 0; 640e1743d02SSøren Schmidt elf_auxargs->entry = entry; 641e1743d02SSøren Schmidt elf_auxargs->trace = elf_trace; 642e1743d02SSøren Schmidt 643e1743d02SSøren Schmidt imgp->auxargs = elf_auxargs; 644e1743d02SSøren Schmidt imgp->interpreted = 0; 645e1743d02SSøren Schmidt 646e1743d02SSøren Schmidt /* don't allow modifying the file while we run it */ 647e1743d02SSøren Schmidt imgp->vp->v_flag |= VTEXT; 648e1743d02SSøren Schmidt 649e1743d02SSøren Schmidt fail: 650e1743d02SSøren Schmidt return error; 651e1743d02SSøren Schmidt } 652e1743d02SSøren Schmidt 653e1743d02SSøren Schmidt static int 654ecbb00a2SDoug Rabson elf_freebsd_fixup(long **stack_base, struct image_params *imgp) 655e1743d02SSøren Schmidt { 656ecbb00a2SDoug Rabson Elf_Auxargs *args = (Elf_Auxargs *)imgp->auxargs; 657ecbb00a2SDoug Rabson long *pos; 658e1743d02SSøren Schmidt 659e1743d02SSøren Schmidt pos = *stack_base + (imgp->argc + imgp->envc + 2); 660e1743d02SSøren Schmidt 661e1743d02SSøren Schmidt if (args->trace) { 662e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_DEBUG, 1); 663e1743d02SSøren Schmidt } 664e1743d02SSøren Schmidt if (args->execfd != -1) { 665e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); 666e1743d02SSøren Schmidt } 667e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); 668e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHENT, args->phent); 669e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); 670e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); 671e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); 672e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); 673e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_BASE, args->base); 674e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_NULL, 0); 675e1743d02SSøren Schmidt 676e1743d02SSøren Schmidt free(imgp->auxargs, M_TEMP); 677e1743d02SSøren Schmidt imgp->auxargs = NULL; 678e1743d02SSøren Schmidt 679e1743d02SSøren Schmidt (*stack_base)--; 680ecbb00a2SDoug Rabson **stack_base = (long)imgp->argc; 681e1743d02SSøren Schmidt return 0; 682e1743d02SSøren Schmidt } 683e1743d02SSøren Schmidt 684e1743d02SSøren Schmidt /* 6858c64af4fSJohn Polstra * Code for generating ELF core dumps. 6868c64af4fSJohn Polstra */ 6878c64af4fSJohn Polstra 6880ff27d31SJohn Polstra typedef void (*segment_callback) __P((vm_map_entry_t, void *)); 6890ff27d31SJohn Polstra 6900ff27d31SJohn Polstra /* Closure for cb_put_phdr(). */ 6910ff27d31SJohn Polstra struct phdr_closure { 6920ff27d31SJohn Polstra Elf_Phdr *phdr; /* Program header to fill in */ 6930ff27d31SJohn Polstra Elf_Off offset; /* Offset of segment in core file */ 6940ff27d31SJohn Polstra }; 6950ff27d31SJohn Polstra 6960ff27d31SJohn Polstra /* Closure for cb_size_segment(). */ 6970ff27d31SJohn Polstra struct sseg_closure { 6980ff27d31SJohn Polstra int count; /* Count of writable segments. */ 6990ff27d31SJohn Polstra size_t size; /* Total size of all writable segments. */ 7000ff27d31SJohn Polstra }; 7010ff27d31SJohn Polstra 7020ff27d31SJohn Polstra static void cb_put_phdr __P((vm_map_entry_t, void *)); 7030ff27d31SJohn Polstra static void cb_size_segment __P((vm_map_entry_t, void *)); 7040ff27d31SJohn Polstra static void each_writable_segment __P((struct proc *, segment_callback, 7050ff27d31SJohn Polstra void *)); 7060ff27d31SJohn Polstra static int elf_corehdr __P((struct proc *, struct vnode *, struct ucred *, 7070ff27d31SJohn Polstra int, void *, size_t)); 7080ff27d31SJohn Polstra static void elf_puthdr __P((struct proc *, void *, size_t *, 7090ff27d31SJohn Polstra const prstatus_t *, const prfpregset_t *, const prpsinfo_t *, int)); 7100ff27d31SJohn Polstra static void elf_putnote __P((void *, size_t *, const char *, int, 7110ff27d31SJohn Polstra const void *, size_t)); 7128c64af4fSJohn Polstra 7138c64af4fSJohn Polstra extern int osreldate; 7148c64af4fSJohn Polstra 7158c64af4fSJohn Polstra int 7168c64af4fSJohn Polstra elf_coredump(p) 7178c64af4fSJohn Polstra register struct proc *p; 7188c64af4fSJohn Polstra { 7198c64af4fSJohn Polstra register struct vnode *vp; 7208c64af4fSJohn Polstra register struct ucred *cred = p->p_cred->pc_ucred; 7218c64af4fSJohn Polstra register struct vmspace *vm = p->p_vmspace; 7228c64af4fSJohn Polstra struct nameidata nd; 7238c64af4fSJohn Polstra struct vattr vattr; 7248c64af4fSJohn Polstra int error, error1; 7258c64af4fSJohn Polstra char *name; /* name of corefile */ 7260ff27d31SJohn Polstra struct sseg_closure seginfo; 7270ff27d31SJohn Polstra void *hdr; 7288c64af4fSJohn Polstra size_t hdrsize; 7298c64af4fSJohn Polstra 7308c64af4fSJohn Polstra STOPEVENT(p, S_CORE, 0); 7318c64af4fSJohn Polstra 7328c64af4fSJohn Polstra if (sugid_coredump == 0 && p->p_flag & P_SUGID) 7338c64af4fSJohn Polstra return (EFAULT); 7340ff27d31SJohn Polstra 7350ff27d31SJohn Polstra /* Size the program segments. */ 7360ff27d31SJohn Polstra seginfo.count = 0; 7370ff27d31SJohn Polstra seginfo.size = 0; 7380ff27d31SJohn Polstra each_writable_segment(p, cb_size_segment, &seginfo); 7390ff27d31SJohn Polstra 7400ff27d31SJohn Polstra /* 7410ff27d31SJohn Polstra * Calculate the size of the core file header area by making 7420ff27d31SJohn Polstra * a dry run of generating it. Nothing is written, but the 7430ff27d31SJohn Polstra * size is calculated. 7440ff27d31SJohn Polstra */ 7450ff27d31SJohn Polstra hdrsize = 0; 7460ff27d31SJohn Polstra elf_puthdr((struct proc *)NULL, (void *)NULL, &hdrsize, 7470ff27d31SJohn Polstra (const prstatus_t *)NULL, (const prfpregset_t *)NULL, 7480ff27d31SJohn Polstra (const prpsinfo_t *)NULL, seginfo.count); 7490ff27d31SJohn Polstra 7500ff27d31SJohn Polstra if (hdrsize + seginfo.size >= p->p_rlimit[RLIMIT_CORE].rlim_cur) 7518c64af4fSJohn Polstra return (EFAULT); 7528c64af4fSJohn Polstra name = expand_name(p->p_comm, p->p_ucred->cr_uid, p->p_pid); 7538c64af4fSJohn Polstra if (name == NULL) 7548c64af4fSJohn Polstra return (EFAULT); /* XXX -- not the best error */ 7558c64af4fSJohn Polstra 7568c64af4fSJohn Polstra NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, name, p); 7578c64af4fSJohn Polstra error = vn_open(&nd, O_CREAT | FWRITE, S_IRUSR | S_IWUSR); 7588c64af4fSJohn Polstra free(name, M_TEMP); 7598c64af4fSJohn Polstra if (error) 7608c64af4fSJohn Polstra return (error); 7618c64af4fSJohn Polstra vp = nd.ni_vp; 7628c64af4fSJohn Polstra 7638c64af4fSJohn Polstra /* Don't dump to non-regular files or files with links. */ 7648c64af4fSJohn Polstra if (vp->v_type != VREG || 7658c64af4fSJohn Polstra VOP_GETATTR(vp, &vattr, cred, p) || vattr.va_nlink != 1) { 7668c64af4fSJohn Polstra error = EFAULT; 7678c64af4fSJohn Polstra goto out; 7688c64af4fSJohn Polstra } 7698c64af4fSJohn Polstra VATTR_NULL(&vattr); 7708c64af4fSJohn Polstra vattr.va_size = 0; 7718c64af4fSJohn Polstra VOP_LEASE(vp, p, cred, LEASE_WRITE); 7728c64af4fSJohn Polstra VOP_SETATTR(vp, &vattr, cred, p); 7738c64af4fSJohn Polstra p->p_acflag |= ACORE; 7740ff27d31SJohn Polstra 7750ff27d31SJohn Polstra 7760ff27d31SJohn Polstra /* 7770ff27d31SJohn Polstra * Allocate memory for building the header, fill it up, 7780ff27d31SJohn Polstra * and write it out. 7790ff27d31SJohn Polstra */ 7800ff27d31SJohn Polstra hdr = malloc(hdrsize, M_TEMP, M_WAITOK); 7810ff27d31SJohn Polstra if (hdr == NULL) { 7820ff27d31SJohn Polstra error = EINVAL; 7830ff27d31SJohn Polstra goto out; 7840ff27d31SJohn Polstra } 7850ff27d31SJohn Polstra error = elf_corehdr(p, vp, cred, seginfo.count, hdr, hdrsize); 7860ff27d31SJohn Polstra 7870ff27d31SJohn Polstra /* Write the contents of all of the writable segments. */ 7880ff27d31SJohn Polstra if (error == 0) { 7890ff27d31SJohn Polstra Elf_Phdr *php; 7900ff27d31SJohn Polstra off_t offset; 7910ff27d31SJohn Polstra int i; 7920ff27d31SJohn Polstra 7930ff27d31SJohn Polstra php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1; 7940ff27d31SJohn Polstra offset = hdrsize; 7950ff27d31SJohn Polstra for (i = 0; i < seginfo.count; i++) { 7960ff27d31SJohn Polstra error = vn_rdwr(UIO_WRITE, vp, (caddr_t)php->p_vaddr, 7970ff27d31SJohn Polstra php->p_filesz, offset, UIO_USERSPACE, 798dada0278SJohn Polstra IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, p); 7990ff27d31SJohn Polstra if (error != 0) 8000ff27d31SJohn Polstra break; 8010ff27d31SJohn Polstra offset += php->p_filesz; 8020ff27d31SJohn Polstra php++; 8030ff27d31SJohn Polstra } 8040ff27d31SJohn Polstra } 8050ff27d31SJohn Polstra free(hdr, M_TEMP); 8060ff27d31SJohn Polstra 8078c64af4fSJohn Polstra out: 8088c64af4fSJohn Polstra VOP_UNLOCK(vp, 0, p); 8098c64af4fSJohn Polstra error1 = vn_close(vp, FWRITE, cred, p); 8108c64af4fSJohn Polstra if (error == 0) 8118c64af4fSJohn Polstra error = error1; 8128c64af4fSJohn Polstra return (error); 8138c64af4fSJohn Polstra } 8148c64af4fSJohn Polstra 8150ff27d31SJohn Polstra /* 8160ff27d31SJohn Polstra * A callback for each_writable_segment() to write out the segment's 8170ff27d31SJohn Polstra * program header entry. 8180ff27d31SJohn Polstra */ 8190ff27d31SJohn Polstra static void 8200ff27d31SJohn Polstra cb_put_phdr(entry, closure) 8210ff27d31SJohn Polstra vm_map_entry_t entry; 8220ff27d31SJohn Polstra void *closure; 8230ff27d31SJohn Polstra { 8240ff27d31SJohn Polstra struct phdr_closure *phc = (struct phdr_closure *)closure; 8250ff27d31SJohn Polstra Elf_Phdr *phdr = phc->phdr; 8260ff27d31SJohn Polstra 8270ff27d31SJohn Polstra phc->offset = round_page(phc->offset); 8280ff27d31SJohn Polstra 8290ff27d31SJohn Polstra phdr->p_type = PT_LOAD; 8300ff27d31SJohn Polstra phdr->p_offset = phc->offset; 8310ff27d31SJohn Polstra phdr->p_vaddr = entry->start; 8320ff27d31SJohn Polstra phdr->p_paddr = 0; 8330ff27d31SJohn Polstra phdr->p_filesz = phdr->p_memsz = entry->end - entry->start; 8340ff27d31SJohn Polstra phdr->p_align = PAGE_SIZE; 8350ff27d31SJohn Polstra phdr->p_flags = 0; 8360ff27d31SJohn Polstra if (entry->protection & VM_PROT_READ) 8370ff27d31SJohn Polstra phdr->p_flags |= PF_R; 8380ff27d31SJohn Polstra if (entry->protection & VM_PROT_WRITE) 8390ff27d31SJohn Polstra phdr->p_flags |= PF_W; 8400ff27d31SJohn Polstra if (entry->protection & VM_PROT_EXECUTE) 8410ff27d31SJohn Polstra phdr->p_flags |= PF_X; 8420ff27d31SJohn Polstra 8430ff27d31SJohn Polstra phc->offset += phdr->p_filesz; 8440ff27d31SJohn Polstra phc->phdr++; 8450ff27d31SJohn Polstra } 8460ff27d31SJohn Polstra 8470ff27d31SJohn Polstra /* 8480ff27d31SJohn Polstra * A callback for each_writable_segment() to gather information about 8490ff27d31SJohn Polstra * the number of segments and their total size. 8500ff27d31SJohn Polstra */ 8510ff27d31SJohn Polstra static void 8520ff27d31SJohn Polstra cb_size_segment(entry, closure) 8530ff27d31SJohn Polstra vm_map_entry_t entry; 8540ff27d31SJohn Polstra void *closure; 8550ff27d31SJohn Polstra { 8560ff27d31SJohn Polstra struct sseg_closure *ssc = (struct sseg_closure *)closure; 8570ff27d31SJohn Polstra 8580ff27d31SJohn Polstra ssc->count++; 8590ff27d31SJohn Polstra ssc->size += entry->end - entry->start; 8600ff27d31SJohn Polstra } 8610ff27d31SJohn Polstra 8620ff27d31SJohn Polstra /* 8630ff27d31SJohn Polstra * For each writable segment in the process's memory map, call the given 8640ff27d31SJohn Polstra * function with a pointer to the map entry and some arbitrary 8650ff27d31SJohn Polstra * caller-supplied data. 8660ff27d31SJohn Polstra */ 8670ff27d31SJohn Polstra static void 8680ff27d31SJohn Polstra each_writable_segment(p, func, closure) 8690ff27d31SJohn Polstra struct proc *p; 8700ff27d31SJohn Polstra segment_callback func; 8710ff27d31SJohn Polstra void *closure; 8720ff27d31SJohn Polstra { 8730ff27d31SJohn Polstra vm_map_t map = &p->p_vmspace->vm_map; 8740ff27d31SJohn Polstra vm_map_entry_t entry; 8750ff27d31SJohn Polstra 8760ff27d31SJohn Polstra for (entry = map->header.next; entry != &map->header; 8770ff27d31SJohn Polstra entry = entry->next) { 8780ff27d31SJohn Polstra vm_object_t obj; 8790ff27d31SJohn Polstra 8800ff27d31SJohn Polstra if (entry->eflags & (MAP_ENTRY_IS_A_MAP|MAP_ENTRY_IS_SUB_MAP) || 8810ff27d31SJohn Polstra (entry->protection & (VM_PROT_READ|VM_PROT_WRITE)) != 8820ff27d31SJohn Polstra (VM_PROT_READ|VM_PROT_WRITE)) 8830ff27d31SJohn Polstra continue; 8840ff27d31SJohn Polstra 8850ff27d31SJohn Polstra if ((obj = entry->object.vm_object) == NULL) 8860ff27d31SJohn Polstra continue; 8870ff27d31SJohn Polstra 8880ff27d31SJohn Polstra /* Find the deepest backing object. */ 8890ff27d31SJohn Polstra while (obj->backing_object != NULL) 8900ff27d31SJohn Polstra obj = obj->backing_object; 8910ff27d31SJohn Polstra 8920ff27d31SJohn Polstra /* Ignore memory-mapped devices and such things. */ 8930ff27d31SJohn Polstra if (obj->type != OBJT_DEFAULT && 8940ff27d31SJohn Polstra obj->type != OBJT_SWAP && 8950ff27d31SJohn Polstra obj->type != OBJT_VNODE) 8960ff27d31SJohn Polstra continue; 8970ff27d31SJohn Polstra 8980ff27d31SJohn Polstra (*func)(entry, closure); 8990ff27d31SJohn Polstra } 9000ff27d31SJohn Polstra } 9010ff27d31SJohn Polstra 9020ff27d31SJohn Polstra /* 9030ff27d31SJohn Polstra * Write the core file header to the file, including padding up to 9040ff27d31SJohn Polstra * the page boundary. 9050ff27d31SJohn Polstra */ 9068c64af4fSJohn Polstra static int 9070ff27d31SJohn Polstra elf_corehdr(p, vp, cred, numsegs, hdr, hdrsize) 9088c64af4fSJohn Polstra struct proc *p; 9098c64af4fSJohn Polstra struct vnode *vp; 9108c64af4fSJohn Polstra struct ucred *cred; 9110ff27d31SJohn Polstra int numsegs; 9120ff27d31SJohn Polstra size_t hdrsize; 9130ff27d31SJohn Polstra void *hdr; 9148c64af4fSJohn Polstra { 9158c64af4fSJohn Polstra struct vmspace *vm = p->p_vmspace; 9168c64af4fSJohn Polstra size_t off; 9178c64af4fSJohn Polstra prstatus_t status; 9188c64af4fSJohn Polstra prfpregset_t fpregset; 9198c64af4fSJohn Polstra prpsinfo_t psinfo; 9208c64af4fSJohn Polstra 9218c64af4fSJohn Polstra /* Gather the information for the header. */ 9228c64af4fSJohn Polstra bzero(&status, sizeof status); 9238c64af4fSJohn Polstra status.pr_version = PRSTATUS_VERSION; 9248c64af4fSJohn Polstra status.pr_statussz = sizeof(prstatus_t); 9258c64af4fSJohn Polstra status.pr_gregsetsz = sizeof(gregset_t); 9268c64af4fSJohn Polstra status.pr_fpregsetsz = sizeof(fpregset_t); 9278c64af4fSJohn Polstra status.pr_osreldate = osreldate; 9288c64af4fSJohn Polstra status.pr_cursig = p->p_sigacts->ps_sig; 9298c64af4fSJohn Polstra status.pr_pid = p->p_pid; 9308c64af4fSJohn Polstra fill_regs(p, &status.pr_reg); 9318c64af4fSJohn Polstra 9328c64af4fSJohn Polstra fill_fpregs(p, &fpregset); 9338c64af4fSJohn Polstra 9348c64af4fSJohn Polstra bzero(&psinfo, sizeof psinfo); 9358c64af4fSJohn Polstra psinfo.pr_version = PRPSINFO_VERSION; 9368c64af4fSJohn Polstra psinfo.pr_psinfosz = sizeof(prpsinfo_t); 9378c64af4fSJohn Polstra strncpy(psinfo.pr_fname, p->p_comm, MAXCOMLEN); 9380ff27d31SJohn Polstra /* XXX - We don't fill in the command line arguments properly yet. */ 9390ff27d31SJohn Polstra strncpy(psinfo.pr_psargs, p->p_comm, PRARGSZ); 9408c64af4fSJohn Polstra 9418c64af4fSJohn Polstra /* Fill in the header. */ 9420ff27d31SJohn Polstra bzero(hdr, hdrsize); 9438c64af4fSJohn Polstra off = 0; 9440ff27d31SJohn Polstra elf_puthdr(p, hdr, &off, &status, &fpregset, &psinfo, numsegs); 9458c64af4fSJohn Polstra 9468c64af4fSJohn Polstra /* Write it to the core file. */ 9470ff27d31SJohn Polstra return vn_rdwr(UIO_WRITE, vp, hdr, hdrsize, (off_t)0, 9488c64af4fSJohn Polstra UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, NULL, p); 949dada0278SJohn Polstra } 950dada0278SJohn Polstra 9518c64af4fSJohn Polstra static void 9520ff27d31SJohn Polstra elf_puthdr(struct proc *p, void *dst, size_t *off, const prstatus_t *status, 9530ff27d31SJohn Polstra const prfpregset_t *fpregset, const prpsinfo_t *psinfo, int numsegs) 9548c64af4fSJohn Polstra { 9558c64af4fSJohn Polstra size_t ehoff; 9568c64af4fSJohn Polstra size_t phoff; 9578c64af4fSJohn Polstra size_t noteoff; 9588c64af4fSJohn Polstra size_t notesz; 9598c64af4fSJohn Polstra 9608c64af4fSJohn Polstra ehoff = *off; 9618c64af4fSJohn Polstra *off += sizeof(Elf_Ehdr); 9628c64af4fSJohn Polstra 9638c64af4fSJohn Polstra phoff = *off; 9640ff27d31SJohn Polstra *off += (numsegs + 1) * sizeof(Elf_Phdr); 9658c64af4fSJohn Polstra 9668c64af4fSJohn Polstra noteoff = *off; 9678c64af4fSJohn Polstra elf_putnote(dst, off, "FreeBSD", NT_PRSTATUS, status, 9688c64af4fSJohn Polstra sizeof *status); 9698c64af4fSJohn Polstra elf_putnote(dst, off, "FreeBSD", NT_FPREGSET, fpregset, 9708c64af4fSJohn Polstra sizeof *fpregset); 9718c64af4fSJohn Polstra elf_putnote(dst, off, "FreeBSD", NT_PRPSINFO, psinfo, 9728c64af4fSJohn Polstra sizeof *psinfo); 9738c64af4fSJohn Polstra notesz = *off - noteoff; 9748c64af4fSJohn Polstra 9750ff27d31SJohn Polstra /* Align up to a page boundary for the program segments. */ 9768c64af4fSJohn Polstra *off = round_page(*off); 9778c64af4fSJohn Polstra 9788c64af4fSJohn Polstra if (dst != NULL) { 9798c64af4fSJohn Polstra Elf_Ehdr *ehdr; 9808c64af4fSJohn Polstra Elf_Phdr *phdr; 9810ff27d31SJohn Polstra struct phdr_closure phc; 9828c64af4fSJohn Polstra 9838c64af4fSJohn Polstra /* 9848c64af4fSJohn Polstra * Fill in the ELF header. 9858c64af4fSJohn Polstra */ 9868c64af4fSJohn Polstra ehdr = (Elf_Ehdr *)((char *)dst + ehoff); 9878c64af4fSJohn Polstra ehdr->e_ident[EI_MAG0] = ELFMAG0; 9888c64af4fSJohn Polstra ehdr->e_ident[EI_MAG1] = ELFMAG1; 9898c64af4fSJohn Polstra ehdr->e_ident[EI_MAG2] = ELFMAG2; 9908c64af4fSJohn Polstra ehdr->e_ident[EI_MAG3] = ELFMAG3; 9918c64af4fSJohn Polstra ehdr->e_ident[EI_CLASS] = ELF_CLASS; 9928c64af4fSJohn Polstra ehdr->e_ident[EI_DATA] = ELF_DATA; 9938c64af4fSJohn Polstra ehdr->e_ident[EI_VERSION] = EV_CURRENT; 9948c64af4fSJohn Polstra ehdr->e_ident[EI_PAD] = 0; 9958c64af4fSJohn Polstra strncpy(ehdr->e_ident + EI_BRAND, "FreeBSD", 9968c64af4fSJohn Polstra EI_NIDENT - EI_BRAND); 9978c64af4fSJohn Polstra ehdr->e_type = ET_CORE; 9988c64af4fSJohn Polstra ehdr->e_machine = ELF_ARCH; 9998c64af4fSJohn Polstra ehdr->e_version = EV_CURRENT; 10008c64af4fSJohn Polstra ehdr->e_entry = 0; 10018c64af4fSJohn Polstra ehdr->e_phoff = phoff; 10028c64af4fSJohn Polstra ehdr->e_flags = 0; 10038c64af4fSJohn Polstra ehdr->e_ehsize = sizeof(Elf_Ehdr); 10048c64af4fSJohn Polstra ehdr->e_phentsize = sizeof(Elf_Phdr); 10050ff27d31SJohn Polstra ehdr->e_phnum = numsegs + 1; 10068c64af4fSJohn Polstra ehdr->e_shentsize = sizeof(Elf_Shdr); 10078c64af4fSJohn Polstra ehdr->e_shnum = 0; 10088c64af4fSJohn Polstra ehdr->e_shstrndx = SHN_UNDEF; 10098c64af4fSJohn Polstra 10108c64af4fSJohn Polstra /* 10118c64af4fSJohn Polstra * Fill in the program header entries. 10128c64af4fSJohn Polstra */ 10138c64af4fSJohn Polstra phdr = (Elf_Phdr *)((char *)dst + phoff); 10148c64af4fSJohn Polstra 10158c64af4fSJohn Polstra /* The note segement. */ 10168c64af4fSJohn Polstra phdr->p_type = PT_NOTE; 10178c64af4fSJohn Polstra phdr->p_offset = noteoff; 10188c64af4fSJohn Polstra phdr->p_vaddr = 0; 10198c64af4fSJohn Polstra phdr->p_paddr = 0; 10208c64af4fSJohn Polstra phdr->p_filesz = notesz; 10218c64af4fSJohn Polstra phdr->p_memsz = 0; 10228c64af4fSJohn Polstra phdr->p_flags = 0; 10238c64af4fSJohn Polstra phdr->p_align = 0; 10248c64af4fSJohn Polstra phdr++; 10258c64af4fSJohn Polstra 10260ff27d31SJohn Polstra /* All the writable segments from the program. */ 10270ff27d31SJohn Polstra phc.phdr = phdr; 10280ff27d31SJohn Polstra phc.offset = *off; 10290ff27d31SJohn Polstra each_writable_segment(p, cb_put_phdr, &phc); 10308c64af4fSJohn Polstra } 10318c64af4fSJohn Polstra } 10328c64af4fSJohn Polstra 10338c64af4fSJohn Polstra static void 10348c64af4fSJohn Polstra elf_putnote(void *dst, size_t *off, const char *name, int type, 10358c64af4fSJohn Polstra const void *desc, size_t descsz) 10368c64af4fSJohn Polstra { 10378c64af4fSJohn Polstra Elf_Note note; 10388c64af4fSJohn Polstra 10398c64af4fSJohn Polstra note.n_namesz = strlen(name) + 1; 10408c64af4fSJohn Polstra note.n_descsz = descsz; 10418c64af4fSJohn Polstra note.n_type = type; 10428c64af4fSJohn Polstra if (dst != NULL) 10438c64af4fSJohn Polstra bcopy(¬e, (char *)dst + *off, sizeof note); 10448c64af4fSJohn Polstra *off += sizeof note; 10458c64af4fSJohn Polstra if (dst != NULL) 10468c64af4fSJohn Polstra bcopy(name, (char *)dst + *off, note.n_namesz); 10478c64af4fSJohn Polstra *off += roundup2(note.n_namesz, sizeof(Elf_Size)); 10488c64af4fSJohn Polstra if (dst != NULL) 10498c64af4fSJohn Polstra bcopy(desc, (char *)dst + *off, note.n_descsz); 10508c64af4fSJohn Polstra *off += roundup2(note.n_descsz, sizeof(Elf_Size)); 10518c64af4fSJohn Polstra } 10528c64af4fSJohn Polstra 10538c64af4fSJohn Polstra /* 1054e1743d02SSøren Schmidt * Tell kern_execve.c about it, with a little help from the linker. 1055e1743d02SSøren Schmidt * Since `const' objects end up in the text segment, TEXT_SET is the 1056e1743d02SSøren Schmidt * correct directive to use. 1057e1743d02SSøren Schmidt */ 1058d8a4f230SBruce Evans static const struct execsw elf_execsw = {exec_elf_imgact, "ELF"}; 1059e1743d02SSøren Schmidt TEXT_SET(execsw_set, elf_execsw); 1060e1743d02SSøren Schmidt 1061