149587Sbostic /*-
263173Sbostic * Copyright (c) 1982, 1986, 1991, 1993
363173Sbostic * The Regents of the University of California. All rights reserved.
465771Sbostic * (c) UNIX System Laboratories, Inc.
565771Sbostic * All or some portions of this file are derived from material licensed
665771Sbostic * to the University of California by American Telephone and Telegraph
765771Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with
865771Sbostic * the permission of UNIX System Laboratories, Inc.
923368Smckusick *
1049587Sbostic * %sccs.include.proprietary.c%
1149587Sbostic *
12*69409Smckusick * @(#)kern_exec.c 8.10 (Berkeley) 05/14/95
1323368Smckusick */
1412789Ssam
1556517Sbostic #include <sys/param.h>
1656517Sbostic #include <sys/systm.h>
1756517Sbostic #include <sys/filedesc.h>
1856517Sbostic #include <sys/kernel.h>
1956517Sbostic #include <sys/proc.h>
2056517Sbostic #include <sys/mount.h>
2156517Sbostic #include <sys/malloc.h>
2256517Sbostic #include <sys/namei.h>
2356517Sbostic #include <sys/vnode.h>
2456517Sbostic #include <sys/file.h>
2556517Sbostic #include <sys/acct.h>
2656517Sbostic #include <sys/exec.h>
2756517Sbostic #include <sys/ktrace.h>
2856517Sbostic #include <sys/resourcevar.h>
2968296Scgd #include <sys/syscallargs.h>
3012789Ssam
3156517Sbostic #include <machine/cpu.h>
3256517Sbostic #include <machine/reg.h>
3337520Smckusick
3456517Sbostic #include <sys/mman.h>
3556517Sbostic #include <vm/vm.h>
3656517Sbostic #include <vm/vm_param.h>
3756517Sbostic #include <vm/vm_map.h>
3856517Sbostic #include <vm/vm_kern.h>
3956517Sbostic #include <vm/vm_pager.h>
4045726Smckusick
4156517Sbostic #include <sys/signalvar.h>
4247652Skarels
4342085Smckusick #ifdef HPUXCOMPAT
4456517Sbostic #include <sys/user.h> /* for pcb */
4556517Sbostic #include <hp/hpux/hpux_exec.h>
4642085Smckusick #endif
4742085Smckusick
4848900Skarels #ifdef COPY_SIGCODE
4948900Skarels extern char sigcode[], esigcode[];
5048900Skarels #define szsigcode (esigcode - sigcode)
5148900Skarels #else
5248900Skarels #define szsigcode 0
5348900Skarels #endif
5448900Skarels
5547540Skarels /*
5647540Skarels * exec system call
5747540Skarels */
execve(p,uap,retval)5842921Smckusick execve(p, uap, retval)
5942921Smckusick register struct proc *p;
6068296Scgd register struct execve_args /* {
6168296Scgd syscallarg(char *) path;
6268296Scgd syscallarg(char **) argp;
6368296Scgd syscallarg(char **) envp;
6468296Scgd } */ *uap;
6568296Scgd register_t *retval;
6612789Ssam {
6747540Skarels register struct ucred *cred = p->p_ucred;
6845914Smckusick register struct filedesc *fdp = p->p_fd;
6952539Storek int na, ne, ucp, ap, cc, ssize;
7012789Ssam register char *cp;
7145914Smckusick register int nc;
7226352Skarels unsigned len;
7312789Ssam int indir, uid, gid;
7412789Ssam char *sharg;
7537728Smckusick struct vnode *vp;
7647733Skarels int resid, error, paged = 0;
7751039Sralph vm_offset_t execargs = 0;
7837728Smckusick struct vattr vattr;
7930577Sbostic char cfarg[MAXINTERP];
8016746Ssam union {
8130577Sbostic char ex_shell[MAXINTERP]; /* #! and interpreter name */
8216746Ssam struct exec ex_exec;
8342085Smckusick #ifdef HPUXCOMPAT
8442085Smckusick struct hpux_exec ex_hexec;
8542085Smckusick #endif
8616746Ssam } exdata;
8742085Smckusick #ifdef HPUXCOMPAT
8842085Smckusick struct hpux_exec hhead;
8942085Smckusick #endif
9047540Skarels struct nameidata nd;
9153124Smckusick struct ps_strings ps;
9212789Ssam
9359378Smckusick NDINIT(&nd, LOOKUP, FOLLOW | SAVENAME, UIO_USERSPACE,
9468296Scgd SCARG(uap, path), p);
9552376Smckusick if (error = namei(&nd))
9644404Skarels return (error);
9752376Smckusick vp = nd.ni_vp;
9867655Smckusick VOP_LEASE(vp, p, cred, LEASE_READ);
99*69409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
10012789Ssam indir = 0;
10142921Smckusick uid = cred->cr_uid;
10242921Smckusick gid = cred->cr_gid;
10348019Smckusick if (error = VOP_GETATTR(vp, &vattr, cred, p))
10437728Smckusick goto bad;
10541400Smckusick if (vp->v_mount->mnt_flag & MNT_NOEXEC) {
10642921Smckusick error = EACCES;
10737728Smckusick goto bad;
10837728Smckusick }
10941400Smckusick if ((vp->v_mount->mnt_flag & MNT_NOSUID) == 0) {
11037728Smckusick if (vattr.va_mode & VSUID)
11137728Smckusick uid = vattr.va_uid;
11237728Smckusick if (vattr.va_mode & VSGID)
11337728Smckusick gid = vattr.va_gid;
11437728Smckusick }
11512789Ssam
11612789Ssam again:
11748019Smckusick if (error = VOP_ACCESS(vp, VEXEC, cred, p))
11812789Ssam goto bad;
11964589Sbostic if ((p->p_flag & P_TRACED) && (error = VOP_ACCESS(vp, VREAD, cred, p)))
12012789Ssam goto bad;
12137728Smckusick if (vp->v_type != VREG ||
12237728Smckusick (vattr.va_mode & (VEXEC|(VEXEC>>3)|(VEXEC>>6))) == 0) {
12342921Smckusick error = EACCES;
12412789Ssam goto bad;
12512789Ssam }
12612789Ssam
12712789Ssam /*
12816750Ssam * Read in first few bytes of file for segment sizes, magic number:
12937728Smckusick * OMAGIC = plain executable
13037728Smckusick * NMAGIC = RO text
13137728Smckusick * ZMAGIC = demand paged RO text
13212789Ssam * Also an ASCII line beginning with #! is
13312789Ssam * the file name of a ``shell'' and arguments may be prepended
13412789Ssam * to the argument list if given here.
13512789Ssam *
13612789Ssam * SHELL NAMES ARE LIMITED IN LENGTH.
13712789Ssam *
13812789Ssam * ONLY ONE ARGUMENT MAY BE PASSED TO THE SHELL FROM
13912789Ssam * THE ASCII LINE.
14012789Ssam */
14116746Ssam exdata.ex_shell[0] = '\0'; /* for zero length files */
14242921Smckusick error = vn_rdwr(UIO_READ, vp, (caddr_t)&exdata, sizeof (exdata),
14348019Smckusick (off_t)0, UIO_SYSSPACE, (IO_UNIT|IO_NODELOCKED), cred, &resid,
14448019Smckusick (struct proc *)0);
14542921Smckusick if (error)
14612789Ssam goto bad;
14712789Ssam #ifndef lint
14821104Skarels if (resid > sizeof(exdata) - sizeof(exdata.ex_exec) &&
14916746Ssam exdata.ex_shell[0] != '#') {
15042921Smckusick error = ENOEXEC;
15112789Ssam goto bad;
15212789Ssam }
15312789Ssam #endif
15453871Smckusick #if defined(hp300) || defined(luna68k)
15542085Smckusick switch ((int)exdata.ex_exec.a_mid) {
15642085Smckusick
15742085Smckusick /*
15842085Smckusick * An ancient hp200 or hp300 binary, shouldn't happen anymore.
15942085Smckusick * Mark as invalid.
16042085Smckusick */
16142085Smckusick case MID_ZERO:
16242085Smckusick exdata.ex_exec.a_magic = 0;
16342085Smckusick break;
16442085Smckusick
16542085Smckusick /*
16642085Smckusick * HP200 series has a smaller page size so we cannot
16742085Smckusick * demand-load or even write protect text, so we just
16842085Smckusick * treat as OMAGIC.
16942085Smckusick */
17042085Smckusick case MID_HP200:
17142085Smckusick exdata.ex_exec.a_magic = OMAGIC;
17242085Smckusick break;
17342085Smckusick
17442085Smckusick case MID_HP300:
17542085Smckusick break;
17642085Smckusick
17742085Smckusick #ifdef HPUXCOMPAT
17842085Smckusick case MID_HPUX:
17942085Smckusick /*
18042085Smckusick * Save a.out header. This is eventually saved in the pcb,
18142085Smckusick * but we cannot do that yet in case the exec fails before
18242085Smckusick * the image is overlayed.
18342085Smckusick */
18442085Smckusick bcopy((caddr_t)&exdata.ex_hexec,
18542085Smckusick (caddr_t)&hhead, sizeof hhead);
18642085Smckusick /*
18742085Smckusick * Shuffle important fields to their BSD locations.
18842085Smckusick * Note that the order in which this is done is important.
18942085Smckusick */
19042085Smckusick exdata.ex_exec.a_text = exdata.ex_hexec.ha_text;
19142085Smckusick exdata.ex_exec.a_data = exdata.ex_hexec.ha_data;
19242085Smckusick exdata.ex_exec.a_bss = exdata.ex_hexec.ha_bss;
19342085Smckusick exdata.ex_exec.a_entry = exdata.ex_hexec.ha_entry;
19442085Smckusick /*
19542085Smckusick * For ZMAGIC files, make sizes consistant with those
19642085Smckusick * generated by BSD ld.
19742085Smckusick */
19842085Smckusick if (exdata.ex_exec.a_magic == ZMAGIC) {
19942085Smckusick exdata.ex_exec.a_text =
20042085Smckusick ctob(btoc(exdata.ex_exec.a_text));
20142085Smckusick nc = exdata.ex_exec.a_data + exdata.ex_exec.a_bss;
20242085Smckusick exdata.ex_exec.a_data =
20342085Smckusick ctob(btoc(exdata.ex_exec.a_data));
20442085Smckusick nc -= (int)exdata.ex_exec.a_data;
20542085Smckusick exdata.ex_exec.a_bss = (nc < 0) ? 0 : nc;
20642085Smckusick }
20742085Smckusick break;
20842085Smckusick #endif
20942085Smckusick }
21042085Smckusick #endif
21126252Skarels switch ((int)exdata.ex_exec.a_magic) {
21212789Ssam
21337728Smckusick case OMAGIC:
21451039Sralph #ifdef COFF
21551039Sralph if (exdata.ex_exec.ex_fhdr.magic != COFF_MAGIC) {
21651039Sralph error = ENOEXEC;
21751039Sralph goto bad;
21851039Sralph }
21951039Sralph #endif
22052539Storek #ifdef sparc
22152539Storek if (exdata.ex_exec.a_mid != MID_SUN_SPARC) {
22252539Storek error = ENOEXEC;
22352539Storek goto bad;
22452539Storek }
22552539Storek #endif
22616746Ssam exdata.ex_exec.a_data += exdata.ex_exec.a_text;
22716746Ssam exdata.ex_exec.a_text = 0;
22812789Ssam break;
22912789Ssam
23037728Smckusick case ZMAGIC:
23152539Storek paged = 1;
23247733Skarels /* FALLTHROUGH */
23352539Storek
23437728Smckusick case NMAGIC:
23551039Sralph #ifdef COFF
23651039Sralph if (exdata.ex_exec.ex_fhdr.magic != COFF_MAGIC) {
23751039Sralph error = ENOEXEC;
23851039Sralph goto bad;
23951039Sralph }
24051039Sralph #endif
24152539Storek #ifdef sparc
24252539Storek if (exdata.ex_exec.a_mid != MID_SUN_SPARC) {
24352539Storek error = ENOEXEC;
24452539Storek goto bad;
24552539Storek }
24652539Storek #endif
24716746Ssam if (exdata.ex_exec.a_text == 0) {
24842921Smckusick error = ENOEXEC;
24912789Ssam goto bad;
25012789Ssam }
25112789Ssam break;
25212789Ssam
25312789Ssam default:
25434477Skarels if (exdata.ex_shell[0] != '#' ||
25534477Skarels exdata.ex_shell[1] != '!' ||
25634477Skarels indir) {
25742921Smckusick error = ENOEXEC;
25812789Ssam goto bad;
25912789Ssam }
26034418Sbostic for (cp = &exdata.ex_shell[2];; ++cp) {
26134477Skarels if (cp >= &exdata.ex_shell[MAXINTERP]) {
26242921Smckusick error = ENOEXEC;
26334418Sbostic goto bad;
26434418Sbostic }
26534418Sbostic if (*cp == '\n') {
26612789Ssam *cp = '\0';
26712789Ssam break;
26812789Ssam }
26934418Sbostic if (*cp == '\t')
27034418Sbostic *cp = ' ';
27112789Ssam }
27234477Skarels cp = &exdata.ex_shell[2];
27334477Skarels while (*cp == ' ')
27434477Skarels cp++;
27552376Smckusick nd.ni_dirp = cp;
27634477Skarels while (*cp && *cp != ' ')
27734477Skarels cp++;
27834644Skarels cfarg[0] = '\0';
27912789Ssam if (*cp) {
28034477Skarels *cp++ = '\0';
28134477Skarels while (*cp == ' ')
28234477Skarels cp++;
28321104Skarels if (*cp)
28430577Sbostic bcopy((caddr_t)cp, (caddr_t)cfarg, MAXINTERP);
28534644Skarels }
28634477Skarels indir = 1;
28737728Smckusick vput(vp);
28852376Smckusick nd.ni_segflg = UIO_SYSSPACE;
28952376Smckusick if (error = namei(&nd))
29044404Skarels return (error);
29152376Smckusick vp = nd.ni_vp;
29267655Smckusick VOP_LEASE(vp, p, cred, LEASE_READ);
293*69409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
29448019Smckusick if (error = VOP_GETATTR(vp, &vattr, cred, p))
29537728Smckusick goto bad;
29642921Smckusick uid = cred->cr_uid; /* shell scripts can't be setuid */
29742921Smckusick gid = cred->cr_gid;
29812789Ssam goto again;
29912789Ssam }
30012789Ssam
30112789Ssam /*
30212789Ssam * Collect arguments on "file" in swap space.
30312789Ssam */
30412789Ssam na = 0;
30512789Ssam ne = 0;
30612789Ssam nc = 0;
30745726Smckusick cc = NCARGS;
30845726Smckusick execargs = kmem_alloc_wait(exec_map, NCARGS);
30951039Sralph #ifdef DIAGNOSTIC
31051039Sralph if (execargs == (vm_offset_t)0)
31151039Sralph panic("execve: kmem_alloc_wait");
31251039Sralph #endif
31345726Smckusick cp = (char *) execargs;
31416750Ssam /*
31516750Ssam * Copy arguments into file in argdev area.
31616750Ssam */
31768296Scgd if (SCARG(uap, argp)) for (;;) {
31812789Ssam ap = NULL;
31921104Skarels sharg = NULL;
32021104Skarels if (indir && na == 0) {
32152376Smckusick sharg = nd.ni_cnd.cn_nameptr;
32221104Skarels ap = (int)sharg;
32368296Scgd SCARG(uap, argp)++; /* ignore argv[0] */
32421104Skarels } else if (indir && (na == 1 && cfarg[0])) {
32521104Skarels sharg = cfarg;
32621104Skarels ap = (int)sharg;
32721104Skarels } else if (indir && (na == 1 || na == 2 && cfarg[0]))
32868296Scgd ap = (int)SCARG(uap, path);
32968296Scgd else if (SCARG(uap, argp)) {
33068296Scgd ap = fuword((caddr_t)SCARG(uap, argp));
33168296Scgd SCARG(uap, argp)++;
33212789Ssam }
33368296Scgd if (ap == NULL && SCARG(uap, envp)) {
33468335Scgd SCARG(uap, argp) = NULL;
33568296Scgd if ((ap = fuword((caddr_t)SCARG(uap, envp))) != NULL)
33668296Scgd SCARG(uap, envp)++, ne++;
33712789Ssam }
33812789Ssam if (ap == NULL)
33912789Ssam break;
34012789Ssam na++;
34116750Ssam if (ap == -1) {
34242921Smckusick error = EFAULT;
34345726Smckusick goto bad;
34416750Ssam }
34512789Ssam do {
34645726Smckusick if (nc >= NCARGS-1) {
34745726Smckusick error = E2BIG;
34845726Smckusick break;
34912789Ssam }
35021104Skarels if (sharg) {
35126352Skarels error = copystr(sharg, cp, (unsigned)cc, &len);
35221104Skarels sharg += len;
35321104Skarels } else {
35426352Skarels error = copyinstr((caddr_t)ap, cp, (unsigned)cc,
35526352Skarels &len);
35621104Skarels ap += len;
35721104Skarels }
35816750Ssam cp += len;
35916750Ssam nc += len;
36016750Ssam cc -= len;
36145356Smckusick } while (error == ENAMETOOLONG);
36245726Smckusick if (error)
36345726Smckusick goto bad;
36412789Ssam }
36552539Storek
36652539Storek /*
36752539Storek * XXX the following is excessively bogus
36852539Storek *
36952539Storek * Compute initial process stack size and location of argc
37052539Storek * and character strings. `nc' is currently just the number
37152539Storek * of characters of arg and env strings.
37252539Storek *
37353124Smckusick * nc = size of ps_strings structure +
37453124Smckusick * size of signal code +
37553124Smckusick * 4 bytes of NULL pointer +
37653124Smckusick * nc,
37753124Smckusick * rounded to nearest integer;
37852539Storek * ucp = USRSTACK - nc; [user characters pointer]
37952539Storek * apsize = padding (if any) +
38052539Storek * 4 bytes of NULL pointer +
38152539Storek * ne 4-byte pointers to env strings +
38252539Storek * 4 bytes of NULL pointer +
38352539Storek * (na-ne) 4-byte pointers to arg strings +
38452539Storek * 4 bytes of argc;
38552539Storek * (this is the same as nc + (na+3)*4)
38652539Storek * ap = ucp - apsize; [user address of argc]
38752539Storek * ssize = ssize + nc + machine-dependent space;
38852539Storek */
38953124Smckusick nc = (sizeof(ps) + szsigcode + 4 + nc + NBPW-1) & ~(NBPW - 1);
39057297Sbostic #if defined(sparc) || defined(mips)
39152539Storek ucp = USRSTACK;
39257297Sbostic ssize = ALIGN(nc + (na + 3) * NBPW);
39352539Storek ap = ucp - ssize;
39452539Storek ucp -= nc;
39557297Sbostic #ifdef sparc
39652539Storek ssize += sizeof(struct rwindow);
39757297Sbostic #endif
39852539Storek #else
39952539Storek ssize = (na + 3) * NBPW;
40052539Storek ucp = USRSTACK - nc;
40152539Storek ap = ucp - ssize;
40252539Storek ssize += nc;
40352539Storek #endif
40452539Storek error = getxfile(p, vp, &exdata.ex_exec, paged, ssize, uid, gid);
40545726Smckusick if (error)
40612789Ssam goto bad;
40765118Spendry
40865118Spendry /* take a reference to the new text vnode (for procfs) */
40965118Spendry if (p->p_textvp)
41065118Spendry vrele(p->p_textvp);
41165118Spendry VREF(vp);
41265118Spendry p->p_textvp = vp;
41365118Spendry
41437728Smckusick vput(vp);
41537728Smckusick vp = NULL;
41612789Ssam
41742085Smckusick #ifdef HPUXCOMPAT
41812789Ssam /*
41942085Smckusick * We are now committed to the exec so we can save the exec
42042085Smckusick * header in the pcb where we can dump it if necessary in core()
42142085Smckusick */
42257305Shibler if (p->p_md.md_flags & MDP_HPUX)
42342085Smckusick bcopy((caddr_t)&hhead,
42457305Shibler (caddr_t)p->p_addr->u_md.md_exec, sizeof hhead);
42542085Smckusick #endif
42642085Smckusick
42742085Smckusick /*
42816750Ssam * Copy back arglist.
42912789Ssam */
43052377Smckusick cpu_setstack(p, ap);
43112789Ssam (void) suword((caddr_t)ap, na-ne);
43212789Ssam nc = 0;
43345726Smckusick cp = (char *) execargs;
43445726Smckusick cc = NCARGS;
43553124Smckusick ps.ps_argvstr = (char *)ucp; /* first argv string */
43653124Smckusick ps.ps_nargvstr = na - ne; /* argc */
43712789Ssam for (;;) {
43812789Ssam ap += NBPW;
43916750Ssam if (na == ne) {
44012789Ssam (void) suword((caddr_t)ap, 0);
44112789Ssam ap += NBPW;
44253124Smckusick ps.ps_envstr = (char *)ucp;
44353124Smckusick ps.ps_nenvstr = ne;
44412789Ssam }
44512789Ssam if (--na < 0)
44612789Ssam break;
44712789Ssam (void) suword((caddr_t)ap, ucp);
44812789Ssam do {
44926352Skarels error = copyoutstr(cp, (caddr_t)ucp, (unsigned)cc,
45026352Skarels &len);
45116786Ssam ucp += len;
45216786Ssam cp += len;
45316786Ssam nc += len;
45416786Ssam cc -= len;
45545356Smckusick } while (error == ENAMETOOLONG);
45616786Ssam if (error == EFAULT)
45716786Ssam panic("exec: EFAULT");
45812789Ssam }
45912789Ssam (void) suword((caddr_t)ap, 0);
46053124Smckusick (void) copyout((caddr_t)&ps, (caddr_t)PS_STRINGS, sizeof(ps));
46121104Skarels
46242921Smckusick execsigs(p);
46321104Skarels
46445914Smckusick for (nc = fdp->fd_lastfile; nc >= 0; --nc) {
46547652Skarels if (fdp->fd_ofileflags[nc] & UF_EXCLOSE) {
46647652Skarels (void) closef(fdp->fd_ofiles[nc], p);
46747652Skarels fdp->fd_ofiles[nc] = NULL;
46847652Skarels fdp->fd_ofileflags[nc] = 0;
46947540Skarels if (nc < fdp->fd_freefile)
47047540Skarels fdp->fd_freefile = nc;
47121104Skarels }
47247652Skarels fdp->fd_ofileflags[nc] &= ~UF_MAPPED;
47321104Skarels }
47447652Skarels /*
47547652Skarels * Adjust fd_lastfile to account for descriptors closed above.
47647652Skarels * Don't decrement fd_lastfile past 0, as it's unsigned.
47747652Skarels */
47847652Skarels while (fdp->fd_lastfile > 0 && fdp->fd_ofiles[fdp->fd_lastfile] == NULL)
47945914Smckusick fdp->fd_lastfile--;
48049562Swilliam setregs(p, exdata.ex_exec.a_entry, retval);
48148900Skarels #ifdef COPY_SIGCODE
48216696Smckusick /*
48345726Smckusick * Install sigcode at top of user stack.
48445726Smckusick */
48553124Smckusick copyout((caddr_t)sigcode, (caddr_t)PS_STRINGS - szsigcode, szsigcode);
48648900Skarels #endif
48745726Smckusick /*
48816696Smckusick * Remember file name for accounting.
48916696Smckusick */
49047540Skarels p->p_acflag &= ~AFORK;
49152376Smckusick if (nd.ni_cnd.cn_namelen > MAXCOMLEN)
49252376Smckusick nd.ni_cnd.cn_namelen = MAXCOMLEN;
49352376Smckusick bcopy((caddr_t)nd.ni_cnd.cn_nameptr, (caddr_t)p->p_comm,
49452539Storek (unsigned)nd.ni_cnd.cn_namelen);
49552376Smckusick p->p_comm[nd.ni_cnd.cn_namelen] = '\0';
49648900Skarels cpu_exec(p);
49712789Ssam bad:
49852376Smckusick FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
49945726Smckusick if (execargs)
50045726Smckusick kmem_free_wakeup(exec_map, execargs, NCARGS);
50137728Smckusick if (vp)
50237728Smckusick vput(vp);
50344404Skarels return (error);
50412789Ssam }
50512789Ssam
50612789Ssam /*
50712789Ssam * Read in and set up memory for executed file.
50812789Ssam */
getxfile(p,vp,ep,paged,ssize,uid,gid)50952539Storek getxfile(p, vp, ep, paged, ssize, uid, gid)
51042921Smckusick register struct proc *p;
51137728Smckusick register struct vnode *vp;
51216746Ssam register struct exec *ep;
51352539Storek int paged, ssize, uid, gid;
51412789Ssam {
51547540Skarels register struct ucred *cred = p->p_ucred;
51652539Storek register struct vmspace *vm = p->p_vmspace;
51752539Storek vm_offset_t addr;
51852539Storek vm_size_t xts, size;
51952539Storek segsz_t ds;
52042085Smckusick off_t toff;
52145726Smckusick int error = 0;
52212789Ssam
52342085Smckusick #ifdef HPUXCOMPAT
52452831Smckusick if (ep->a_mid == MID_HPUX)
52552831Smckusick toff = paged ? CLBYTES : sizeof(struct hpux_exec);
52652831Smckusick else
52745726Smckusick #endif
52851039Sralph #ifdef COFF
52951039Sralph toff = N_TXTOFF(*ep);
53051039Sralph #else
53152539Storek #ifdef sparc
53252539Storek if (ep->a_mid == MID_SUN_SPARC)
53352539Storek toff = paged ? 0 : sizeof(struct exec);
53452539Storek else
53552539Storek #endif
53647733Skarels if (paged)
53757974Sralph #ifdef mips
53857974Sralph toff = 0;
53957974Sralph #else
54045726Smckusick toff = CLBYTES;
54157974Sralph #endif
54212789Ssam else
54345726Smckusick toff = sizeof (struct exec);
54451039Sralph #endif
54537728Smckusick if (ep->a_text != 0 && (vp->v_flag & VTEXT) == 0 &&
54650108Smckusick vp->v_writecount != 0)
54750108Smckusick return (ETXTBSY);
54812789Ssam
54912789Ssam /*
55012789Ssam * Compute text and data sizes and make sure not too large.
55152539Storek * Text size is rounded to an ``ld page''; data+bss is left
55252539Storek * in machine pages. Check data and bss separately as they
55352539Storek * may overflow when summed together. (XXX not done yet)
55412789Ssam */
55552539Storek xts = roundup(ep->a_text, __LDPGSZ);
55616750Ssam ds = clrnd(btoc(ep->a_data + ep->a_bss));
55747652Skarels
55847652Skarels /*
55947652Skarels * If we're sharing the address space, allocate a new space
56047652Skarels * and release our reference to the old one. Otherwise,
56147652Skarels * empty out the existing vmspace.
56247652Skarels */
56352539Storek #ifdef sparc
56452539Storek kill_user_windows(p); /* before addrs go away */
56552539Storek #endif
56647652Skarels if (vm->vm_refcnt > 1) {
56749562Swilliam p->p_vmspace = vmspace_alloc(VM_MIN_ADDRESS,
56849562Swilliam VM_MAXUSER_ADDRESS, 1);
56947652Skarels vmspace_free(vm);
57047652Skarels vm = p->p_vmspace;
57147652Skarels } else {
57245726Smckusick #ifdef SYSVSHM
57347652Skarels if (vm->vm_shm)
57447652Skarels shmexit(p);
57545726Smckusick #endif
57649562Swilliam (void) vm_map_remove(&vm->vm_map, VM_MIN_ADDRESS,
57749562Swilliam VM_MAXUSER_ADDRESS);
57847652Skarels }
57912789Ssam /*
58047540Skarels * If parent is waiting for us to exec or exit,
58164589Sbostic * P_PPWAIT will be set; clear it and wakeup parent.
58212789Ssam */
58364589Sbostic if (p->p_flag & P_PPWAIT) {
58464589Sbostic p->p_flag &= ~P_PPWAIT;
58547540Skarels wakeup((caddr_t) p->p_pptr);
58612789Ssam }
58759933Sakito #if defined(HP380) || defined(LUNA2)
58857305Shibler /* default to copyback caching on 68040 */
58957305Shibler if (mmutype == MMU_68040)
59057305Shibler p->p_md.md_flags |= (MDP_CCBDATA|MDP_CCBSTACK);
59157305Shibler #endif
59242085Smckusick #ifdef HPUXCOMPAT
59357305Shibler p->p_md.md_flags &= ~(MDP_HPUX|MDP_HPUXMMAP);
59457305Shibler /* note that we are an HP-UX binary */
59542085Smckusick if (ep->a_mid == MID_HPUX)
59657305Shibler p->p_md.md_flags |= MDP_HPUX;
59757305Shibler /* deal with miscellaneous attributes */
59857305Shibler if (ep->a_trsize & HPUXM_VALID) {
59957305Shibler if (ep->a_trsize & HPUXM_DATAWT)
60057305Shibler p->p_md.md_flags &= ~MDP_CCBDATA;
60157305Shibler if (ep->a_trsize & HPUXM_STKWT)
60257305Shibler p->p_md.md_flags &= ~MDP_CCBSTACK;
60357305Shibler }
60442085Smckusick #endif
60551039Sralph #ifdef ULTRIXCOMPAT
60651039Sralph /*
60751039Sralph * Always start out as an ULTRIX process.
60851039Sralph * A system call in crt0.o will change us to BSD system calls later.
60951039Sralph */
61051039Sralph p->p_md.md_flags |= MDP_ULTRIX;
61151039Sralph #endif
61264589Sbostic p->p_flag |= P_EXEC;
61351039Sralph #ifndef COFF
61445726Smckusick addr = VM_MIN_ADDRESS;
61552539Storek if (vm_allocate(&vm->vm_map, &addr, xts + ctob(ds), FALSE)) {
61645726Smckusick uprintf("Cannot allocate text+data space\n");
61745726Smckusick error = ENOMEM; /* XXX */
61845726Smckusick goto badmap;
61945726Smckusick }
62051039Sralph vm->vm_taddr = (caddr_t)VM_MIN_ADDRESS;
62152539Storek vm->vm_daddr = (caddr_t)(VM_MIN_ADDRESS + xts);
62251039Sralph #else /* COFF */
62351039Sralph addr = (vm_offset_t)ep->ex_aout.codeStart;
62451039Sralph vm->vm_taddr = (caddr_t)addr;
62552539Storek if (vm_allocate(&vm->vm_map, &addr, xts, FALSE)) {
62651039Sralph uprintf("Cannot allocate text space\n");
62751039Sralph error = ENOMEM; /* XXX */
62851039Sralph goto badmap;
62951039Sralph }
63051039Sralph addr = (vm_offset_t)ep->ex_aout.heapStart;
63151039Sralph vm->vm_daddr = (caddr_t)addr;
63251039Sralph if (vm_allocate(&vm->vm_map, &addr, round_page(ctob(ds)), FALSE)) {
63351039Sralph uprintf("Cannot allocate data space\n");
63451039Sralph error = ENOMEM; /* XXX */
63551039Sralph goto badmap;
63651039Sralph }
63751039Sralph #endif /* COFF */
63845726Smckusick size = round_page(MAXSSIZ); /* XXX */
63949690Swilliam #ifdef i386
64049690Swilliam addr = trunc_page(USRSTACK - size) - NBPG; /* XXX */
64149690Swilliam #else
64249562Swilliam addr = trunc_page(USRSTACK - size);
64349690Swilliam #endif
64447540Skarels if (vm_allocate(&vm->vm_map, &addr, size, FALSE)) {
64545726Smckusick uprintf("Cannot allocate stack space\n");
64645726Smckusick error = ENOMEM; /* XXX */
64745726Smckusick goto badmap;
64845726Smckusick }
64949562Swilliam size -= round_page(p->p_rlimit[RLIMIT_STACK].rlim_cur);
65049562Swilliam if (vm_map_protect(&vm->vm_map, addr, addr+size, VM_PROT_NONE, FALSE)) {
65149562Swilliam uprintf("Cannot protect stack space\n");
65249562Swilliam error = ENOMEM;
65349562Swilliam goto badmap;
65449562Swilliam }
65547540Skarels vm->vm_maxsaddr = (caddr_t)addr;
65612789Ssam
65747733Skarels if (paged == 0) {
65847652Skarels /*
65947652Skarels * Read in data segment.
66047652Skarels */
66147540Skarels (void) vn_rdwr(UIO_READ, vp, vm->vm_daddr, (int) ep->a_data,
66247540Skarels (off_t)(toff + ep->a_text), UIO_USERSPACE,
66348019Smckusick (IO_UNIT|IO_NODELOCKED), cred, (int *)0, p);
66447652Skarels /*
66547652Skarels * Read in text segment if necessary (0410),
66647652Skarels * and read-protect it.
66747652Skarels */
66845726Smckusick if (ep->a_text > 0) {
66947540Skarels error = vn_rdwr(UIO_READ, vp, vm->vm_taddr,
67053311Smckusick (int)ep->a_text, toff, UIO_USERSPACE,
67153311Smckusick (IO_UNIT|IO_NODELOCKED), cred, (int *)0, p);
67253311Smckusick (void) vm_map_protect(&vm->vm_map,
67353311Smckusick (vm_offset_t)vm->vm_taddr,
67453311Smckusick (vm_offset_t)vm->vm_taddr + trunc_page(ep->a_text),
67553311Smckusick VM_PROT_READ|VM_PROT_EXECUTE, FALSE);
67645726Smckusick }
67745726Smckusick } else {
67845726Smckusick /*
67945726Smckusick * Allocate a region backed by the exec'ed vnode.
68045726Smckusick */
68151039Sralph #ifndef COFF
68245726Smckusick addr = VM_MIN_ADDRESS;
68352539Storek size = round_page(xts + ep->a_data);
68458594Shibler error = vm_mmap(&vm->vm_map, &addr, size,
68558594Shibler VM_PROT_ALL, VM_PROT_ALL,
68654296Smckusick MAP_COPY|MAP_FIXED,
68747540Skarels (caddr_t)vp, (vm_offset_t)toff);
68852539Storek (void) vm_map_protect(&vm->vm_map, addr, addr + xts,
68947540Skarels VM_PROT_READ|VM_PROT_EXECUTE, FALSE);
69051039Sralph #else /* COFF */
69151039Sralph addr = (vm_offset_t)vm->vm_taddr;
69252539Storek size = xts;
69351039Sralph error = vm_mmap(&vm->vm_map, &addr, size,
69458594Shibler VM_PROT_READ|VM_PROT_EXECUTE, VM_PROT_ALL,
69554296Smckusick MAP_COPY|MAP_FIXED,
69651039Sralph (caddr_t)vp, (vm_offset_t)toff);
69751039Sralph toff += size;
69851039Sralph addr = (vm_offset_t)vm->vm_daddr;
69951039Sralph size = round_page(ep->a_data);
70058594Shibler error = vm_mmap(&vm->vm_map, &addr, size,
70158594Shibler VM_PROT_ALL, VM_PROT_ALL,
70254296Smckusick MAP_COPY|MAP_FIXED,
70351039Sralph (caddr_t)vp, (vm_offset_t)toff);
70451039Sralph #endif /* COFF */
70547652Skarels vp->v_flag |= VTEXT;
70629946Skarels }
70752539Storek if (error) {
70845726Smckusick badmap:
70957533Smckusick killproc(p, "VM allocation in exec");
71064589Sbostic p->p_flag |= P_NOSWAP;
71145726Smckusick return(error);
71245726Smckusick }
71312789Ssam
71412789Ssam /*
71512789Ssam * set SUID/SGID protections, if no tracing
71612789Ssam */
71764589Sbostic p->p_flag &= ~P_SUGID;
71864589Sbostic if ((p->p_flag & P_TRACED) == 0) {
71945355Smarc if (uid != cred->cr_uid || gid != cred->cr_gid) {
72047540Skarels p->p_ucred = cred = crcopy(cred);
72165746Shibler #ifdef KTRACE
72245355Smarc /*
72345355Smarc * If process is being ktraced, turn off - unless
72445355Smarc * root set it.
72545355Smarc */
72645355Smarc if (p->p_tracep && !(p->p_traceflag & KTRFAC_ROOT)) {
72745355Smarc vrele(p->p_tracep);
72845355Smarc p->p_tracep = NULL;
72945355Smarc p->p_traceflag = 0;
73045355Smarc }
73165746Shibler #endif
73252539Storek cred->cr_uid = uid;
73352539Storek cred->cr_gid = gid;
73464589Sbostic p->p_flag |= P_SUGID;
73545355Smarc }
73612789Ssam } else
73738928Skarels psignal(p, SIGTRAP);
73847540Skarels p->p_cred->p_svuid = cred->cr_uid;
73947540Skarels p->p_cred->p_svgid = cred->cr_gid;
74052539Storek vm->vm_tsize = btoc(xts);
74147540Skarels vm->vm_dsize = ds;
74253743Smccanne vm->vm_ssize = btoc(ssize);
74364589Sbostic if (p->p_flag & P_PROFIL)
74454134Smckusick stopprofclock(p);
74529946Skarels #if defined(tahoe)
74648900Skarels /* move this when tahoe cpu_exec is created */
74748900Skarels p->p_addr->u_pcb.pcb_savacc.faddr = (float *)NULL;
74829946Skarels #endif
74942921Smckusick return (0);
75012789Ssam }
751