The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/imgact_elf.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1995-1996 Søren Schmidt
    3  * Copyright (c) 1996 Peter Wemm
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer
   11  *    in this position and unchanged.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. The name of the author may not be used to endorse or promote products
   16  *    derived from this software withough specific prior written permission
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   28  *
   29  * $FreeBSD$
   30  */
   31 
   32 #include "opt_rlimit.h"
   33 
   34 #include <sys/param.h>
   35 #include <sys/acct.h>
   36 #include <sys/exec.h>
   37 #include <sys/fcntl.h>
   38 #include <sys/imgact.h>
   39 #include <sys/imgact_elf.h>
   40 #include <sys/kernel.h>
   41 #include <sys/malloc.h>
   42 #include <sys/mman.h>
   43 #include <sys/namei.h>
   44 #include <sys/pioctl.h>
   45 #include <sys/proc.h>
   46 #include <sys/procfs.h>
   47 #include <sys/resourcevar.h>
   48 #include <sys/signalvar.h>
   49 #include <sys/stat.h>
   50 #include <sys/syscall.h>
   51 #include <sys/sysctl.h>
   52 #include <sys/sysent.h>
   53 #include <sys/systm.h>
   54 #include <sys/vnode.h>
   55 
   56 #include <vm/vm.h>
   57 #include <vm/vm_kern.h>
   58 #include <vm/vm_param.h>
   59 #include <vm/pmap.h>
   60 #include <sys/lock.h>
   61 #include <vm/vm_map.h>
   62 #include <vm/vm_object.h>
   63 #include <vm/vm_prot.h>
   64 #include <vm/vm_extern.h>
   65 
   66 #include <machine/elf.h>
   67 #include <machine/md_var.h>
   68 
   69 __ElfType(Brandinfo);
   70 __ElfType(Auxargs);
   71 
   72 static int elf_check_header __P((const Elf_Ehdr *hdr, int type));
   73 static int elf_freebsd_fixup __P((long **stack_base,
   74     struct image_params *imgp));
   75 static int elf_load_file __P((struct proc *p, const char *file, u_long *addr,
   76     u_long *entry));
   77 static int elf_load_section __P((struct proc *p,
   78     struct vmspace *vmspace, struct vnode *vp,
   79     vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz,
   80     vm_prot_t prot));
   81 static int exec_elf_imgact __P((struct image_params *imgp));
   82 
   83 static int elf_trace = 0;
   84 SYSCTL_INT(_debug, OID_AUTO, elf_trace, CTLFLAG_RW, &elf_trace, 0, "");
   85 
   86 static struct sysentvec elf_freebsd_sysvec = {
   87         SYS_MAXSYSCALL,
   88         sysent,
   89         0,
   90         0,
   91         0,
   92         0,
   93         0,
   94         0,
   95         elf_freebsd_fixup,
   96         sendsig,
   97         sigcode,
   98         &szsigcode,
   99         0,
  100         "FreeBSD ELF",
  101         elf_coredump
  102 };
  103 
  104 static Elf_Brandinfo freebsd_brand_info = {
  105                                                 "FreeBSD",
  106                                                 "",
  107                                                 "/usr/libexec/ld-elf.so.1",
  108                                                 &elf_freebsd_sysvec
  109                                           };
  110 static Elf_Brandinfo *elf_brand_list[MAX_BRANDS] = {
  111                                                         &freebsd_brand_info,
  112                                                         NULL, NULL, NULL,
  113                                                         NULL, NULL, NULL, NULL
  114                                                     };
  115 
  116 int
  117 elf_insert_brand_entry(Elf_Brandinfo *entry)
  118 {
  119         int i;
  120 
  121         for (i=1; i<MAX_BRANDS; i++) {
  122                 if (elf_brand_list[i] == NULL) {
  123                         elf_brand_list[i] = entry;
  124                         break;
  125                 }
  126         }
  127         if (i == MAX_BRANDS)
  128                 return -1;
  129         return 0;
  130 }
  131 
  132 int
  133 elf_remove_brand_entry(Elf_Brandinfo *entry)
  134 {
  135         int i;
  136 
  137         for (i=1; i<MAX_BRANDS; i++) {
  138                 if (elf_brand_list[i] == entry) {
  139                         elf_brand_list[i] = NULL;
  140                         break;
  141                 }
  142         }
  143         if (i == MAX_BRANDS)
  144                 return -1;
  145         return 0;
  146 }
  147 
  148 int
  149 elf_brand_inuse(Elf_Brandinfo *entry)
  150 {
  151         struct proc *p;
  152 
  153         for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
  154                 if (p->p_sysent == entry->sysvec)
  155                         return TRUE;
  156         }
  157 
  158         return FALSE;
  159 }
  160 
  161 static int
  162 elf_check_header(const Elf_Ehdr *hdr, int type)
  163 {
  164         if (!IS_ELF(*hdr) ||
  165             hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||
  166             hdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
  167             hdr->e_ident[EI_VERSION] != EV_CURRENT)
  168                 return ENOEXEC;
  169 
  170         if (!ELF_MACHINE_OK(hdr->e_machine))
  171                 return ENOEXEC;
  172 
  173         if (hdr->e_type != type || hdr->e_version != ELF_TARG_VER)
  174                 return ENOEXEC;
  175         
  176         return 0;
  177 }
  178 
  179 static int
  180 elf_load_section(struct proc *p, struct vmspace *vmspace, struct vnode *vp, vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, vm_prot_t prot)
  181 {
  182         size_t map_len;
  183         vm_offset_t map_addr;
  184         int error, rv;
  185         size_t copy_len;
  186         vm_object_t object;
  187         vm_offset_t file_addr;
  188         vm_offset_t data_buf = 0;
  189 
  190         object = vp->v_object;
  191         error = 0;
  192 
  193         map_addr = trunc_page((vm_offset_t)vmaddr);
  194         file_addr = trunc_page(offset);
  195 
  196         /*
  197          * We have two choices.  We can either clear the data in the last page
  198          * of an oversized mapping, or we can start the anon mapping a page
  199          * early and copy the initialized data into that first page.  We
  200          * choose the second..
  201          */
  202         if (memsz > filsz)
  203                 map_len = trunc_page(offset+filsz) - file_addr;
  204         else
  205                 map_len = round_page(offset+filsz) - file_addr;
  206 
  207         if (map_len != 0) {
  208                 vm_object_reference(object);
  209                 vm_map_lock(&vmspace->vm_map);
  210                 rv = vm_map_insert(&vmspace->vm_map,
  211                                       object,
  212                                       file_addr,        /* file offset */
  213                                       map_addr,         /* virtual start */
  214                                       map_addr + map_len,/* virtual end */
  215                                       prot,
  216                                       VM_PROT_ALL,
  217                                       MAP_COPY_NEEDED | MAP_COPY_ON_WRITE);
  218                 vm_map_unlock(&vmspace->vm_map);
  219                 if (rv != KERN_SUCCESS) {
  220                         vm_object_deallocate(object);
  221                         return EINVAL;
  222                 }
  223 
  224                 /* prefault the page tables */
  225                 pmap_object_init_pt(&vmspace->vm_pmap,
  226                                     map_addr,
  227                                     object,
  228                                     (vm_pindex_t) OFF_TO_IDX(file_addr),
  229                                     map_len,
  230                                     0);
  231 
  232                 /* we can stop now if we've covered it all */
  233                 if (memsz == filsz)
  234                         return 0;
  235         }
  236 
  237 
  238         /*
  239          * We have to get the remaining bit of the file into the first part
  240          * of the oversized map segment.  This is normally because the .data
  241          * segment in the file is extended to provide bss.  It's a neat idea
  242          * to try and save a page, but it's a pain in the behind to implement.
  243          */
  244         copy_len = (offset + filsz) - trunc_page(offset + filsz);
  245         map_addr = trunc_page((vm_offset_t)vmaddr + filsz);
  246         map_len = round_page((vm_offset_t)vmaddr + memsz) - map_addr;
  247 
  248         /* This had damn well better be true! */
  249         if (map_len != 0) {
  250                 vm_map_lock(&vmspace->vm_map);
  251                 rv = vm_map_insert(&vmspace->vm_map, NULL, 0,
  252                                         map_addr, map_addr + map_len,
  253                                         VM_PROT_ALL, VM_PROT_ALL, 0);
  254                 vm_map_unlock(&vmspace->vm_map);
  255                 if (rv != KERN_SUCCESS)
  256                         return EINVAL; 
  257         }
  258 
  259         if (copy_len != 0) {
  260                 vm_object_reference(object);
  261                 rv = vm_map_find(exec_map,
  262                                  object, 
  263                                  trunc_page(offset + filsz),
  264                                  &data_buf,
  265                                  PAGE_SIZE,
  266                                  TRUE,
  267                                  VM_PROT_READ,
  268                                  VM_PROT_ALL,
  269                                  MAP_COPY_ON_WRITE | MAP_COPY_NEEDED);
  270                 if (rv != KERN_SUCCESS) {
  271                         vm_object_deallocate(object);
  272                         return EINVAL;
  273                 }
  274                 pmap_object_init_pt(exec_map->pmap, data_buf, object,
  275                         (vm_pindex_t) OFF_TO_IDX(trunc_page(offset + filsz)),
  276                         PAGE_SIZE, 1);
  277 
  278                 /* send the page fragment to user space */
  279                 error = copyout((caddr_t)data_buf, (caddr_t)map_addr, copy_len);
  280                 vm_map_remove(exec_map, data_buf, data_buf + PAGE_SIZE);
  281                 if (error)
  282                         return (error);
  283         }
  284 
  285         /*
  286          * set it to the specified protection
  287          */
  288         vm_map_protect(&vmspace->vm_map, map_addr, map_addr + map_len,  prot,
  289                        FALSE);
  290 
  291         return error;
  292 }
  293 
  294 static int
  295 elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry)
  296 {
  297         Elf_Ehdr *hdr = NULL;
  298         Elf_Phdr *phdr = NULL;
  299         struct nameidata nd;
  300         struct vmspace *vmspace = p->p_vmspace;
  301         struct vattr attr;
  302         struct image_params image_params, *imgp;
  303         vm_prot_t prot;
  304         unsigned long text_size = 0, data_size = 0;
  305         unsigned long text_addr = 0, data_addr = 0;
  306         int error, i;
  307 
  308         imgp = &image_params;
  309         /*
  310          * Initialize part of the common data
  311          */
  312         imgp->proc = p;
  313         imgp->uap = NULL;
  314         imgp->attr = &attr;
  315         imgp->firstpage = NULL;
  316         imgp->image_header = (char *)kmem_alloc_wait(exec_map, PAGE_SIZE);
  317 
  318         if (imgp->image_header == NULL) {
  319                 nd.ni_vp = NULL;
  320                 error = ENOMEM;
  321                 goto fail;
  322         }
  323 
  324         NDINIT(&nd, LOOKUP, LOCKLEAF|FOLLOW, UIO_SYSSPACE, file, p);   
  325                          
  326         if (error = namei(&nd)) {
  327                 nd.ni_vp = NULL;
  328                 goto fail;
  329         }
  330 
  331         imgp->vp = nd.ni_vp;
  332 
  333         /*
  334          * Check permissions, modes, uid, etc on the file, and "open" it.
  335          */
  336         error = exec_check_permissions(imgp);
  337         if (error) {
  338                 VOP_UNLOCK(nd.ni_vp, 0, p);
  339                 goto fail;
  340         }
  341 
  342         error = exec_map_first_page(imgp);
  343         VOP_UNLOCK(nd.ni_vp, 0, p);
  344         if (error)
  345                 goto fail;
  346 
  347         hdr = (Elf_Ehdr *)imgp->image_header;
  348         if (error = elf_check_header(hdr, ET_DYN))
  349                 goto fail;
  350 
  351         /* Only support headers that fit within first page for now */
  352         if ((hdr->e_phoff > PAGE_SIZE) ||
  353             (hdr->e_phoff + hdr->e_phentsize * hdr->e_phnum) > PAGE_SIZE) {
  354                 error = ENOEXEC;
  355                 goto fail;
  356         }
  357 
  358         phdr = (Elf_Phdr *)(imgp->image_header + hdr->e_phoff);
  359 
  360         for (i = 0; i < hdr->e_phnum; i++) {
  361                 if (phdr[i].p_type == PT_LOAD) {        /* Loadable segment */
  362                         prot = 0;
  363                         if (phdr[i].p_flags & PF_X)
  364                                 prot |= VM_PROT_EXECUTE;
  365                         if (phdr[i].p_flags & PF_W)
  366                                 prot |= VM_PROT_WRITE;
  367                         if (phdr[i].p_flags & PF_R)
  368                                 prot |= VM_PROT_READ;
  369 
  370                         if (error = elf_load_section(p, vmspace, nd.ni_vp,
  371                                                      phdr[i].p_offset,
  372                                                      (caddr_t)phdr[i].p_vaddr +
  373                                                         (*addr),
  374                                                      phdr[i].p_memsz,
  375                                                      phdr[i].p_filesz, prot)) 
  376                                 goto fail;
  377 
  378                         /*
  379                          * Is this .text or .data ??
  380                          *
  381                          * We only handle one each of those yet XXX
  382                          */
  383                         if (hdr->e_entry >= phdr[i].p_vaddr &&
  384                         hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) {
  385                                 text_addr = trunc_page(phdr[i].p_vaddr+(*addr));
  386                                 text_size = round_page(phdr[i].p_memsz +
  387                                                        phdr[i].p_vaddr -
  388                                                        trunc_page(phdr[i].p_vaddr));
  389                                 *entry=(unsigned long)hdr->e_entry+(*addr);
  390                         } else {
  391                                 data_addr = trunc_page(phdr[i].p_vaddr+(*addr));
  392                                 data_size = round_page(phdr[i].p_memsz +
  393                                                        phdr[i].p_vaddr -
  394                                                        trunc_page(phdr[i].p_vaddr));
  395                         }
  396                 }
  397         }
  398 
  399 fail:
  400         if (imgp->firstpage)
  401                 exec_unmap_first_page(imgp);
  402         if (imgp->image_header)
  403                 kmem_free_wakeup(exec_map, (vm_offset_t)imgp->image_header,
  404                         PAGE_SIZE);
  405         if (nd.ni_vp)
  406                 vrele(nd.ni_vp);
  407 
  408         return error;
  409 }
  410 
  411 static int
  412 exec_elf_imgact(struct image_params *imgp)
  413 {
  414         const Elf_Ehdr *hdr = (const Elf_Ehdr *) imgp->image_header;
  415         const Elf_Phdr *phdr;
  416         Elf_Auxargs *elf_auxargs = NULL;
  417         struct vmspace *vmspace;
  418         vm_prot_t prot;
  419         u_long text_size = 0, data_size = 0;
  420         u_long text_addr = 0, data_addr = 0;
  421         u_long addr, entry = 0, proghdr = 0;
  422         int error, i;
  423         const char *interp = NULL;
  424         Elf_Brandinfo *brand_info;
  425         char *brand;
  426         char path[MAXPATHLEN];
  427 
  428         /*
  429          * Do we have a valid ELF header ?
  430          */
  431         if (elf_check_header(hdr, ET_EXEC))
  432                 return -1;
  433 
  434         /*
  435          * From here on down, we return an errno, not -1, as we've
  436          * detected an ELF file.
  437          */
  438 
  439         if ((hdr->e_phoff > PAGE_SIZE) ||
  440             (hdr->e_phoff + hdr->e_phentsize * hdr->e_phnum) > PAGE_SIZE) {
  441                 /* Only support headers in first page for now */
  442                 return ENOEXEC;
  443         }
  444         phdr = (const Elf_Phdr*)(imgp->image_header + hdr->e_phoff);
  445         
  446         /*
  447          * From this point on, we may have resources that need to be freed.
  448          */
  449         if (error = exec_extract_strings(imgp))
  450                 goto fail;
  451 
  452         exec_new_vmspace(imgp);
  453 
  454         vmspace = imgp->proc->p_vmspace;
  455 
  456         for (i = 0; i < hdr->e_phnum; i++) {
  457                 switch(phdr[i].p_type) {
  458 
  459                 case PT_LOAD:   /* Loadable segment */
  460                         prot = 0;
  461                         if (phdr[i].p_flags & PF_X)
  462                                 prot |= VM_PROT_EXECUTE;
  463                         if (phdr[i].p_flags & PF_W)
  464                                 prot |= VM_PROT_WRITE;
  465                         if (phdr[i].p_flags & PF_R)
  466                                 prot |= VM_PROT_READ;
  467 
  468                         if (error = elf_load_section(imgp->proc,
  469                                                      vmspace, imgp->vp,
  470                                                      phdr[i].p_offset,
  471                                                      (caddr_t)phdr[i].p_vaddr,
  472                                                      phdr[i].p_memsz,
  473                                                      phdr[i].p_filesz, prot)) 
  474                                 goto fail;
  475 
  476                         /*
  477                          * Is this .text or .data ??
  478                          *
  479                          * We only handle one each of those yet XXX
  480                          */
  481                         if (hdr->e_entry >= phdr[i].p_vaddr &&
  482                         hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) {
  483                                 text_addr = trunc_page(phdr[i].p_vaddr);
  484                                 text_size = round_page(phdr[i].p_memsz +
  485                                                        phdr[i].p_vaddr -
  486                                                        text_addr);
  487                                 entry = (u_long)hdr->e_entry;
  488                         } else {
  489                                 data_addr = trunc_page(phdr[i].p_vaddr);
  490                                 data_size = round_page(phdr[i].p_memsz +
  491                                                        phdr[i].p_vaddr -
  492                                                        data_addr);
  493                         }
  494                         break;
  495                 case PT_INTERP: /* Path to interpreter */
  496                         if (phdr[i].p_filesz > MAXPATHLEN ||
  497                             phdr[i].p_offset + phdr[i].p_filesz > PAGE_SIZE) {
  498                                 error = ENOEXEC;
  499                                 goto fail;
  500                         }
  501                         interp = imgp->image_header + phdr[i].p_offset;
  502                         break;
  503                 case PT_PHDR:   /* Program header table info */
  504                         proghdr = phdr[i].p_vaddr;
  505                         break;
  506                 default:
  507                         break;
  508                 }
  509         }
  510 
  511         vmspace->vm_tsize = text_size >> PAGE_SHIFT;
  512         vmspace->vm_taddr = (caddr_t)(uintptr_t)text_addr;
  513         vmspace->vm_dsize = data_size >> PAGE_SHIFT;
  514         vmspace->vm_daddr = (caddr_t)(uintptr_t)data_addr;
  515 
  516         addr = ELF_RTLD_ADDR(vmspace);
  517 
  518         imgp->entry_addr = entry;
  519 
  520         /* If the executable has a brand, search for it in the brand list. */
  521         brand_info = NULL;
  522         brand = (char *)&hdr->e_ident[EI_BRAND];
  523         if (brand[0] != '\0') {
  524                 for (i = 0;  i < MAX_BRANDS;  i++) {
  525                         Elf_Brandinfo *bi = elf_brand_list[i];
  526 
  527                         if (bi != NULL && strcmp(brand, bi->brand) == 0) {
  528                                 brand_info = bi;
  529                                 break;
  530                         }
  531                 }
  532         }
  533 
  534         /* Lacking a known brand, search for a recognized interpreter. */
  535         if (brand_info == NULL && interp != NULL) {
  536                 for (i = 0;  i < MAX_BRANDS;  i++) {
  537                         Elf_Brandinfo *bi = elf_brand_list[i];
  538 
  539                         if (bi != NULL &&
  540                             strcmp(interp, bi->interp_path) == 0) {
  541                                 brand_info = bi;
  542                                 break;
  543                         }
  544                 }
  545         }
  546 
  547 #ifdef __alpha__
  548         /* XXX - Assume FreeBSD on the alpha. */
  549         if (brand_info == NULL)
  550                 brand_info = &freebsd_brand_info;
  551 #endif
  552 
  553         if (brand_info == NULL) {
  554                 if (brand[0] == 0)
  555                         uprintf("ELF binary type not known."
  556                             "  Use \"brandelf\" to brand it.\n");
  557                 else
  558                         uprintf("ELF binary type \"%.*s\" not known.\n",
  559                             EI_NIDENT - EI_BRAND, brand);
  560                 error = ENOEXEC;
  561                 goto fail;
  562         }
  563 
  564         imgp->proc->p_sysent = brand_info->sysvec;
  565         if (interp != NULL) {
  566                 snprintf(path, sizeof(path), "%s%s",
  567                     brand_info->emul_path, interp);
  568                 if ((error = elf_load_file(imgp->proc, path, &addr,
  569                     &imgp->entry_addr)) != 0) {
  570                         if ((error = elf_load_file(imgp->proc, interp, &addr,
  571                                                    &imgp->entry_addr)) != 0) {
  572                                 uprintf("ELF interpreter %s not found\n", path);
  573                                 goto fail;
  574                         }
  575                 }
  576         }
  577 
  578         /*
  579          * Construct auxargs table (used by the fixup routine)
  580          */
  581         elf_auxargs = malloc(sizeof(Elf_Auxargs), M_TEMP, M_WAITOK);
  582         elf_auxargs->execfd = -1;
  583         elf_auxargs->phdr = proghdr;
  584         elf_auxargs->phent = hdr->e_phentsize;
  585         elf_auxargs->phnum = hdr->e_phnum;
  586         elf_auxargs->pagesz = PAGE_SIZE;
  587         elf_auxargs->base = addr;
  588         elf_auxargs->flags = 0;
  589         elf_auxargs->entry = entry;
  590         elf_auxargs->trace = elf_trace;
  591 
  592         imgp->auxargs = elf_auxargs;
  593         imgp->interpreted = 0;
  594 
  595         /* don't allow modifying the file while we run it */
  596         imgp->vp->v_flag |= VTEXT;
  597         
  598 fail:
  599         return error;
  600 }
  601 
  602 static int
  603 elf_freebsd_fixup(long **stack_base, struct image_params *imgp)
  604 {
  605         Elf_Auxargs *args = (Elf_Auxargs *)imgp->auxargs;
  606         long *pos;
  607 
  608         pos = *stack_base + (imgp->argc + imgp->envc + 2);
  609 
  610         if (args->trace) {
  611                 AUXARGS_ENTRY(pos, AT_DEBUG, 1);
  612         }
  613         if (args->execfd != -1) {
  614                 AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
  615         }
  616         AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
  617         AUXARGS_ENTRY(pos, AT_PHENT, args->phent);
  618         AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum);
  619         AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz);
  620         AUXARGS_ENTRY(pos, AT_FLAGS, args->flags);
  621         AUXARGS_ENTRY(pos, AT_ENTRY, args->entry);
  622         AUXARGS_ENTRY(pos, AT_BASE, args->base);
  623         AUXARGS_ENTRY(pos, AT_NULL, 0);
  624 
  625         free(imgp->auxargs, M_TEMP);
  626         imgp->auxargs = NULL;
  627 
  628         (*stack_base)--;
  629         suword(*stack_base, (long) imgp->argc);
  630         return 0;
  631 } 
  632 
  633 /*
  634  * Code for generating ELF core dumps.
  635  */
  636 
  637 typedef void (*segment_callback) __P((vm_map_entry_t, void *));
  638 
  639 /* Closure for cb_put_phdr(). */
  640 struct phdr_closure {
  641         Elf_Phdr *phdr;         /* Program header to fill in */
  642         Elf_Off offset;         /* Offset of segment in core file */
  643 };
  644 
  645 /* Closure for cb_size_segment(). */
  646 struct sseg_closure {
  647         int count;              /* Count of writable segments. */
  648         size_t size;            /* Total size of all writable segments. */
  649 };
  650 
  651 static void cb_put_phdr __P((vm_map_entry_t, void *));
  652 static void cb_size_segment __P((vm_map_entry_t, void *));
  653 static void each_writable_segment __P((struct proc *, segment_callback,
  654     void *));
  655 static int elf_corehdr __P((struct proc *, struct vnode *, struct ucred *,
  656     int, void *, size_t));
  657 static void elf_puthdr __P((struct proc *, void *, size_t *,
  658     const prstatus_t *, const prfpregset_t *, const prpsinfo_t *, int));
  659 static void elf_putnote __P((void *, size_t *, const char *, int,
  660     const void *, size_t));
  661 
  662 extern int osreldate;
  663 
  664 int
  665 elf_coredump(p, vp, limit)
  666         register struct proc *p;
  667         register struct vnode *vp;
  668         off_t limit;
  669 {
  670         register struct ucred *cred = p->p_cred->pc_ucred;
  671         int error = 0;
  672         struct sseg_closure seginfo;
  673         void *hdr;
  674         size_t hdrsize;
  675 
  676         /* Size the program segments. */
  677         seginfo.count = 0;
  678         seginfo.size = 0;
  679         each_writable_segment(p, cb_size_segment, &seginfo);
  680 
  681         /*
  682          * Calculate the size of the core file header area by making
  683          * a dry run of generating it.  Nothing is written, but the
  684          * size is calculated.
  685          */
  686         hdrsize = 0;
  687         elf_puthdr((struct proc *)NULL, (void *)NULL, &hdrsize,
  688             (const prstatus_t *)NULL, (const prfpregset_t *)NULL,
  689             (const prpsinfo_t *)NULL, seginfo.count);
  690 
  691         if (hdrsize + seginfo.size >= limit)
  692                 return (EFAULT);
  693 
  694         /*
  695          * Allocate memory for building the header, fill it up,
  696          * and write it out.
  697          */
  698         hdr = malloc(hdrsize, M_TEMP, M_WAITOK);
  699         if (hdr == NULL) {
  700                 return EINVAL;
  701         }
  702         error = elf_corehdr(p, vp, cred, seginfo.count, hdr, hdrsize);
  703 
  704         /* Write the contents of all of the writable segments. */
  705         if (error == 0) {
  706                 Elf_Phdr *php;
  707                 off_t offset;
  708                 int i;
  709 
  710                 php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1;
  711                 offset = hdrsize;
  712                 for (i = 0;  i < seginfo.count;  i++) {
  713                         error = vn_rdwr(UIO_WRITE, vp, (caddr_t)php->p_vaddr,
  714                             php->p_filesz, offset, UIO_USERSPACE,
  715                             IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, p);
  716                         if (error != 0)
  717                                 break;
  718                         offset += php->p_filesz;
  719                         php++;
  720                 }
  721         }
  722         free(hdr, M_TEMP);
  723         
  724         return error;
  725 }
  726 
  727 /*
  728  * A callback for each_writable_segment() to write out the segment's
  729  * program header entry.
  730  */
  731 static void
  732 cb_put_phdr(entry, closure)
  733         vm_map_entry_t entry;
  734         void *closure;
  735 {
  736         struct phdr_closure *phc = (struct phdr_closure *)closure;
  737         Elf_Phdr *phdr = phc->phdr;
  738 
  739         phc->offset = round_page(phc->offset);
  740 
  741         phdr->p_type = PT_LOAD;
  742         phdr->p_offset = phc->offset;
  743         phdr->p_vaddr = entry->start;
  744         phdr->p_paddr = 0;
  745         phdr->p_filesz = phdr->p_memsz = entry->end - entry->start;
  746         phdr->p_align = PAGE_SIZE;
  747         phdr->p_flags = 0;
  748         if (entry->protection & VM_PROT_READ)
  749                 phdr->p_flags |= PF_R;
  750         if (entry->protection & VM_PROT_WRITE)
  751                 phdr->p_flags |= PF_W;
  752         if (entry->protection & VM_PROT_EXECUTE)
  753                 phdr->p_flags |= PF_X;
  754 
  755         phc->offset += phdr->p_filesz;
  756         phc->phdr++;
  757 }
  758 
  759 /*
  760  * A callback for each_writable_segment() to gather information about
  761  * the number of segments and their total size.
  762  */
  763 static void
  764 cb_size_segment(entry, closure)
  765         vm_map_entry_t entry;
  766         void *closure;
  767 {
  768         struct sseg_closure *ssc = (struct sseg_closure *)closure;
  769 
  770         ssc->count++;
  771         ssc->size += entry->end - entry->start;
  772 }
  773 
  774 /*
  775  * For each writable segment in the process's memory map, call the given
  776  * function with a pointer to the map entry and some arbitrary
  777  * caller-supplied data.
  778  */
  779 static void
  780 each_writable_segment(p, func, closure)
  781         struct proc *p;
  782         segment_callback func;
  783         void *closure;
  784 {
  785         vm_map_t map = &p->p_vmspace->vm_map;
  786         vm_map_entry_t entry;
  787 
  788         for (entry = map->header.next;  entry != &map->header;
  789             entry = entry->next) {
  790                 vm_object_t obj;
  791 
  792                 if (entry->eflags & (MAP_ENTRY_IS_A_MAP|MAP_ENTRY_IS_SUB_MAP) ||
  793                     (entry->protection & (VM_PROT_READ|VM_PROT_WRITE)) !=
  794                     (VM_PROT_READ|VM_PROT_WRITE))
  795                         continue;
  796 
  797                 if ((obj = entry->object.vm_object) == NULL)
  798                         continue;
  799 
  800                 /* Find the deepest backing object. */
  801                 while (obj->backing_object != NULL)
  802                         obj = obj->backing_object;
  803 
  804                 /* Ignore memory-mapped devices and such things. */
  805                 if (obj->type != OBJT_DEFAULT &&
  806                     obj->type != OBJT_SWAP &&
  807                     obj->type != OBJT_VNODE)
  808                         continue;
  809 
  810                 (*func)(entry, closure);
  811         }
  812 }
  813 
  814 /*
  815  * Write the core file header to the file, including padding up to
  816  * the page boundary.
  817  */
  818 static int
  819 elf_corehdr(p, vp, cred, numsegs, hdr, hdrsize)
  820         struct proc *p;
  821         struct vnode *vp;
  822         struct ucred *cred;
  823         int numsegs;
  824         size_t hdrsize;
  825         void *hdr;
  826 {
  827         size_t off;
  828         prstatus_t status;
  829         prfpregset_t fpregset;
  830         prpsinfo_t psinfo;
  831 
  832         /* Gather the information for the header. */
  833         bzero(&status, sizeof status);
  834         status.pr_version = PRSTATUS_VERSION;
  835         status.pr_statussz = sizeof(prstatus_t);
  836         status.pr_gregsetsz = sizeof(gregset_t);
  837         status.pr_fpregsetsz = sizeof(fpregset_t);
  838         status.pr_osreldate = osreldate;
  839         status.pr_cursig = p->p_sig;
  840         status.pr_pid = p->p_pid;
  841         fill_regs(p, &status.pr_reg);
  842 
  843         fill_fpregs(p, &fpregset);
  844 
  845         bzero(&psinfo, sizeof psinfo);
  846         psinfo.pr_version = PRPSINFO_VERSION;
  847         psinfo.pr_psinfosz = sizeof(prpsinfo_t);
  848         strncpy(psinfo.pr_fname, p->p_comm, MAXCOMLEN);
  849         /* XXX - We don't fill in the command line arguments properly yet. */
  850         strncpy(psinfo.pr_psargs, p->p_comm, PRARGSZ);
  851 
  852         /* Fill in the header. */
  853         bzero(hdr, hdrsize);
  854         off = 0;
  855         elf_puthdr(p, hdr, &off, &status, &fpregset, &psinfo, numsegs);
  856 
  857         /* Write it to the core file. */
  858         return vn_rdwr(UIO_WRITE, vp, hdr, hdrsize, (off_t)0,
  859             UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, NULL, p);
  860 }
  861 
  862 static void
  863 elf_puthdr(struct proc *p, void *dst, size_t *off, const prstatus_t *status,
  864     const prfpregset_t *fpregset, const prpsinfo_t *psinfo, int numsegs)
  865 {
  866         size_t ehoff;
  867         size_t phoff;
  868         size_t noteoff;
  869         size_t notesz;
  870 
  871         ehoff = *off;
  872         *off += sizeof(Elf_Ehdr);
  873 
  874         phoff = *off;
  875         *off += (numsegs + 1) * sizeof(Elf_Phdr);
  876 
  877         noteoff = *off;
  878         elf_putnote(dst, off, "FreeBSD", NT_PRSTATUS, status,
  879             sizeof *status);
  880         elf_putnote(dst, off, "FreeBSD", NT_FPREGSET, fpregset,
  881             sizeof *fpregset);
  882         elf_putnote(dst, off, "FreeBSD", NT_PRPSINFO, psinfo,
  883             sizeof *psinfo);
  884         notesz = *off - noteoff;
  885 
  886         /* Align up to a page boundary for the program segments. */
  887         *off = round_page(*off);
  888 
  889         if (dst != NULL) {
  890                 Elf_Ehdr *ehdr;
  891                 Elf_Phdr *phdr;
  892                 struct phdr_closure phc;
  893 
  894                 /*
  895                  * Fill in the ELF header.
  896                  */
  897                 ehdr = (Elf_Ehdr *)((char *)dst + ehoff);
  898                 ehdr->e_ident[EI_MAG0] = ELFMAG0;
  899                 ehdr->e_ident[EI_MAG1] = ELFMAG1;
  900                 ehdr->e_ident[EI_MAG2] = ELFMAG2;
  901                 ehdr->e_ident[EI_MAG3] = ELFMAG3;
  902                 ehdr->e_ident[EI_CLASS] = ELF_CLASS;
  903                 ehdr->e_ident[EI_DATA] = ELF_DATA;
  904                 ehdr->e_ident[EI_VERSION] = EV_CURRENT;
  905                 ehdr->e_ident[EI_PAD] = 0;
  906                 strncpy(ehdr->e_ident + EI_BRAND, "FreeBSD",
  907                     EI_NIDENT - EI_BRAND);
  908                 ehdr->e_type = ET_CORE;
  909                 ehdr->e_machine = ELF_ARCH;
  910                 ehdr->e_version = EV_CURRENT;
  911                 ehdr->e_entry = 0;
  912                 ehdr->e_phoff = phoff;
  913                 ehdr->e_flags = 0;
  914                 ehdr->e_ehsize = sizeof(Elf_Ehdr);
  915                 ehdr->e_phentsize = sizeof(Elf_Phdr);
  916                 ehdr->e_phnum = numsegs + 1;
  917                 ehdr->e_shentsize = sizeof(Elf_Shdr);
  918                 ehdr->e_shnum = 0;
  919                 ehdr->e_shstrndx = SHN_UNDEF;
  920 
  921                 /*
  922                  * Fill in the program header entries.
  923                  */
  924                 phdr = (Elf_Phdr *)((char *)dst + phoff);
  925 
  926                 /* The note segement. */
  927                 phdr->p_type = PT_NOTE;
  928                 phdr->p_offset = noteoff;
  929                 phdr->p_vaddr = 0;
  930                 phdr->p_paddr = 0;
  931                 phdr->p_filesz = notesz;
  932                 phdr->p_memsz = 0;
  933                 phdr->p_flags = 0;
  934                 phdr->p_align = 0;
  935                 phdr++;
  936 
  937                 /* All the writable segments from the program. */
  938                 phc.phdr = phdr;
  939                 phc.offset = *off;
  940                 each_writable_segment(p, cb_put_phdr, &phc);
  941         }
  942 }
  943 
  944 static void
  945 elf_putnote(void *dst, size_t *off, const char *name, int type,
  946     const void *desc, size_t descsz)
  947 {
  948         Elf_Note note;
  949 
  950         note.n_namesz = strlen(name) + 1;
  951         note.n_descsz = descsz;
  952         note.n_type = type;
  953         if (dst != NULL)
  954                 bcopy(&note, (char *)dst + *off, sizeof note);
  955         *off += sizeof note;
  956         if (dst != NULL)
  957                 bcopy(name, (char *)dst + *off, note.n_namesz);
  958         *off += roundup2(note.n_namesz, sizeof(Elf_Size));
  959         if (dst != NULL)
  960                 bcopy(desc, (char *)dst + *off, note.n_descsz);
  961         *off += roundup2(note.n_descsz, sizeof(Elf_Size));
  962 }
  963 
  964 /*
  965  * Tell kern_execve.c about it, with a little help from the linker.
  966  * Since `const' objects end up in the text segment, TEXT_SET is the
  967  * correct directive to use.
  968  */
  969 static const struct execsw elf_execsw = {exec_elf_imgact, "ELF"};
  970 EXEC_SET(elf, elf_execsw);

Cache object: 8ac599b689d4dd41f61a3e200ff6f91f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.