Subject: COMPAT_NETBSD32's execve, copy/paste of code
To: None <tech-kern@netbsd.org>
From: Quentin Garnier <cube@cubidou.net>
List: tech-kern
Date: 07/11/2005 00:15:33
--m1UC1K4AOz1Ywdkx
Content-Type: multipart/mixed; boundary="C94crkcyjafcjHxo"
Content-Disposition: inline


--C94crkcyjafcjHxo
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

Hi folks,

On my path to a complete netbsd32 emulation, I could see that some
syscalls in the compat_netbsd32 code were copied and adapted from the
native counterpart.

The problem is that those syscalls are very hard to maintain.  I fixed
netbsd32_wait4() this morning, and this afternoon, while trying to
implement rasctl(2), I discovered that netbsd32_execve() was broken in
a similar way:  some changes done to the native syscall have not been
reported to the compat_netbsd32 version.

The reason why there is a need for a slightly different version is
because those syscalls manipulate data in userspace that have different
size depending on the emulation.  Therefore you cannot always use
copyin()/copyout().

To properly fix netbsd32_wait4(), the only thing that would be needed is
a slighly smarter copyin()/copyout() that would check if the supposedly
user address is actually a kernel address or not, and in the former case
only do a memcpy().  I don't know if it easy to do that, even if it ends
as a set of MD implementations.  I do know that it wouldn't be only
useful for compat_netbsd32, though.

However, a smarter copyin() is not enough when it comes to arrays of
structs of a size different from the native version.  This is the case
of execve(2) (and others, I know at least kevent(2)).

netbsd32_execve() was missing the calls related to RAS support, which
showed that however close it was to the native sys_execve(), it had
drifted apart from it.

The solution I propose for such syscalls that access an array in user
space is to use a helper function that takes an additional argument
which is a pointer to a function that will do the copyin() (or a
copyout(), in execve(2)'s case it's only a copyin() though), and the
translation in the compat_netbsd32 case.

That way the actual syscall is only slowed down by a few function calls,
and remain readable.

See for yourself with the attached patch for execve(2).

There might be smarter ways of doing this, I'm open to suggestions.  But
keep in mind that we want to avoid as much as possible duplicating code,
but not at the expense of the native syscall's speed.

The other solution is to teach people to think of compat_netbsd32
whenever they touch a syscall, but this has obviously failed, and is
doomed to fail anyway.

Comments?

--=20
Quentin Garnier - cube@cubidou.net - cube@NetBSD.org
"When I find the controls, I'll go where I like, I'll know where I want
to be, but maybe for now I'll stay right here on a silent sea."
KT Tunstall, Silent Sea, Eye to the Telescope, 2004.

--C94crkcyjafcjHxo
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="execve.diff"
Content-Transfer-Encoding: quoted-printable

Index: compat/netbsd32/netbsd32_execve.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /rep/NetBSD-src/cvs/src/sys/compat/netbsd32/netbsd32_execve.c,v
retrieving revision 1.22
diff -u -r1.22 netbsd32_execve.c
--- compat/netbsd32/netbsd32_execve.c	2005/05/31 00:41:09	1.22
+++ compat/netbsd32/netbsd32_execve.c	2005/07/10 21:57:49
@@ -61,476 +61,30 @@
=20
 #include <sys/verified_exec.h>
=20
-/* this is provided by kern/kern_exec.c */
-extern u_int exec_maxhdrsz;
-#if defined(LKM) || defined(_LKM)
-extern struct lock exec_lock;
-#endif
+static int
+netbsd32_execve_fetch_element(char * const *array, u_int index, char **val=
ue)
+{
+	int error;
+	netbsd32_charp const *a32 =3D (void const *)array;
+	netbsd32_charp e;
+
+	error =3D copyin(a32 + index, &e, sizeof(e));
+	if (error)
+		return error;
+	*value =3D (char *)(uintptr_t)e;
+	return 0;
+}
=20
-/*
- * Need to completly reimplement this syscall due to argument copying.
- */
-/* ARGSUSED */
 int
