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.84 2020/04/13 19:23:18 ad 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.84 2020/04/13 19:23:18 ad Exp $");
   35 
   36 #include "opt_pax.h"
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/proc.h>
   41 #include <sys/kmem.h>
   42 #include <sys/vnode.h>
   43 #include <sys/filedesc.h>
   44 #include <sys/exec.h>
   45 #include <sys/mman.h>
   46 #include <sys/resourcevar.h>
   47 #include <sys/device.h>
   48 #include <sys/pax.h>
   49 
   50 #include <uvm/uvm_extern.h>
   51 
   52 #define VMCMD_EVCNT_DECL(name)                                  \
   53 static struct evcnt vmcmd_ev_##name =                           \
   54     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "vmcmd", #name);   \
   55 EVCNT_ATTACH_STATIC(vmcmd_ev_##name)
   56 
   57 #define VMCMD_EVCNT_INCR(name)                                  \
   58     vmcmd_ev_##name.ev_count++
   59 
   60 VMCMD_EVCNT_DECL(calls);
   61 VMCMD_EVCNT_DECL(extends);
   62 VMCMD_EVCNT_DECL(kills);
   63 
   64 #ifdef DEBUG_STACK
   65 #define DPRINTF(a) uprintf a
   66 #else
   67 #define DPRINTF(a)
   68 #endif
   69 
   70 unsigned int user_stack_guard_size = 1024 * 1024;
   71 unsigned int user_thread_stack_guard_size = 64 * 1024;
   72 
   73 /*
   74  * new_vmcmd():
   75  *      create a new vmcmd structure and fill in its fields based
   76  *      on function call arguments.  make sure objects ref'd by
   77  *      the vmcmd are 'held'.
   78  */
   79 
   80 void
   81 new_vmcmd(struct exec_vmcmd_set *evsp,
   82     int (*proc)(struct lwp * l, struct exec_vmcmd *),
   83     vsize_t len, vaddr_t addr, struct vnode *vp, u_long offset,
   84     u_int prot, int flags)
   85 {
   86         struct exec_vmcmd *vcp;
   87 
   88         VMCMD_EVCNT_INCR(calls);
   89         KASSERT(proc != vmcmd_map_pagedvn || (vp->v_iflag & VI_TEXT));
   90         KASSERT(vp == NULL || vrefcnt(vp) > 0);
   91 
   92         if (evsp->evs_used >= evsp->evs_cnt)
   93                 vmcmdset_extend(evsp);
   94         vcp = &evsp->evs_cmds[evsp->evs_used++];
   95         vcp->ev_proc = proc;
   96         vcp->ev_len = len;
   97         vcp->ev_addr = addr;
   98         if ((vcp->ev_vp = vp) != NULL)
   99                 vref(vp);
  100         vcp->ev_offset = offset;
  101         vcp->ev_prot = prot;
  102         vcp->ev_flags = flags;
  103 }
  104 
  105 void
  106 vmcmdset_extend(struct exec_vmcmd_set *evsp)
  107 {
  108         struct exec_vmcmd *nvcp;
  109         u_int ocnt;
  110 
  111 #ifdef DIAGNOSTIC
  112         if (evsp->evs_used < evsp->evs_cnt)
  113                 panic("vmcmdset_extend: not necessary");
  114 #endif
  115 
  116         /* figure out number of entries in new set */
  117         if ((ocnt = evsp->evs_cnt) != 0) {
  118                 evsp->evs_cnt += ocnt;
  119                 VMCMD_EVCNT_INCR(extends);
  120         } else
  121                 evsp->evs_cnt = EXEC_DEFAULT_VMCMD_SETSIZE;
  122 
  123         /* allocate it */
  124         nvcp = kmem_alloc(evsp->evs_cnt * sizeof(struct exec_vmcmd), KM_SLEEP);
  125 
  126         /* free the old struct, if there was one, and record the new one */
  127         if (ocnt) {
  128                 memcpy(nvcp, evsp->evs_cmds,
  129                     (ocnt * sizeof(struct exec_vmcmd)));
  130                 kmem_free(evsp->evs_cmds, ocnt * sizeof(struct exec_vmcmd));
  131         }
  132         evsp->evs_cmds = nvcp;
  133 }
  134 
  135 void
  136 kill_vmcmds(struct exec_vmcmd_set *evsp)
  137 {
  138         struct exec_vmcmd *vcp;
  139         u_int i;
  140 
  141         VMCMD_EVCNT_INCR(kills);
  142 
  143         if (evsp->evs_cnt == 0)
  144                 return;
  145 
  146         for (i = 0; i < evsp->evs_used; i++) {
  147                 vcp = &evsp->evs_cmds[i];
  148                 if (vcp->ev_vp != NULL)
  149                         vrele(vcp->ev_vp);
  150         }
  151         kmem_free(evsp->evs_cmds, evsp->evs_cnt * sizeof(struct exec_vmcmd));
  152         evsp->evs_used = evsp->evs_cnt = 0;
  153 }
  154 
  155 /*
  156  * vmcmd_map_pagedvn():
  157  *      handle vmcmd which specifies that a vnode should be mmap'd.
  158  *      appropriate for handling demand-paged text and data segments.
  159  */
  160 
  161 static int
  162 vmcmd_get_prot(struct lwp *l, const struct exec_vmcmd *cmd, vm_prot_t *prot,
  163     vm_prot_t *maxprot)
  164 {
  165 
  166         *prot = cmd->ev_prot;
  167         *maxprot = PAX_MPROTECT_MAXPROTECT(l, *prot, 0, UVM_PROT_ALL);
  168 
  169         if ((*prot & *maxprot) != *prot)
  170                 return EACCES;
  171         return PAX_MPROTECT_VALIDATE(l, *prot);
  172 }
  173 
  174 int
  175 vmcmd_map_pagedvn(struct lwp *l, struct exec_vmcmd *cmd)
  176 {
  177         struct uvm_object *uobj;
  178         struct vnode *vp = cmd->ev_vp;
  179         struct proc *p = l->l_proc;
  180         int error;
  181         vm_prot_t prot, maxprot;
  182 
  183         KASSERT(vp->v_iflag & VI_TEXT);
  184 
  185         /*
  186          * map the vnode in using uvm_map.
  187          */
  188 
  189         if (cmd->ev_len == 0)
  190                 return 0;
  191         if (cmd->ev_offset & PAGE_MASK)
  192                 return EINVAL;
  193         if (cmd->ev_addr & PAGE_MASK)
  194                 return EINVAL;
  195         if (cmd->ev_len & PAGE_MASK)
  196                 return EINVAL;
  197 
  198         if ((error = vmcmd_get_prot(l, cmd, &prot, &maxprot)) != 0)
  199                 return error;
  200 
  201         /*
  202          * check the file system's opinion about mmapping the file
  203          */
  204 
  205         error = VOP_MMAP(vp, prot, l->l_cred);
  206         if (error)
  207                 return error;
  208 
  209         if ((vp->v_vflag & VV_MAPPED) == 0) {
  210                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  211                 vp->v_vflag |= VV_MAPPED;
  212                 VOP_UNLOCK(vp);
  213         }
  214 
  215         /*
  216          * do the map, reference the object for this map entry
  217          */
  218         uobj = &vp->v_uobj;
  219         vref(vp);
  220 
  221         error = uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr, cmd->ev_len,
  222                 uobj, cmd->ev_offset, 0,
  223                 UVM_MAPFLAG(prot, maxprot, UVM_INH_COPY,
  224                         UVM_ADV_NORMAL, UVM_FLAG_COPYONW|UVM_FLAG_FIXED));
  225         if (error) {
  226                 uobj->pgops->pgo_detach(uobj);
  227         }
  228         return error;
  229 }
  230 
  231 /*
  232  * vmcmd_map_readvn():
  233  *      handle vmcmd which specifies that a vnode should be read from.
  234  *      appropriate for non-demand-paged text/data segments, i.e. impure
  235  *      objects (a la OMAGIC and NMAGIC).
  236  */
  237 int
  238 vmcmd_map_readvn(struct lwp *l, struct exec_vmcmd *cmd)
  239 {
  240         struct proc *p = l->l_proc;
  241         int error;
  242         long diff;
  243 
  244         if (cmd->ev_len == 0)
  245                 return 0;
  246 
  247         diff = cmd->ev_addr - trunc_page(cmd->ev_addr);
  248         cmd->ev_addr -= diff;                   /* required by uvm_map */
  249         cmd->ev_offset -= diff;
  250         cmd->ev_len += diff;
  251 
  252         error = uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr,
  253                         round_page(cmd->ev_len), NULL, UVM_UNKNOWN_OFFSET, 0,
  254                         UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_INH_COPY,
  255                         UVM_ADV_NORMAL,
  256                         UVM_FLAG_FIXED|UVM_FLAG_OVERLAY|UVM_FLAG_COPYONW));
  257 
  258         if (error)
  259                 return error;
  260 
  261         return vmcmd_readvn(l, cmd);
  262 }
  263 
  264 int
  265 vmcmd_readvn(struct lwp *l, struct exec_vmcmd *cmd)
  266 {
  267         struct proc *p = l->l_proc;
  268         int error;
  269         vm_prot_t prot, maxprot;
  270 
  271         error = vn_rdwr(UIO_READ, cmd->ev_vp, (void *)cmd->ev_addr,
  272             cmd->ev_len, cmd->ev_offset, UIO_USERSPACE, IO_UNIT,
  273             l->l_cred, NULL, l);
  274         if (error)
  275                 return error;
  276 
  277         if ((error = vmcmd_get_prot(l, cmd, &prot, &maxprot)) != 0)
  278                 return error;
  279 
  280 #ifdef PMAP_NEED_PROCWR
  281         /*
  282          * we had to write the process, make sure the pages are synched
  283          * with the instruction cache.
  284          */
  285         if (prot & VM_PROT_EXECUTE)
  286                 pmap_procwr(p, cmd->ev_addr, cmd->ev_len);
  287 #endif
  288 
  289         /*
  290          * we had to map in the area at PROT_ALL so that vn_rdwr()
  291          * could write to it.   however, the caller seems to want
  292          * it mapped read-only, so now we are going to have to call
  293          * uvm_map_protect() to fix up the protection.  ICK.
  294          */
  295         if (maxprot != VM_PROT_ALL) {
  296                 error = uvm_map_protect(&p->p_vmspace->vm_map,
  297                                 trunc_page(cmd->ev_addr),
  298                                 round_page(cmd->ev_addr + cmd->ev_len),
  299                                 maxprot, true);
  300                 if (error)
  301                         return error;
  302         }
  303 
  304         if (prot != maxprot) {
  305                 error = uvm_map_protect(&p->p_vmspace->vm_map,
  306                                 trunc_page(cmd->ev_addr),
  307                                 round_page(cmd->ev_addr + cmd->ev_len),
  308                                 prot, false);
  309                 if (error)
  310                         return error;
  311         }
  312 
  313         return 0;
  314 }
  315 
  316 /*
  317  * vmcmd_map_zero():
  318  *      handle vmcmd which specifies a zero-filled address space region.  The
  319  *      address range must be first allocated, then protected appropriately.
  320  */
  321 
  322 int
  323 vmcmd_map_zero(struct lwp *l, struct exec_vmcmd *cmd)
  324 {
  325         struct proc *p = l->l_proc;
  326         int error;
  327         long diff;
  328         vm_prot_t prot, maxprot;
  329 
  330         diff = cmd->ev_addr - trunc_page(cmd->ev_addr);
  331         cmd->ev_addr -= diff;                   /* required by uvm_map */
  332         cmd->ev_len += diff;
  333 
  334         if ((error = vmcmd_get_prot(l, cmd, &prot, &maxprot)) != 0)
  335                 return error;
  336 
  337         error = uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr,
  338                         round_page(cmd->ev_len), NULL, UVM_UNKNOWN_OFFSET, 0,
  339                         UVM_MAPFLAG(prot, maxprot, UVM_INH_COPY,
  340                         UVM_ADV_NORMAL,
  341                         UVM_FLAG_FIXED|UVM_FLAG_COPYONW));
  342         if (cmd->ev_flags & VMCMD_STACK)
  343                 curproc->p_vmspace->vm_issize += atop(round_page(cmd->ev_len));
  344         return error;
  345 }
  346 
  347 /*
  348  * exec_read():
  349  *
  350  *      Read from vnode into buffer at offset.
  351  */
  352 int
  353 exec_read(struct lwp *l, struct vnode *vp, u_long off, void *bf, size_t size,
  354     int ioflg)
  355 {
  356         int error;
  357         size_t resid;
  358 
  359         KASSERT((ioflg & IO_NODELOCKED) == 0 || VOP_ISLOCKED(vp) != LK_NONE);
  360 
  361         if ((error = vn_rdwr(UIO_READ, vp, bf, size, off, UIO_SYSSPACE,
  362             ioflg, l->l_cred, &resid, NULL)) != 0)
  363                 return error;
  364         /*
  365          * See if we got all of it
  366          */
  367         if (resid != 0)
  368                 return ENOEXEC;
  369         return 0;
  370 }
  371 
  372 /*
  373  * exec_setup_stack(): Set up the stack segment for an elf
  374  * executable.
  375  *
  376  * Note that the ep_ssize parameter must be set to be the current stack
  377  * limit; this is adjusted in the body of execve() to yield the
  378  * appropriate stack segment usage once the argument length is
  379  * calculated.
  380  *
  381  * This function returns an int for uniformity with other (future) formats'
  382  * stack setup functions.  They might have errors to return.
  383  */
  384 
  385 int
  386 exec_setup_stack(struct lwp *l, struct exec_package *epp)
  387 {
  388         vsize_t max_stack_size;
  389         vaddr_t access_linear_min;
  390         vsize_t access_size;
  391         vaddr_t noaccess_linear_min;
  392         vsize_t noaccess_size;
  393 
  394 #ifndef USRSTACK32
  395 #define USRSTACK32      (0x00000000ffffffffL&~PGOFSET)
  396 #endif
  397 #ifndef MAXSSIZ32
  398 #define MAXSSIZ32       (MAXSSIZ >> 2)
  399 #endif
  400 
  401         if (epp->ep_flags & EXEC_32) {
  402                 epp->ep_minsaddr = USRSTACK32;
  403                 max_stack_size = MAXSSIZ32;
  404         } else {
  405                 epp->ep_minsaddr = USRSTACK;
  406                 max_stack_size = MAXSSIZ;
  407         }
  408 
  409         DPRINTF(("ep_minsaddr=%#jx max_stack_size=%#jx\n",
  410             (uintmax_t)epp->ep_minsaddr, (uintmax_t)max_stack_size));
  411 
  412         pax_aslr_stack(epp, &max_stack_size);
  413 
  414         DPRINTF(("[RLIMIT_STACK].lim_cur=%#jx max_stack_size=%#jx\n",
  415             (uintmax_t)l->l_proc->p_rlimit[RLIMIT_STACK].rlim_cur,
  416             (uintmax_t)max_stack_size));
  417         epp->ep_ssize = MIN(l->l_proc->p_rlimit[RLIMIT_STACK].rlim_cur,
  418             max_stack_size);
  419 
  420         l->l_proc->p_stackbase = epp->ep_minsaddr;
  421         
  422         epp->ep_maxsaddr = (vaddr_t)STACK_GROW(epp->ep_minsaddr,
  423             max_stack_size);
  424 
  425         DPRINTF(("ep_ssize=%#jx ep_minsaddr=%#jx ep_maxsaddr=%#jx\n",
  426             (uintmax_t)epp->ep_ssize, (uintmax_t)epp->ep_minsaddr,
  427             (uintmax_t)epp->ep_maxsaddr));
  428 
  429         /*
  430          * set up commands for stack.  note that this takes *two*, one to
  431          * map the part of the stack which we can access, and one to map
  432          * the part which we can't.
  433          *
  434          * arguably, it could be made into one, but that would require the
  435          * addition of another mapping proc, which is unnecessary
  436          */
  437         access_size = epp->ep_ssize;
  438         access_linear_min = (vaddr_t)STACK_ALLOC(epp->ep_minsaddr, access_size);
  439         noaccess_size = max_stack_size - access_size;
  440         noaccess_linear_min = (vaddr_t)STACK_ALLOC(STACK_GROW(epp->ep_minsaddr,
  441             access_size), noaccess_size);
  442 
  443         DPRINTF(("access_size=%#jx, access_linear_min=%#jx, "
  444             "noaccess_size=%#jx, noaccess_linear_min=%#jx\n",
  445             (uintmax_t)access_size, (uintmax_t)access_linear_min,
  446             (uintmax_t)noaccess_size, (uintmax_t)noaccess_linear_min));
  447 
  448         if (user_stack_guard_size > 0) {
  449 #ifdef __MACHINE_STACK_GROWS_UP
  450                 vsize_t guard_size = MIN(VM_MAXUSER_ADDRESS - epp->ep_maxsaddr, user_stack_guard_size);
  451                 if (guard_size > 0)
  452                         NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, guard_size,
  453                             epp->ep_maxsaddr, NULL, 0, VM_PROT_NONE);
  454 #else
  455                 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, user_stack_guard_size,
  456                     epp->ep_maxsaddr - user_stack_guard_size, NULL, 0, VM_PROT_NONE);
  457 #endif
  458         }
  459         if (noaccess_size > 0 && noaccess_size <= MAXSSIZ) {
  460                 NEW_VMCMD2(&epp->ep_vmcmds, vmcmd_map_zero, noaccess_size,
  461                     noaccess_linear_min, NULL, 0, VM_PROT_NONE, VMCMD_STACK);
  462         }
  463         KASSERT(access_size > 0 && access_size <= MAXSSIZ);
  464         NEW_VMCMD2(&epp->ep_vmcmds, vmcmd_map_zero, access_size,
  465             access_linear_min, NULL, 0, VM_PROT_READ | VM_PROT_WRITE,
  466             VMCMD_STACK);
  467 
  468         return 0;
  469 }

Cache object: c9900d32dd4c3df031097a6aad2dce52


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