Split sys_execve() and add execve1() that does most of the work, and takes
as an argument a function that will retrieve an element of the pointer arrays in user space. This allows COMPAT_NETBSD32 to share the code for the emulated version of execve(2), and fixes various issues that came from the slow drift between the two implementations. Note: when splitting up a syscall function, I'll use two different ways of naming the resulting helper function. If it stills does copyin/out operations, it will be named <syscall>1(). If it does not (as it was the case for get/setitimer), it will be named do<syscall>.
This commit is contained in:
parent
08fd92bac5
commit
355bcba766
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: netbsd32_execve.c,v 1.22 2005/05/31 00:41:09 christos Exp $ */
|
/* $NetBSD: netbsd32_execve.c,v 1.23 2005/07/11 20:15:26 cube Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1998, 2001 Matthew R. Green
|
* Copyright (c) 1998, 2001 Matthew R. Green
|
||||||
@ -29,508 +29,48 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: netbsd32_execve.c,v 1.22 2005/05/31 00:41:09 christos Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: netbsd32_execve.c,v 1.23 2005/07/11 20:15:26 cube Exp $");
|
||||||
|
|
||||||
#if defined(_KERNEL_OPT)
|
|
||||||
#include "opt_ktrace.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/systm.h>
|
#include <sys/systm.h>
|
||||||
#include <sys/malloc.h>
|
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <sys/ktrace.h>
|
|
||||||
#include <sys/vnode.h>
|
#include <sys/vnode.h>
|
||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
#include <sys/filedesc.h>
|
#include <sys/filedesc.h>
|
||||||
#include <sys/namei.h>
|
|
||||||
|
|
||||||
#include <uvm/uvm_extern.h>
|
|
||||||
|
|
||||||
#include <sys/sa.h>
|
#include <sys/sa.h>
|
||||||
#include <sys/syscallargs.h>
|
#include <sys/syscallargs.h>
|
||||||
#include <sys/proc.h>
|
#include <sys/proc.h>
|
||||||
#include <sys/acct.h>
|
|
||||||
#include <sys/exec.h>
|
#include <sys/exec.h>
|
||||||
|
|
||||||
#include <compat/netbsd32/netbsd32.h>
|
#include <compat/netbsd32/netbsd32.h>
|
||||||
#include <compat/netbsd32/netbsd32_syscall.h>
|
#include <compat/netbsd32/netbsd32_syscall.h>
|
||||||
#include <compat/netbsd32/netbsd32_syscallargs.h>
|
#include <compat/netbsd32/netbsd32_syscallargs.h>
|
||||||
|
|
||||||
#include <sys/verified_exec.h>
|
static int
|
||||||
|
netbsd32_execve_fetch_element(char * const *array, size_t index, char **value)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
netbsd32_charp const *a32 = (void const *)array;
|
||||||
|
netbsd32_charp e;
|
||||||
|
|
||||||
/* this is provided by kern/kern_exec.c */
|
error = copyin(a32 + index, &e, sizeof(e));
|
||||||
extern u_int exec_maxhdrsz;
|
if (error)
|
||||||
#if defined(LKM) || defined(_LKM)
|
return error;
|
||||||
extern struct lock exec_lock;
|
*value = (char *)NETBSD32PTR64(e);
|
||||||
#endif
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Need to completly reimplement this syscall due to argument copying.
|
|
||||||
*/
|
|
||||||
/* ARGSUSED */
|
|
||||||
int
|
int
|
||||||
netbsd32_execve(l, v, retval)
|
netbsd32_execve(struct lwp *l, void *v, register_t *retval)
|
||||||
struct lwp *l;
|
|
||||||
void *v;
|
|
||||||
register_t *retval;
|
|
||||||
{
|
{
|
||||||
struct netbsd32_execve_args /* {
|
struct netbsd32_execve_args /* {
|
||||||
syscallarg(const netbsd32_charp) path;
|
syscallarg(const netbsd32_charp) path;
|
||||||
syscallarg(netbsd32_charpp) argp;
|
syscallarg(netbsd32_charpp) argp;
|
||||||
syscallarg(netbsd32_charpp) envp;
|
syscallarg(netbsd32_charpp) envp;
|
||||||
} */ *uap = v;
|
} */ *uap = v;
|
||||||
struct sys_execve_args ua;
|
|
||||||
caddr_t sg;
|
|
||||||
struct proc *p = l->l_proc;
|
|
||||||
|
|
||||||
NETBSD32TOP_UAP(path, const char);
|
return execve1(l, NETBSD32PTR64(SCARG(uap, path)),
|
||||||
NETBSD32TOP_UAP(argp, char *);
|
NETBSD32PTR64(SCARG(uap, argp)), NETBSD32PTR64(SCARG(uap, envp)),
|
||||||
NETBSD32TOP_UAP(envp, char *);
|
netbsd32_execve_fetch_element);
|
||||||
sg = stackgap_init(p, 0);
|
|
||||||
CHECK_ALT_EXIST(p, &sg, SCARG(&ua, path));
|
|
||||||
|
|
||||||
return netbsd32_execve2(l, &ua, retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
netbsd32_execve2(l, uap, retval)
|
|
||||||
struct lwp *l;
|
|
||||||
struct sys_execve_args *uap;
|
|
||||||
register_t *retval;
|
|
||||||
{
|
|
||||||
/* Function args */
|
|
||||||
struct proc *p = l->l_proc;
|
|
||||||
int error, i;
|
|
||||||
struct exec_package pack;
|
|
||||||
struct nameidata nid;
|
|
||||||
struct vattr attr;
|
|
||||||
struct ucred *cred = p->p_ucred;
|
|
||||||
char *argp;
|
|
||||||
netbsd32_charp const *cpp;
|
|
||||||
char *dp;
|
|
||||||
netbsd32_charp sp;
|
|
||||||
long argc, envc;
|
|
||||||
size_t len;
|
|
||||||
char *stack;
|
|
||||||
struct ps_strings arginfo;
|
|
||||||
struct vmspace *vm;
|
|
||||||
char **tmpfap;
|
|
||||||
int szsigcode;
|
|
||||||
struct exec_vmcmd *base_vcp = NULL;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Init the namei data to point the file user's program name.
|
|
||||||
* This is done here rather than in check_exec(), so that it's
|
|
||||||
* possible to override this settings if any of makecmd/probe
|
|
||||||
* functions call check_exec() recursively - for example,
|
|
||||||
* see exec_script_makecmds().
|
|
||||||
*/
|
|
||||||
NDINIT(&nid, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* initialize the fields of the exec package.
|
|
||||||
*/
|
|
||||||
pack.ep_name = SCARG(uap, path);
|
|
||||||
pack.ep_hdr = malloc(exec_maxhdrsz, M_EXEC, M_WAITOK);
|
|
||||||
pack.ep_hdrlen = exec_maxhdrsz;
|
|
||||||
pack.ep_hdrvalid = 0;
|
|
||||||
pack.ep_ndp = &nid;
|
|
||||||
pack.ep_emul_arg = NULL;
|
|
||||||
pack.ep_vmcmds.evs_cnt = 0;
|
|
||||||
pack.ep_vmcmds.evs_used = 0;
|
|
||||||
pack.ep_vap = &attr;
|
|
||||||
pack.ep_flags = 0;
|
|
||||||
|
|
||||||
#if defined(LKM) || defined(_LKM)
|
|
||||||
lockmgr(&exec_lock, LK_SHARED, NULL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* see if we can run it. */
|
|
||||||
#ifdef VERIFIED_EXEC
|
|
||||||
if ((error = check_exec(p, &pack, VERIEXEC_DIRECT)) != 0)
|
|
||||||
#else
|
|
||||||
if ((error = check_exec(p, &pack)) != 0)
|
|
||||||
#endif
|
|
||||||
goto freehdr;
|
|
||||||
|
|
||||||
/* XXX -- THE FOLLOWING SECTION NEEDS MAJOR CLEANUP */
|
|
||||||
|
|
||||||
/* allocate an argument buffer */
|
|
||||||
argp = (char *) uvm_km_alloc(exec_map, NCARGS, 0,
|
|
||||||
UVM_KMF_PAGEABLE|UVM_KMF_WAITVA);
|
|
||||||
#ifdef DIAGNOSTIC
|
|
||||||
if (argp == (vaddr_t) 0)
|
|
||||||
panic("netbsd32_execve: argp == NULL");
|
|
||||||
#endif
|
|
||||||
dp = argp;
|
|
||||||
argc = 0;
|
|
||||||
|
|
||||||
/* copy the fake args list, if there's one, freeing it as we go */
|
|
||||||
if (pack.ep_flags & EXEC_HASARGL) {
|
|
||||||
tmpfap = pack.ep_fa;
|
|
||||||
while (*tmpfap != NULL) {
|
|
||||||
char *cp;
|
|
||||||
|
|
||||||
cp = *tmpfap;
|
|
||||||
while (*cp)
|
|
||||||
*dp++ = *cp++;
|
|
||||||
dp++;
|
|
||||||
|
|
||||||
FREE(*tmpfap, M_EXEC);
|
|
||||||
tmpfap++; argc++;
|
|
||||||
}
|
|
||||||
FREE(pack.ep_fa, M_EXEC);
|
|
||||||
pack.ep_flags &= ~EXEC_HASARGL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now get argv & environment */
|
|
||||||
if (!(cpp = (const netbsd32_charp *)SCARG(uap, argp))) {
|
|
||||||
error = EINVAL;
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pack.ep_flags & EXEC_SKIPARG)
|
|
||||||
cpp++;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
len = argp + ARG_MAX - dp;
|
|
||||||
if ((error = copyin(cpp, &sp, sizeof(sp))) != 0)
|
|
||||||
goto bad;
|
|
||||||
if (!sp)
|
|
||||||
break;
|
|
||||||
if ((error = copyinstr((char *)(u_long)sp, dp,
|
|
||||||
len, &len)) != 0) {
|
|
||||||
if (error == ENAMETOOLONG)
|
|
||||||
error = E2BIG;
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
dp += len;
|
|
||||||
cpp++;
|
|
||||||
argc++;
|
|
||||||
}
|
|
||||||
|
|
||||||
envc = 0;
|
|
||||||
/* environment need not be there */
|
|
||||||
if ((cpp = (const netbsd32_charp *)SCARG(uap, envp)) != NULL ) {
|
|
||||||
while (1) {
|
|
||||||
len = argp + ARG_MAX - dp;
|
|
||||||
if ((error = copyin(cpp, &sp, sizeof(sp))) != 0)
|
|
||||||
goto bad;
|
|
||||||
if (!sp)
|
|
||||||
break;
|
|
||||||
if ((error = copyinstr((char *)(u_long)sp,
|
|
||||||
dp, len, &len)) != 0) {
|
|
||||||
if (error == ENAMETOOLONG)
|
|
||||||
error = E2BIG;
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
dp += len;
|
|
||||||
cpp++;
|
|
||||||
envc++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dp = (char *) ALIGN(dp);
|
|
||||||
|
|
||||||
szsigcode = pack.ep_es->es_emul->e_esigcode -
|
|
||||||
pack.ep_es->es_emul->e_sigcode;
|
|
||||||
|
|
||||||
/* Now check if args & environ fit into new stack */
|
|
||||||
if (pack.ep_flags & EXEC_32)
|
|
||||||
len = ((argc + envc + 2 + pack.ep_es->es_arglen) *
|
|
||||||
sizeof(int) + sizeof(int) + dp + STACKGAPLEN +
|
|
||||||
szsigcode + sizeof(struct ps_strings)) - argp;
|
|
||||||
else
|
|
||||||
len = ((argc + envc + 2 + pack.ep_es->es_arglen) *
|
|
||||||
sizeof(char *) + sizeof(int) + dp + STACKGAPLEN +
|
|
||||||
szsigcode + sizeof(struct ps_strings)) - argp;
|
|
||||||
|
|
||||||
len = ALIGN(len); /* make the stack "safely" aligned */
|
|
||||||
|
|
||||||
if (len > pack.ep_ssize) { /* in effect, compare to initial limit */
|
|
||||||
error = ENOMEM;
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* adjust "active stack depth" for process VSZ */
|
|
||||||
pack.ep_ssize = len; /* maybe should go elsewhere, but... */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Do whatever is necessary to prepare the address space
|
|
||||||
* for remapping. Note that this might replace the current
|
|
||||||
* vmspace with another!
|
|
||||||
*/
|
|
||||||
uvmspace_exec(l, VM_MIN_ADDRESS, (vaddr_t)pack.ep_minsaddr);
|
|
||||||
|
|
||||||
/* Now map address space */
|
|
||||||
vm = p->p_vmspace;
|
|
||||||
vm->vm_taddr = (char *) pack.ep_taddr;
|
|
||||||
vm->vm_tsize = btoc(pack.ep_tsize);
|
|
||||||
vm->vm_daddr = (char *) pack.ep_daddr;
|
|
||||||
vm->vm_dsize = btoc(pack.ep_dsize);
|
|
||||||
vm->vm_ssize = btoc(pack.ep_ssize);
|
|
||||||
vm->vm_maxsaddr = (char *) pack.ep_maxsaddr;
|
|
||||||
vm->vm_minsaddr = (char *) pack.ep_minsaddr;
|
|
||||||
|
|
||||||
/* create the new process's VM space by running the vmcmds */
|
|
||||||
#ifdef DIAGNOSTIC
|
|
||||||
if (pack.ep_vmcmds.evs_used == 0)
|
|
||||||
panic("netbsd32_execve: no vmcmds");
|
|
||||||
#endif
|
|
||||||
for (i = 0; i < pack.ep_vmcmds.evs_used && !error; i++) {
|
|
||||||
struct exec_vmcmd *vcp;
|
|
||||||
|
|
||||||
vcp = &pack.ep_vmcmds.evs_cmds[i];
|
|
||||||
if (vcp->ev_flags & VMCMD_RELATIVE) {
|
|
||||||
#ifdef DIAGNOSTIC
|
|
||||||
if (base_vcp == NULL)
|
|
||||||
panic("netbsd32_execve: relative vmcmd with no base");
|
|
||||||
if (vcp->ev_flags & VMCMD_BASE)
|
|
||||||
panic("netbsd32_execve: illegal base & relative vmcmd");
|
|
||||||
#endif
|
|
||||||
vcp->ev_addr += base_vcp->ev_addr;
|
|
||||||
}
|
|
||||||
error = (*vcp->ev_proc)(p, vcp);
|
|
||||||
#ifdef DEBUG
|
|
||||||
if (error) {
|
|
||||||
int j;
|
|
||||||
|
|
||||||
for (j = 0; j <= i; j++)
|
|
||||||
printf("vmcmd[%d] = %#lx/%#lx @ %#lx\n", j,
|
|
||||||
vcp[j-i].ev_addr, vcp[j-i].ev_len,
|
|
||||||
vcp[j-i].ev_offset);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (vcp->ev_flags & VMCMD_BASE)
|
|
||||||
base_vcp = vcp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* free the vmspace-creation commands, and release their references */
|
|
||||||
kill_vmcmds(&pack.ep_vmcmds);
|
|
||||||
|
|
||||||
/* if an error happened, deallocate and punt */
|
|
||||||
if (error) {
|
|
||||||
#ifdef DEBUG
|
|
||||||
printf("netbsd32_execve: vmcmd %i failed: %d\n", i-1, error);
|
|
||||||
#endif
|
|
||||||
goto exec_abort;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remember information about the process */
|
|
||||||
arginfo.ps_nargvstr = argc;
|
|
||||||
arginfo.ps_nenvstr = envc;
|
|
||||||
|
|
||||||
stack = (char *) (vm->vm_minsaddr - len);
|
|
||||||
/* Now copy argc, args & environ to new stack */
|
|
||||||
error = (*pack.ep_es->es_copyargs)(p, &pack, &arginfo,
|
|
||||||
&stack, argp);
|
|
||||||
if (error) {
|
|
||||||
#ifdef DEBUG
|
|
||||||
printf("netbsd32_execve: copyargs failed\n");
|
|
||||||
#endif
|
|
||||||
goto exec_abort;
|
|
||||||
}
|
|
||||||
/* restore the stack back to its original point */
|
|
||||||
stack = (char *) (vm->vm_minsaddr - len);
|
|
||||||
|
|
||||||
/* fill process ps_strings info */
|
|
||||||
p->p_psstr = (struct ps_strings *)(vm->vm_minsaddr -
|
|
||||||
sizeof(struct ps_strings));
|
|
||||||
p->p_psargv = offsetof(struct ps_strings, ps_argvstr);
|
|
||||||
p->p_psnargv = offsetof(struct ps_strings, ps_nargvstr);
|
|
||||||
p->p_psenv = offsetof(struct ps_strings, ps_envstr);
|
|
||||||
p->p_psnenv = offsetof(struct ps_strings, ps_nenvstr);
|
|
||||||
|
|
||||||
/* copy out the process's ps_strings structure */
|
|
||||||
if (copyout(&arginfo, (char *)p->p_psstr, sizeof(arginfo))) {
|
|
||||||
#ifdef DEBUG
|
|
||||||
printf("netbsd32_execve: ps_strings copyout failed\n");
|
|
||||||
#endif
|
|
||||||
goto exec_abort;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* copy out the process's signal trapoline code */
|
|
||||||
if (szsigcode) {
|
|
||||||
if (copyout((char *)pack.ep_es->es_emul->e_sigcode,
|
|
||||||
p->p_sigctx.ps_sigcode = (char *)p->p_psstr - szsigcode,
|
|
||||||
szsigcode)) {
|
|
||||||
#ifdef DEBUG
|
|
||||||
printf("netbsd32_execve: sig trampoline copyout failed\n");
|
|
||||||
#endif
|
|
||||||
goto exec_abort;
|
|
||||||
}
|
|
||||||
#ifdef PMAP_NEED_PROCWR
|
|
||||||
/* This is code. Let the pmap do what is needed. */
|
|
||||||
pmap_procwr(p, (vaddr_t)p->p_sigctx.ps_sigcode, szsigcode);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
stopprofclock(p); /* stop profiling */
|
|
||||||
fdcloseexec(p); /* handle close on exec */
|
|
||||||
execsigs(p); /* reset catched signals */
|
|
||||||
l->l_ctxlink = NULL; /* reset ucontext link */
|
|
||||||
|
|
||||||
/* set command name & other accounting info */
|
|
||||||
len = min(nid.ni_cnd.cn_namelen, MAXCOMLEN);
|
|
||||||
memcpy(p->p_comm, nid.ni_cnd.cn_nameptr, len);
|
|
||||||
p->p_comm[len] = 0;
|
|
||||||
p->p_acflag &= ~AFORK;
|
|
||||||
|
|
||||||
/* record proc's vnode, for use by procfs and others */
|
|
||||||
if (p->p_textvp)
|
|
||||||
vrele(p->p_textvp);
|
|
||||||
VREF(pack.ep_vp);
|
|
||||||
p->p_textvp = pack.ep_vp;
|
|
||||||
|
|
||||||
p->p_flag |= P_EXEC;
|
|
||||||
if (p->p_flag & P_PPWAIT) {
|
|
||||||
p->p_flag &= ~P_PPWAIT;
|
|
||||||
wakeup((caddr_t) p->p_pptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* deal with set[ug]id.
|
|
||||||
* MNT_NOSUID has already been used to disable s[ug]id.
|
|
||||||
*/
|
|
||||||
if ((p->p_flag & P_TRACED) == 0 &&
|
|
||||||
|
|
||||||
(((attr.va_mode & S_ISUID) != 0 &&
|
|
||||||
p->p_ucred->cr_uid != attr.va_uid) ||
|
|
||||||
|
|
||||||
((attr.va_mode & S_ISGID) != 0 &&
|
|
||||||
p->p_ucred->cr_gid != attr.va_gid))) {
|
|
||||||
/*
|
|
||||||
* Mark the process as SUGID before we do
|
|
||||||
* anything that might block.
|
|
||||||
*/
|
|
||||||
p_sugid(p);
|
|
||||||
|
|
||||||
p->p_ucred = crcopy(cred);
|
|
||||||
#ifdef KTRACE
|
|
||||||
/*
|
|
||||||
* If process is being ktraced, turn off - unless
|
|
||||||
* root set it.
|
|
||||||
*/
|
|
||||||
if (p->p_tracep && !(p->p_traceflag & KTRFAC_ROOT))
|
|
||||||
ktrderef(p);
|
|
||||||
#endif
|
|
||||||
if (attr.va_mode & S_ISUID)
|
|
||||||
p->p_ucred->cr_uid = attr.va_uid;
|
|
||||||
if (attr.va_mode & S_ISGID)
|
|
||||||
p->p_ucred->cr_gid = attr.va_gid;
|
|
||||||
} else
|
|
||||||
p->p_flag &= ~P_SUGID;
|
|
||||||
p->p_cred->p_svuid = p->p_ucred->cr_uid;
|
|
||||||
p->p_cred->p_svgid = p->p_ucred->cr_gid;
|
|
||||||
|
|
||||||
doexechooks(p);
|
|
||||||
|
|
||||||
uvm_km_free(exec_map, (vaddr_t) argp, NCARGS, UVM_KMF_PAGEABLE);
|
|
||||||
|
|
||||||
PNBUF_PUT(nid.ni_cnd.cn_pnbuf);
|
|
||||||
vn_lock(pack.ep_vp, LK_EXCLUSIVE | LK_RETRY);
|
|
||||||
VOP_CLOSE(pack.ep_vp, FREAD, cred, p);
|
|
||||||
vput(pack.ep_vp);
|
|
||||||
|
|
||||||
/* setup new registers and do misc. setup. */
|
|
||||||
(*pack.ep_es->es_emul->e_setregs)(l, &pack, (u_long) stack);
|
|
||||||
if (pack.ep_es->es_setregs)
|
|
||||||
(*pack.ep_es->es_setregs)(l, &pack, (u_long) stack);
|
|
||||||
|
|
||||||
if (p->p_flag & P_TRACED)
|
|
||||||
psignal(p, SIGTRAP);
|
|
||||||
|
|
||||||
free(pack.ep_hdr, M_EXEC);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Call emulation specific exec hook. This can setup setup per-process
|
|
||||||
* p->p_emuldata or do any other per-process stuff an emulation needs.
|
|
||||||
*
|
|
||||||
* If we are executing process of different emulation than the
|
|
||||||
* original forked process, call e_proc_exit() of the old emulation
|
|
||||||
* first, then e_proc_exec() of new emulation. If the emulation is
|
|
||||||
* same, the exec hook code should deallocate any old emulation
|
|
||||||
* resources held previously by this process.
|
|
||||||
*/
|
|
||||||
if (p->p_emul && p->p_emul->e_proc_exit
|
|
||||||
&& p->p_emul != pack.ep_es->es_emul)
|
|
||||||
(*p->p_emul->e_proc_exit)(p);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Call exec hook. Emulation code may NOT store reference to anything
|
|
||||||
* from &pack.
|
|
||||||
*/
|
|
||||||
if (pack.ep_es->es_emul->e_proc_exec)
|
|
||||||
(*pack.ep_es->es_emul->e_proc_exec)(p, &pack);
|
|
||||||
|
|
||||||
/* update p_emul, the old value is no longer needed */
|
|
||||||
p->p_emul = pack.ep_es->es_emul;
|
|
||||||
|
|
||||||
/* ...and the same for p_execsw */
|
|
||||||
p->p_execsw = pack.ep_es;
|
|
||||||
|
|
||||||
#ifdef __HAVE_SYSCALL_INTERN
|
|
||||||
(*p->p_emul->e_syscall_intern)(p);
|
|
||||||
#endif
|
|
||||||
#ifdef KTRACE
|
|
||||||
if (KTRPOINT(p, KTR_EMUL))
|
|
||||||
ktremul(p);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(LKM) || defined(_LKM)
|
|
||||||
lockmgr(&exec_lock, LK_RELEASE, NULL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return (EJUSTRETURN);
|
|
||||||
|
|
||||||
bad:
|
|
||||||
/* free the vmspace-creation commands, and release their references */
|
|
||||||
kill_vmcmds(&pack.ep_vmcmds);
|
|
||||||
/* kill any opened file descriptor, if necessary */
|
|
||||||
if (pack.ep_flags & EXEC_HASFD) {
|
|
||||||
pack.ep_flags &= ~EXEC_HASFD;
|
|
||||||
(void) fdrelease(p, pack.ep_fd);
|
|
||||||
}
|
|
||||||
/* close and put the exec'd file */
|
|
||||||
vn_lock(pack.ep_vp, LK_EXCLUSIVE | LK_RETRY);
|
|
||||||
VOP_CLOSE(pack.ep_vp, FREAD, cred, p);
|
|
||||||
vput(pack.ep_vp);
|
|
||||||
PNBUF_PUT(nid.ni_cnd.cn_pnbuf);
|
|
||||||
uvm_km_free(exec_map, (vaddr_t) argp, NCARGS, UVM_KMF_PAGEABLE);
|
|
||||||
|
|
||||||
freehdr:
|
|
||||||
#if defined(LKM) || defined(_LKM)
|
|
||||||
lockmgr(&exec_lock, LK_RELEASE, NULL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
free(pack.ep_hdr, M_EXEC);
|
|
||||||
return error;
|
|
||||||
|
|
||||||
exec_abort:
|
|
||||||
#if defined(LKM) || defined(_LKM)
|
|
||||||
lockmgr(&exec_lock, LK_RELEASE, NULL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
uvm_deallocate(&vm->vm_map, VM_MIN_ADDRESS,
|
|
||||||
VM_MAXUSER_ADDRESS - VM_MIN_ADDRESS);
|
|
||||||
if (pack.ep_emul_arg)
|
|
||||||
FREE(pack.ep_emul_arg, M_TEMP);
|
|
||||||
PNBUF_PUT(nid.ni_cnd.cn_pnbuf);
|
|
||||||
vn_lock(pack.ep_vp, LK_EXCLUSIVE | LK_RETRY);
|
|
||||||
VOP_CLOSE(pack.ep_vp, FREAD, cred, p);
|
|
||||||
vput(pack.ep_vp);
|
|
||||||
uvm_km_free(exec_map, (vaddr_t) argp, NCARGS, UVM_KMF_PAGEABLE);
|
|
||||||
free(pack.ep_hdr, M_EXEC);
|
|
||||||
exit1(l, W_EXITCODE(error, SIGABRT));
|
|
||||||
|
|
||||||
/* NOTREACHED */
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: kern_exec.c,v 1.203 2005/07/10 04:20:34 christos Exp $ */
|
/* $NetBSD: kern_exec.c,v 1.204 2005/07/11 20:15:26 cube Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (C) 1993, 1994, 1996 Christopher G. Demetriou
|
* Copyright (C) 1993, 1994, 1996 Christopher G. Demetriou
|
||||||
@ -33,7 +33,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.203 2005/07/10 04:20:34 christos Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.204 2005/07/11 20:15:26 cube Exp $");
|
||||||
|
|
||||||
#include "opt_ktrace.h"
|
#include "opt_ktrace.h"
|
||||||
#include "opt_syscall_debug.h"
|
#include "opt_syscall_debug.h"
|
||||||
@ -363,6 +363,12 @@ bad1:
|
|||||||
#define STACK_PTHREADSPACE 0
|
#define STACK_PTHREADSPACE 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int
|
||||||
|
execve_fetch_element(char * const *array, size_t index, char **value)
|
||||||
|
{
|
||||||
|
return copyin(array + index, value, sizeof(*value));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* exec system call
|
* exec system call
|
||||||
*/
|
*/
|
||||||
@ -375,6 +381,15 @@ sys_execve(struct lwp *l, void *v, register_t *retval)
|
|||||||
syscallarg(char * const *) argp;
|
syscallarg(char * const *) argp;
|
||||||
syscallarg(char * const *) envp;
|
syscallarg(char * const *) envp;
|
||||||
} */ *uap = v;
|
} */ *uap = v;
|
||||||
|
|
||||||
|
return execve1(l, SCARG(uap, path), SCARG(uap, argp),
|
||||||
|
SCARG(uap, envp), execve_fetch_element);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
execve1(struct lwp *l, const char *path, char * const *args,
|
||||||
|
char * const *envs, execve_fetch_element_t fetch_element)
|
||||||
|
{
|
||||||
int error;
|
int error;
|
||||||
u_int i;
|
u_int i;
|
||||||
struct exec_package pack;
|
struct exec_package pack;
|
||||||
@ -383,7 +398,6 @@ sys_execve(struct lwp *l, void *v, register_t *retval)
|
|||||||
struct proc *p;
|
struct proc *p;
|
||||||
struct ucred *cred;
|
struct ucred *cred;
|
||||||
char *argp;
|
char *argp;
|
||||||
char * const *cpp;
|
|
||||||
char *dp, *sp;
|
char *dp, *sp;
|
||||||
long argc, envc;
|
long argc, envc;
|
||||||
size_t len;
|
size_t len;
|
||||||
@ -428,14 +442,14 @@ sys_execve(struct lwp *l, void *v, register_t *retval)
|
|||||||
if (ISSET(p->p_flag, P_SYSTRACE))
|
if (ISSET(p->p_flag, P_SYSTRACE))
|
||||||
systrace_execve0(p);
|
systrace_execve0(p);
|
||||||
|
|
||||||
error = copyinstr(SCARG(uap, path), pathbuf, sizeof(pathbuf),
|
error = copyinstr(path, pathbuf, sizeof(pathbuf),
|
||||||
&pathbuflen);
|
&pathbuflen);
|
||||||
if (error)
|
if (error)
|
||||||
goto clrflg;
|
goto clrflg;
|
||||||
|
|
||||||
NDINIT(&nid, LOOKUP, NOFOLLOW, UIO_SYSSPACE, pathbuf, p);
|
NDINIT(&nid, LOOKUP, NOFOLLOW, UIO_SYSSPACE, pathbuf, p);
|
||||||
#else
|
#else
|
||||||
NDINIT(&nid, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
|
NDINIT(&nid, LOOKUP, NOFOLLOW, UIO_USERSPACE, path, p);
|
||||||
#endif /* SYSTRACE */
|
#endif /* SYSTRACE */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -444,7 +458,7 @@ sys_execve(struct lwp *l, void *v, register_t *retval)
|
|||||||
#ifdef SYSTRACE
|
#ifdef SYSTRACE
|
||||||
pack.ep_name = pathbuf;
|
pack.ep_name = pathbuf;
|
||||||
#else
|
#else
|
||||||
pack.ep_name = SCARG(uap, path);
|
pack.ep_name = path;
|
||||||
#endif /* SYSTRACE */
|
#endif /* SYSTRACE */
|
||||||
pack.ep_hdr = malloc(exec_maxhdrsz, M_EXEC, M_WAITOK);
|
pack.ep_hdr = malloc(exec_maxhdrsz, M_EXEC, M_WAITOK);
|
||||||
pack.ep_hdrlen = exec_maxhdrsz;
|
pack.ep_hdrlen = exec_maxhdrsz;
|
||||||
@ -499,17 +513,18 @@ sys_execve(struct lwp *l, void *v, register_t *retval)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Now get argv & environment */
|
/* Now get argv & environment */
|
||||||
if (!(cpp = SCARG(uap, argp))) {
|
if (args == NULL) {
|
||||||
error = EINVAL;
|
error = EINVAL;
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
/* 'i' will index the argp/envp element to be retrieved */
|
||||||
|
i = 0;
|
||||||
if (pack.ep_flags & EXEC_SKIPARG)
|
if (pack.ep_flags & EXEC_SKIPARG)
|
||||||
cpp++;
|
i++;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
len = argp + ARG_MAX - dp;
|
len = argp + ARG_MAX - dp;
|
||||||
if ((error = copyin(cpp, &sp, sizeof(sp))) != 0)
|
if ((error = (*fetch_element)(args, i, &sp)) != 0)
|
||||||
goto bad;
|
goto bad;
|
||||||
if (!sp)
|
if (!sp)
|
||||||
break;
|
break;
|
||||||
@ -523,16 +538,17 @@ sys_execve(struct lwp *l, void *v, register_t *retval)
|
|||||||
ktrkmem(p, KTR_EXEC_ARG, dp, len - 1);
|
ktrkmem(p, KTR_EXEC_ARG, dp, len - 1);
|
||||||
#endif
|
#endif
|
||||||
dp += len;
|
dp += len;
|
||||||
cpp++;
|
i++;
|
||||||
argc++;
|
argc++;
|
||||||
}
|
}
|
||||||
|
|
||||||
envc = 0;
|
envc = 0;
|
||||||
/* environment need not be there */
|
/* environment need not be there */
|
||||||
if ((cpp = SCARG(uap, envp)) != NULL ) {
|
if (envs != NULL) {
|
||||||
|
i = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
len = argp + ARG_MAX - dp;
|
len = argp + ARG_MAX - dp;
|
||||||
if ((error = copyin(cpp, &sp, sizeof(sp))) != 0)
|
if ((error = (*fetch_element)(envs, i, &sp)) != 0)
|
||||||
goto bad;
|
goto bad;
|
||||||
if (!sp)
|
if (!sp)
|
||||||
break;
|
break;
|
||||||
@ -546,7 +562,7 @@ sys_execve(struct lwp *l, void *v, register_t *retval)
|
|||||||
ktrkmem(p, KTR_EXEC_ENV, dp, len - 1);
|
ktrkmem(p, KTR_EXEC_ENV, dp, len - 1);
|
||||||
#endif
|
#endif
|
||||||
dp += len;
|
dp += len;
|
||||||
cpp++;
|
i++;
|
||||||
envc++;
|
envc++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: exec.h,v 1.109 2005/06/10 11:36:38 tron Exp $ */
|
/* $NetBSD: exec.h,v 1.110 2005/07/11 20:15:26 cube Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 1992, 1993
|
* Copyright (c) 1992, 1993
|
||||||
@ -284,6 +284,10 @@ void new_vmcmd(struct exec_vmcmd_set *,
|
|||||||
#define NEW_VMCMD2(evsp,proc,len,addr,vp,offset,prot,flags) \
|
#define NEW_VMCMD2(evsp,proc,len,addr,vp,offset,prot,flags) \
|
||||||
new_vmcmd(evsp,proc,len,addr,vp,offset,prot,flags)
|
new_vmcmd(evsp,proc,len,addr,vp,offset,prot,flags)
|
||||||
|
|
||||||
|
typedef int (*execve_fetch_element_t)(char * const *, size_t, char **);
|
||||||
|
int execve1(struct lwp *, const char *, char * const *, char * const *,
|
||||||
|
execve_fetch_element_t);
|
||||||
|
|
||||||
#endif /* _KERNEL */
|
#endif /* _KERNEL */
|
||||||
|
|
||||||
#include <sys/exec_aout.h>
|
#include <sys/exec_aout.h>
|
||||||
|
Loading…
Reference in New Issue
Block a user