-netbsd32_execve(l, v, retval)
-	struct lwp *l;
-	void *v;
-	register_t *retval;
+netbsd32_execve(struct lwp *l, void *v, register_t *retval)
 {
 	struct netbsd32_execve_args /* {
 		syscallarg(const netbsd32_charp) path;
 		syscallarg(netbsd32_charpp) argp;
 		syscallarg(netbsd32_charpp) envp;
 	} */ *uap =3D v;
-	struct sys_execve_args ua;
-	caddr_t sg;
-	struct proc *p =3D l->l_proc;
-
-	NETBSD32TOP_UAP(path, const char);
-	NETBSD32TOP_UAP(argp, char *);
-	NETBSD32TOP_UAP(envp, char *);
-	sg =3D 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 =3D l->l_proc;
-	int error, i;
-	struct exec_package pack;
-	struct nameidata nid;
-	struct vattr attr;
-	struct ucred *cred =3D 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 =3D 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 =3D SCARG(uap, path);
-	pack.ep_hdr =3D malloc(exec_maxhdrsz, M_EXEC, M_WAITOK);
-	pack.ep_hdrlen =3D exec_maxhdrsz;
-	pack.ep_hdrvalid =3D 0;
-	pack.ep_ndp =3D &nid;
-	pack.ep_emul_arg =3D NULL;
-	pack.ep_vmcmds.evs_cnt =3D 0;
-	pack.ep_vmcmds.evs_used =3D 0;
-	pack.ep_vap =3D &attr;
-	pack.ep_flags =3D 0;
-
-#if defined(LKM) || defined(_LKM)
-	lockmgr(&exec_lock, LK_SHARED, NULL);
-#endif
-
-	/* see if we can run it. */
-#ifdef VERIFIED_EXEC
-	if ((error =3D check_exec(p, &pack, VERIEXEC_DIRECT)) !=3D 0)
-#else
-	if ((error =3D check_exec(p, &pack)) !=3D 0)
-#endif
-		goto freehdr;
-
-	/* XXX -- THE FOLLOWING SECTION NEEDS MAJOR CLEANUP */
-
-	/* allocate an argument buffer */
-	argp =3D (char *) uvm_km_alloc(exec_map, NCARGS, 0,
-	    UVM_KMF_PAGEABLE|UVM_KMF_WAITVA);
-#ifdef DIAGNOSTIC
-	if (argp =3D=3D (vaddr_t) 0)
-		panic("netbsd32_execve: argp =3D=3D NULL");
-#endif
-	dp =3D argp;
-	argc =3D 0;
-
-	/* copy the fake args list, if there's one, freeing it as we go */
-	if (pack.ep_flags & EXEC_HASARGL) {
-		tmpfap =3D pack.ep_fa;
-		while (*tmpfap !=3D NULL) {
-			char *cp;
-
-			cp =3D *tmpfap;
-			while (*cp)
-				*dp++ =3D *cp++;
-			dp++;
-
-			FREE(*tmpfap, M_EXEC);
-			tmpfap++; argc++;
-		}
-		FREE(pack.ep_fa, M_EXEC);
-		pack.ep_flags &=3D ~EXEC_HASARGL;
-	}
-
-	/* Now get argv & environment */
-	if (!(cpp =3D (const netbsd32_charp *)SCARG(uap, argp))) {
-		error =3D EINVAL;
-		goto bad;
-	}
-
-	if (pack.ep_flags & EXEC_SKIPARG)
-		cpp++;
-
-	while (1) {
-		len =3D argp + ARG_MAX - dp;
-		if ((error =3D copyin(cpp, &sp, sizeof(sp))) !=3D 0)
-			goto bad;
-		if (!sp)
-			break;
-		if ((error =3D copyinstr((char *)(u_long)sp, dp,
-				       len, &len)) !=3D 0) {
-			if (error =3D=3D ENAMETOOLONG)
-				error =3D E2BIG;
-			goto bad;
-		}
-		dp +=3D len;
-		cpp++;
-		argc++;
-	}
-
-	envc =3D 0;
-	/* environment need not be there */
-	if ((cpp =3D (const netbsd32_charp *)SCARG(uap, envp)) !=3D NULL ) {
-		while (1) {
-			len =3D argp + ARG_MAX - dp;
-			if ((error =3D copyin(cpp, &sp, sizeof(sp))) !=3D 0)
-				goto bad;
-			if (!sp)
-				break;
-			if ((error =3D copyinstr((char *)(u_long)sp,
-					       dp, len, &len)) !=3D 0) {
-				if (error =3D=3D ENAMETOOLONG)
-					error =3D E2BIG;
-				goto bad;
-			}
-			dp +=3D len;
-			cpp++;
-			envc++;
-		}
-	}
-
-	dp =3D (char *) ALIGN(dp);
-
-	szsigcode =3D 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 =3D ((argc + envc + 2 + pack.ep_es->es_arglen) *
-		    sizeof(int) + sizeof(int) + dp + STACKGAPLEN +
-		    szsigcode + sizeof(struct ps_strings)) - argp;
-	else
-		len =3D ((argc + envc + 2 + pack.ep_es->es_arglen) *
-		    sizeof(char *) + sizeof(int) + dp + STACKGAPLEN +
-		    szsigcode + sizeof(struct ps_strings)) - argp;
-
-	len =3D ALIGN(len);	/* make the stack "safely" aligned */
-
-	if (len > pack.ep_ssize) { /* in effect, compare to initial limit */
-		error =3D ENOMEM;
-		goto bad;
-	}
-
-	/* adjust "active stack depth" for process VSZ */
-	pack.ep_ssize =3D 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 =3D p->p_vmspace;
-	vm->vm_taddr =3D (char *) pack.ep_taddr;
-	vm->vm_tsize =3D btoc(pack.ep_tsize);
-	vm->vm_daddr =3D (char *) pack.ep_daddr;
-	vm->vm_dsize =3D btoc(pack.ep_dsize);
-	vm->vm_ssize =3D btoc(pack.ep_ssize);
-	vm->vm_maxsaddr =3D (char *) pack.ep_maxsaddr;
-	vm->vm_minsaddr =3D (char *) pack.ep_minsaddr;
-
-	/* create the new process's VM space by running the vmcmds */
-#ifdef DIAGNOSTIC
-	if (pack.ep_vmcmds.evs_used =3D=3D 0)
-		panic("netbsd32_execve: no vmcmds");
-#endif
-	for (i =3D 0; i < pack.ep_vmcmds.evs_used && !error; i++) {
-		struct exec_vmcmd *vcp;
-
-		vcp =3D &pack.ep_vmcmds.evs_cmds[i];
-		if (vcp->ev_flags & VMCMD_RELATIVE) {
-#ifdef DIAGNOSTIC
-			if (base_vcp =3D=3D 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 +=3D base_vcp->ev_addr;
-		}
-		error =3D (*vcp->ev_proc)(p, vcp);
-#ifdef DEBUG
-		if (error) {
-			int j;
-
-			for (j =3D 0; j <=3D i; j++)
-				printf("vmcmd[%d] =3D %#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 =3D vcp;
-	}
-
-	/* free the vmspace-creation commands, and release their references */
-	kill_vmcmds(&pack.ep_vmcmds);
=20
-	/* 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 =3D argc;
-	arginfo.ps_nenvstr =3D envc;
-
-	stack =3D (char *) (vm->vm_minsaddr - len);
-	/* Now copy argc, args & environ to new stack */
-	error =3D (*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 =3D (char *) (vm->vm_minsaddr - len);
-
-	/* fill process ps_strings info */
-	p->p_psstr =3D (struct ps_strings *)(vm->vm_minsaddr -
-	    sizeof(struct ps_strings));
-	p->p_psargv =3D offsetof(struct ps_strings, ps_argvstr);
-	p->p_psnargv =3D offsetof(struct ps_strings, ps_nargvstr);
-	p->p_psenv =3D offsetof(struct ps_strings, ps_envstr);
-	p->p_psnenv =3D 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 =3D (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 =3D NULL;	/* reset ucontext link */
-
-	/* set command name & other accounting info */
-	len =3D min(nid.ni_cnd.cn_namelen, MAXCOMLEN);
-	memcpy(p->p_comm, nid.ni_cnd.cn_nameptr, len);
-	p->p_comm[len] =3D 0;
-	p->p_acflag &=3D ~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 =3D pack.ep_vp;
-
-	p->p_flag |=3D P_EXEC;
-	if (p->p_flag & P_PPWAIT) {
-		p->p_flag &=3D ~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) =3D=3D 0 &&
-
-	    (((attr.va_mode & S_ISUID) !=3D 0 &&
-	      p->p_ucred->cr_uid !=3D attr.va_uid) ||
-
-	     ((attr.va_mode & S_ISGID) !=3D 0 &&
-	      p->p_ucred->cr_gid !=3D attr.va_gid))) {
-		/*
-		 * Mark the process as SUGID before we do
-		 * anything that might block.
-		 */
-		p_sugid(p);
-
-		p->p_ucred =3D 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 =3D attr.va_uid;
-		if (attr.va_mode & S_ISGID)
-			p->p_ucred->cr_gid =3D attr.va_gid;
-	} else
-		p->p_flag &=3D ~P_SUGID;
-	p->p_cred->p_svuid =3D p->p_ucred->cr_uid;
-	p->p_cred->p_svgid =3D 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 !=3D 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 =3D pack.ep_es->es_emul;
-
-	/* ...and the same for p_execsw */
-	p->p_execsw =3D 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 &=3D ~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;
+	return doexecve(l, NETBSD32PTR64(SCARG(uap, path)),
+	    NETBSD32PTR64(SCARG(uap, argp)), NETBSD32PTR64(SCARG(uap, envp)),
+	    netbsd32_execve_fetch_element);
 }
Index: kern/kern_exec.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /rep/NetBSD-src/cvs/src/sys/kern/kern_exec.c,v
retrieving revision 1.202
diff -u -r1.202 kern_exec.c
--- kern/kern_exec.c	2005/07/10 00:54:54	1.202
+++ kern/kern_exec.c	2005/07/10 21:39:51
@@ -359,6 +359,12 @@
 #define STACK_PTHREADSPACE 0
 #endif
=20
+static int
+execve_fetch_element(char * const *array, u_int index, char **value)
+{
+	return copyin(array + index, value, sizeof(*value));
+}
+
 /*
  * exec system call
  */
@@ -371,6 +377,15 @@
 		syscallarg(char * const *)	argp;
 		syscallarg(char * const *)	envp;
 	} */ *uap =3D v;
+
+	return doexecve(l, SCARG(uap, path), SCARG(uap, argp),
+	    SCARG(uap, envp), execve_fetch_element);
+}
+
+int
+doexecve(struct lwp *l, const char *path, char * const *args,
+    char * const *envs, execve_fetch_element_t fetch_element)
+{
 	int			error;
 	u_int			i;
 	struct exec_package	pack;
@@ -379,7 +394,6 @@
 	struct proc		*p;
 	struct ucred		*cred;
 	char			*argp;
-	char * const		*cpp;
 	char			*dp, *sp;
 	long			argc, envc;
 	size_t			len;
@@ -424,14 +438,14 @@
 	if (ISSET(p->p_flag, P_SYSTRACE))
 		systrace_execve0(p);
=20
-	error =3D copyinstr(SCARG(uap, path), pathbuf, sizeof(pathbuf),
+	error =3D copyinstr(path, pathbuf, sizeof(pathbuf),
 			  &pathbuflen);
 	if (error)
 		goto clrflg;
=20
 	NDINIT(&nid, LOOKUP, NOFOLLOW, UIO_SYSSPACE, pathbuf, p);
 #else
-	NDINIT(&nid, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
+	NDINIT(&nid, LOOKUP, NOFOLLOW, UIO_USERSPACE, path, p);
 #endif /* SYSTRACE */
=20
 	/*
@@ -440,7 +454,7 @@
 #ifdef SYSTRACE
 	pack.ep_name =3D pathbuf;
 #else
-	pack.ep_name =3D SCARG(uap, path);
+	pack.ep_name =3D path;
 #endif /* SYSTRACE */
 	pack.ep_hdr =3D malloc(exec_maxhdrsz, M_EXEC, M_WAITOK);
 	pack.ep_hdrlen =3D exec_maxhdrsz;
@@ -495,17 +509,18 @@
 	}
=20
 	/* Now get argv & environment */
-	if (!(cpp =3D SCARG(uap, argp))) {
+	if (args =3D=3D NULL) {
 		error =3D EINVAL;
 		goto bad;
 	}
-
+	/* 'i' will index the argp/envp element to be retrieved */
+	i =3D 0;
 	if (pack.ep_flags & EXEC_SKIPARG)
-		cpp++;
+		i++;
=20
 	while (1) {
 		len =3D argp + ARG_MAX - dp;
-		if ((error =3D copyin(cpp, &sp, sizeof(sp))) !=3D 0)
+		if ((error =3D fetch_element(args, i, &sp)) !=3D 0)
 			goto bad;
 		if (!sp)
 			break;
@@ -519,16 +534,17 @@
 			ktrkmem(p, KTR_EXEC_ARG, dp, len - 1);
 #endif
 		dp +=3D len;
-		cpp++;
+		i++;
 		argc++;
 	}
=20
 	envc =3D 0;
 	/* environment need not be there */
-	if ((cpp =3D SCARG(uap, envp)) !=3D NULL ) {
+	if (envs !=3D NULL ) {
+		i =3D 0;
 		while (1) {
 			len =3D argp + ARG_MAX - dp;
-			if ((error =3D copyin(cpp, &sp, sizeof(sp))) !=3D 0)
+			if ((error =3D fetch_element(envs, i, &sp)) !=3D 0)
 				goto bad;
 			if (!sp)
 				break;
@@ -542,7 +558,7 @@
 				ktrkmem(p, KTR_EXEC_ENV, dp, len - 1);
 #endif
 			dp +=3D len;
-			cpp++;
+			i++;
 			envc++;
 		}
 	}
Index: sys/exec.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /rep/NetBSD-src/cvs/src/sys/sys/exec.h,v
retrieving revision 1.109
diff -u -r1.109 exec.h
--- sys/exec.h	2005/06/10 11:36:38	1.109
+++ sys/exec.h	2005/07/10 21:40:06
@@ -284,6 +284,10 @@
 #define	NEW_VMCMD2(evsp,proc,len,addr,vp,offset,prot,flags) \
 	new_vmcmd(evsp,proc,len,addr,vp,offset,prot,flags)
=20
+typedef	int (*execve_fetch_element_t)(char * const *, u_int, char **);
+int	doexecve(struct lwp *, const char *, char * const *, char * const *,
+    execve_fetch_element_t);
+
 #endif /* _KERNEL */
=20
 #include <sys/exec_aout.h>

--C94crkcyjafcjHxo--

--m1UC1K4AOz1Ywdkx
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.6 (NetBSD)

iQEVAwUBQtGeBdgoQloHrPnoAQKaFQf/SJjSpt4AWlxzpDJ0r7ylG0OtpeIiiLvc
SbzaZNap2bFxg1xk5ZTbq6NDhQ0/pL1/lF5K8dtXmSwmGRQtPwrIYAVlNIMcCydy
4hCyZsBwVjxDOtOjKi8BiCdEt2aImK43ht/TFNhhQbu5dIUSDEMNkL7E3sEZmZ4U
HO4sqqU0xu2b+wLO9LSvaP/IaJTKwHjYO378Gf91oqtx8I00jNUSaTFBQl0E4n7E
7+T6dmZLgyYovdDc+uEg018YQ/odvCVSVk0XnIxEixvDVlTgRJx81+F9PLbJhxy8
ygUZMaABO0AKbvWy/JH9BZCHNU9YXBrf4G4pkWcgGBS1d2hebV67dw==
=XnVG
-----END PGP SIGNATURE-----

--m1UC1K4AOz1Ywdkx--