account for I/O's in progress
[unix-history] / usr / src / sys / kern / kern_exec.c
CommitLineData
da7c5cc6 1/*
c4ec2128
KM
2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3 * All rights reserved.
da7c5cc6 4 *
c4ec2128
KM
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 *
c65056fe 17 * @(#)kern_exec.c 7.18 (Berkeley) %G%
da7c5cc6 18 */
28db9b87 19
94368568
JB
20#include "param.h"
21#include "systm.h"
22#include "map.h"
94368568
JB
23#include "user.h"
24#include "kernel.h"
25#include "proc.h"
c4ec2128
KM
26#include "mount.h"
27#include "ucred.h"
28#include "malloc.h"
94368568 29#include "buf.h"
c4ec2128 30#include "vnode.h"
94368568
JB
31#include "seg.h"
32#include "vm.h"
33#include "text.h"
34#include "file.h"
35#include "uio.h"
36#include "acct.h"
37#include "exec.h"
28db9b87 38
d301d150
KM
39#include "machine/reg.h"
40#include "machine/pte.h"
41#include "machine/psl.h"
42#include "machine/mtpr.h"
43
28db9b87
SL
44/*
45 * exec system call, with and without environments.
46 */
47struct execa {
48 char *fname;
49 char **argp;
50 char **envp;
51};
52
53execv()
54{
55 ((struct execa *)u.u_ap)->envp = NULL;
56 execve();
57}
58
59execve()
60{
61 register nc;
62 register char *cp;
63 register struct buf *bp;
c4ec2128 64 struct buf *tbp;
28db9b87 65 register struct execa *uap;
8011f5df
MK
66 int na, ne, ucp, ap, cc;
67 unsigned len;
28db9b87
SL
68 int indir, uid, gid;
69 char *sharg;
c4ec2128 70 struct vnode *vp;
28db9b87 71 swblk_t bno;
c4ec2128 72 struct vattr vattr;
28db9b87 73 char cfname[MAXCOMLEN + 1];
cb9392ae 74 char cfarg[MAXINTERP];
9fd50f35 75 union {
cb9392ae 76 char ex_shell[MAXINTERP]; /* #! and interpreter name */
9fd50f35
SL
77 struct exec ex_exec;
78 } exdata;
715baff1 79 register struct nameidata *ndp = &u.u_nd;
f3aaea26 80 int resid, error;
ec67a3ce
MK
81#ifdef SECSIZE
82 extern long argdbsize; /* XXX */
83#endif SECSIZE
28db9b87 84
c4ec2128 85 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
715baff1
KM
86 ndp->ni_segflg = UIO_USERSPACE;
87 ndp->ni_dirp = ((struct execa *)u.u_ap)->fname;
c4ec2128 88 if (u.u_error = namei(ndp)) {
28db9b87 89 return;
c4ec2128
KM
90 }
91 vp = ndp->ni_vp;
28db9b87
SL
92 bno = 0;
93 bp = 0;
94 indir = 0;
ba7abd07
MK
95 uid = u.u_cred->cr_uid;
96 gid = u.u_cred->cr_gid;
c4ec2128
KM
97 if (u.u_error = VOP_GETATTR(vp, &vattr, u.u_cred))
98 goto bad;
99 if (vp->v_mount->m_flag & M_NOEXEC) {
4193b6f2 100 u.u_error = EACCES;
c4ec2128
KM
101 goto bad;
102 }
103 if ((vp->v_mount->m_flag & M_NOSUID) == 0) {
104 if (vattr.va_mode & VSUID)
105 uid = vattr.va_uid;
106 if (vattr.va_mode & VSGID)
107 gid = vattr.va_gid;
108 }
28db9b87
SL
109
110 again:
0aa3b235 111 if (u.u_error = VOP_ACCESS(vp, VEXEC, u.u_cred))
28db9b87 112 goto bad;
c4ec2128 113 if ((u.u_procp->p_flag & STRC) &&
0aa3b235 114 (u.u_error = VOP_ACCESS(vp, VREAD, u.u_cred)))
28db9b87 115 goto bad;
c4ec2128
KM
116 if (vp->v_type != VREG ||
117 (vattr.va_mode & (VEXEC|(VEXEC>>3)|(VEXEC>>6))) == 0) {
28db9b87
SL
118 u.u_error = EACCES;
119 goto bad;
120 }
121
122 /*
f3aaea26 123 * Read in first few bytes of file for segment sizes, magic number:
c4ec2128
KM
124 * OMAGIC = plain executable
125 * NMAGIC = RO text
126 * ZMAGIC = demand paged RO text
28db9b87
SL
127 * Also an ASCII line beginning with #! is
128 * the file name of a ``shell'' and arguments may be prepended
129 * to the argument list if given here.
130 *
131 * SHELL NAMES ARE LIMITED IN LENGTH.
132 *
133 * ONLY ONE ARGUMENT MAY BE PASSED TO THE SHELL FROM
134 * THE ASCII LINE.
135 */
9fd50f35 136 exdata.ex_shell[0] = '\0'; /* for zero length files */
c4ec2128
KM
137 u.u_error = vn_rdwr(UIO_READ, vp, (caddr_t)&exdata, sizeof (exdata),
138 (off_t)0, UIO_SYSSPACE, (IO_UNIT|IO_NODELOCKED), u.u_cred, &resid);
28db9b87
SL
139 if (u.u_error)
140 goto bad;
28db9b87 141#ifndef lint
ce66cb03 142 if (resid > sizeof(exdata) - sizeof(exdata.ex_exec) &&
9fd50f35 143 exdata.ex_shell[0] != '#') {
28db9b87
SL
144 u.u_error = ENOEXEC;
145 goto bad;
146 }
147#endif
aec7dd3b 148 switch ((int)exdata.ex_exec.a_magic) {
28db9b87 149
c4ec2128 150 case OMAGIC:
9fd50f35
SL
151 exdata.ex_exec.a_data += exdata.ex_exec.a_text;
152 exdata.ex_exec.a_text = 0;
28db9b87
SL
153 break;
154
c4ec2128
KM
155 case ZMAGIC:
156 case NMAGIC:
9fd50f35 157 if (exdata.ex_exec.a_text == 0) {
28db9b87
SL
158 u.u_error = ENOEXEC;
159 goto bad;
160 }
161 break;
162
163 default:
446115cb
MK
164 if (exdata.ex_shell[0] != '#' ||
165 exdata.ex_shell[1] != '!' ||
166 indir) {
28db9b87
SL
167 u.u_error = ENOEXEC;
168 goto bad;
169 }
d26813a4 170 for (cp = &exdata.ex_shell[2];; ++cp) {
446115cb 171 if (cp >= &exdata.ex_shell[MAXINTERP]) {
d26813a4
KB
172 u.u_error = ENOEXEC;
173 goto bad;
174 }
175 if (*cp == '\n') {
28db9b87
SL
176 *cp = '\0';
177 break;
178 }
d26813a4
KB
179 if (*cp == '\t')
180 *cp = ' ';
28db9b87 181 }
446115cb
MK
182 cp = &exdata.ex_shell[2];
183 while (*cp == ' ')
184 cp++;
715baff1 185 ndp->ni_dirp = cp;
446115cb
MK
186 while (*cp && *cp != ' ')
187 cp++;
e7db1101 188 cfarg[0] = '\0';
28db9b87 189 if (*cp) {
446115cb
MK
190 *cp++ = '\0';
191 while (*cp == ' ')
192 cp++;
ce66cb03 193 if (*cp)
cb9392ae 194 bcopy((caddr_t)cp, (caddr_t)cfarg, MAXINTERP);
e7db1101 195 }
446115cb 196 indir = 1;
c4ec2128
KM
197 vput(vp);
198 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
715baff1 199 ndp->ni_segflg = UIO_SYSSPACE;
c4ec2128 200 if (u.u_error = namei(ndp))
28db9b87 201 return;
c4ec2128
KM
202 vp = ndp->ni_vp;
203 if (u.u_error = VOP_GETATTR(vp, &vattr, u.u_cred))
204 goto bad;
ce66cb03
MK
205 bcopy((caddr_t)ndp->ni_dent.d_name, (caddr_t)cfname,
206 MAXCOMLEN);
207 cfname[MAXCOMLEN] = '\0';
ba7abd07
MK
208 uid = u.u_cred->cr_uid; /* shell scripts can't be setuid */
209 gid = u.u_cred->cr_gid;
28db9b87
SL
210 goto again;
211 }
212
213 /*
214 * Collect arguments on "file" in swap space.
215 */
216 na = 0;
217 ne = 0;
218 nc = 0;
f3aaea26 219 cc = 0;
28db9b87 220 uap = (struct execa *)u.u_ap;
ec67a3ce
MK
221#ifdef SECSIZE
222 bno = rmalloc(argmap, (clrnd((int)btoc(NCARGS))) * CLBYTES / argdbsize);
223#else SECSIZE
9fd50f35 224 bno = rmalloc(argmap, (long)ctod(clrnd((int)btoc(NCARGS))));
ec67a3ce 225#endif SECSIZE
9fd50f35 226 if (bno == 0) {
d03b3d84 227 swkill(u.u_procp, "exec: no swap space");
28db9b87
SL
228 goto bad;
229 }
230 if (bno % CLSIZE)
231 panic("execa rmalloc");
f3aaea26
SL
232 /*
233 * Copy arguments into file in argdev area.
234 */
28db9b87
SL
235 if (uap->argp) for (;;) {
236 ap = NULL;
ce66cb03
MK
237 sharg = NULL;
238 if (indir && na == 0) {
239 sharg = cfname;
240 ap = (int)sharg;
241 uap->argp++; /* ignore argv[0] */
242 } else if (indir && (na == 1 && cfarg[0])) {
243 sharg = cfarg;
244 ap = (int)sharg;
245 } else if (indir && (na == 1 || na == 2 && cfarg[0]))
28db9b87
SL
246 ap = (int)uap->fname;
247 else if (uap->argp) {
248 ap = fuword((caddr_t)uap->argp);
249 uap->argp++;
250 }
f3aaea26 251 if (ap == NULL && uap->envp) {
28db9b87 252 uap->argp = NULL;
f3aaea26
SL
253 if ((ap = fuword((caddr_t)uap->envp)) != NULL)
254 uap->envp++, ne++;
28db9b87
SL
255 }
256 if (ap == NULL)
257 break;
258 na++;
f3aaea26 259 if (ap == -1) {
1daa95c7 260 u.u_error = EFAULT;
f3aaea26
SL
261 break;
262 }
28db9b87 263 do {
f3aaea26
SL
264 if (cc <= 0) {
265 /*
266 * We depend on NCARGS being a multiple of
ec67a3ce 267 * CLBYTES. This way we need only check
f3aaea26
SL
268 * overflow before each buffer allocation.
269 */
270 if (nc >= NCARGS-1) {
271 error = E2BIG;
272 break;
273 }
28db9b87
SL
274 if (bp)
275 bdwrite(bp);
ec67a3ce
MK
276 cc = CLBYTES;
277#ifdef SECSIZE
278 bp = getblk(argdev, bno + nc / argdbsize, cc,
279 argdbsize);
280#else SECSIZE
c4ec2128 281 bp = getblk(argdev_vp, bno + ctod(nc/NBPG), cc);
ec67a3ce 282#endif SECSIZE
28db9b87
SL
283 cp = bp->b_un.b_addr;
284 }
ce66cb03 285 if (sharg) {
8011f5df 286 error = copystr(sharg, cp, (unsigned)cc, &len);
ce66cb03
MK
287 sharg += len;
288 } else {
8011f5df
MK
289 error = copyinstr((caddr_t)ap, cp, (unsigned)cc,
290 &len);
ce66cb03
MK
291 ap += len;
292 }
f3aaea26
SL
293 cp += len;
294 nc += len;
295 cc -= len;
296 } while (error == ENOENT);
297 if (error) {
298 u.u_error = error;
299 if (bp)
300 brelse(bp);
301 bp = 0;
302 goto badarg;
303 }
28db9b87
SL
304 }
305 if (bp)
306 bdwrite(bp);
307 bp = 0;
308 nc = (nc + NBPW-1) & ~(NBPW-1);
c4ec2128 309 getxfile(vp, &exdata.ex_exec, nc + (na+4)*NBPW, uid, gid, u.u_cred);
28db9b87
SL
310 if (u.u_error) {
311badarg:
c4ec2128 312 for (cc = 0; cc < nc; cc += CLBYTES) {
2fd88d7d 313 (void) baddr(argdev_vp, bno + ctod(cc/NBPG),
9ad9d3f8 314 CLBYTES, NOCRED, &tbp);
c4ec2128 315 bp = tbp;
ec67a3ce 316#endif SECSIZE
28db9b87
SL
317 if (bp) {
318 bp->b_flags |= B_AGE; /* throw away */
319 bp->b_flags &= ~B_DELWRI; /* cancel io */
320 brelse(bp);
321 bp = 0;
322 }
323 }
324 goto bad;
325 }
c4ec2128
KM
326 vput(vp);
327 vp = NULL;
28db9b87
SL
328
329 /*
f3aaea26 330 * Copy back arglist.
28db9b87
SL
331 */
332 ucp = USRSTACK - nc - NBPW;
333 ap = ucp - na*NBPW - 3*NBPW;
334 u.u_ar0[SP] = ap;
335 (void) suword((caddr_t)ap, na-ne);
336 nc = 0;
72d4f41a 337 cc = 0;
28db9b87
SL
338 for (;;) {
339 ap += NBPW;
f3aaea26 340 if (na == ne) {
28db9b87
SL
341 (void) suword((caddr_t)ap, 0);
342 ap += NBPW;
343 }
344 if (--na < 0)
345 break;
346 (void) suword((caddr_t)ap, ucp);
347 do {
72d4f41a 348 if (cc <= 0) {
28db9b87
SL
349 if (bp)
350 brelse(bp);
ec67a3ce
MK
351 cc = CLBYTES;
352#ifdef SECSIZE
353 bp = bread(argdev, bno + nc / argdbsize, cc,
354 argdbsize);
355#else SECSIZE
c4ec2128 356 error = bread(argdev_vp,
9ad9d3f8
KM
357 (daddr_t)(bno + ctod(nc / NBPG)), cc,
358 NOCRED, &tbp);
c4ec2128 359 bp = tbp;
ec67a3ce 360#endif SECSIZE
28db9b87
SL
361 bp->b_flags |= B_AGE; /* throw away */
362 bp->b_flags &= ~B_DELWRI; /* cancel io */
363 cp = bp->b_un.b_addr;
364 }
8011f5df
MK
365 error = copyoutstr(cp, (caddr_t)ucp, (unsigned)cc,
366 &len);
72d4f41a
SL
367 ucp += len;
368 cp += len;
369 nc += len;
370 cc -= len;
371 } while (error == ENOENT);
372 if (error == EFAULT)
373 panic("exec: EFAULT");
28db9b87
SL
374 }
375 (void) suword((caddr_t)ap, 0);
ce66cb03 376
ba7abd07 377 execsigs(u.u_procp);
ce66cb03
MK
378
379 for (nc = u.u_lastfile; nc >= 0; --nc) {
380 if (u.u_pofile[nc] & UF_EXCLOSE) {
69be5b7a 381 (void) closef(u.u_ofile[nc]);
ce66cb03
MK
382 u.u_ofile[nc] = NULL;
383 u.u_pofile[nc] = 0;
384 }
385 u.u_pofile[nc] &= ~UF_MAPPED;
386 }
387 while (u.u_lastfile >= 0 && u.u_ofile[u.u_lastfile] == NULL)
388 u.u_lastfile--;
9fd50f35 389 setregs(exdata.ex_exec.a_entry);
715baff1
KM
390 /*
391 * Remember file name for accounting.
392 */
393 u.u_acflag &= ~AFORK;
ce66cb03
MK
394 if (indir)
395 bcopy((caddr_t)cfname, (caddr_t)u.u_comm, MAXCOMLEN);
396 else {
397 if (ndp->ni_dent.d_namlen > MAXCOMLEN)
398 ndp->ni_dent.d_namlen = MAXCOMLEN;
399 bcopy((caddr_t)ndp->ni_dent.d_name, (caddr_t)u.u_comm,
400 (unsigned)(ndp->ni_dent.d_namlen + 1));
401 }
28db9b87
SL
402bad:
403 if (bp)
404 brelse(bp);
405 if (bno)
ec67a3ce
MK
406#ifdef SECSIZE
407 rmfree(argmap, (clrnd((int)btoc(NCARGS))) * CLBYTES / argdbsize,
408 bno);
409#else SECSIZE
28db9b87 410 rmfree(argmap, (long)ctod(clrnd((int) btoc(NCARGS))), bno);
ec67a3ce 411#endif SECSIZE
c4ec2128
KM
412 if (vp)
413 vput(vp);
28db9b87
SL
414}
415
416/*
417 * Read in and set up memory for executed file.
418 */
c4ec2128
KM
419getxfile(vp, ep, nargc, uid, gid, cred)
420 register struct vnode *vp;
9fd50f35 421 register struct exec *ep;
28db9b87 422 int nargc, uid, gid;
c4ec2128 423 struct ucred *cred;
28db9b87 424{
ba7abd07 425 register struct proc *p = u.u_procp;
0c48b03e 426 size_t ts, ds, ids, uds, ss;
28db9b87
SL
427 int pagi;
428
c4ec2128
KM
429 if (ep->a_magic == ZMAGIC)
430 pagi = SPAGV;
28db9b87
SL
431 else
432 pagi = 0;
c4ec2128 433 if (vp->v_text && (vp->v_text->x_flag & XTRC)) {
ce08d752
MK
434 u.u_error = ETXTBSY;
435 goto bad;
436 }
c4ec2128 437 if (ep->a_text != 0 && (vp->v_flag & VTEXT) == 0 &&
c65056fe 438 vp->v_usecount != 1) {
28db9b87
SL
439 register struct file *fp;
440
441 for (fp = file; fp < fileNFILE; fp++) {
c4ec2128 442 if (fp->f_type == DTYPE_VNODE &&
28db9b87 443 fp->f_count > 0 &&
c4ec2128
KM
444 (struct vnode *)fp->f_data == vp &&
445 (fp->f_flag & FWRITE)) {
28db9b87
SL
446 u.u_error = ETXTBSY;
447 goto bad;
448 }
449 }
450 }
451
452 /*
453 * Compute text and data sizes and make sure not too large.
0c48b03e
KM
454 * NB - Check data and bss separately as they may overflow
455 * when summed together.
28db9b87 456 */
9fd50f35 457 ts = clrnd(btoc(ep->a_text));
0c48b03e
KM
458 ids = clrnd(btoc(ep->a_data));
459 uds = clrnd(btoc(ep->a_bss));
f3aaea26 460 ds = clrnd(btoc(ep->a_data + ep->a_bss));
28db9b87 461 ss = clrnd(SSIZE + btoc(nargc));
0c48b03e 462 if (chksize((unsigned)ts, (unsigned)ids, (unsigned)uds, (unsigned)ss))
28db9b87
SL
463 goto bad;
464
465 /*
466 * Make sure enough space to start process.
467 */
468 u.u_cdmap = zdmap;
469 u.u_csmap = zdmap;
470 if (swpexpand(ds, ss, &u.u_cdmap, &u.u_csmap) == NULL)
471 goto bad;
472
473 /*
c4ec2128 474 * At this point, we are committed to the new image!
28db9b87
SL
475 * Release virtual memory resources of old process, and
476 * initialize the virtual memory of the new process.
477 * If we resulted from vfork(), instead wakeup our
478 * parent who will set SVFDONE when he has taken back
479 * our resources.
480 */
ba7abd07 481 if ((p->p_flag & SVFORK) == 0)
28db9b87
SL
482 vrelvm();
483 else {
ba7abd07
MK
484 p->p_flag &= ~SVFORK;
485 p->p_flag |= SKEEP;
486 wakeup((caddr_t)p);
487 while ((p->p_flag & SVFDONE) == 0)
488 sleep((caddr_t)p, PZERO - 1);
489 p->p_flag &= ~(SVFDONE|SKEEP);
28db9b87 490 }
ba7abd07
MK
491 p->p_flag &= ~(SPAGV|SSEQL|SUANOM);
492 p->p_flag |= pagi | SEXEC;
28db9b87
SL
493 u.u_dmap = u.u_cdmap;
494 u.u_smap = u.u_csmap;
495 vgetvm(ts, ds, ss);
496
497 if (pagi == 0)
c4ec2128 498 u.u_error = vn_rdwr(UIO_READ, vp,
28db9b87 499 (char *)ctob(dptov(u.u_procp, 0)),
9fd50f35 500 (int)ep->a_data,
8011f5df 501 (off_t)(sizeof (struct exec) + ep->a_text),
c4ec2128
KM
502 UIO_USERSPACE, (IO_UNIT|IO_NODELOCKED), cred, (int *)0);
503 xalloc(vp, ep, pagi, cred);
fb1db32c
MK
504#if defined(tahoe)
505 /*
506 * Define new keys.
507 */
ba7abd07
MK
508 if (p->p_textp == 0) { /* use existing code key if shared */
509 ckeyrelease(p->p_ckey);
510 p->p_ckey = getcodekey();
fb1db32c 511 }
ba7abd07
MK
512 mtpr(CCK, p->p_ckey);
513 dkeyrelease(p->p_dkey);
514 p->p_dkey = getdatakey();
515 mtpr(DCK, p->p_dkey);
fb1db32c 516#endif
ba7abd07 517 if (pagi && p->p_textp)
18f30b25 518 vinifod(u.u_procp, (struct fpte *)dptopte(p, 0),
ba7abd07 519 PG_FTEXT, p->p_textp->x_vptr,
8011f5df 520 (long)(1 + ts/CLSIZE), (size_t)btoc(ep->a_data));
28db9b87 521
fb1db32c 522#if defined(vax) || defined(tahoe)
28db9b87 523 /* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */
28db9b87
SL
524 mtpr(TBIA, 0);
525#endif
526
28db9b87
SL
527 /*
528 * set SUID/SGID protections, if no tracing
529 */
ba7abd07
MK
530 if ((p->p_flag&STRC)==0) {
531 if (uid != u.u_cred->cr_uid || gid != u.u_cred->cr_gid)
c4ec2128 532 u.u_cred = crcopy(u.u_cred);
ba7abd07
MK
533 u.u_cred->cr_uid = uid;
534 u.u_cred->cr_gid = gid;
535 p->p_uid = uid;
28db9b87 536 } else
ba7abd07
MK
537 psignal(p, SIGTRAP);
538 p->p_svuid = p->p_uid;
539 p->p_svgid = u.u_cred->cr_gid;
28db9b87
SL
540 u.u_tsize = ts;
541 u.u_dsize = ds;
542 u.u_ssize = ss;
d4a03a57 543 u.u_prof.pr_scale = 0;
fb1db32c
MK
544#if defined(tahoe)
545 u.u_pcb.pcb_savacc.faddr = (float *)NULL;
546#endif
28db9b87
SL
547bad:
548 return;
549}