Source to kern/kern_exec.c
/*
* Copyright (C) 1993 Christopher G. Demetriou
* Copyright (C) 1992 Wolfgang Solfrank.
* Copyright (C) 1992 TooLs GmbH.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by TooLs GmbH.
* 4. The name of TooLs GmbH may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* kern_exec.c,v 1.20 1993/07/13 22:13:19 cgd Exp
*/
#undef SETUIDSCRIPTS /* Define this for setuid scripts */
#ifdef SETUIDSCRIPTS
#define FDSCRIPTS /* setuid scripts probably also want this */
#endif
#include "param.h"
#include "systm.h"
#include "filedesc.h"
#include "kernel.h"
#include "proc.h"
#include "mount.h"
#include "malloc.h"
#include "namei.h"
#include "vnode.h"
/* #include "seg.h" ??? -- cgd */
#include "file.h"
#include "acct.h"
#include "exec.h"
#include "ktrace.h"
#include "resourcevar.h"
#include "wait.h"
#include "machine/cpu.h"
#include "machine/reg.h"
#include "machine/exec.h"
#include "mman.h"
#include "vm/vm.h"
#include "vm/vm_param.h"
#include "vm/vm_map.h"
#include "vm/vm_kern.h"
#include "vm/vm_pager.h"
#include "signalvar.h"
#include "kinfo_proc.h"
#ifdef COPY_SIGCODE
extern char sigcode[], esigcode[];
#define szsigcode (esigcode - sigcode)
#else
#define szsigcode 0
#endif
#ifdef FDSCRIPTS
/* The returned attributes are only good for set[ug]id scripts/programs */
static checkaout(p,ndp,vpp,ap,hdr,fdp,argp,argc,epp)
struct proc *p;
struct nameidata *ndp;
struct vnode **vpp;
struct vattr *ap;
struct exec *hdr;
int *fdp;
char **argp;
int *argc;
struct exec_package *epp;
#else
static checkaout(p,ndp,vpp,ap,hdr,argp,argc,epp)
struct proc *p;
struct nameidata *ndp;
struct vnode **vpp;
struct vattr *ap;
struct exec *hdr;
char **argp;
int *argc;
struct exec_package *epp;
#endif
{
int error;
struct vnode *vp;
char *cp, *ep, *name;
int resid;
/* XXX - THIS ENTIRE FUCTION SHOULD BE REWRITTEN - cgd */
/* first get the vnode */
if (error = namei(ndp,p))
return error;
*vpp = vp = ndp->ni_vp;
/* check for regular file */
if (vp->v_type != VREG) {
error = EACCES;
goto bad1;
}
/* get attributes */
if (error = VOP_GETATTR(vp,ap,p->p_ucred,p))
goto bad1;
/* Check mount point */
if (vp->v_mount->mnt_flag&MNT_NOEXEC) {
error = ENOEXEC;
goto bad1;
}
if ((vp->v_mount->mnt_flag&MNT_NOSUID) || (p->p_flag&STRC))
ap->va_mode &= ~(VSUID|VSGID);
/* for root we have to check for any exec bit on */
/* doing it always doesn't hurt) */
if (!(ap->va_mode&0111)) {
error = EACCES;
goto bad1;
}
/* check access */
if ((error = VOP_ACCESS(vp,VEXEC,p->p_ucred,p))
|| (error = VOP_OPEN(vp,FREAD,p->p_ucred,p)))
goto bad1;
/* now we have the file, get the exec header */
if (error = vn_rdwr(UIO_READ,vp,(caddr_t)hdr,sizeof(*hdr),0,
UIO_SYSSPACE,IO_NODELOCKED,p->p_ucred,&resid,p))
goto bad2;
if (!resid && !(hdr->a_text&PGOFSET) && !(hdr->a_data&PGOFSET)) {
/* sanity check: if it could get by the above, and still be a
* shell script. if so, don't try the vmcmd tricks.
*/
cp = (char *)hdr;
if (!(*cp == '#' && cp[1] == '!')) {
/* set up the vmcmds for creation of the process address space */
epp->ep_execp = hdr;
epp->ep_vp = vp;
epp->ep_vap = ap;
if (error = exec_makecmds(p, epp))
goto bad2;
if (epp->ep_entry > VM_MAXUSER_ADDRESS) {
error = ENOEXEC;
goto bad2;
}
/* check limits */
if ((epp->ep_tsize > MAXTSIZ) ||
(epp->ep_dsize > p->p_rlimit[RLIMIT_DATA].rlim_cur) ||
(epp->ep_ssize > p->p_rlimit[RLIMIT_STACK].rlim_cur)) {
error = ENOMEM;
goto bad2;
}
return 0;
}
}
/* scripts only if it's the first round */
cp = (char *)hdr;
ep = (char *)(hdr + 1) - resid;
if (ndp->ni_segflg == UIO_USERSPACE && *cp == '#' && cp[1] == '!') {
#ifdef SETUIDSCRIPTS
struct vattr attr;
#define ATTRP &attr
#else
#define ATTRP ap
#endif
#ifdef FDSCRIPTS
struct file *fp;
int fd;
extern struct fileops vnops;
char fdscripts = 0;
/* we want to give the interpreter /dev/fd/xxx if the script is:
set[ug]id or
execute only */
if (VOP_ACCESS(vp,VREAD,p->p_ucred,p) == EACCES
|| (ap->va_mode&(VSUID|VSGID)))
fdscripts = 1;
if (fdscripts) {
if (error = falloc(p,&fp,&fd))
goto bad2;
VOP_UNLOCK(vp);
fp->f_type = DTYPE_VNODE;
fp->f_ops = &vnops;
fp->f_data = (caddr_t)vp;
fp->f_flag = FREAD;
} else {
#endif
VOP_UNLOCK(vp);
vn_close(vp,FREAD,p->p_ucred,p);
#ifdef FDSCRIPTS
}
#endif
for (cp += 2; cp < ep; cp++) {
switch (*cp) {
case ' ':
case '\t':
continue;
}
break;
}
if (cp >= ep)
error = EACCES;
++*argc;
for (name = cp; cp < ep; cp++) {
switch (*cp) {
default:
*(*argp)++ = *cp;
continue;
case '\0':
case '\n':
ep = cp;
case ' ':
case '\t':
*(*argp)++ = *cp++ = 0;
goto out1;
}
break;
}
out1:
for (; cp < ep; cp++) {
switch (*cp) {
case ' ':
case '\t':
continue;
case '\0':
case '\n':
ep = cp;
}
break;
}
if (cp < ep) {
++*argc;
for (; cp < ep; cp++) {
switch (*cp) {
default:
*(*argp)++ = *cp;
continue;
case '\0':
case '\n':
*(*argp)++ = 0;
goto out2;
}
break;
}
}
out2:
#ifdef FDSCRIPTS
if (fdscripts) {
sprintf(*argp,"/dev/fd/%d",fd);
*fdp = fd;
} else
#endif
strcpy(*argp,ndp->ni_pnbuf);
while (*(*argp)++);
++*argc;
ndp->ni_dirp = name;
ndp->ni_segflg = UIO_SYSSPACE;
#ifdef FDSCRIPTS
if (!error && !(error = checkaout(p,ndp,vpp,ATTRP,hdr,&fd,argp,
argc,epp))) {
#else
if (!error && !(error = checkaout(p,ndp,vpp,ATTRP,hdr,argp,
argc,epp))) {
#endif
#ifdef SETUIDSCRIPTS
if (!(ap->va_mode&VSUID))
ap->va_uid = attr.va_uid;
if (!(ap->va_mode&VSGID))
ap->va_gid = attr.va_gid;
ap->va_mode |= attr.va_mode&(VSUID|VSGID);
#endif
return 0;
}
#ifdef FDSCRIPTS
if (fdscripts) {
closefd(p,fd);
goto bad2;
}
#endif
return error;
}
error = ENOEXEC;
bad2:
VOP_UNLOCK(vp);
vn_close(vp,FREAD,p->p_ucred,p);
FREE(ndp->ni_pnbuf,M_NAMEI);
return error;
bad1:
FREE(ndp->ni_pnbuf,M_NAMEI);
vput(vp);
return error;
}
#ifdef FDSCRIPTS
static closefd(p,fd)
struct proc *p;
{
/* have to close file again */
if (p->p_fd->fd_lastfile == fd)
p->p_fd->fd_lastfile--;
if (p->p_fd->fd_freefile > fd)
p->p_fd->fd_freefile = fd;
closef(p->p_fd->fd_ofiles[fd],p);
p->p_fd->fd_ofiles[fd] = 0;
}
#endif
#ifdef EXEC_DEBUG
exec_print_vmspaceinfo(struct proc *p)
{
printf("process vmspace:\n");
printf("\tvm_taddr: 0x%x\n", p->p_vmspace->vm_taddr);
printf("\tvm_tsize: 0x%x\n", p->p_vmspace->vm_tsize);
printf("\tvm_daddr: 0x%x\n", p->p_vmspace->vm_daddr);
printf("\tvm_dsize: 0x%x\n", p->p_vmspace->vm_dsize);
printf("\tvm_ssize: 0x%x\n", p->p_vmspace->vm_ssize);
printf("\tvm_maxsaddr: 0x%x\n", p->p_vmspace->vm_maxsaddr);
/* handy place for debugger breakpoint, but name is too long... */
asm(".globl _exec_print_vmspaceinfo_leave ; _exec_print_vmspaceinfo_leave:");
}
#endif
#ifdef EXEC_DEBUG
exec_print_argstring(char *str, int len, char **ap, char *a)
{
printf("(0x%x)-> \t0x%x \t: %s (%d)\n", ap, a, str, len);
}
#endif
/*
* exec system call
*/
struct execve_args {
char *fname;
char **argp;
char **envp;
};
/* ARGSUSED */
execve(p, uap, retval)
register struct proc *p;
register struct execve_args *uap;
int *retval;
{
/*
* Body deleted.
*/
/*
* And reimplemented by ws.
* I think this should be vastly more machine dependent
* (e.g. stack up/down, startup stack format etc.)
*/
int error;
struct vnode *vp;
struct nameidata nid;
struct ucred *cred = p->p_ucred;
char *argp;
struct exec hdr;
char **cpp, *dp, *sp, *np;
int argc, envc, len;
char *stack;
struct vattr attr;
struct ps_strings arginfo;
struct exec_package pack;
#ifdef FDSCRIPTS
int fd;
#endif
/* get space for argv & environment */
/* was: if(!(dp = argp = (char *)kmem_alloc_wait(exec_map,ARG_MAX))) - cgd */
MALLOC(argp, char *, ARG_MAX, M_EXEC, M_WAITOK);
if(!argp)
panic("exec: can't allocate ARG_MAX");
dp = argp;
argc = 0;
#ifdef FDSCRIPTS
fd = -1;
#endif
nid.ni_dirp = uap->fname;
nid.ni_segflg = UIO_USERSPACE;
nid.ni_nameiop = LOOKUP|FOLLOW|LOCKLEAF|SAVENAME;
/* checkaout possibly copies arguments for scripts */
#ifdef FDSCRIPTS
if (error = checkaout(p,&nid,&vp,&attr,&hdr,&fd,&dp,&argc,&pack))
#else
if (error = checkaout(p,&nid,&vp,&attr,&hdr,&dp,&argc,&pack))
#endif
goto freeargs;
/* Now get argv & environment */
if (!(cpp = uap->argp)) {
error = EINVAL;
goto bad;
}
if (argc > 0) {
/* it is a script, so we have to skip the 0th arg */
cpp++;
/* check access to arg here? */
}
#ifdef EXEC_DEBUG
printf("start of args = 0x%x\n", dp);
#endif
while (1) {
len = argp + ARG_MAX - dp;
if (error = copyin(cpp,&sp,sizeof(sp)))
goto bad;
if (!sp)
break;
if (error = copyinstr(sp,dp,len,(u_int *)&len)) {
if (error == ENAMETOOLONG)
error = E2BIG;
goto bad;
}
dp += len;
cpp++;
argc++;
}
#ifdef EXEC_DEBUG
printf("end of args = 0x%x\n", dp);
#endif
envc = 0;
if (cpp = uap->envp) { /* environment need not be there */
while (1) {
len = argp + ARG_MAX - dp;
if (error = copyin(cpp,&sp,sizeof(sp)))
goto bad;
if (!sp)
break;
if (error = copyinstr(sp,dp,len,(u_int *)&len)) {
if (error == ENAMETOOLONG)
error = E2BIG;
goto bad;
}
dp += len;
cpp++;
envc++;
}
dp = (char *)ALIGN(dp);
}
#ifdef EXEC_DEBUG
printf("end of env = 0x%x\n", dp);
printf("argc/envc = %d/%d\n", argc, envc);
#endif
/* Now check if args & environ fit into new stack */
len = ((argc + envc + 2) * sizeof(char *) + sizeof(int) +
dp + sizeof(struct ps_strings) + szsigcode) - argp;
len = roundup(len, sizeof(char *));
if (len > p->p_rlimit[RLIMIT_STACK].rlim_cur) {
error = ENOMEM;
goto bad;
}
/* Unmap old program */
vm_deallocate(&p->p_vmspace->vm_map,0,USRSTACK);
/* Now map address space */
p->p_vmspace->vm_taddr = (char *) pack.ep_taddr;
p->p_vmspace->vm_tsize = btoc(pack.ep_tsize);
p->p_vmspace->vm_daddr = (char *) pack.ep_daddr;
p->p_vmspace->vm_dsize = btoc(pack.ep_dsize);
p->p_vmspace->vm_ssize = btoc(pack.ep_ssize);
p->p_vmspace->vm_maxsaddr = (char *) pack.ep_maxsaddr;
if (error = exec_runcmds(p, &pack))
goto exec_abort;
kill_vmcmd(&pack.ep_vcp);
/* remember information about the process */
arginfo.ps_nargvstr = argc;
arginfo.ps_nenvstr = envc;
/* Now copy argc, args & environ to new stack */
stack = (char *)(USRSTACK - len);
#ifdef EXEC_DEBUG
printf("stack wants to live at: 0x%x\n", stack);
#endif
cpp = (char **)stack;
if (copyout(&argc,cpp++,sizeof(argc)))
goto exec_abort;
#ifdef EXEC_DEBUG
printf("0x%x \targ count: %d\n", (cpp - 1), argc);
#endif
dp = (char *)(cpp + argc + envc + 2);
arginfo.ps_argvstr = dp; /* remember location of argv for later */
for (sp = argp; --argc >= 0; sp += len, dp += len) {
len = strlen(sp) + 1;
if (copyout(&dp,cpp++,sizeof(dp))
|| copyoutstr(sp,dp,len,0))
goto exec_abort;
#ifdef EXEC_DEBUG
exec_print_argstring(sp, len, (cpp - 1), dp);
#endif
}
np = 0;
if (copyout(&np,cpp++,sizeof(np)))
goto exec_abort;
arginfo.ps_envstr = dp; /* remember location of env for later */
for (; --envc >= 0; sp += len, dp += len) {
len = strlen(sp) + 1;
if (copyout(&dp,cpp++,sizeof(dp))
|| copyoutstr(sp,dp,len,0))
goto exec_abort;
#ifdef EXEC_DEBUG
exec_print_argstring(sp, len, (cpp - 1), dp);
#endif
}
if (copyout(&np,cpp,sizeof(np)))
goto exec_abort;
/* copy out the process's ps_strings structure */
if (copyout(&arginfo, (char *)PS_STRINGS, sizeof(arginfo)))
goto exec_abort;
#ifdef COPY_SIGCODE
/* copy out the process's signal trapoline code */
if (copyout((char *)sigcode, ((char *)PS_STRINGS) - szsigcode,
szsigcode)) {
goto exec_abort;
}
#endif
fdcloseexec(p); /* handle close on exec */
execsigs(p); /* reset catched signals */
/* set command name & other accounting info */
len = MIN(nid.ni_namelen,MAXCOMLEN);
bcopy(nid.ni_ptr,p->p_comm,len);
p->p_comm[len] = 0;
p->p_acflag &= ~AFORK;
p->p_flag |= SEXEC;
if (p->p_flag&SPPWAIT) {
p->p_flag &= ~SPPWAIT;
wakeup((caddr_t)p->p_pptr);
}
/*
*deal with set[ug]id
* MNT_NOEXEC and STRC have already been used to disable s[ug]id
*/
if (attr.va_mode&VSUID) {
p->p_ucred = crcopy(cred);
p->p_ucred->cr_uid = attr.va_uid;
}
p->p_cred->p_svuid = p->p_ucred->cr_uid;
if (attr.va_mode&VSGID) {
p->p_ucred = crcopy(p->p_ucred);
p->p_ucred->cr_gid = attr.va_gid;
}
p->p_cred->p_svgid = p->p_ucred->cr_gid;
/* what else? */
/* was: kmem_free_wakeup(exec_map,argp,ARG_MAX); - cgd */
FREE(argp, M_EXEC);
FREE(nid.ni_pnbuf,M_NAMEI);
VOP_CLOSE(vp,FREAD,cred,p);
vput(vp);
/* setup new registers */
setregs(p, hdr.a_entry, (u_long) stack, retval);
#ifdef EXEC_DEBUG
printf("exec returning normally\n");
#endif
if (p->p_flag & STRC)
psignal(p, SIGTRAP);
return EJUSTRETURN;
bad:
FREE(nid.ni_pnbuf,M_NAMEI);
VOP_CLOSE(vp,FREAD,cred,p);
vput(vp);
#ifdef FDSCRIPTS
if (fd)
closefd(p,fd);
#endif
freeargs:
/* was: kmem_free_wakeup(exec_map,argp,ARG_MAX); - cgd */
FREE(argp, M_EXEC);
#ifdef EXEC_DEBUG
printf("exec returning on error\n");
#endif
return error;
exec_abort:
/* the old process doesn't exist anymore. exit gracefully.
*
* get rid of the (new) address space we have created, if any,
* get rid of our namei data and vnode, and exit noting failure
*/
#ifdef EXEC_DEBUG
printf("exec bailing out (abort)\n");
#endif
vm_deallocate(&p->p_vmspace->vm_map,0,USRSTACK);
FREE(nid.ni_pnbuf,M_NAMEI);
VOP_CLOSE(vp,FREAD,cred,p);
vput(vp);
kexit(p, W_EXITCODE(0, SIGABRT));
kexit(p, -1);
/* NOTREACHED */
return 0;
}
int
exec_runcmds(p, epp)
struct proc *p;
struct exec_package *epp;
{
struct exec_vmcmd *cur = epp->ep_vcp;
int error;
while (cur && !(error = (*cur->ev_proc)(p, cur)))
cur = cur->ev_next;
return error;
}
int
exec_makecmds(p, epp)
struct proc *p;
struct exec_package *epp;
{
u_long midmag, magic;
u_short mid;
int error;
epp->ep_vcp = NULL;
midmag = ntohl(epp->ep_execp->a_midmag);
mid = (midmag >> 16 ) & 0x3ff;
magic = midmag & 0xffff;
#ifdef EXEC_DEBUG
printf("exec_makecmds: a_midmag is %x, magic=%x mid=%x\n",
epp->ep_execp->a_midmag, magic, mid);
#endif
midmag = mid<<16 | magic;
switch (midmag) {
case (MID_MACHINE << 16) | ZMAGIC:
error = exec_prep_zmagic(p, epp);
break;
case (MID_MACHINE << 16) | OMAGIC:
case (MID_MACHINE << 16) | NMAGIC:
default:
error = cpu_exec_makecmds(p, epp);
}
if (error && epp->ep_vcp)
kill_vmcmd(&epp->ep_vcp);
bad:
#ifdef EXEC_DEBUG
printf("exec_makecmds returning with error = %d\n", error);
#endif
return error;
}
void
kill_vmcmd(vcpp)
struct exec_vmcmd **vcpp;
{
struct exec_vmcmd *cur, *next;
cur = *vcpp;
*vcpp = NULL;
while (cur != NULL) {
if (cur->ev_vp != NULL)
vrele(cur->ev_vp);
next = cur->ev_next;
FREE(cur, M_EXEC);
cur = next;
}
}
inline struct exec_vmcmd *
new_vmcmd(proc, len, addr, vp, offset, prot)
int (*proc) __P((struct proc *p, struct exec_vmcmd *));
unsigned long len;
unsigned long addr;
struct vnode *vp;
unsigned long offset;
unsigned long prot;
{
struct exec_vmcmd *tmpcmdp;
MALLOC(tmpcmdp, struct exec_vmcmd *, sizeof(struct exec_vmcmd),
M_EXEC, M_WAITOK);
tmpcmdp->ev_next = NULL;
tmpcmdp->ev_proc = proc;
tmpcmdp->ev_len = len;
tmpcmdp->ev_addr = addr;
if ((tmpcmdp->ev_vp = vp) != NULL)
vref(vp);
tmpcmdp->ev_offset = offset;
tmpcmdp->ev_prot = prot;
return tmpcmdp;
}
int
exec_prep_zmagic(p, epp)
struct proc *p;
struct exec_package *epp;
{
struct exec *execp = epp->ep_execp;
struct exec_vmcmd *ccmdp;
epp->ep_taddr = USRTEXT;
epp->ep_tsize = execp->a_text;
epp->ep_daddr = epp->ep_taddr + execp->a_text;
epp->ep_dsize = execp->a_data + execp->a_bss;
epp->ep_maxsaddr = USRSTACK - MAXSSIZ;
epp->ep_minsaddr = USRSTACK;
epp->ep_ssize = p->p_rlimit[RLIMIT_STACK].rlim_cur;
epp->ep_entry = execp->a_entry;
/* check if vnode is in open for writing, because we want to demand-page
* out of it. if it is, don't do it, for various reasons
*/
if ((execp->a_text != 0 || execp->a_data != 0) &&
(epp->ep_vp->v_flag & VTEXT) == 0 && epp->ep_vp->v_writecount != 0) {
#ifdef DIAGNOSTIC
if (epp->ep_vp->v_flag & VTEXT)
panic("exec: a VTEXT vnode has writecount != 0\n");
#endif
epp->ep_vcp = NULL;
return ETXTBSY;
}
epp->ep_vp->v_flag |= VTEXT;
/* set up command for text segment */
epp->ep_vcp = new_vmcmd(vmcmd_map_pagedvn,
execp->a_text,
epp->ep_taddr,
epp->ep_vp,
0,
VM_PROT_READ|VM_PROT_EXECUTE);
ccmdp = epp->ep_vcp;
/* set up command for data segment */
ccmdp->ev_next = new_vmcmd(vmcmd_map_pagedvn,
execp->a_data,
epp->ep_daddr,
epp->ep_vp,
execp->a_text,
VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
ccmdp = ccmdp->ev_next;
/* set up command for bss segment */
ccmdp->ev_next = new_vmcmd(vmcmd_map_zero,
execp->a_bss,
epp->ep_daddr + execp->a_data,
0,
0,
VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
ccmdp = ccmdp->ev_next;
/* set up commands for stack. note that this takes *two*, one
* to map the part of the stack which we can access, and one
* to map the part which we can't.
*
* arguably, it could be made into one, but that would require
* the addition of another mapping proc, which is unnecessary
*
* note that in memory, thigns assumed to be:
* 0 ....... ep_maxsaddr <stack> ep_minsaddr
*/
ccmdp->ev_next = new_vmcmd(vmcmd_map_zero,
((epp->ep_minsaddr - epp->ep_ssize) -
epp->ep_maxsaddr),
epp->ep_maxsaddr,
0,
0,
VM_PROT_NONE);
ccmdp = ccmdp->ev_next;
ccmdp->ev_next = new_vmcmd(vmcmd_map_zero,
epp->ep_ssize,
(epp->ep_minsaddr - epp->ep_ssize),
0,
0,
VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
return 0;
}
int vmcmd_map_pagedvn(p,cmd )
struct proc *p;
struct exec_vmcmd *cmd;
{
/* note that if you're going to map part of an process as being paged from
* a vnode, that vnode had damn well better be marked as VTEXT. that's
* handled in the routine which sets up the vmcmd to call this routine.
*/
#ifdef EXEC_DEBUG
printf("vmcmd_map_pagedvn: mapping into addr %x for len %x (%x/%x)\n",
cmd->ev_addr, cmd->ev_len, cmd->ev_prot, VM_PROT_DEFAULT);
#endif
return vm_mmap(&p->p_vmspace->vm_map,
&cmd->ev_addr,
cmd->ev_len,
cmd->ev_prot,
VM_PROT_DEFAULT,
MAP_FIXED|MAP_FILE|MAP_COPY,
cmd->ev_vp,
cmd->ev_offset);
}
int vmcmd_map_zero(p, cmd)
struct proc *p;
struct exec_vmcmd *cmd;
{
int error;
#ifdef EXEC_DEBUG
printf("vmcmd_map_zero: mapping into addr %x for len %x (%x/%x)\n",
cmd->ev_addr, cmd->ev_len, cmd->ev_prot, VM_PROT_DEFAULT);
#endif
error = vm_allocate(&p->p_vmspace->vm_map,
&cmd->ev_addr,
cmd->ev_len,
0);
if (error)
return error;
return vm_protect(&p->p_vmspace->vm_map,
cmd->ev_addr,
cmd->ev_len,
FALSE,
cmd->ev_prot);
}