xref: /openbsd-src/sys/kern/kern_exec.c (revision 131b88b7644b35e8c11076b61c4b82a23c06b3f6)
1*131b88b7Sjca /*	$OpenBSD: kern_exec.c,v 1.183 2016/09/03 14:28:24 jca Exp $	*/
25ac46f4aSniklas /*	$NetBSD: kern_exec.c,v 1.75 1996/02/09 18:59:28 christos Exp $	*/
3df930be7Sderaadt 
4df930be7Sderaadt /*-
5df930be7Sderaadt  * Copyright (C) 1993, 1994 Christopher G. Demetriou
6df930be7Sderaadt  * Copyright (C) 1992 Wolfgang Solfrank.
7df930be7Sderaadt  * Copyright (C) 1992 TooLs GmbH.
8df930be7Sderaadt  * All rights reserved.
9df930be7Sderaadt  *
10df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
11df930be7Sderaadt  * modification, are permitted provided that the following conditions
12df930be7Sderaadt  * are met:
13df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
14df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
15df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
16df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
17df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
18df930be7Sderaadt  * 3. All advertising materials mentioning features or use of this software
19df930be7Sderaadt  *    must display the following acknowledgement:
20df930be7Sderaadt  *	This product includes software developed by TooLs GmbH.
21df930be7Sderaadt  * 4. The name of TooLs GmbH may not be used to endorse or promote products
22df930be7Sderaadt  *    derived from this software without specific prior written permission.
23df930be7Sderaadt  *
24df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
25df930be7Sderaadt  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26df930be7Sderaadt  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27df930be7Sderaadt  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28df930be7Sderaadt  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29df930be7Sderaadt  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
30df930be7Sderaadt  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31df930be7Sderaadt  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32df930be7Sderaadt  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
33df930be7Sderaadt  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34df930be7Sderaadt  */
35df930be7Sderaadt 
36df930be7Sderaadt #include <sys/param.h>
37df930be7Sderaadt #include <sys/systm.h>
38df930be7Sderaadt #include <sys/filedesc.h>
39df930be7Sderaadt #include <sys/kernel.h>
40df930be7Sderaadt #include <sys/proc.h>
41df930be7Sderaadt #include <sys/mount.h>
42df930be7Sderaadt #include <sys/malloc.h>
43dbe27ba0Stedu #include <sys/pool.h>
44df930be7Sderaadt #include <sys/namei.h>
45df930be7Sderaadt #include <sys/vnode.h>
46df930be7Sderaadt #include <sys/file.h>
47df930be7Sderaadt #include <sys/acct.h>
48df930be7Sderaadt #include <sys/exec.h>
49df930be7Sderaadt #include <sys/ktrace.h>
50df930be7Sderaadt #include <sys/resourcevar.h>
51df930be7Sderaadt #include <sys/wait.h>
52df930be7Sderaadt #include <sys/mman.h>
53df930be7Sderaadt #include <sys/signalvar.h>
54df930be7Sderaadt #include <sys/stat.h>
55faa48718Sart #include <sys/conf.h>
56df174574Sderaadt #include <sys/pledge.h>
575ac46f4aSniklas #ifdef SYSVSHM
585ac46f4aSniklas #include <sys/shm.h>
595ac46f4aSniklas #endif
60df930be7Sderaadt 
61df930be7Sderaadt #include <sys/syscallargs.h>
62df930be7Sderaadt 
63fde894e5Stedu #include <uvm/uvm_extern.h>
64fde894e5Stedu 
65c6319251Sguenther #ifdef __HAVE_MD_TCB
66c6319251Sguenther # include <machine/tcb.h>
67c6319251Sguenther #endif
68c6319251Sguenther 
69b324ced2Skettenis const struct kmem_va_mode kv_exec = {
70b324ced2Skettenis 	.kv_wait = 1,
71b324ced2Skettenis 	.kv_map = &exec_map
72b324ced2Skettenis };
73b324ced2Skettenis 
74586305f1Sart /*
754a5480feSart  * Map the shared signal code.
764a5480feSart  */
77924be113Sguenther int exec_sigcode_map(struct process *, struct emul *);
784a5480feSart 
794a5480feSart /*
80b8736dc1Sderaadt  * If non-zero, stackgap_random specifies the upper limit of the random gap size
812bda40dcSmiod  * added to the fixed stack position. Must be n^2.
82586305f1Sart  */
83312d058fSderaadt int stackgap_random = STACKGAP_RANDOM;
84586305f1Sart 
85df930be7Sderaadt /*
86df930be7Sderaadt  * check exec:
87df930be7Sderaadt  * given an "executable" described in the exec package's namei info,
88df930be7Sderaadt  * see what we can do with it.
89df930be7Sderaadt  *
90df930be7Sderaadt  * ON ENTRY:
91df930be7Sderaadt  *	exec package with appropriate namei info
92df930be7Sderaadt  *	proc pointer of exec'ing proc
93df930be7Sderaadt  *	NO SELF-LOCKED VNODES
94df930be7Sderaadt  *
95df930be7Sderaadt  * ON EXIT:
96df930be7Sderaadt  *	error:	nothing held, etc.  exec header still allocated.
97df930be7Sderaadt  *	ok:	filled exec package, one locked vnode.
98df930be7Sderaadt  *
99df930be7Sderaadt  * EXEC SWITCH ENTRY:
100df930be7Sderaadt  * 	Locked vnode to check, exec package, proc.
101df930be7Sderaadt  *
102df930be7Sderaadt  * EXEC SWITCH EXIT:
103df930be7Sderaadt  *	ok:	return 0, filled exec package, one locked vnode.
104df930be7Sderaadt  *	error:	destructive:
105a3c911baSschwarze  *			everything deallocated except exec header.
106d84b7fccSmiod  *		non-destructive:
107df930be7Sderaadt  *			error code, locked vnode, exec header unmodified
108df930be7Sderaadt  */
109df930be7Sderaadt int
110158fb4f9Sjsg check_exec(struct proc *p, struct exec_package *epp)
111df930be7Sderaadt {
112df930be7Sderaadt 	int error, i;
113df930be7Sderaadt 	struct vnode *vp;
114df930be7Sderaadt 	struct nameidata *ndp;
1159b355cb2Smillert 	size_t resid;
116df930be7Sderaadt 
117df930be7Sderaadt 	ndp = epp->ep_ndp;
118df930be7Sderaadt 	ndp->ni_cnd.cn_nameiop = LOOKUP;
119df930be7Sderaadt 	ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF | SAVENAME;
120df930be7Sderaadt 	/* first get the vnode */
1215ac46f4aSniklas 	if ((error = namei(ndp)) != 0)
122bcfbf755Sniklas 		return (error);
123df930be7Sderaadt 	epp->ep_vp = vp = ndp->ni_vp;
124df930be7Sderaadt 
125df930be7Sderaadt 	/* check for regular file */
12668bf7897Stholo 	if (vp->v_type == VDIR) {
12768bf7897Stholo 		error = EISDIR;
12868bf7897Stholo 		goto bad1;
12968bf7897Stholo 	}
130df930be7Sderaadt 	if (vp->v_type != VREG) {
131df930be7Sderaadt 		error = EACCES;
132df930be7Sderaadt 		goto bad1;
133df930be7Sderaadt 	}
134df930be7Sderaadt 
135df930be7Sderaadt 	/* get attributes */
1365ac46f4aSniklas 	if ((error = VOP_GETATTR(vp, epp->ep_vap, p->p_ucred, p)) != 0)
137df930be7Sderaadt 		goto bad1;
138df930be7Sderaadt 
139df930be7Sderaadt 	/* Check mount point */
140df930be7Sderaadt 	if (vp->v_mount->mnt_flag & MNT_NOEXEC) {
141df930be7Sderaadt 		error = EACCES;
142df930be7Sderaadt 		goto bad1;
143df930be7Sderaadt 	}
144e55d0f86Sart 
14551f754c1Sart 	if ((vp->v_mount->mnt_flag & MNT_NOSUID))
14651f754c1Sart 		epp->ep_vap->va_mode &= ~(VSUID | VSGID);
147bfa108a0Sderaadt 
148df930be7Sderaadt 	/* check access.  for root we have to see if any exec bit on */
1495ac46f4aSniklas 	if ((error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p)) != 0)
150df930be7Sderaadt 		goto bad1;
151df930be7Sderaadt 	if ((epp->ep_vap->va_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0) {
152df930be7Sderaadt 		error = EACCES;
153df930be7Sderaadt 		goto bad1;
154df930be7Sderaadt 	}
155df930be7Sderaadt 
156df930be7Sderaadt 	/* try to open it */
1575ac46f4aSniklas 	if ((error = VOP_OPEN(vp, FREAD, p->p_ucred, p)) != 0)
158df930be7Sderaadt 		goto bad1;
159df930be7Sderaadt 
160d84dbf2eSart 	/* unlock vp, we need it unlocked from here */
161937fcae7Snatano 	VOP_UNLOCK(vp, p);
162d84dbf2eSart 
163df930be7Sderaadt 	/* now we have the file, get the exec header */
1645ac46f4aSniklas 	error = vn_rdwr(UIO_READ, vp, epp->ep_hdr, epp->ep_hdrlen, 0,
165d84dbf2eSart 	    UIO_SYSSPACE, 0, p->p_ucred, &resid, p);
1665ac46f4aSniklas 	if (error)
167df930be7Sderaadt 		goto bad2;
168df930be7Sderaadt 	epp->ep_hdrvalid = epp->ep_hdrlen - resid;
169df930be7Sderaadt 
170df930be7Sderaadt 	/*
171df930be7Sderaadt 	 * set up the vmcmds for creation of the process
172df930be7Sderaadt 	 * address space
173df930be7Sderaadt 	 */
174df930be7Sderaadt 	error = ENOEXEC;
175df930be7Sderaadt 	for (i = 0; i < nexecs && error != 0; i++) {
176df930be7Sderaadt 		int newerror;
177df930be7Sderaadt 
178df930be7Sderaadt 		if (execsw[i].es_check == NULL)
179df930be7Sderaadt 			continue;
180df930be7Sderaadt 		newerror = (*execsw[i].es_check)(p, epp);
181e20a449dStedu 		if (!newerror && !(epp->ep_emul->e_flags & EMUL_ENABLED))
182800da8d8Smiod 			newerror = EPERM;
183df930be7Sderaadt 		/* make sure the first "interesting" error code is saved. */
184df930be7Sderaadt 		if (!newerror || error == ENOEXEC)
185df930be7Sderaadt 			error = newerror;
186df930be7Sderaadt 		if (epp->ep_flags & EXEC_DESTR && error != 0)
187bcfbf755Sniklas 			return (error);
188df930be7Sderaadt 	}
189df930be7Sderaadt 	if (!error) {
190df930be7Sderaadt 		/* check that entry point is sane */
191ab30c277Spefo 		if (epp->ep_entry > VM_MAXUSER_ADDRESS) {
192df930be7Sderaadt 			error = ENOEXEC;
193ab30c277Spefo 		}
194df930be7Sderaadt 
195df930be7Sderaadt 		/* check limits */
196df930be7Sderaadt 		if ((epp->ep_tsize > MAXTSIZ) ||
197df930be7Sderaadt 		    (epp->ep_dsize > p->p_rlimit[RLIMIT_DATA].rlim_cur))
198df930be7Sderaadt 			error = ENOMEM;
199df930be7Sderaadt 
200df930be7Sderaadt 		if (!error)
201df930be7Sderaadt 			return (0);
202df930be7Sderaadt 	}
203df930be7Sderaadt 
204df930be7Sderaadt 	/*
205df930be7Sderaadt 	 * free any vmspace-creation commands,
206df930be7Sderaadt 	 * and release their references
207df930be7Sderaadt 	 */
208df930be7Sderaadt 	kill_vmcmds(&epp->ep_vmcmds);
209df930be7Sderaadt 
210df930be7Sderaadt bad2:
211df930be7Sderaadt 	/*
212d84dbf2eSart 	 * close the vnode, free the pathname buf, and punt.
213df930be7Sderaadt 	 */
214df930be7Sderaadt 	vn_close(vp, FREAD, p->p_ucred, p);
215dbe27ba0Stedu 	pool_put(&namei_pool, ndp->ni_cnd.cn_pnbuf);
216bcfbf755Sniklas 	return (error);
217df930be7Sderaadt 
218df930be7Sderaadt bad1:
219df930be7Sderaadt 	/*
220df930be7Sderaadt 	 * free the namei pathname buffer, and put the vnode
221df930be7Sderaadt 	 * (which we don't yet have open).
222df930be7Sderaadt 	 */
223dbe27ba0Stedu 	pool_put(&namei_pool, ndp->ni_cnd.cn_pnbuf);
224df930be7Sderaadt 	vput(vp);
225bcfbf755Sniklas 	return (error);
226df930be7Sderaadt }
227df930be7Sderaadt 
228df930be7Sderaadt /*
229df930be7Sderaadt  * exec system call
230df930be7Sderaadt  */
2315ac46f4aSniklas int
232158fb4f9Sjsg sys_execve(struct proc *p, void *v, register_t *retval)
233df930be7Sderaadt {
234586305f1Sart 	struct sys_execve_args /* {
23501b77f95Shenning 		syscallarg(const char *) path;
23601b77f95Shenning 		syscallarg(char *const *) argp;
23701b77f95Shenning 		syscallarg(char *const *) envp;
238df930be7Sderaadt 	} */ *uap = v;
239e20a449dStedu 	int error;
240df930be7Sderaadt 	struct exec_package pack;
241df930be7Sderaadt 	struct nameidata nid;
242df930be7Sderaadt 	struct vattr attr;
243df930be7Sderaadt 	struct ucred *cred = p->p_ucred;
244df930be7Sderaadt 	char *argp;
245d8434bb1Stholo 	char * const *cpp, *dp, *sp;
2465e0c3889Sguenther #ifdef KTRACE
2475e0c3889Sguenther 	char *env_start;
2485e0c3889Sguenther #endif
249bfb8af8fSguenther 	struct process *pr = p->p_p;
250df930be7Sderaadt 	long argc, envc;
251586305f1Sart 	size_t len, sgap;
252cc576edfSmickey #ifdef MACHINE_STACK_GROWS_UP
253cc576edfSmickey 	size_t slen;
254cc576edfSmickey #endif
255df930be7Sderaadt 	char *stack;
256df930be7Sderaadt 	struct ps_strings arginfo;
257924be113Sguenther 	struct vmspace *vm = pr->ps_vmspace;
258df930be7Sderaadt 	char **tmpfap;
259eb5fafa1Sderaadt 	extern struct emul emul_native;
2607359b57aStedu 	struct vnode *otvp;
261df930be7Sderaadt 
2622ea51a70Sguenther 	/* get other threads to stop */
2632ea51a70Sguenther 	if ((error = single_thread_set(p, SINGLE_UNWIND, 1)))
2641192233bSguenther 		return (error);
2652ea51a70Sguenther 
266df930be7Sderaadt 	/*
267d5f75ac0Sart 	 * Cheap solution to complicated problems.
268d5f75ac0Sart 	 * Mark this process as "leave me alone, I'm execing".
269d5f75ac0Sart 	 */
2706b6f3ef9Sguenther 	atomic_setbits_int(&pr->ps_flags, PS_INEXEC);
271d5f75ac0Sart 
27245573b1fSkettenis 	NDINIT(&nid, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
273345a92b4Ssemarie 	nid.ni_pledge = PLEDGE_EXEC;
274df930be7Sderaadt 
275df930be7Sderaadt 	/*
276df930be7Sderaadt 	 * initialize the fields of the exec package.
277df930be7Sderaadt 	 */
278d8434bb1Stholo 	pack.ep_name = (char *)SCARG(uap, path);
279176819c2Sart 	pack.ep_hdr = malloc(exec_maxhdrsz, M_EXEC, M_WAITOK);
280df930be7Sderaadt 	pack.ep_hdrlen = exec_maxhdrsz;
281df930be7Sderaadt 	pack.ep_hdrvalid = 0;
282df930be7Sderaadt 	pack.ep_ndp = &nid;
283c0c22b04Stedu 	pack.ep_interp = NULL;
284df930be7Sderaadt 	pack.ep_emul_arg = NULL;
2851bdf816eSart 	VMCMDSET_INIT(&pack.ep_vmcmds);
286df930be7Sderaadt 	pack.ep_vap = &attr;
287eb5fafa1Sderaadt 	pack.ep_emul = &emul_native;
288df930be7Sderaadt 	pack.ep_flags = 0;
289df930be7Sderaadt 
290df930be7Sderaadt 	/* see if we can run it. */
291ab30c277Spefo 	if ((error = check_exec(p, &pack)) != 0) {
292df930be7Sderaadt 		goto freehdr;
293ab30c277Spefo 	}
294df930be7Sderaadt 
295df930be7Sderaadt 	/* XXX -- THE FOLLOWING SECTION NEEDS MAJOR CLEANUP */
296df930be7Sderaadt 
297df930be7Sderaadt 	/* allocate an argument buffer */
298b324ced2Skettenis 	argp = km_alloc(NCARGS, &kv_exec, &kp_pageable, &kd_waitok);
299df930be7Sderaadt #ifdef DIAGNOSTIC
300b5099d50Snordin 	if (argp == NULL)
301df930be7Sderaadt 		panic("execve: argp == NULL");
302df930be7Sderaadt #endif
303df930be7Sderaadt 	dp = argp;
304df930be7Sderaadt 	argc = 0;
305df930be7Sderaadt 
306df930be7Sderaadt 	/* copy the fake args list, if there's one, freeing it as we go */
307df930be7Sderaadt 	if (pack.ep_flags & EXEC_HASARGL) {
308df930be7Sderaadt 		tmpfap = pack.ep_fa;
309df930be7Sderaadt 		while (*tmpfap != NULL) {
310df930be7Sderaadt 			char *cp;
311df930be7Sderaadt 
312df930be7Sderaadt 			cp = *tmpfap;
313df930be7Sderaadt 			while (*cp)
314df930be7Sderaadt 				*dp++ = *cp++;
315227892b1Sthib 			*dp++ = '\0';
316df930be7Sderaadt 
3179e8577e7Stedu 			free(*tmpfap, M_EXEC, 0);
318df930be7Sderaadt 			tmpfap++; argc++;
319df930be7Sderaadt 		}
3209e8577e7Stedu 		free(pack.ep_fa, M_EXEC, 0);
321df930be7Sderaadt 		pack.ep_flags &= ~EXEC_HASARGL;
322df930be7Sderaadt 	}
323df930be7Sderaadt 
324df930be7Sderaadt 	/* Now get argv & environment */
325df930be7Sderaadt 	if (!(cpp = SCARG(uap, argp))) {
326a5ceb13eSmickey 		error = EFAULT;
327df930be7Sderaadt 		goto bad;
328df930be7Sderaadt 	}
329df930be7Sderaadt 
330df930be7Sderaadt 	if (pack.ep_flags & EXEC_SKIPARG)
331df930be7Sderaadt 		cpp++;
332df930be7Sderaadt 
333df930be7Sderaadt 	while (1) {
334df930be7Sderaadt 		len = argp + ARG_MAX - dp;
3355ac46f4aSniklas 		if ((error = copyin(cpp, &sp, sizeof(sp))) != 0)
336df930be7Sderaadt 			goto bad;
337df930be7Sderaadt 		if (!sp)
338df930be7Sderaadt 			break;
3395ac46f4aSniklas 		if ((error = copyinstr(sp, dp, len, &len)) != 0) {
340df930be7Sderaadt 			if (error == ENAMETOOLONG)
341df930be7Sderaadt 				error = E2BIG;
342df930be7Sderaadt 			goto bad;
343df930be7Sderaadt 		}
344df930be7Sderaadt 		dp += len;
345df930be7Sderaadt 		cpp++;
346df930be7Sderaadt 		argc++;
347df930be7Sderaadt 	}
348df930be7Sderaadt 
34974212563Stedu 	/* must have at least one argument */
35074212563Stedu 	if (argc == 0) {
35174212563Stedu 		error = EINVAL;
35274212563Stedu 		goto bad;
35374212563Stedu 	}
35474212563Stedu 
3555e0c3889Sguenther #ifdef KTRACE
3565e0c3889Sguenther 	if (KTRPOINT(p, KTR_EXECARGS))
3575e0c3889Sguenther 		ktrexec(p, KTR_EXECARGS, argp, dp - argp);
3585e0c3889Sguenther #endif
3595e0c3889Sguenther 
360df930be7Sderaadt 	envc = 0;
361507f831cSmickey 	/* environment does not need to be there */
3625ac46f4aSniklas 	if ((cpp = SCARG(uap, envp)) != NULL ) {
3635e0c3889Sguenther #ifdef KTRACE
3645e0c3889Sguenther 		env_start = dp;
3655e0c3889Sguenther #endif
366df930be7Sderaadt 		while (1) {
367df930be7Sderaadt 			len = argp + ARG_MAX - dp;
3685ac46f4aSniklas 			if ((error = copyin(cpp, &sp, sizeof(sp))) != 0)
369df930be7Sderaadt 				goto bad;
370df930be7Sderaadt 			if (!sp)
371df930be7Sderaadt 				break;
3725ac46f4aSniklas 			if ((error = copyinstr(sp, dp, len, &len)) != 0) {
373df930be7Sderaadt 				if (error == ENAMETOOLONG)
374df930be7Sderaadt 					error = E2BIG;
375df930be7Sderaadt 				goto bad;
376df930be7Sderaadt 			}
377df930be7Sderaadt 			dp += len;
378df930be7Sderaadt 			cpp++;
379df930be7Sderaadt 			envc++;
380df930be7Sderaadt 		}
3815e0c3889Sguenther 
3825e0c3889Sguenther #ifdef KTRACE
3835e0c3889Sguenther 		if (KTRPOINT(p, KTR_EXECENV))
3845e0c3889Sguenther 			ktrexec(p, KTR_EXECENV, env_start, dp - env_start);
3855e0c3889Sguenther #endif
386df930be7Sderaadt 	}
387df930be7Sderaadt 
388b8736dc1Sderaadt 	dp = (char *)(((long)dp + _STACKALIGNBYTES) & ~_STACKALIGNBYTES);
389df930be7Sderaadt 
390586305f1Sart 	sgap = STACKGAPLEN;
3912bda40dcSmiod 
3922bda40dcSmiod 	/*
3932bda40dcSmiod 	 * If we have enabled random stackgap, the stack itself has already
3942bda40dcSmiod 	 * been moved from a random location, but is still aligned to a page
3952bda40dcSmiod 	 * boundary.  Provide the lower bits of random placement now.
3962bda40dcSmiod 	 */
397b8736dc1Sderaadt 	if (stackgap_random != 0) {
3982bda40dcSmiod 		sgap += arc4random() & PAGE_MASK;
399b8736dc1Sderaadt 		sgap = (sgap + _STACKALIGNBYTES) & ~_STACKALIGNBYTES;
400b8736dc1Sderaadt 	}
401b8736dc1Sderaadt 
402df930be7Sderaadt 	/* Now check if args & environ fit into new stack */
403df930be7Sderaadt 	len = ((argc + envc + 2 + pack.ep_emul->e_arglen) * sizeof(char *) +
4044a5480feSart 	    sizeof(long) + dp + sgap + sizeof(struct ps_strings)) - argp;
405df930be7Sderaadt 
406b8736dc1Sderaadt 	len = (len + _STACKALIGNBYTES) &~ _STACKALIGNBYTES;
407df930be7Sderaadt 
408df930be7Sderaadt 	if (len > pack.ep_ssize) { /* in effect, compare to initial limit */
409df930be7Sderaadt 		error = ENOMEM;
410df930be7Sderaadt 		goto bad;
411df930be7Sderaadt 	}
412df930be7Sderaadt 
413df930be7Sderaadt 	/* adjust "active stack depth" for process VSZ */
414df930be7Sderaadt 	pack.ep_ssize = len;	/* maybe should go elsewhere, but... */
415df930be7Sderaadt 
41686607369Sart 	/*
4172ea51a70Sguenther 	 * we're committed: any further errors will kill the process, so
4182ea51a70Sguenther 	 * kill the other threads now.
4192ea51a70Sguenther 	 */
4202ea51a70Sguenther 	single_thread_set(p, SINGLE_EXIT, 0);
4212ea51a70Sguenther 
4222ea51a70Sguenther 	/*
42386607369Sart 	 * Prepare vmspace for remapping. Note that uvmspace_exec can replace
424924be113Sguenther 	 * pr_vmspace!
42586607369Sart 	 */
426cac1bff1Sart 	uvmspace_exec(p, VM_MIN_ADDRESS, VM_MAXUSER_ADDRESS);
427df930be7Sderaadt 
428924be113Sguenther 	vm = pr->ps_vmspace;
429df930be7Sderaadt 	/* Now map address space */
430ff3fdef1Skettenis 	vm->vm_taddr = (char *)trunc_page(pack.ep_taddr);
431ff3fdef1Skettenis 	vm->vm_tsize = atop(round_page(pack.ep_taddr + pack.ep_tsize) -
432ff3fdef1Skettenis 	    trunc_page(pack.ep_taddr));
433ff3fdef1Skettenis 	vm->vm_daddr = (char *)trunc_page(pack.ep_daddr);
434ff3fdef1Skettenis 	vm->vm_dsize = atop(round_page(pack.ep_daddr + pack.ep_dsize) -
435ff3fdef1Skettenis 	    trunc_page(pack.ep_daddr));
4360ebeee85Sderaadt 	vm->vm_dused = 0;
43776d52da2Smartin 	vm->vm_ssize = atop(round_page(pack.ep_ssize));
438df930be7Sderaadt 	vm->vm_maxsaddr = (char *)pack.ep_maxsaddr;
439d9040bf8Smickey 	vm->vm_minsaddr = (char *)pack.ep_minsaddr;
440df930be7Sderaadt 
441df930be7Sderaadt 	/* create the new process's VM space by running the vmcmds */
442df930be7Sderaadt #ifdef DIAGNOSTIC
443df930be7Sderaadt 	if (pack.ep_vmcmds.evs_used == 0)
444df930be7Sderaadt 		panic("execve: no vmcmds");
445df930be7Sderaadt #endif
4461e04e351Sart 	error = exec_process_vmcmds(p, &pack);
447df930be7Sderaadt 
448df930be7Sderaadt 	/* if an error happened, deallocate and punt */
449df930be7Sderaadt 	if (error)
450df930be7Sderaadt 		goto exec_abort;
451df930be7Sderaadt 
45256b6d613Skettenis 	/* old "stackgap" is gone now */
45356b6d613Skettenis 	pr->ps_stackgap = 0;
45456b6d613Skettenis 
45556b6d613Skettenis #ifdef MACHINE_STACK_GROWS_UP
4567180d9eaSmiod 	pr->ps_strings = (vaddr_t)vm->vm_maxsaddr + sgap;
45756b6d613Skettenis         if (uvm_map_protect(&vm->vm_map, (vaddr_t)vm->vm_maxsaddr,
45856b6d613Skettenis             trunc_page(pr->ps_strings), PROT_NONE, TRUE))
45956b6d613Skettenis                 goto exec_abort;
46056b6d613Skettenis #else
4617180d9eaSmiod 	pr->ps_strings = (vaddr_t)vm->vm_minsaddr - sizeof(arginfo) - sgap;
46256b6d613Skettenis         if (uvm_map_protect(&vm->vm_map,
46356b6d613Skettenis             round_page(pr->ps_strings + sizeof(arginfo)),
46456b6d613Skettenis             (vaddr_t)vm->vm_minsaddr, PROT_NONE, TRUE))
46556b6d613Skettenis                 goto exec_abort;
46656b6d613Skettenis #endif
46756b6d613Skettenis 
468df930be7Sderaadt 	/* remember information about the process */
469df930be7Sderaadt 	arginfo.ps_nargvstr = argc;
470df930be7Sderaadt 	arginfo.ps_nenvstr = envc;
471df930be7Sderaadt 
472910e6419Smickey #ifdef MACHINE_STACK_GROWS_UP
4737180d9eaSmiod 	stack = (char *)vm->vm_maxsaddr + sizeof(arginfo) + sgap;
474f18df0c5Skettenis 	slen = len - sizeof(arginfo) - sgap;
475910e6419Smickey #else
4767180d9eaSmiod 	stack = (char *)(vm->vm_minsaddr - len);
477910e6419Smickey #endif
478df930be7Sderaadt 	/* Now copy argc, args & environ to new stack */
479df930be7Sderaadt 	if (!(*pack.ep_emul->e_copyargs)(&pack, &arginfo, stack, argp))
480df930be7Sderaadt 		goto exec_abort;
481df930be7Sderaadt 
482df930be7Sderaadt 	/* copy out the process's ps_strings structure */
483a78264c4Skettenis 	if (copyout(&arginfo, (char *)pr->ps_strings, sizeof(arginfo)))
484df930be7Sderaadt 		goto exec_abort;
485df930be7Sderaadt 
48618914fdfSguenther 	stopprofclock(pr);	/* stop profiling */
487df930be7Sderaadt 	fdcloseexec(p);		/* handle close on exec */
488611924b3Smiod 	execsigs(p);		/* reset caught signals */
489c6319251Sguenther 	TCB_SET(p, NULL);	/* reset the TCB address */
490440e6fe6Sguenther 	pr->ps_kbind_addr = 0;	/* reset the kbind bits */
491440e6fe6Sguenther 	pr->ps_kbind_cookie = 0;
4927730d1d9Sderaadt 	arc4random_buf(&pr->ps_sigcookie, sizeof pr->ps_sigcookie);
493df930be7Sderaadt 
494df930be7Sderaadt 	/* set command name & other accounting info */
49591ba896dStedu 	memset(p->p_comm, 0, sizeof(p->p_comm));
496df930be7Sderaadt 	len = min(nid.ni_cnd.cn_namelen, MAXCOMLEN);
4972955d5bcStedu 	memcpy(p->p_comm, nid.ni_cnd.cn_nameptr, len);
4980839b846Smikeb 	pr->ps_acflag &= ~AFORK;
499df930be7Sderaadt 
500cf6677a6Sguenther 	/* record proc's vnode, for use by sysctl */
5014ab8ed70Sguenther 	otvp = pr->ps_textvp;
502627b2c48Sthib 	vref(pack.ep_vp);
5034ab8ed70Sguenther 	pr->ps_textvp = pack.ep_vp;
5047359b57aStedu 	if (otvp)
5057359b57aStedu 		vrele(otvp);
506df930be7Sderaadt 
507e2590abeSguenther 	atomic_setbits_int(&pr->ps_flags, PS_EXEC);
508c0ce47d9Sguenther 	if (pr->ps_flags & PS_PPWAIT) {
509c0ce47d9Sguenther 		atomic_clearbits_int(&pr->ps_flags, PS_PPWAIT);
510c0ce47d9Sguenther 		atomic_clearbits_int(&pr->ps_pptr->ps_flags, PS_ISPWAIT);
511bfb8af8fSguenther 		wakeup(pr->ps_pptr);
512df930be7Sderaadt 	}
513df930be7Sderaadt 
514df930be7Sderaadt 	/*
515855755d9Smillert 	 * If process does execve() while it has a mismatched real,
516bfb8af8fSguenther 	 * effective, or saved uid/gid, we set PS_SUGIDEXEC.
51725b40de6Sderaadt 	 */
518d559b8cbSguenther 	if (cred->cr_uid != cred->cr_ruid ||
519d559b8cbSguenther 	    cred->cr_uid != cred->cr_svuid ||
520d559b8cbSguenther 	    cred->cr_gid != cred->cr_rgid ||
521d559b8cbSguenther 	    cred->cr_gid != cred->cr_svgid)
522bfb8af8fSguenther 		atomic_setbits_int(&pr->ps_flags, PS_SUGIDEXEC);
523855755d9Smillert 	else
524bfb8af8fSguenther 		atomic_clearbits_int(&pr->ps_flags, PS_SUGIDEXEC);
52525b40de6Sderaadt 
526df174574Sderaadt 	atomic_clearbits_int(&pr->ps_flags, PS_PLEDGE);
527df174574Sderaadt 	pledge_dropwpaths(pr);
528609289baSderaadt 
52925b40de6Sderaadt 	/*
530df930be7Sderaadt 	 * deal with set[ug]id.
53151f754c1Sart 	 * MNT_NOEXEC has already been used to disable s[ug]id.
532df930be7Sderaadt 	 */
53351f754c1Sart 	if ((attr.va_mode & (VSUID | VSGID)) && proc_cansugid(p)) {
534bbf7a176Sderaadt 		int i;
535bbf7a176Sderaadt 
536bfb8af8fSguenther 		atomic_setbits_int(&pr->ps_flags, PS_SUGID|PS_SUGIDEXEC);
53751f754c1Sart 
538df930be7Sderaadt #ifdef KTRACE
539df930be7Sderaadt 		/*
540df930be7Sderaadt 		 * If process is being ktraced, turn off - unless
541df930be7Sderaadt 		 * root set it.
542df930be7Sderaadt 		 */
543a2e04e14Sguenther 		if (pr->ps_tracevp && !(pr->ps_traceflag & KTRFAC_ROOT))
544a2e04e14Sguenther 			ktrcleartrace(pr);
545df930be7Sderaadt #endif
546d559b8cbSguenther 		p->p_ucred = cred = crcopy(cred);
547df930be7Sderaadt 		if (attr.va_mode & VSUID)
548d559b8cbSguenther 			cred->cr_uid = attr.va_uid;
549df930be7Sderaadt 		if (attr.va_mode & VSGID)
550d559b8cbSguenther 			cred->cr_gid = attr.va_gid;
551bbf7a176Sderaadt 
552bbf7a176Sderaadt 		/*
553bba8c139Sderaadt 		 * For set[ug]id processes, a few caveats apply to
554bba8c139Sderaadt 		 * stdin, stdout, and stderr.
555bbf7a176Sderaadt 		 */
556638f0017Sguenther 		error = 0;
557638f0017Sguenther 		fdplock(p->p_fd);
558bbf7a176Sderaadt 		for (i = 0; i < 3; i++) {
559c3315ca6Sderaadt 			struct file *fp = NULL;
560c3315ca6Sderaadt 
561af97e5cfSart 			/*
562af97e5cfSart 			 * NOTE - This will never return NULL because of
5632addf348Sjmc 			 * immature fds. The file descriptor table is not
564af97e5cfSart 			 * shared because we're suid.
565af97e5cfSart 			 */
566af97e5cfSart 			fp = fd_getfile(p->p_fd, i);
567c3315ca6Sderaadt 
568c3315ca6Sderaadt 			/*
569c3315ca6Sderaadt 			 * Ensure that stdin, stdout, and stderr are already
570c3315ca6Sderaadt 			 * allocated.  We do not want userland to accidentally
571c3315ca6Sderaadt 			 * allocate descriptors in this range which has implied
572c3315ca6Sderaadt 			 * meaning to libc.
573c3315ca6Sderaadt 			 */
574c3315ca6Sderaadt 			if (fp == NULL) {
575c3315ca6Sderaadt 				short flags = FREAD | (i == 0 ? 0 : FWRITE);
576faa48718Sart 				struct vnode *vp;
577bbf7a176Sderaadt 				int indx;
57858d9451eSart 
579bbf7a176Sderaadt 				if ((error = falloc(p, &fp, &indx)) != 0)
580638f0017Sguenther 					break;
581faa48718Sart #ifdef DIAGNOSTIC
582faa48718Sart 				if (indx != i)
583faa48718Sart 					panic("sys_execve: falloc indx != i");
584faa48718Sart #endif
585faa48718Sart 				if ((error = cdevvp(getnulldev(), &vp)) != 0) {
586bb720fc6Sprovos 					fdremove(p->p_fd, indx);
58743c6a78bSart 					closef(fp, p);
588638f0017Sguenther 					break;
589bbf7a176Sderaadt 				}
590d559b8cbSguenther 				if ((error = VOP_OPEN(vp, flags, cred, p)) != 0) {
591faa48718Sart 					fdremove(p->p_fd, indx);
59243c6a78bSart 					closef(fp, p);
593faa48718Sart 					vrele(vp);
594638f0017Sguenther 					break;
595faa48718Sart 				}
596faa48718Sart 				if (flags & FWRITE)
597faa48718Sart 					vp->v_writecount++;
59858d9451eSart 				fp->f_flag = flags;
599bbf7a176Sderaadt 				fp->f_type = DTYPE_VNODE;
600bbf7a176Sderaadt 				fp->f_ops = &vnops;
601faa48718Sart 				fp->f_data = (caddr_t)vp;
60206a89b59Sguenther 				FILE_SET_MATURE(fp, p);
603bbf7a176Sderaadt 			}
604bbf7a176Sderaadt 		}
605638f0017Sguenther 		fdpunlock(p->p_fd);
606638f0017Sguenther 		if (error)
607638f0017Sguenther 			goto exec_abort;
60825b40de6Sderaadt 	} else
609bfb8af8fSguenther 		atomic_clearbits_int(&pr->ps_flags, PS_SUGID);
610d559b8cbSguenther 
611a9ddc286Sguenther 	/*
612a9ddc286Sguenther 	 * Reset the saved ugids and update the process's copy of the
613a9ddc286Sguenther 	 * creds if the creds have been changed
614a9ddc286Sguenther 	 */
615d559b8cbSguenther 	if (cred->cr_uid != cred->cr_svuid ||
616d559b8cbSguenther 	    cred->cr_gid != cred->cr_svgid) {
617d559b8cbSguenther 		/* make sure we have unshared ucreds */
618d559b8cbSguenther 		p->p_ucred = cred = crcopy(cred);
619d559b8cbSguenther 		cred->cr_svuid = cred->cr_uid;
620d559b8cbSguenther 		cred->cr_svgid = cred->cr_gid;
621d559b8cbSguenther 	}
622df930be7Sderaadt 
623a9ddc286Sguenther 	if (pr->ps_ucred != cred) {
624a9ddc286Sguenther 		struct ucred *ocred;
625a9ddc286Sguenther 
626a9ddc286Sguenther 		ocred = pr->ps_ucred;
627a9ddc286Sguenther 		crhold(cred);
628a9ddc286Sguenther 		pr->ps_ucred = cred;
629a9ddc286Sguenther 		crfree(ocred);
630a9ddc286Sguenther 	}
631a9ddc286Sguenther 
632bfb8af8fSguenther 	if (pr->ps_flags & PS_SUGIDEXEC) {
633baf3eb4dSderaadt 		int i, s = splclock();
634baf3eb4dSderaadt 
6358f15e6a4Sguenther 		timeout_del(&pr->ps_realit_to);
6368f15e6a4Sguenther 		for (i = 0; i < nitems(pr->ps_timer); i++) {
6378f15e6a4Sguenther 			timerclear(&pr->ps_timer[i].it_interval);
6388f15e6a4Sguenther 			timerclear(&pr->ps_timer[i].it_value);
639baf3eb4dSderaadt 		}
64021b2622bSderaadt 		splx(s);
64121b2622bSderaadt 	}
64221b2622bSderaadt 
6437b36c281Sguenther 	/* reset CPU time usage for the thread, but not the process */
6447b36c281Sguenther 	timespecclear(&p->p_tu.tu_runtime);
6457b36c281Sguenther 	p->p_tu.tu_uticks = p->p_tu.tu_sticks = p->p_tu.tu_iticks = 0;
6467b36c281Sguenther 
647b324ced2Skettenis 	km_free(argp, NCARGS, &kv_exec, &kp_pageable);
648df930be7Sderaadt 
649dbe27ba0Stedu 	pool_put(&namei_pool, nid.ni_cnd.cn_pnbuf);
650d84dbf2eSart 	vn_close(pack.ep_vp, FREAD, cred, p);
651df930be7Sderaadt 
6521a12e8a7Sprovos 	/*
6531a12e8a7Sprovos 	 * notify others that we exec'd
6541a12e8a7Sprovos 	 */
655bfb8af8fSguenther 	KNOTE(&pr->ps_klist, NOTE_EXEC);
6561a12e8a7Sprovos 
657df930be7Sderaadt 	/* setup new registers and do misc. setup. */
658ab30c277Spefo 	if (pack.ep_emul->e_fixup != NULL) {
659ab30c277Spefo 		if ((*pack.ep_emul->e_fixup)(p, &pack) != 0)
660ab30c277Spefo 			goto free_pack_abort;
661ab30c277Spefo 	}
662910e6419Smickey #ifdef MACHINE_STACK_GROWS_UP
663cc576edfSmickey 	(*pack.ep_emul->e_setregs)(p, &pack, (u_long)stack + slen, retval);
664910e6419Smickey #else
665df930be7Sderaadt 	(*pack.ep_emul->e_setregs)(p, &pack, (u_long)stack, retval);
666910e6419Smickey #endif
667df930be7Sderaadt 
6684a5480feSart 	/* map the process's signal trampoline code */
669924be113Sguenther 	if (exec_sigcode_map(pr, pack.ep_emul))
670c0c22b04Stedu 		goto free_pack_abort;
6714a5480feSart 
6724c0d1b1bSmiod #ifdef __HAVE_EXEC_MD_MAP
6734c0d1b1bSmiod 	/* perform md specific mappings that process might need */
6744c0d1b1bSmiod 	if (exec_md_map(p, &pack))
6754c0d1b1bSmiod 		goto free_pack_abort;
6764c0d1b1bSmiod #endif
6774c0d1b1bSmiod 
6786b6f3ef9Sguenther 	if (pr->ps_flags & PS_TRACED)
679df930be7Sderaadt 		psignal(p, SIGTRAP);
680df930be7Sderaadt 
6817da957a5Sderaadt 	free(pack.ep_hdr, M_EXEC, pack.ep_hdrlen);
682df930be7Sderaadt 
683abc163f4Stedu 	/*
684abc163f4Stedu 	 * Call emulation specific exec hook. This can setup per-process
685abc163f4Stedu 	 * p->p_emuldata or do any other per-process stuff an emulation needs.
686abc163f4Stedu 	 *
687abc163f4Stedu 	 * If we are executing process of different emulation than the
688abc163f4Stedu 	 * original forked process, call e_proc_exit() of the old emulation
689abc163f4Stedu 	 * first, then e_proc_exec() of new emulation. If the emulation is
690abc163f4Stedu 	 * same, the exec hook code should deallocate any old emulation
691abc163f4Stedu 	 * resources held previously by this process.
692abc163f4Stedu 	 */
6938f76f5adSguenther 	if (pr->ps_emul && pr->ps_emul->e_proc_exit &&
6948f76f5adSguenther 	    pr->ps_emul != pack.ep_emul)
6958f76f5adSguenther 		(*pr->ps_emul->e_proc_exit)(p);
696abc163f4Stedu 
697d9f343eeSderaadt 	p->p_descfd = 255;
698d9f343eeSderaadt 	if ((pack.ep_flags & EXEC_HASFD) && pack.ep_fd < 255)
699d9f343eeSderaadt 		p->p_descfd = pack.ep_fd;
700d9f343eeSderaadt 
701f68ce565Sderaadt 	if (pack.ep_flags & EXEC_WXNEEDED)
702f68ce565Sderaadt 		p->p_p->ps_flags |= PS_WXNEEDED;
703*131b88b7Sjca 	else
704*131b88b7Sjca 		p->p_p->ps_flags &= ~PS_WXNEEDED;
705f68ce565Sderaadt 
706abc163f4Stedu 	/*
707abc163f4Stedu 	 * Call exec hook. Emulation code may NOT store reference to anything
708abc163f4Stedu 	 * from &pack.
709abc163f4Stedu 	 */
710abc163f4Stedu 	if (pack.ep_emul->e_proc_exec)
711abc163f4Stedu 		(*pack.ep_emul->e_proc_exec)(p, &pack);
712abc163f4Stedu 
7135e0c3889Sguenther 	/* update ps_emul, the old value is no longer needed */
7145e0c3889Sguenther 	pr->ps_emul = pack.ep_emul;
7155c025fc6Smarius 
7166b6f3ef9Sguenther 	atomic_clearbits_int(&pr->ps_flags, PS_INEXEC);
7174ec19540Skettenis 	single_thread_clear(p, P_SUSPSIG);
7185c025fc6Smarius 
719bcfbf755Sniklas 	return (0);
720df930be7Sderaadt 
721df930be7Sderaadt bad:
722df930be7Sderaadt 	/* free the vmspace-creation commands, and release their references */
723df930be7Sderaadt 	kill_vmcmds(&pack.ep_vmcmds);
724df930be7Sderaadt 	/* kill any opened file descriptor, if necessary */
725df930be7Sderaadt 	if (pack.ep_flags & EXEC_HASFD) {
726df930be7Sderaadt 		pack.ep_flags &= ~EXEC_HASFD;
727638f0017Sguenther 		fdplock(p->p_fd);
728df930be7Sderaadt 		(void) fdrelease(p, pack.ep_fd);
729638f0017Sguenther 		fdpunlock(p->p_fd);
730df930be7Sderaadt 	}
731c0c22b04Stedu 	if (pack.ep_interp != NULL)
732335c12deSmickey 		pool_put(&namei_pool, pack.ep_interp);
733c0c22b04Stedu 	if (pack.ep_emul_arg != NULL)
7347da957a5Sderaadt 		free(pack.ep_emul_arg, M_TEMP, pack.ep_emul_argsize);
735df930be7Sderaadt 	/* close and put the exec'd file */
736d84dbf2eSart 	vn_close(pack.ep_vp, FREAD, cred, p);
737dbe27ba0Stedu 	pool_put(&namei_pool, nid.ni_cnd.cn_pnbuf);
738b324ced2Skettenis 	km_free(argp, NCARGS, &kv_exec, &kp_pageable);
739df930be7Sderaadt 
740df930be7Sderaadt freehdr:
7417da957a5Sderaadt 	free(pack.ep_hdr, M_EXEC, pack.ep_hdrlen);
7426b6f3ef9Sguenther 	atomic_clearbits_int(&pr->ps_flags, PS_INEXEC);
7434ec19540Skettenis 	single_thread_clear(p, P_SUSPSIG);
744a792ab75Sart 
745bcfbf755Sniklas 	return (error);
746df930be7Sderaadt 
747df930be7Sderaadt exec_abort:
748df930be7Sderaadt 	/*
749df930be7Sderaadt 	 * the old process doesn't exist anymore.  exit gracefully.
750df930be7Sderaadt 	 * get rid of the (new) address space we have created, if any, get rid
751df930be7Sderaadt 	 * of our namei data and vnode, and exit noting failure
752df930be7Sderaadt 	 */
75356e05e0fSart 	uvm_deallocate(&vm->vm_map, VM_MIN_ADDRESS,
75456e05e0fSart 		VM_MAXUSER_ADDRESS - VM_MIN_ADDRESS);
755c0c22b04Stedu 	if (pack.ep_interp != NULL)
756335c12deSmickey 		pool_put(&namei_pool, pack.ep_interp);
757c0c22b04Stedu 	if (pack.ep_emul_arg != NULL)
7587da957a5Sderaadt 		free(pack.ep_emul_arg, M_TEMP, pack.ep_emul_argsize);
759dbe27ba0Stedu 	pool_put(&namei_pool, nid.ni_cnd.cn_pnbuf);
760d84dbf2eSart 	vn_close(pack.ep_vp, FREAD, cred, p);
761b324ced2Skettenis 	km_free(argp, NCARGS, &kv_exec, &kp_pageable);
762ab30c277Spefo 
763ab30c277Spefo free_pack_abort:
7647da957a5Sderaadt 	free(pack.ep_hdr, M_EXEC, pack.ep_hdrlen);
765802bb6acStedu 	exit1(p, W_EXITCODE(0, SIGABRT), EXIT_NORMAL);
766df930be7Sderaadt 
767df930be7Sderaadt 	/* NOTREACHED */
7686b6f3ef9Sguenther 	atomic_clearbits_int(&pr->ps_flags, PS_INEXEC);
769a792ab75Sart 
770bcfbf755Sniklas 	return (0);
771df930be7Sderaadt }
772df930be7Sderaadt 
773df930be7Sderaadt 
774df930be7Sderaadt void *
775158fb4f9Sjsg copyargs(struct exec_package *pack, struct ps_strings *arginfo, void *stack,
776158fb4f9Sjsg     void *argp)
777df930be7Sderaadt {
778df930be7Sderaadt 	char **cpp = stack;
779df930be7Sderaadt 	char *dp, *sp;
780df930be7Sderaadt 	size_t len;
781df930be7Sderaadt 	void *nullp = NULL;
782d2b5d78fSart 	long argc = arginfo->ps_nargvstr;
783df930be7Sderaadt 	int envc = arginfo->ps_nenvstr;
784df930be7Sderaadt 
785df930be7Sderaadt 	if (copyout(&argc, cpp++, sizeof(argc)))
786bcfbf755Sniklas 		return (NULL);
787df930be7Sderaadt 
788df930be7Sderaadt 	dp = (char *) (cpp + argc + envc + 2 + pack->ep_emul->e_arglen);
789df930be7Sderaadt 	sp = argp;
790df930be7Sderaadt 
791df930be7Sderaadt 	/* XXX don't copy them out, remap them! */
792df930be7Sderaadt 	arginfo->ps_argvstr = cpp; /* remember location of argv for later */
793df930be7Sderaadt 
794df930be7Sderaadt 	for (; --argc >= 0; sp += len, dp += len)
795df930be7Sderaadt 		if (copyout(&dp, cpp++, sizeof(dp)) ||
796df930be7Sderaadt 		    copyoutstr(sp, dp, ARG_MAX, &len))
797bcfbf755Sniklas 			return (NULL);
798df930be7Sderaadt 
799df930be7Sderaadt 	if (copyout(&nullp, cpp++, sizeof(nullp)))
800bcfbf755Sniklas 		return (NULL);
801df930be7Sderaadt 
802df930be7Sderaadt 	arginfo->ps_envstr = cpp; /* remember location of envp for later */
803df930be7Sderaadt 
804df930be7Sderaadt 	for (; --envc >= 0; sp += len, dp += len)
805df930be7Sderaadt 		if (copyout(&dp, cpp++, sizeof(dp)) ||
806df930be7Sderaadt 		    copyoutstr(sp, dp, ARG_MAX, &len))
807bcfbf755Sniklas 			return (NULL);
808df930be7Sderaadt 
809df930be7Sderaadt 	if (copyout(&nullp, cpp++, sizeof(nullp)))
810bcfbf755Sniklas 		return (NULL);
811df930be7Sderaadt 
812bcfbf755Sniklas 	return (cpp);
813df930be7Sderaadt }
8144a5480feSart 
8154a5480feSart int
816924be113Sguenther exec_sigcode_map(struct process *pr, struct emul *e)
8174a5480feSart {
8184a5480feSart 	vsize_t sz;
8194a5480feSart 
8204a5480feSart 	sz = (vaddr_t)e->e_esigcode - (vaddr_t)e->e_sigcode;
8214a5480feSart 
8224a5480feSart 	/*
8234a5480feSart 	 * If we don't have a sigobject for this emulation, create one.
8244a5480feSart 	 *
8254a5480feSart 	 * sigobject is an anonymous memory object (just like SYSV shared
8264a5480feSart 	 * memory) that we keep a permanent reference to and that we map
8274a5480feSart 	 * in all processes that need this sigcode. The creation is simple,
8284a5480feSart 	 * we create an object, add a permanent reference to it, map it in
8294a5480feSart 	 * kernel space, copy out the sigcode to it and unmap it.
8307fb77204Sgrange 	 * Then we map it with PROT_READ|PROT_EXEC into the process just
8314a5480feSart 	 * the way sys_mmap would map it.
8324a5480feSart 	 */
8334a5480feSart 	if (e->e_sigobject == NULL) {
834b983598cSderaadt 		extern int sigfillsiz;
835b983598cSderaadt 		extern u_char sigfill[];
836b983598cSderaadt 		size_t off;
8374a5480feSart 		vaddr_t va;
8384a5480feSart 		int r;
8394a5480feSart 
8404a5480feSart 		e->e_sigobject = uao_create(sz, 0);
8414a5480feSart 		uao_reference(e->e_sigobject);	/* permanent reference */
8424a5480feSart 
8434a5480feSart 		if ((r = uvm_map(kernel_map, &va, round_page(sz), e->e_sigobject,
8441e8cdc2eSderaadt 		    0, 0, UVM_MAPFLAG(PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE,
84515cd8707Sguenther 		    MAP_INHERIT_SHARE, MADV_RANDOM, 0)))) {
846e481f8e1Smillert 			uao_detach(e->e_sigobject);
8474a5480feSart 			return (ENOMEM);
8484a5480feSart 		}
849b983598cSderaadt 
850b983598cSderaadt 		for (off = 0; off < round_page(sz); off += sigfillsiz)
851b983598cSderaadt 			memcpy((caddr_t)va + off, sigfill, sigfillsiz);
852b983598cSderaadt 		memcpy((caddr_t)va, e->e_sigcode, sz);
8534a5480feSart 		uvm_unmap(kernel_map, va, va + round_page(sz));
8544a5480feSart 	}
8554a5480feSart 
856924be113Sguenther 	pr->ps_sigcode = 0; /* no hint */
8574a5480feSart 	uao_reference(e->e_sigobject);
858924be113Sguenther 	if (uvm_map(&pr->ps_vmspace->vm_map, &pr->ps_sigcode, round_page(sz),
8591e8cdc2eSderaadt 	    e->e_sigobject, 0, 0, UVM_MAPFLAG(PROT_READ | PROT_EXEC,
86012ccc845Skettenis 	    PROT_READ | PROT_WRITE | PROT_EXEC, MAP_INHERIT_COPY,
861a47732feSkettenis 	    MADV_RANDOM, UVM_FLAG_COPYONW))) {
862e481f8e1Smillert 		uao_detach(e->e_sigobject);
8634a5480feSart 		return (ENOMEM);
8644a5480feSart 	}
8654a5480feSart 
8667730d1d9Sderaadt 	/* Calculate PC at point of sigreturn entry */
8677730d1d9Sderaadt 	pr->ps_sigcoderet = pr->ps_sigcode +
8687730d1d9Sderaadt 	    (pr->ps_emul->e_esigret - pr->ps_emul->e_sigcode);
8697730d1d9Sderaadt 
8704a5480feSart 	return (0);
8714a5480feSart }
872