xref: /freebsd/sys/kern/kern_exec.c (revision 6d5a0a8c236d7f2b270d4abd38ac94c0c08fb424)
126f9a767SRodney W. Grimes /*
226f9a767SRodney W. Grimes  * Copyright (c) 1993, David Greenman
326f9a767SRodney W. Grimes  * All rights reserved.
4df8bae1dSRodney W. Grimes  *
5df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
6df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
7df8bae1dSRodney W. Grimes  * are met:
8df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
9df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
10df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
11df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
12df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
13df8bae1dSRodney W. Grimes  *
1426f9a767SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1726f9a767SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
25df8bae1dSRodney W. Grimes  *
266d5a0a8cSDavid Greenman  *	$Id: kern_exec.c,v 1.54 1997/04/04 01:30:33 davidg Exp $
27df8bae1dSRodney W. Grimes  */
28df8bae1dSRodney W. Grimes 
29df8bae1dSRodney W. Grimes #include <sys/param.h>
3026f9a767SRodney W. Grimes #include <sys/systm.h>
31d2d3e875SBruce Evans #include <sys/sysproto.h>
3226f9a767SRodney W. Grimes #include <sys/signalvar.h>
3326f9a767SRodney W. Grimes #include <sys/kernel.h>
3426f9a767SRodney W. Grimes #include <sys/mount.h>
35797f2d22SPoul-Henning Kamp #include <sys/filedesc.h>
36079cc25bSDavid Greenman #include <sys/fcntl.h>
3726f9a767SRodney W. Grimes #include <sys/acct.h>
3826f9a767SRodney W. Grimes #include <sys/exec.h>
3926f9a767SRodney W. Grimes #include <sys/imgact.h>
40e1743d02SSøren Schmidt #include <sys/imgact_elf.h>
4126f9a767SRodney W. Grimes #include <sys/wait.h>
42a794e791SBruce Evans #include <sys/proc.h>
4326f9a767SRodney W. Grimes #include <sys/malloc.h>
44a794e791SBruce Evans #include <sys/namei.h>
451e1e0b44SSøren Schmidt #include <sys/sysent.h>
4626f9a767SRodney W. Grimes #include <sys/syslog.h>
47797f2d22SPoul-Henning Kamp #include <sys/shm.h>
4899ac3bc8SPeter Wemm #include <sys/sysctl.h>
49a794e791SBruce Evans #include <sys/vnode.h>
509caaadb6SDavid Greenman #include <sys/buf.h>
5126f9a767SRodney W. Grimes 
5226f9a767SRodney W. Grimes #include <vm/vm.h>
53efeaf95aSDavid Greenman #include <vm/vm_param.h>
54efeaf95aSDavid Greenman #include <vm/vm_prot.h>
55996c772fSJohn Dyson #include <sys/lock.h>
56efeaf95aSDavid Greenman #include <vm/pmap.h>
57efeaf95aSDavid Greenman #include <vm/vm_map.h>
5826f9a767SRodney W. Grimes #include <vm/vm_kern.h>
59efeaf95aSDavid Greenman #include <vm/vm_extern.h>
6026f9a767SRodney W. Grimes 
6126f9a767SRodney W. Grimes #include <machine/reg.h>
6226f9a767SRodney W. Grimes 
6387b6de2bSPoul-Henning Kamp static int *exec_copyout_strings __P((struct image_params *));
64df8bae1dSRodney W. Grimes 
65f23b4c91SGarrett Wollman static int exec_check_permissions(struct image_params *);
66f23b4c91SGarrett Wollman 
67df8bae1dSRodney W. Grimes /*
6899ac3bc8SPeter Wemm  * XXX trouble here if sizeof(caddr_t) != sizeof(int), other parts
6999ac3bc8SPeter Wemm  * of the sysctl code also assumes this, and sizeof(int) == sizeof(long).
7099ac3bc8SPeter Wemm  */
716120fef1SDavid Greenman static struct ps_strings *ps_strings = PS_STRINGS;
7299ac3bc8SPeter Wemm SYSCTL_INT(_kern, KERN_PS_STRINGS, ps_strings, 0, &ps_strings, 0, "");
7399ac3bc8SPeter Wemm 
7499ac3bc8SPeter Wemm static caddr_t usrstack = (caddr_t)USRSTACK;
7599ac3bc8SPeter Wemm SYSCTL_INT(_kern, KERN_USRSTACK, usrstack, 0, &usrstack, 0, "");
7699ac3bc8SPeter Wemm 
7799ac3bc8SPeter Wemm /*
7826f9a767SRodney W. Grimes  * execsw_set is constructed for us by the linker.  Each of the items
7926f9a767SRodney W. Grimes  * is a pointer to a `const struct execsw', hence the double pointer here.
80df8bae1dSRodney W. Grimes  */
8187b6de2bSPoul-Henning Kamp static const struct execsw **execsw =
8287b6de2bSPoul-Henning Kamp 	(const struct execsw **)&execsw_set.ls_items[0];
8326f9a767SRodney W. Grimes 
84d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
85ad7507e2SSteven Wallace struct execve_args {
86ad7507e2SSteven Wallace         char    *fname;
87ad7507e2SSteven Wallace         char    **argv;
88ad7507e2SSteven Wallace         char    **envv;
89ad7507e2SSteven Wallace };
90d2d3e875SBruce Evans #endif
91ad7507e2SSteven Wallace 
9226f9a767SRodney W. Grimes /*
9326f9a767SRodney W. Grimes  * execve() system call.
9426f9a767SRodney W. Grimes  */
9526f9a767SRodney W. Grimes int
9626f9a767SRodney W. Grimes execve(p, uap, retval)
9726f9a767SRodney W. Grimes 	struct proc *p;
9826f9a767SRodney W. Grimes 	register struct execve_args *uap;
9926f9a767SRodney W. Grimes 	int *retval;
100df8bae1dSRodney W. Grimes {
10126f9a767SRodney W. Grimes 	struct nameidata nd, *ndp;
10226f9a767SRodney W. Grimes 	int *stack_base;
103bb56ec4aSPoul-Henning Kamp 	int error, len, i;
104c52007c2SDavid Greenman 	struct image_params image_params, *imgp;
10526f9a767SRodney W. Grimes 	struct vattr attr;
1069caaadb6SDavid Greenman 	struct buf *bp = NULL;
10726f9a767SRodney W. Grimes 
108c52007c2SDavid Greenman 	imgp = &image_params;
109df8bae1dSRodney W. Grimes 
110df8bae1dSRodney W. Grimes 	/*
111c52007c2SDavid Greenman 	 * Initialize part of the common data
112df8bae1dSRodney W. Grimes 	 */
113c52007c2SDavid Greenman 	imgp->proc = p;
114c52007c2SDavid Greenman 	imgp->uap = uap;
115c52007c2SDavid Greenman 	imgp->attr = &attr;
116c52007c2SDavid Greenman 	imgp->image_header = NULL;
117c52007c2SDavid Greenman 	imgp->argc = imgp->envc = 0;
118c52007c2SDavid Greenman 	imgp->entry_addr = 0;
119c52007c2SDavid Greenman 	imgp->vmspace_destroyed = 0;
120c52007c2SDavid Greenman 	imgp->interpreted = 0;
121c52007c2SDavid Greenman 	imgp->interpreter_name[0] = '\0';
122e1743d02SSøren Schmidt 	imgp->auxargs = NULL;
12326f9a767SRodney W. Grimes 
12426f9a767SRodney W. Grimes 	/*
12526f9a767SRodney W. Grimes 	 * Allocate temporary demand zeroed space for argument and
12626f9a767SRodney W. Grimes 	 *	environment strings
12726f9a767SRodney W. Grimes 	 */
12886064318SDavid Greenman 	imgp->stringbase = (char *)kmem_alloc_wait(exec_map, ARG_MAX);
129c2f9f36bSDavid Greenman 	if (imgp->stringbase == NULL) {
13026f9a767SRodney W. Grimes 		error = ENOMEM;
13126f9a767SRodney W. Grimes 		goto exec_fail;
13226f9a767SRodney W. Grimes 	}
133c52007c2SDavid Greenman 	imgp->stringp = imgp->stringbase;
134c52007c2SDavid Greenman 	imgp->stringspace = ARG_MAX;
13526f9a767SRodney W. Grimes 
13626f9a767SRodney W. Grimes 	/*
13726f9a767SRodney W. Grimes 	 * Translate the file name. namei() returns a vnode pointer
13826f9a767SRodney W. Grimes 	 *	in ni_vp amoung other things.
13926f9a767SRodney W. Grimes 	 */
14026f9a767SRodney W. Grimes 	ndp = &nd;
141b35ba931SDavid Greenman 	NDINIT(ndp, LOOKUP, LOCKLEAF | FOLLOW | SAVENAME,
1423ed8a403SDavid Greenman 	    UIO_USERSPACE, uap->fname, p);
14326f9a767SRodney W. Grimes 
14426f9a767SRodney W. Grimes interpret:
14526f9a767SRodney W. Grimes 
14626f9a767SRodney W. Grimes 	error = namei(ndp);
14726f9a767SRodney W. Grimes 	if (error) {
14886064318SDavid Greenman 		kmem_free_wakeup(exec_map, (vm_offset_t)imgp->stringbase, ARG_MAX);
14926f9a767SRodney W. Grimes 		goto exec_fail;
15026f9a767SRodney W. Grimes 	}
15126f9a767SRodney W. Grimes 
152c52007c2SDavid Greenman 	imgp->vp = ndp->ni_vp;
153c52007c2SDavid Greenman 	if (imgp->vp == NULL) {
15426f9a767SRodney W. Grimes 		error = ENOEXEC;
15526f9a767SRodney W. Grimes 		goto exec_fail_dealloc;
15626f9a767SRodney W. Grimes 	}
15726f9a767SRodney W. Grimes 
15826f9a767SRodney W. Grimes 	/*
1599022e4adSDavid Greenman 	 * Check file permissions (also 'opens' file)
1609022e4adSDavid Greenman 	 */
161c52007c2SDavid Greenman 	error = exec_check_permissions(imgp);
1628677f509SDavid Greenman 	if (error) {
1638677f509SDavid Greenman 		VOP_UNLOCK(imgp->vp, 0, p);
16426f9a767SRodney W. Grimes 		goto exec_fail_dealloc;
1658677f509SDavid Greenman 	}
16626f9a767SRodney W. Grimes 
16726f9a767SRodney W. Grimes 	/*
1689caaadb6SDavid Greenman 	 * Get the image header, which we define here as meaning the first
1699caaadb6SDavid Greenman 	 * page of the executable.
17026f9a767SRodney W. Grimes 	 */
1719caaadb6SDavid Greenman 	if (imgp->vp->v_mount && imgp->vp->v_mount->mnt_stat.f_iosize >= PAGE_SIZE) {
1729caaadb6SDavid Greenman 		/*
1739caaadb6SDavid Greenman 		 * Get a buffer with (at least) the first page.
1749caaadb6SDavid Greenman 		 */
1759caaadb6SDavid Greenman 		error = bread(imgp->vp, 0, imgp->vp->v_mount->mnt_stat.f_iosize,
1769caaadb6SDavid Greenman 		     p->p_ucred, &bp);
1779caaadb6SDavid Greenman 		imgp->image_header = bp->b_data;
1789caaadb6SDavid Greenman 	} else {
1799caaadb6SDavid Greenman 		/*
1809caaadb6SDavid Greenman 		 * The filesystem block size is too small, so do this the hard
1819caaadb6SDavid Greenman 		 * way. Malloc some space and read PAGE_SIZE worth of the image
1829caaadb6SDavid Greenman 		 * header into it.
1839caaadb6SDavid Greenman 		 */
1849caaadb6SDavid Greenman 		imgp->image_header = malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
1859caaadb6SDavid Greenman 		error = vn_rdwr(UIO_READ, imgp->vp, (void *)imgp->image_header, PAGE_SIZE, 0,
1869caaadb6SDavid Greenman 		    UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, NULL, p);
1879caaadb6SDavid Greenman 	}
1889caaadb6SDavid Greenman 	VOP_UNLOCK(imgp->vp, 0, p);
1896d5a0a8cSDavid Greenman 	if (error)
19026f9a767SRodney W. Grimes 		goto exec_fail_dealloc;
19126f9a767SRodney W. Grimes 
19226f9a767SRodney W. Grimes 	/*
19326f9a767SRodney W. Grimes 	 * Loop through list of image activators, calling each one.
19426f9a767SRodney W. Grimes 	 *	If there is no match, the activator returns -1. If there
19526f9a767SRodney W. Grimes 	 *	is a match, but there was an error during the activation,
19626f9a767SRodney W. Grimes 	 *	the error is returned. Otherwise 0 means success. If the
19726f9a767SRodney W. Grimes 	 *	image is interpreted, loop back up and try activating
19826f9a767SRodney W. Grimes 	 *	the interpreter.
19926f9a767SRodney W. Grimes 	 */
20026f9a767SRodney W. Grimes 	for (i = 0; execsw[i]; ++i) {
20126f9a767SRodney W. Grimes 		if (execsw[i]->ex_imgact)
202c52007c2SDavid Greenman 			error = (*execsw[i]->ex_imgact)(imgp);
20326f9a767SRodney W. Grimes 		else
20426f9a767SRodney W. Grimes 			continue;
20526f9a767SRodney W. Grimes 		if (error == -1)
20626f9a767SRodney W. Grimes 			continue;
20726f9a767SRodney W. Grimes 		if (error)
20826f9a767SRodney W. Grimes 			goto exec_fail_dealloc;
209c52007c2SDavid Greenman 		if (imgp->interpreted) {
2109caaadb6SDavid Greenman 			/* free old bp/image_header */
2119caaadb6SDavid Greenman 			if (bp != NULL) {
2129caaadb6SDavid Greenman 				brelse(bp);
2139caaadb6SDavid Greenman 				bp = NULL;
2149caaadb6SDavid Greenman 			} else {
2159caaadb6SDavid Greenman 				free((void *)imgp->image_header, M_TEMP);
2166d5a0a8cSDavid Greenman 				imgp->image_header = NULL;
2179caaadb6SDavid Greenman 			}
21826f9a767SRodney W. Grimes 			/* free old vnode and name buffer */
219f5277ae7SDavid Greenman 			vrele(ndp->ni_vp);
22026f9a767SRodney W. Grimes 			FREE(ndp->ni_cnd.cn_pnbuf, M_NAMEI);
22126f9a767SRodney W. Grimes 			/* set new name to that of the interpreter */
222b35ba931SDavid Greenman 			NDINIT(ndp, LOOKUP, LOCKLEAF | FOLLOW | SAVENAME,
223c52007c2SDavid Greenman 			    UIO_SYSSPACE, imgp->interpreter_name, p);
22426f9a767SRodney W. Grimes 			goto interpret;
22526f9a767SRodney W. Grimes 		}
22626f9a767SRodney W. Grimes 		break;
22726f9a767SRodney W. Grimes 	}
22826f9a767SRodney W. Grimes 	/* If we made it through all the activators and none matched, exit. */
22926f9a767SRodney W. Grimes 	if (error == -1) {
23026f9a767SRodney W. Grimes 		error = ENOEXEC;
23126f9a767SRodney W. Grimes 		goto exec_fail_dealloc;
23226f9a767SRodney W. Grimes 	}
23326f9a767SRodney W. Grimes 
23426f9a767SRodney W. Grimes 	/*
23526f9a767SRodney W. Grimes 	 * Copy out strings (args and env) and initialize stack base
23626f9a767SRodney W. Grimes 	 */
237c52007c2SDavid Greenman 	stack_base = exec_copyout_strings(imgp);
23826f9a767SRodney W. Grimes 	p->p_vmspace->vm_minsaddr = (char *)stack_base;
23926f9a767SRodney W. Grimes 
24026f9a767SRodney W. Grimes 	/*
2411e1e0b44SSøren Schmidt 	 * If custom stack fixup routine present for this process
2421e1e0b44SSøren Schmidt 	 * let it do the stack setup.
2431e1e0b44SSøren Schmidt 	 * Else stuff argument count as first item on stack
24426f9a767SRodney W. Grimes 	 */
2451e1e0b44SSøren Schmidt 	if (p->p_sysent->sv_fixup)
246c52007c2SDavid Greenman 		(*p->p_sysent->sv_fixup)(&stack_base, imgp);
2471e1e0b44SSøren Schmidt 	else
248c52007c2SDavid Greenman 		suword(--stack_base, imgp->argc);
24926f9a767SRodney W. Grimes 
25026f9a767SRodney W. Grimes 	/* close files on exec */
25126f9a767SRodney W. Grimes 	fdcloseexec(p);
25226f9a767SRodney W. Grimes 
25326f9a767SRodney W. Grimes 	/* reset caught signals */
25426f9a767SRodney W. Grimes 	execsigs(p);
25526f9a767SRodney W. Grimes 
25626f9a767SRodney W. Grimes 	/* name this process - nameiexec(p, ndp) */
25726f9a767SRodney W. Grimes 	len = min(ndp->ni_cnd.cn_namelen,MAXCOMLEN);
25826f9a767SRodney W. Grimes 	bcopy(ndp->ni_cnd.cn_nameptr, p->p_comm, len);
25926f9a767SRodney W. Grimes 	p->p_comm[len] = 0;
26026f9a767SRodney W. Grimes 
26126f9a767SRodney W. Grimes 	/*
26224b34f09SSujal Patel 	 * mark as execed, wakeup the process that vforked (if any) and tell
26326f9a767SRodney W. Grimes 	 * it that it now has it's own resources back
26426f9a767SRodney W. Grimes 	 */
26526f9a767SRodney W. Grimes 	p->p_flag |= P_EXEC;
26626f9a767SRodney W. Grimes 	if (p->p_pptr && (p->p_flag & P_PPWAIT)) {
26726f9a767SRodney W. Grimes 		p->p_flag &= ~P_PPWAIT;
26826f9a767SRodney W. Grimes 		wakeup((caddr_t)p->p_pptr);
26926f9a767SRodney W. Grimes 	}
27026f9a767SRodney W. Grimes 
27126f9a767SRodney W. Grimes 	/*
272c52007c2SDavid Greenman 	 * Implement image setuid/setgid. Disallow if the process is
273c52007c2SDavid Greenman 	 * being traced.
274c52007c2SDavid Greenman 	 */
275c52007c2SDavid Greenman 	if ((attr.va_mode & (VSUID | VSGID)) &&
276c52007c2SDavid Greenman 	    (p->p_flag & P_TRACED) == 0) {
277c52007c2SDavid Greenman 		/*
278c52007c2SDavid Greenman 		 * Turn off syscall tracing for set-id programs, except for
27926f9a767SRodney W. Grimes 		 * root.
28026f9a767SRodney W. Grimes 		 */
281c52007c2SDavid Greenman 		if (p->p_tracep && suser(p->p_ucred, &p->p_acflag)) {
28226f9a767SRodney W. Grimes 			p->p_traceflag = 0;
28326f9a767SRodney W. Grimes 			vrele(p->p_tracep);
284c52007c2SDavid Greenman 			p->p_tracep = NULL;
28526f9a767SRodney W. Grimes 		}
286c52007c2SDavid Greenman 		/*
287c52007c2SDavid Greenman 		 * Set the new credentials.
288c52007c2SDavid Greenman 		 */
28926f9a767SRodney W. Grimes 		p->p_ucred = crcopy(p->p_ucred);
290c52007c2SDavid Greenman 		if (attr.va_mode & VSUID)
29126f9a767SRodney W. Grimes 			p->p_ucred->cr_uid = attr.va_uid;
292c52007c2SDavid Greenman 		if (attr.va_mode & VSGID)
29326f9a767SRodney W. Grimes 			p->p_ucred->cr_groups[0] = attr.va_gid;
29426f9a767SRodney W. Grimes 		p->p_flag |= P_SUGID;
295c52007c2SDavid Greenman 	} else {
296e47bda07SDavid Greenman 	        if (p->p_ucred->cr_uid == p->p_cred->p_ruid &&
297e47bda07SDavid Greenman 		    p->p_ucred->cr_gid == p->p_cred->p_rgid)
298c52007c2SDavid Greenman 			p->p_flag &= ~P_SUGID;
29926f9a767SRodney W. Grimes 	}
30026f9a767SRodney W. Grimes 
30126f9a767SRodney W. Grimes 	/*
302c52007c2SDavid Greenman 	 * Implement correct POSIX saved-id behavior.
30326f9a767SRodney W. Grimes 	 */
30426f9a767SRodney W. Grimes 	p->p_cred->p_svuid = p->p_ucred->cr_uid;
30526f9a767SRodney W. Grimes 	p->p_cred->p_svgid = p->p_ucred->cr_gid;
30626f9a767SRodney W. Grimes 
30726f9a767SRodney W. Grimes 	/*
3082a531c80SDavid Greenman 	 * Store the vp for use in procfs
3092a531c80SDavid Greenman 	 */
3102a531c80SDavid Greenman 	if (p->p_textvp)		/* release old reference */
3112a531c80SDavid Greenman 		vrele(p->p_textvp);
3122a531c80SDavid Greenman 	VREF(ndp->ni_vp);
3132a531c80SDavid Greenman 	p->p_textvp = ndp->ni_vp;
3142a531c80SDavid Greenman 
3152a531c80SDavid Greenman 	/*
31626f9a767SRodney W. Grimes 	 * If tracing the process, trap to debugger so breakpoints
31726f9a767SRodney W. Grimes 	 * 	can be set before the program executes.
31826f9a767SRodney W. Grimes 	 */
31926f9a767SRodney W. Grimes 	if (p->p_flag & P_TRACED)
32026f9a767SRodney W. Grimes 		psignal(p, SIGTRAP);
32126f9a767SRodney W. Grimes 
32226f9a767SRodney W. Grimes 	/* clear "fork but no exec" flag, as we _are_ execing */
32326f9a767SRodney W. Grimes 	p->p_acflag &= ~AFORK;
32426f9a767SRodney W. Grimes 
32526f9a767SRodney W. Grimes 	/* Set entry address */
326c52007c2SDavid Greenman 	setregs(p, imgp->entry_addr, (u_long)stack_base);
32726f9a767SRodney W. Grimes 
32826f9a767SRodney W. Grimes 	/*
32926f9a767SRodney W. Grimes 	 * free various allocated resources
33026f9a767SRodney W. Grimes 	 */
33186064318SDavid Greenman 	kmem_free_wakeup(exec_map, (vm_offset_t)imgp->stringbase, ARG_MAX);
3329caaadb6SDavid Greenman 	if (bp != NULL)
3339caaadb6SDavid Greenman 		brelse(bp);
3349caaadb6SDavid Greenman 	else if (imgp->image_header != NULL)
3359caaadb6SDavid Greenman 		free((void *)imgp->image_header, M_TEMP);
336f5277ae7SDavid Greenman 	vrele(ndp->ni_vp);
33726f9a767SRodney W. Grimes 	FREE(ndp->ni_cnd.cn_pnbuf, M_NAMEI);
33826f9a767SRodney W. Grimes 
33926f9a767SRodney W. Grimes 	return (0);
34026f9a767SRodney W. Grimes 
34126f9a767SRodney W. Grimes exec_fail_dealloc:
342c2f9f36bSDavid Greenman 	if (imgp->stringbase != NULL)
34386064318SDavid Greenman 		kmem_free_wakeup(exec_map, (vm_offset_t)imgp->stringbase, ARG_MAX);
3449caaadb6SDavid Greenman 	if (bp != NULL)
3459caaadb6SDavid Greenman 		brelse(bp);
3469caaadb6SDavid Greenman 	else if (imgp->image_header != NULL)
3479caaadb6SDavid Greenman 		free((void *)imgp->image_header, M_TEMP);
348f5277ae7SDavid Greenman 	if (ndp->ni_vp)
349f5277ae7SDavid Greenman 		vrele(ndp->ni_vp);
35026f9a767SRodney W. Grimes 	FREE(ndp->ni_cnd.cn_pnbuf, M_NAMEI);
35126f9a767SRodney W. Grimes 
35226f9a767SRodney W. Grimes exec_fail:
353c52007c2SDavid Greenman 	if (imgp->vmspace_destroyed) {
35426f9a767SRodney W. Grimes 		/* sorry, no more process anymore. exit gracefully */
35526f9a767SRodney W. Grimes 		exit1(p, W_EXITCODE(0, SIGABRT));
35626f9a767SRodney W. Grimes 		/* NOT REACHED */
35726f9a767SRodney W. Grimes 		return(0);
35826f9a767SRodney W. Grimes 	} else {
35926f9a767SRodney W. Grimes 		return(error);
36026f9a767SRodney W. Grimes 	}
36126f9a767SRodney W. Grimes }
36226f9a767SRodney W. Grimes 
36326f9a767SRodney W. Grimes /*
36426f9a767SRodney W. Grimes  * Destroy old address space, and allocate a new stack
36526f9a767SRodney W. Grimes  *	The new stack is only SGROWSIZ large because it is grown
36626f9a767SRodney W. Grimes  *	automatically in trap.c.
36726f9a767SRodney W. Grimes  */
36826f9a767SRodney W. Grimes int
369c52007c2SDavid Greenman exec_new_vmspace(imgp)
370c52007c2SDavid Greenman 	struct image_params *imgp;
37126f9a767SRodney W. Grimes {
37226f9a767SRodney W. Grimes 	int error;
373c52007c2SDavid Greenman 	struct vmspace *vmspace = imgp->proc->p_vmspace;
37426f9a767SRodney W. Grimes 	caddr_t	stack_addr = (caddr_t) (USRSTACK - SGROWSIZ);
37526f9a767SRodney W. Grimes 
376c52007c2SDavid Greenman 	imgp->vmspace_destroyed = 1;
37726f9a767SRodney W. Grimes 
37826f9a767SRodney W. Grimes 	/* Blow away entire process VM */
3793d903220SDoug Rabson 	if (vmspace->vm_shm)
380c52007c2SDavid Greenman 		shmexit(imgp->proc);
3819d3fbbb5SJohn Dyson 	pmap_remove_pages(&vmspace->vm_pmap, 0, USRSTACK);
3822cb544c3SJohn Dyson 	vm_map_remove(&vmspace->vm_map, 0, USRSTACK);
38326f9a767SRodney W. Grimes 
38426f9a767SRodney W. Grimes 	/* Allocate a new stack */
38568940ac1SDavid Greenman 	error = vm_map_find(&vmspace->vm_map, NULL, 0, (vm_offset_t *)&stack_addr,
386bd7e5f99SJohn Dyson 	    SGROWSIZ, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0);
38726f9a767SRodney W. Grimes 	if (error)
38826f9a767SRodney W. Grimes 		return(error);
38926f9a767SRodney W. Grimes 
39026f9a767SRodney W. Grimes 	vmspace->vm_ssize = SGROWSIZ >> PAGE_SHIFT;
39126f9a767SRodney W. Grimes 
39226f9a767SRodney W. Grimes 	/* Initialize maximum stack address */
39326f9a767SRodney W. Grimes 	vmspace->vm_maxsaddr = (char *)USRSTACK - MAXSSIZ;
39426f9a767SRodney W. Grimes 
39526f9a767SRodney W. Grimes 	return(0);
39626f9a767SRodney W. Grimes }
39726f9a767SRodney W. Grimes 
39826f9a767SRodney W. Grimes /*
39926f9a767SRodney W. Grimes  * Copy out argument and environment strings from the old process
40026f9a767SRodney W. Grimes  *	address space into the temporary string buffer.
40126f9a767SRodney W. Grimes  */
40226f9a767SRodney W. Grimes int
403c52007c2SDavid Greenman exec_extract_strings(imgp)
404c52007c2SDavid Greenman 	struct image_params *imgp;
40526f9a767SRodney W. Grimes {
40626f9a767SRodney W. Grimes 	char	**argv, **envv;
40726f9a767SRodney W. Grimes 	char	*argp, *envp;
4080fd1a014SDavid Greenman 	int	error, length;
40926f9a767SRodney W. Grimes 
41026f9a767SRodney W. Grimes 	/*
41126f9a767SRodney W. Grimes 	 * extract arguments first
41226f9a767SRodney W. Grimes 	 */
41326f9a767SRodney W. Grimes 
414c52007c2SDavid Greenman 	argv = imgp->uap->argv;
41526f9a767SRodney W. Grimes 
4160fd1a014SDavid Greenman 	if (argv) {
417bb56ec4aSPoul-Henning Kamp 		while ((argp = (caddr_t) fuword(argv++))) {
41826f9a767SRodney W. Grimes 			if (argp == (caddr_t) -1)
41926f9a767SRodney W. Grimes 				return (EFAULT);
420c52007c2SDavid Greenman 			if ((error = copyinstr(argp, imgp->stringp,
421c52007c2SDavid Greenman 			    imgp->stringspace, &length))) {
4220fd1a014SDavid Greenman 				if (error == ENAMETOOLONG)
42326f9a767SRodney W. Grimes 					return(E2BIG);
4240fd1a014SDavid Greenman 				return (error);
4250fd1a014SDavid Greenman 			}
426c52007c2SDavid Greenman 			imgp->stringspace -= length;
427c52007c2SDavid Greenman 			imgp->stringp += length;
428c52007c2SDavid Greenman 			imgp->argc++;
42926f9a767SRodney W. Grimes 		}
4300fd1a014SDavid Greenman 	}
43126f9a767SRodney W. Grimes 
43226f9a767SRodney W. Grimes 	/*
43326f9a767SRodney W. Grimes 	 * extract environment strings
43426f9a767SRodney W. Grimes 	 */
43526f9a767SRodney W. Grimes 
436c52007c2SDavid Greenman 	envv = imgp->uap->envv;
43726f9a767SRodney W. Grimes 
4380fd1a014SDavid Greenman 	if (envv) {
439bb56ec4aSPoul-Henning Kamp 		while ((envp = (caddr_t) fuword(envv++))) {
44026f9a767SRodney W. Grimes 			if (envp == (caddr_t) -1)
44126f9a767SRodney W. Grimes 				return (EFAULT);
442c52007c2SDavid Greenman 			if ((error = copyinstr(envp, imgp->stringp,
443c52007c2SDavid Greenman 			    imgp->stringspace, &length))) {
4440fd1a014SDavid Greenman 				if (error == ENAMETOOLONG)
44526f9a767SRodney W. Grimes 					return(E2BIG);
4460fd1a014SDavid Greenman 				return (error);
4470fd1a014SDavid Greenman 			}
448c52007c2SDavid Greenman 			imgp->stringspace -= length;
449c52007c2SDavid Greenman 			imgp->stringp += length;
450c52007c2SDavid Greenman 			imgp->envc++;
45126f9a767SRodney W. Grimes 		}
4520fd1a014SDavid Greenman 	}
45326f9a767SRodney W. Grimes 
45426f9a767SRodney W. Grimes 	return (0);
45526f9a767SRodney W. Grimes }
45626f9a767SRodney W. Grimes 
45726f9a767SRodney W. Grimes /*
45826f9a767SRodney W. Grimes  * Copy strings out to the new process address space, constructing
45926f9a767SRodney W. Grimes  *	new arg and env vector tables. Return a pointer to the base
46026f9a767SRodney W. Grimes  *	so that it can be used as the initial stack pointer.
46126f9a767SRodney W. Grimes  */
46226f9a767SRodney W. Grimes int *
463c52007c2SDavid Greenman exec_copyout_strings(imgp)
464c52007c2SDavid Greenman 	struct image_params *imgp;
46526f9a767SRodney W. Grimes {
46626f9a767SRodney W. Grimes 	int argc, envc;
46726f9a767SRodney W. Grimes 	char **vectp;
46826f9a767SRodney W. Grimes 	char *stringp, *destp;
46926f9a767SRodney W. Grimes 	int *stack_base;
47093f6448cSDavid Greenman 	struct ps_strings *arginfo;
471d66a5066SPeter Wemm 	int szsigcode;
47226f9a767SRodney W. Grimes 
47326f9a767SRodney W. Grimes 	/*
47426f9a767SRodney W. Grimes 	 * Calculate string base and vector table pointers.
475d66a5066SPeter Wemm 	 * Also deal with signal trampoline code for this exec type.
47626f9a767SRodney W. Grimes 	 */
47793f6448cSDavid Greenman 	arginfo = PS_STRINGS;
478d66a5066SPeter Wemm 	szsigcode = *(imgp->proc->p_sysent->sv_szsigcode);
479d66a5066SPeter Wemm 	destp =	(caddr_t)arginfo - szsigcode - SPARE_USRSPACE -
4801ed012f9SPeter Wemm 		roundup((ARG_MAX - imgp->stringspace), sizeof(char *));
4811ed012f9SPeter Wemm 
48226f9a767SRodney W. Grimes 	/*
483d66a5066SPeter Wemm 	 * install sigcode
484d66a5066SPeter Wemm 	 */
485d66a5066SPeter Wemm 	if (szsigcode)
486d66a5066SPeter Wemm 		copyout(imgp->proc->p_sysent->sv_sigcode,
487d66a5066SPeter Wemm 			((caddr_t)arginfo - szsigcode), szsigcode);
488d66a5066SPeter Wemm 
489d66a5066SPeter Wemm 	/*
490e1743d02SSøren Schmidt 	 * If we have a valid auxargs ptr, prepare some room
491e1743d02SSøren Schmidt 	 * on the stack.
492e1743d02SSøren Schmidt 	 */
493e1743d02SSøren Schmidt 	if (imgp->auxargs)
494e1743d02SSøren Schmidt 	/*
495e1743d02SSøren Schmidt 	 * The '+ 2' is for the null pointers at the end of each of the
496e1743d02SSøren Schmidt 	 * arg and env vector sets, and 'AT_COUNT*2' is room for the
497e1743d02SSøren Schmidt 	 * ELF Auxargs data.
498e1743d02SSøren Schmidt 	 */
499e1743d02SSøren Schmidt 		vectp = (char **)(destp - (imgp->argc + imgp->envc + 2 +
500e1743d02SSøren Schmidt 				  AT_COUNT*2) * sizeof(char*));
501e1743d02SSøren Schmidt 	else
502e1743d02SSøren Schmidt 	/*
50326f9a767SRodney W. Grimes 	 * The '+ 2' is for the null pointers at the end of each of the
50426f9a767SRodney W. Grimes 	 * arg and env vector sets
50526f9a767SRodney W. Grimes 	 */
506e1743d02SSøren Schmidt 		vectp = (char **)
507e1743d02SSøren Schmidt 			(destp - (imgp->argc + imgp->envc + 2) * sizeof(char*));
50826f9a767SRodney W. Grimes 
50926f9a767SRodney W. Grimes 	/*
51026f9a767SRodney W. Grimes 	 * vectp also becomes our initial stack base
51126f9a767SRodney W. Grimes 	 */
51226f9a767SRodney W. Grimes 	stack_base = (int *)vectp;
51326f9a767SRodney W. Grimes 
514c52007c2SDavid Greenman 	stringp = imgp->stringbase;
515c52007c2SDavid Greenman 	argc = imgp->argc;
516c52007c2SDavid Greenman 	envc = imgp->envc;
51726f9a767SRodney W. Grimes 
51893f6448cSDavid Greenman 	/*
5193aed948bSDavid Greenman 	 * Copy out strings - arguments and environment.
52093f6448cSDavid Greenman 	 */
521c52007c2SDavid Greenman 	copyout(stringp, destp, ARG_MAX - imgp->stringspace);
52293f6448cSDavid Greenman 
52393f6448cSDavid Greenman 	/*
5243aed948bSDavid Greenman 	 * Fill in "ps_strings" struct for ps, w, etc.
5253aed948bSDavid Greenman 	 */
5261ed012f9SPeter Wemm 	suword(&arginfo->ps_argvstr, (int)vectp);
5273aed948bSDavid Greenman 	suword(&arginfo->ps_nargvstr, argc);
5283aed948bSDavid Greenman 
5293aed948bSDavid Greenman 	/*
5303aed948bSDavid Greenman 	 * Fill in argument portion of vector table.
53193f6448cSDavid Greenman 	 */
53226f9a767SRodney W. Grimes 	for (; argc > 0; --argc) {
5333aed948bSDavid Greenman 		suword(vectp++, (int)destp);
5343aed948bSDavid Greenman 		while (*stringp++ != 0)
5353aed948bSDavid Greenman 			destp++;
5363aed948bSDavid Greenman 		destp++;
53726f9a767SRodney W. Grimes 	}
53826f9a767SRodney W. Grimes 
53926f9a767SRodney W. Grimes 	/* a null vector table pointer seperates the argp's from the envp's */
5406ab46d52SBruce Evans 	suword(vectp++, 0);
54126f9a767SRodney W. Grimes 
5421ed012f9SPeter Wemm 	suword(&arginfo->ps_envstr, (int)vectp);
5433aed948bSDavid Greenman 	suword(&arginfo->ps_nenvstr, envc);
54493f6448cSDavid Greenman 
54593f6448cSDavid Greenman 	/*
5463aed948bSDavid Greenman 	 * Fill in environment portion of vector table.
54793f6448cSDavid Greenman 	 */
54826f9a767SRodney W. Grimes 	for (; envc > 0; --envc) {
5493aed948bSDavid Greenman 		suword(vectp++, (int)destp);
5503aed948bSDavid Greenman 		while (*stringp++ != 0)
5513aed948bSDavid Greenman 			destp++;
5523aed948bSDavid Greenman 		destp++;
55326f9a767SRodney W. Grimes 	}
55426f9a767SRodney W. Grimes 
55526f9a767SRodney W. Grimes 	/* end of vector table is a null pointer */
5566ab46d52SBruce Evans 	suword(vectp, 0);
55726f9a767SRodney W. Grimes 
55826f9a767SRodney W. Grimes 	return (stack_base);
55926f9a767SRodney W. Grimes }
56026f9a767SRodney W. Grimes 
56126f9a767SRodney W. Grimes /*
56226f9a767SRodney W. Grimes  * Check permissions of file to execute.
56326f9a767SRodney W. Grimes  *	Return 0 for success or error code on failure.
56426f9a767SRodney W. Grimes  */
565f23b4c91SGarrett Wollman static int
566c52007c2SDavid Greenman exec_check_permissions(imgp)
567c52007c2SDavid Greenman 	struct image_params *imgp;
56826f9a767SRodney W. Grimes {
569c52007c2SDavid Greenman 	struct proc *p = imgp->proc;
570c52007c2SDavid Greenman 	struct vnode *vp = imgp->vp;
571c52007c2SDavid Greenman 	struct vattr *attr = imgp->attr;
57226f9a767SRodney W. Grimes 	int error;
57326f9a767SRodney W. Grimes 
57426f9a767SRodney W. Grimes 	/* Get file attributes */
575c52007c2SDavid Greenman 	error = VOP_GETATTR(vp, attr, p->p_ucred, p);
57626f9a767SRodney W. Grimes 	if (error)
57726f9a767SRodney W. Grimes 		return (error);
57826f9a767SRodney W. Grimes 
57926f9a767SRodney W. Grimes 	/*
58026f9a767SRodney W. Grimes 	 * 1) Check if file execution is disabled for the filesystem that this
58126f9a767SRodney W. Grimes 	 *	file resides on.
58226f9a767SRodney W. Grimes 	 * 2) Insure that at least one execute bit is on - otherwise root
58326f9a767SRodney W. Grimes 	 *	will always succeed, and we don't want to happen unless the
58426f9a767SRodney W. Grimes 	 *	file really is executable.
58526f9a767SRodney W. Grimes 	 * 3) Insure that the file is a regular file.
58626f9a767SRodney W. Grimes 	 */
587c52007c2SDavid Greenman 	if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
58826f9a767SRodney W. Grimes 	    ((attr->va_mode & 0111) == 0) ||
58926f9a767SRodney W. Grimes 	    (attr->va_type != VREG)) {
59026f9a767SRodney W. Grimes 		return (EACCES);
59126f9a767SRodney W. Grimes 	}
59226f9a767SRodney W. Grimes 
59326f9a767SRodney W. Grimes 	/*
59426f9a767SRodney W. Grimes 	 * Zero length files can't be exec'd
59526f9a767SRodney W. Grimes 	 */
59626f9a767SRodney W. Grimes 	if (attr->va_size == 0)
59726f9a767SRodney W. Grimes 		return (ENOEXEC);
59826f9a767SRodney W. Grimes 
59926f9a767SRodney W. Grimes 	/*
60026f9a767SRodney W. Grimes 	 *  Check for execute permission to file based on current credentials.
60126f9a767SRodney W. Grimes 	 */
602c52007c2SDavid Greenman 	error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
60326f9a767SRodney W. Grimes 	if (error)
60426f9a767SRodney W. Grimes 		return (error);
60526f9a767SRodney W. Grimes 
6066d5a0a8cSDavid Greenman 	/*
6076d5a0a8cSDavid Greenman 	 * Check number of open-for-writes on the file and deny execution
6086d5a0a8cSDavid Greenman 	 * if there are any.
6096d5a0a8cSDavid Greenman 	 */
6106d5a0a8cSDavid Greenman 	if (vp->v_writecount)
6116d5a0a8cSDavid Greenman 		return (ETXTBSY);
6126d5a0a8cSDavid Greenman 
6136d5a0a8cSDavid Greenman 	/*
6146d5a0a8cSDavid Greenman 	 * Call filesystem specific open routine (which does nothing in the
6156d5a0a8cSDavid Greenman 	 * general case).
6166d5a0a8cSDavid Greenman 	 */
617c52007c2SDavid Greenman 	error = VOP_OPEN(vp, FREAD, p->p_ucred, p);
61826f9a767SRodney W. Grimes 	if (error)
61926f9a767SRodney W. Grimes 		return (error);
62026f9a767SRodney W. Grimes 
6216d5a0a8cSDavid Greenman 	/*
6226d5a0a8cSDavid Greenman 	 * Disable setuid/setgid if the filesystem prohibits it or if
6236d5a0a8cSDavid Greenman 	 * the process is being traced.
6246d5a0a8cSDavid Greenman 	 */
6256d5a0a8cSDavid Greenman         if ((vp->v_mount->mnt_flag & MNT_NOSUID) || (p->p_flag & P_TRACED))
6266d5a0a8cSDavid Greenman 		attr->va_mode &= ~(VSUID | VSGID);
6276d5a0a8cSDavid Greenman 
62826f9a767SRodney W. Grimes 	return (0);
629df8bae1dSRodney W. Grimes }
630