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/exec_subr.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 /*      $NetBSD: exec_subr.c,v 1.41 2003/08/29 01:44:02 junyoung Exp $  */
    2 
    3 /*
    4  * Copyright (c) 1993, 1994, 1996 Christopher G. Demetriou
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   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. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *      This product includes software developed by Christopher G. Demetriou.
   18  * 4. The name of the author may not be used to endorse or promote products
   19  *    derived from this software without specific prior written permission
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __KERNEL_RCSID(0, "$NetBSD: exec_subr.c,v 1.41 2003/08/29 01:44:02 junyoung Exp $");
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/proc.h>
   39 #include <sys/malloc.h>
   40 #include <sys/vnode.h>
   41 #include <sys/filedesc.h>
   42 #include <sys/exec.h>
   43 #include <sys/mman.h>
   44 #include <sys/resourcevar.h>
   45 
   46 #include <uvm/uvm.h>
   47 
   48 /*
   49  * XXX cgd 960926: this module should collect simple statistics
   50  * (calls, extends, kills).
   51  */
   52 
   53 /*
   54  * new_vmcmd():
   55  *      create a new vmcmd structure and fill in its fields based
   56  *      on function call arguments.  make sure objects ref'd by
   57  *      the vmcmd are 'held'.
   58  */
   59 
   60 void
   61 new_vmcmd(struct exec_vmcmd_set *evsp,
   62     int (*proc)(struct proc * p, struct exec_vmcmd *),
   63     u_long len, u_long addr, struct vnode *vp, u_long offset,
   64     u_int prot, int flags)
   65 {
   66         struct exec_vmcmd    *vcp;
   67 
   68         if (evsp->evs_used >= evsp->evs_cnt)
   69                 vmcmdset_extend(evsp);
   70         vcp = &evsp->evs_cmds[evsp->evs_used++];
   71         vcp->ev_proc = proc;
   72         vcp->ev_len = len;
   73         vcp->ev_addr = addr;
   74         if ((vcp->ev_vp = vp) != NULL)
   75                 vref(vp);
   76         vcp->ev_offset = offset;
   77         vcp->ev_prot = prot;
   78         vcp->ev_flags = flags;
   79 }
   80 
   81 void
   82 vmcmdset_extend(struct exec_vmcmd_set *evsp)
   83 {
   84         struct exec_vmcmd *nvcp;
   85         u_int ocnt;
   86 
   87 #ifdef DIAGNOSTIC
   88         if (evsp->evs_used < evsp->evs_cnt)
   89                 panic("vmcmdset_extend: not necessary");
   90 #endif
   91 
   92         /* figure out number of entries in new set */
   93         ocnt = evsp->evs_cnt;
   94         evsp->evs_cnt += ocnt ? ocnt : EXEC_DEFAULT_VMCMD_SETSIZE;
   95 
   96         /* allocate it */
   97         nvcp = malloc(evsp->evs_cnt * sizeof(struct exec_vmcmd),
   98             M_EXEC, M_WAITOK);
   99 
  100         /* free the old struct, if there was one, and record the new one */
  101         if (ocnt) {
  102                 memcpy(nvcp, evsp->evs_cmds,
  103                     (ocnt * sizeof(struct exec_vmcmd)));
  104                 free(evsp->evs_cmds, M_EXEC);
  105         }
  106         evsp->evs_cmds = nvcp;
  107 }
  108 
  109 void
  110 kill_vmcmds(struct exec_vmcmd_set *evsp)
  111 {
  112         struct exec_vmcmd *vcp;
  113         u_int i;
  114 
  115         if (evsp->evs_cnt == 0)
  116                 return;
  117 
  118         for (i = 0; i < evsp->evs_used; i++) {
  119                 vcp = &evsp->evs_cmds[i];
  120                 if (vcp->ev_vp != NULL)
  121                         vrele(vcp->ev_vp);
  122         }
  123         evsp->evs_used = evsp->evs_cnt = 0;
  124         free(evsp->evs_cmds, M_EXEC);
  125 }
  126 
  127 /*
  128  * vmcmd_map_pagedvn():
  129  *      handle vmcmd which specifies that a vnode should be mmap'd.
  130  *      appropriate for handling demand-paged text and data segments.
  131  */
  132 
  133 int
  134 vmcmd_map_pagedvn(struct proc *p, struct exec_vmcmd *cmd)
  135 {
  136         struct uvm_object *uobj;
  137         int error;
  138 
  139         KASSERT(cmd->ev_vp->v_flag & VTEXT);
  140 
  141         /*
  142          * map the vnode in using uvm_map.
  143          */
  144 
  145         if (cmd->ev_len == 0)
  146                 return(0);
  147         if (cmd->ev_offset & PAGE_MASK)
  148                 return(EINVAL);
  149         if (cmd->ev_addr & PAGE_MASK)
  150                 return(EINVAL);
  151         if (cmd->ev_len & PAGE_MASK)
  152                 return(EINVAL);
  153 
  154         /*
  155          * first, attach to the object
  156          */
  157 
  158         uobj = uvn_attach(cmd->ev_vp, VM_PROT_READ|VM_PROT_EXECUTE);
  159         if (uobj == NULL)
  160                 return(ENOMEM);
  161         VREF(cmd->ev_vp);
  162 
  163         /*
  164          * do the map
  165          */
  166 
  167         error = uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr, cmd->ev_len, 
  168                 uobj, cmd->ev_offset, 0,
  169                 UVM_MAPFLAG(cmd->ev_prot, VM_PROT_ALL, UVM_INH_COPY, 
  170                         UVM_ADV_NORMAL, UVM_FLAG_COPYONW|UVM_FLAG_FIXED));
  171         if (error) {
  172                 uobj->pgops->pgo_detach(uobj);
  173         }
  174         return error;
  175 }
  176 
  177 /*
  178  * vmcmd_map_readvn():
  179  *      handle vmcmd which specifies that a vnode should be read from.
  180  *      appropriate for non-demand-paged text/data segments, i.e. impure
  181  *      objects (a la OMAGIC and NMAGIC).
  182  */
  183 int
  184 vmcmd_map_readvn(struct proc *p, struct exec_vmcmd *cmd)
  185 {
  186         int error;
  187         long diff;
  188 
  189         if (cmd->ev_len == 0)
  190                 return 0;
  191 
  192         diff = cmd->ev_addr - trunc_page(cmd->ev_addr);
  193         cmd->ev_addr -= diff;                   /* required by uvm_map */
  194         cmd->ev_offset -= diff;
  195         cmd->ev_len += diff;
  196 
  197         error = uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr, 
  198                         round_page(cmd->ev_len), NULL, UVM_UNKNOWN_OFFSET, 0,
  199                         UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_INH_COPY,
  200                         UVM_ADV_NORMAL,
  201                         UVM_FLAG_FIXED|UVM_FLAG_OVERLAY|UVM_FLAG_COPYONW));
  202 
  203         if (error)
  204                 return error;
  205 
  206         return vmcmd_readvn(p, cmd);
  207 }
  208 
  209 int
  210 vmcmd_readvn(struct proc *p, struct exec_vmcmd *cmd)
  211 {
  212         int error;
  213 
  214         error = vn_rdwr(UIO_READ, cmd->ev_vp, (caddr_t)cmd->ev_addr,
  215             cmd->ev_len, cmd->ev_offset, UIO_USERSPACE, IO_UNIT,
  216             p->p_ucred, NULL, p);
  217         if (error)
  218                 return error;
  219 
  220 #ifdef PMAP_NEED_PROCWR
  221         /*
  222          * we had to write the process, make sure the pages are synched
  223          * with the instruction cache.
  224          */
  225         if (cmd->ev_prot & VM_PROT_EXECUTE)
  226                 pmap_procwr(p, cmd->ev_addr, cmd->ev_len);
  227 #endif
  228 
  229         if (cmd->ev_prot != (VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE)) {
  230 
  231                 /*
  232                  * we had to map in the area at PROT_ALL so that vn_rdwr()
  233                  * could write to it.   however, the caller seems to want
  234                  * it mapped read-only, so now we are going to have to call
  235                  * uvm_map_protect() to fix up the protection.  ICK.
  236                  */
  237 
  238                 return uvm_map_protect(&p->p_vmspace->vm_map, 
  239                                 trunc_page(cmd->ev_addr),
  240                                 round_page(cmd->ev_addr + cmd->ev_len),
  241                                 cmd->ev_prot, FALSE);
  242         }
  243         return 0;
  244 }
  245 
  246 /*
  247  * vmcmd_map_zero():
  248  *      handle vmcmd which specifies a zero-filled address space region.  The
  249  *      address range must be first allocated, then protected appropriately.
  250  */
  251 
  252 int
  253 vmcmd_map_zero(struct proc *p, struct exec_vmcmd *cmd)
  254 {
  255         int error;
  256         long diff;
  257 
  258         diff = cmd->ev_addr - trunc_page(cmd->ev_addr);
  259         cmd->ev_addr -= diff;                   /* required by uvm_map */
  260         cmd->ev_len += diff;
  261 
  262         error = uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr, 
  263                         round_page(cmd->ev_len), NULL, UVM_UNKNOWN_OFFSET, 0,
  264                         UVM_MAPFLAG(cmd->ev_prot, UVM_PROT_ALL, UVM_INH_COPY,
  265                         UVM_ADV_NORMAL,
  266                         UVM_FLAG_FIXED|UVM_FLAG_COPYONW));
  267         return error;
  268 }
  269 
  270 /*
  271  * exec_read_from():
  272  *
  273  *      Read from vnode into buffer at offset.
  274  */
  275 int
  276 exec_read_from(struct proc *p, struct vnode *vp, u_long off, void *buf,
  277     size_t size)
  278 {
  279         int error;
  280         size_t resid;
  281 
  282         if ((error = vn_rdwr(UIO_READ, vp, buf, size, off, UIO_SYSSPACE,
  283             0, p->p_ucred, &resid, p)) != 0)
  284                 return error;
  285         /*
  286          * See if we got all of it
  287          */
  288         if (resid != 0)
  289                 return ENOEXEC;
  290         return 0;
  291 }
  292 
  293 /*
  294  * exec_setup_stack(): Set up the stack segment for an elf
  295  * executable.
  296  *
  297  * Note that the ep_ssize parameter must be set to be the current stack
  298  * limit; this is adjusted in the body of execve() to yield the
  299  * appropriate stack segment usage once the argument length is
  300  * calculated.
  301  *
  302  * This function returns an int for uniformity with other (future) formats'
  303  * stack setup functions.  They might have errors to return.
  304  */
  305 
  306 int
  307 exec_setup_stack(struct proc *p, struct exec_package *epp)
  308 {
  309         u_long max_stack_size;
  310         u_long access_linear_min, access_size;
  311         u_long noaccess_linear_min, noaccess_size;
  312 
  313 #ifndef USRSTACK32
  314 #define USRSTACK32      (0x00000000ffffffffL&~PGOFSET)
  315 #endif
  316 
  317         if (epp->ep_flags & EXEC_32) {
  318                 epp->ep_minsaddr = USRSTACK32;
  319                 max_stack_size = MAXSSIZ;
  320         } else {
  321                 epp->ep_minsaddr = USRSTACK;
  322                 max_stack_size = MAXSSIZ;
  323         }
  324         epp->ep_maxsaddr = (u_long)STACK_GROW(epp->ep_minsaddr, 
  325                 max_stack_size);
  326         epp->ep_ssize = p->p_rlimit[RLIMIT_STACK].rlim_cur;
  327 
  328         /*
  329          * set up commands for stack.  note that this takes *two*, one to
  330          * map the part of the stack which we can access, and one to map
  331          * the part which we can't.
  332          *
  333          * arguably, it could be made into one, but that would require the
  334          * addition of another mapping proc, which is unnecessary
  335          */
  336         access_size = epp->ep_ssize;
  337         access_linear_min = (u_long)STACK_ALLOC(epp->ep_minsaddr, access_size);
  338         noaccess_size = max_stack_size - access_size;
  339         noaccess_linear_min = (u_long)STACK_ALLOC(STACK_GROW(epp->ep_minsaddr, 
  340             access_size), noaccess_size);
  341         if (noaccess_size > 0) {
  342                 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, noaccess_size,
  343                     noaccess_linear_min, NULL, 0, VM_PROT_NONE);
  344         }
  345         KASSERT(access_size > 0);
  346         NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, access_size,
  347             access_linear_min, NULL, 0, VM_PROT_READ | VM_PROT_WRITE);
  348 
  349         return 0;
  350 }

Cache object: 97fd7190b1d7ac943b9468cda2c5817d


[ 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.