LCOV - code coverage report
Current view: top level - kern - exec_subr.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 125 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 8 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: exec_subr.c,v 1.55 2018/04/12 17:13:44 deraadt Exp $  */
       2             : /*      $NetBSD: exec_subr.c,v 1.9 1994/12/04 03:10:42 mycroft Exp $    */
       3             : 
       4             : /*
       5             :  * Copyright (c) 1993, 1994 Christopher G. Demetriou
       6             :  * All rights reserved.
       7             :  *
       8             :  * Redistribution and use in source and binary forms, with or without
       9             :  * modification, are permitted provided that the following conditions
      10             :  * are met:
      11             :  * 1. Redistributions of source code must retain the above copyright
      12             :  *    notice, this list of conditions and the following disclaimer.
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  * 3. All advertising materials mentioning features or use of this software
      17             :  *    must display the following acknowledgement:
      18             :  *      This product includes software developed by Christopher G. Demetriou.
      19             :  * 4. The name of the author may not be used to endorse or promote products
      20             :  *    derived from this software without specific prior written permission
      21             :  *
      22             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
      23             :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      24             :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      25             :  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
      26             :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      27             :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      28             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      29             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      30             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      31             :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      32             :  */
      33             : 
      34             : #include <sys/param.h>
      35             : #include <sys/systm.h>
      36             : #include <sys/proc.h>
      37             : #include <sys/malloc.h>
      38             : #include <sys/vnode.h>
      39             : #include <sys/exec.h>
      40             : #include <sys/mman.h>
      41             : #include <sys/resourcevar.h>
      42             : 
      43             : #include <uvm/uvm_extern.h>
      44             : 
      45             : #ifdef DEBUG
      46             : /*
      47             :  * new_vmcmd():
      48             :  *      create a new vmcmd structure and fill in its fields based
      49             :  *      on function call arguments.  make sure objects ref'd by
      50             :  *      the vmcmd are 'held'.
      51             :  *
      52             :  * If not debugging, this is a macro, so it's expanded inline.
      53             :  */
      54             : 
      55             : void
      56             : new_vmcmd(struct exec_vmcmd_set *evsp,
      57             :     int (*proc)(struct proc *, struct exec_vmcmd *), u_long len, u_long addr,
      58             :     struct vnode *vp, u_long offset, u_int prot, int flags)
      59             : {
      60             :         struct exec_vmcmd    *vcp;
      61             : 
      62             :         if (evsp->evs_used >= evsp->evs_cnt)
      63             :                 vmcmdset_extend(evsp);
      64             :         vcp = &evsp->evs_cmds[evsp->evs_used++];
      65             :         vcp->ev_proc = proc;
      66             :         vcp->ev_len = len;
      67             :         vcp->ev_addr = addr;
      68             :         if ((vcp->ev_vp = vp) != NULL)
      69             :                 vref(vp);
      70             :         vcp->ev_offset = offset;
      71             :         vcp->ev_prot = prot;
      72             :         vcp->ev_flags = flags;
      73             : }
      74             : #endif /* DEBUG */
      75             : 
      76             : void
      77           0 : vmcmdset_extend(struct exec_vmcmd_set *evsp)
      78             : {
      79             :         struct exec_vmcmd *nvcp;
      80             :         u_int ocnt;
      81             : 
      82             : #ifdef DIAGNOSTIC
      83           0 :         if (evsp->evs_used < evsp->evs_cnt)
      84           0 :                 panic("vmcmdset_extend: not necessary");
      85             : #endif
      86             : 
      87             :         ocnt = evsp->evs_cnt;
      88           0 :         KASSERT(ocnt > 0);
      89             :         /* figure out number of entries in new set */
      90           0 :         evsp->evs_cnt += ocnt;
      91             : 
      92             :         /* reallocate the command set */
      93           0 :         nvcp = mallocarray(evsp->evs_cnt, sizeof(*nvcp), M_EXEC,
      94             :             M_WAITOK);
      95           0 :         memcpy(nvcp, evsp->evs_cmds, ocnt * sizeof(*nvcp));
      96           0 :         if (evsp->evs_cmds != evsp->evs_start)
      97           0 :                 free(evsp->evs_cmds, M_EXEC, ocnt * sizeof(*nvcp));
      98           0 :         evsp->evs_cmds = nvcp;
      99           0 : }
     100             : 
     101             : void
     102           0 : kill_vmcmds(struct exec_vmcmd_set *evsp)
     103             : {
     104             :         struct exec_vmcmd *vcp;
     105             :         int i;
     106             : 
     107           0 :         for (i = 0; i < evsp->evs_used; i++) {
     108           0 :                 vcp = &evsp->evs_cmds[i];
     109           0 :                 if (vcp->ev_vp != NULLVP)
     110           0 :                         vrele(vcp->ev_vp);
     111             :         }
     112             : 
     113             :         /*
     114             :          * Free old vmcmds and reset the array.
     115             :          */
     116           0 :         evsp->evs_used = 0;
     117           0 :         if (evsp->evs_cmds != evsp->evs_start)
     118           0 :                 free(evsp->evs_cmds, M_EXEC,
     119           0 :                     evsp->evs_cnt * sizeof(struct exec_vmcmd));
     120           0 :         evsp->evs_cmds = evsp->evs_start;
     121           0 :         evsp->evs_cnt = EXEC_DEFAULT_VMCMD_SETSIZE;
     122           0 : }
     123             : 
     124             : int
     125           0 : exec_process_vmcmds(struct proc *p, struct exec_package *epp)
     126             : {
     127             :         struct exec_vmcmd *base_vc = NULL;
     128             :         int error = 0;
     129             :         int i;
     130             : 
     131           0 :         for (i = 0; i < epp->ep_vmcmds.evs_used && !error; i++) {
     132             :                 struct exec_vmcmd *vcp;
     133             : 
     134           0 :                 vcp = &epp->ep_vmcmds.evs_cmds[i];
     135             : 
     136           0 :                 if (vcp->ev_flags & VMCMD_RELATIVE) {
     137             : #ifdef DIAGNOSTIC
     138           0 :                         if (base_vc == NULL)
     139           0 :                                 panic("exec_process_vmcmds: RELATIVE no base");
     140             : #endif
     141           0 :                         vcp->ev_addr += base_vc->ev_addr;
     142           0 :                 }
     143           0 :                 error = (*vcp->ev_proc)(p, vcp);
     144           0 :                 if (vcp->ev_flags & VMCMD_BASE) {
     145             :                         base_vc = vcp;
     146           0 :                 }
     147             :         }
     148             : 
     149           0 :         kill_vmcmds(&epp->ep_vmcmds);
     150             : 
     151           0 :         return (error);
     152             : }
     153             : 
     154             : /*
     155             :  * vmcmd_map_pagedvn():
     156             :  *      handle vmcmd which specifies that a vnode should be mmap'd.
     157             :  *      appropriate for handling demand-paged text and data segments.
     158             :  */
     159             : 
     160             : int
     161           0 : vmcmd_map_pagedvn(struct proc *p, struct exec_vmcmd *cmd)
     162             : {
     163             :         /*
     164             :          * note that if you're going to map part of a process as being
     165             :          * paged from a vnode, that vnode had damn well better be marked as
     166             :          * VTEXT.  that's handled in the routine which sets up the vmcmd to
     167             :          * call this routine.
     168             :          */
     169             :         struct uvm_object *uobj;
     170             :         int error;
     171             : 
     172             :         /*
     173             :          * map the vnode in using uvm_map.
     174             :          */
     175             : 
     176           0 :         if (cmd->ev_len == 0)
     177           0 :                 return (0);
     178           0 :         if (cmd->ev_offset & PAGE_MASK)
     179           0 :                 return (EINVAL);
     180           0 :         if (cmd->ev_addr & PAGE_MASK)
     181           0 :                 return (EINVAL);
     182           0 :         if (cmd->ev_len & PAGE_MASK)
     183           0 :                 return (EINVAL);
     184             : 
     185             :         /*
     186             :          * first, attach to the object
     187             :          */
     188             : 
     189           0 :         uobj = uvn_attach(cmd->ev_vp, PROT_READ | PROT_EXEC);
     190           0 :         if (uobj == NULL)
     191           0 :                 return (ENOMEM);
     192             : 
     193             :         /*
     194             :          * do the map
     195             :          */
     196             : 
     197           0 :         error = uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr, cmd->ev_len,
     198           0 :             uobj, cmd->ev_offset, 0,
     199           0 :             UVM_MAPFLAG(cmd->ev_prot, PROT_MASK, MAP_INHERIT_COPY,
     200             :             MADV_NORMAL, UVM_FLAG_COPYONW|UVM_FLAG_FIXED));
     201             : 
     202             :         /*
     203             :          * check for error
     204             :          */
     205             : 
     206           0 :         if (error) {
     207             :                 /*
     208             :                  * error: detach from object
     209             :                  */
     210           0 :                 uobj->pgops->pgo_detach(uobj);
     211           0 :         }
     212             : 
     213           0 :         return (error);
     214           0 : }
     215             : 
     216             : /*
     217             :  * vmcmd_map_readvn():
     218             :  *      handle vmcmd which specifies that a vnode should be read from.
     219             :  *      appropriate for non-demand-paged text/data segments, i.e. impure
     220             :  *      objects (a la OMAGIC and NMAGIC).
     221             :  */
     222             : 
     223             : int
     224           0 : vmcmd_map_readvn(struct proc *p, struct exec_vmcmd *cmd)
     225             : {
     226             :         int error;
     227             :         vm_prot_t prot;
     228             : 
     229           0 :         if (cmd->ev_len == 0)
     230           0 :                 return (0);
     231             : 
     232           0 :         prot = cmd->ev_prot;
     233             : 
     234           0 :         cmd->ev_addr = trunc_page(cmd->ev_addr); /* required by uvm_map */
     235           0 :         error = uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr,
     236           0 :             round_page(cmd->ev_len), NULL, UVM_UNKNOWN_OFFSET, 0,
     237           0 :             UVM_MAPFLAG(prot | PROT_WRITE, PROT_MASK, MAP_INHERIT_COPY,
     238             :             MADV_NORMAL, UVM_FLAG_FIXED|UVM_FLAG_OVERLAY|UVM_FLAG_COPYONW));
     239             : 
     240           0 :         if (error)
     241           0 :                 return (error);
     242             : 
     243           0 :         error = vn_rdwr(UIO_READ, cmd->ev_vp, (caddr_t)cmd->ev_addr,
     244           0 :             cmd->ev_len, cmd->ev_offset, UIO_USERSPACE, IO_UNIT,
     245           0 :             p->p_ucred, NULL, p);
     246           0 :         if (error)
     247           0 :                 return (error);
     248             : 
     249           0 :         if ((prot & PROT_WRITE) == 0) {
     250             :                 /*
     251             :                  * we had to map in the area at PROT_WRITE so that vn_rdwr()
     252             :                  * could write to it.   however, the caller seems to want
     253             :                  * it mapped read-only, so now we are going to have to call
     254             :                  * uvm_map_protect() to fix up the protection.  ICK.
     255             :                  */
     256           0 :                 return (uvm_map_protect(&p->p_vmspace->vm_map,
     257           0 :                     trunc_page(cmd->ev_addr),
     258           0 :                     round_page(cmd->ev_addr + cmd->ev_len),
     259             :                     prot, FALSE));
     260             :         }
     261           0 :         return (0);
     262           0 : }
     263             : 
     264             : /*
     265             :  * vmcmd_map_zero():
     266             :  *      handle vmcmd which specifies a zero-filled address space region.
     267             :  */
     268             : 
     269             : int
     270           0 : vmcmd_map_zero(struct proc *p, struct exec_vmcmd *cmd)
     271             : {
     272           0 :         if (cmd->ev_len == 0)
     273           0 :                 return (0);
     274             :         
     275           0 :         cmd->ev_addr = trunc_page(cmd->ev_addr); /* required by uvm_map */
     276           0 :         return (uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr,
     277           0 :             round_page(cmd->ev_len), NULL, UVM_UNKNOWN_OFFSET, 0,
     278           0 :             UVM_MAPFLAG(cmd->ev_prot, PROT_MASK, MAP_INHERIT_COPY,
     279             :             MADV_NORMAL, UVM_FLAG_FIXED|UVM_FLAG_COPYONW |
     280             :             (cmd->ev_flags & VMCMD_STACK ? UVM_FLAG_STACK : 0))));
     281           0 : }
     282             : 
     283             : /*
     284             :  * vmcmd_randomize():
     285             :  *      handle vmcmd which specifies a randomized address space region.
     286             :  */
     287             : #define RANDOMIZE_CTX_THRESHOLD 512
     288             : int
     289           0 : vmcmd_randomize(struct proc *p, struct exec_vmcmd *cmd)
     290             : {
     291             :         int error;
     292             :         struct arc4random_ctx *ctx;
     293             :         char *buf;
     294             :         size_t sublen, off = 0;
     295           0 :         size_t len = cmd->ev_len;
     296             : 
     297           0 :         if (len == 0)
     298           0 :                 return (0);
     299           0 :         if (len > ELF_RANDOMIZE_LIMIT)
     300           0 :                 return (EINVAL);
     301             : 
     302           0 :         buf = malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
     303           0 :         if (len < RANDOMIZE_CTX_THRESHOLD) {
     304           0 :                 arc4random_buf(buf, len);
     305           0 :                 error = copyout(buf, (void *)cmd->ev_addr, len);
     306           0 :                 explicit_bzero(buf, len);
     307           0 :         } else {
     308           0 :                 ctx = arc4random_ctx_new();
     309           0 :                 do {
     310           0 :                         sublen = MIN(len, PAGE_SIZE);
     311           0 :                         arc4random_ctx_buf(ctx, buf, sublen);
     312           0 :                         error = copyout(buf, (void *)cmd->ev_addr + off, sublen);
     313           0 :                         if (error)
     314             :                                 break;
     315           0 :                         off += sublen;
     316           0 :                         len -= sublen;
     317           0 :                         sched_pause(yield);
     318           0 :                 } while (len);
     319           0 :                 arc4random_ctx_free(ctx);
     320           0 :                 explicit_bzero(buf, PAGE_SIZE);
     321             :         }
     322           0 :         free(buf, M_TEMP, PAGE_SIZE);
     323           0 :         return (error);
     324           0 : }
     325             : 
     326             : #ifndef MAXSSIZ_GUARD
     327             : #define MAXSSIZ_GUARD   (1024 * 1024)
     328             : #endif
     329             : 
     330             : /*
     331             :  * exec_setup_stack(): Set up the stack segment for an executable.
     332             :  *
     333             :  * Note that the ep_ssize parameter must be set to be the current stack
     334             :  * limit; this is adjusted in the body of execve() to yield the
     335             :  * appropriate stack segment usage once the argument length is
     336             :  * calculated.
     337             :  *
     338             :  * This function returns an int for uniformity with other (future) formats'
     339             :  * stack setup functions.  They might have errors to return.
     340             :  */
     341             : 
     342             : int
     343           0 : exec_setup_stack(struct proc *p, struct exec_package *epp)
     344             : {
     345             :         vaddr_t sgap;
     346             : 
     347             : #ifdef MACHINE_STACK_GROWS_UP
     348             :         epp->ep_maxsaddr = USRSTACK;
     349             :         epp->ep_minsaddr = USRSTACK + MAXSSIZ;
     350             : #else
     351           0 :         epp->ep_maxsaddr = USRSTACK - MAXSSIZ - MAXSSIZ_GUARD;
     352           0 :         epp->ep_minsaddr = USRSTACK;
     353             : #endif
     354           0 :         epp->ep_ssize = round_page(p->p_rlimit[RLIMIT_STACK].rlim_cur);
     355             : 
     356           0 :         if (stackgap_random != 0) {
     357           0 :                 sgap = arc4random() & (stackgap_random - 1);
     358           0 :                 sgap = trunc_page(sgap);
     359             : 
     360             : #ifdef MACHINE_STACK_GROWS_UP
     361             :                 epp->ep_maxsaddr += sgap;
     362             :                 epp->ep_minsaddr += sgap;
     363             : #else
     364           0 :                 epp->ep_maxsaddr -= sgap;
     365           0 :                 epp->ep_minsaddr -= sgap;
     366             : #endif
     367           0 :         }
     368             : 
     369             :         /*
     370             :          * set up commands for stack.  note that this takes *two*, one to
     371             :          * map the part of the stack which we can access, and one to map
     372             :          * the part which we can't.
     373             :          *
     374             :          * arguably, it could be made into one, but that would require the
     375             :          * addition of another mapping proc, which is unnecessary
     376             :          *
     377             :          * note that in memory, things assumed to be: 0 ....... ep_maxsaddr
     378             :          * <stack> ep_minsaddr
     379             :          */
     380             : #ifdef MACHINE_STACK_GROWS_UP
     381             :         NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero,
     382             :             ((epp->ep_minsaddr - epp->ep_ssize) - epp->ep_maxsaddr),
     383             :             epp->ep_maxsaddr + epp->ep_ssize, NULLVP, 0,
     384             :             PROT_NONE);
     385             :         NEW_VMCMD2(&epp->ep_vmcmds, vmcmd_map_zero, epp->ep_ssize,
     386             :             epp->ep_maxsaddr, NULLVP, 0,
     387             :             PROT_READ | PROT_WRITE, VMCMD_STACK);
     388             : #else
     389           0 :         NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero,
     390             :             ((epp->ep_minsaddr - epp->ep_ssize) - epp->ep_maxsaddr),
     391             :             epp->ep_maxsaddr, NULLVP, 0,
     392             :             PROT_NONE);
     393           0 :         NEW_VMCMD2(&epp->ep_vmcmds, vmcmd_map_zero, epp->ep_ssize,
     394             :             (epp->ep_minsaddr - epp->ep_ssize), NULLVP, 0,
     395             :             PROT_READ | PROT_WRITE, VMCMD_STACK);
     396             : #endif
     397             : 
     398           0 :         return (0);
     399             : }

Generated by: LCOV version 1.13