mv ISSIG from param.h and rename to CURSIG (now returns signal num)
[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 *
af34b142 17 * @(#)kern_exec.c 7.20 (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 317 if (bp) {
a4292a03 318 bp->b_flags |= B_INVAL; /* throw away */
28db9b87
SL
319 brelse(bp);
320 bp = 0;
321 }
322 }
323 goto bad;
324 }
c4ec2128
KM
325 vput(vp);
326 vp = NULL;
28db9b87
SL
327
328 /*
f3aaea26 329 * Copy back arglist.
28db9b87
SL
330 */
331 ucp = USRSTACK - nc - NBPW;
332 ap = ucp - na*NBPW - 3*NBPW;
333 u.u_ar0[SP] = ap;
334 (void) suword((caddr_t)ap, na-ne);
335 nc = 0;
72d4f41a 336 cc = 0;
28db9b87
SL
337 for (;;) {
338 ap += NBPW;
f3aaea26 339 if (na == ne) {
28db9b87
SL
340 (void) suword((caddr_t)ap, 0);
341 ap += NBPW;
342 }
343 if (--na < 0)
344 break;
345 (void) suword((caddr_t)ap, ucp);
346 do {
72d4f41a 347 if (cc <= 0) {
28db9b87
SL
348 if (bp)
349 brelse(bp);
ec67a3ce
MK
350 cc = CLBYTES;
351#ifdef SECSIZE
352 bp = bread(argdev, bno + nc / argdbsize, cc,
353 argdbsize);
354#else SECSIZE
c4ec2128 355 error = bread(argdev_vp,
9ad9d3f8
KM
356 (daddr_t)(bno + ctod(nc / NBPG)), cc,
357 NOCRED, &tbp);
c4ec2128 358 bp = tbp;
ec67a3ce 359#endif SECSIZE
a4292a03 360 bp->b_flags |= B_INVAL; /* throw away */
28db9b87
SL
361 cp = bp->b_un.b_addr;
362 }
8011f5df
MK
363 error = copyoutstr(cp, (caddr_t)ucp, (unsigned)cc,
364 &len);
72d4f41a
SL
365 ucp += len;
366 cp += len;
367 nc += len;
368 cc -= len;
369 } while (error == ENOENT);
370 if (error == EFAULT)
371 panic("exec: EFAULT");
28db9b87
SL
372 }
373 (void) suword((caddr_t)ap, 0);
ce66cb03 374
ba7abd07 375 execsigs(u.u_procp);
ce66cb03
MK
376
377 for (nc = u.u_lastfile; nc >= 0; --nc) {
378 if (u.u_pofile[nc] & UF_EXCLOSE) {
69be5b7a 379 (void) closef(u.u_ofile[nc]);
ce66cb03
MK
380 u.u_ofile[nc] = NULL;
381 u.u_pofile[nc] = 0;
382 }
383 u.u_pofile[nc] &= ~UF_MAPPED;
384 }
385 while (u.u_lastfile >= 0 && u.u_ofile[u.u_lastfile] == NULL)
386 u.u_lastfile--;
9fd50f35 387 setregs(exdata.ex_exec.a_entry);
715baff1
KM
388 /*
389 * Remember file name for accounting.
390 */
391 u.u_acflag &= ~AFORK;
ce66cb03 392 if (indir)
af34b142 393 bcopy((caddr_t)cfname, (caddr_t)u.u_procp->p_comm, MAXCOMLEN);
ce66cb03
MK
394 else {
395 if (ndp->ni_dent.d_namlen > MAXCOMLEN)
396 ndp->ni_dent.d_namlen = MAXCOMLEN;
af34b142 397 bcopy((caddr_t)ndp->ni_dent.d_name, (caddr_t)u.u_procp->p_comm,
ce66cb03
MK
398 (unsigned)(ndp->ni_dent.d_namlen + 1));
399 }
28db9b87
SL
400bad:
401 if (bp)
402 brelse(bp);
403 if (bno)
ec67a3ce
MK
404#ifdef SECSIZE
405 rmfree(argmap, (clrnd((int)btoc(NCARGS))) * CLBYTES / argdbsize,
406 bno);
407#else SECSIZE
28db9b87 408 rmfree(argmap, (long)ctod(clrnd((int) btoc(NCARGS))), bno);
ec67a3ce 409#endif SECSIZE
c4ec2128
KM
410 if (vp)
411 vput(vp);
28db9b87
SL
412}
413
414/*
415 * Read in and set up memory for executed file.
416 */
c4ec2128
KM
417getxfile(vp, ep, nargc, uid, gid, cred)
418 register struct vnode *vp;
9fd50f35 419 register struct exec *ep;
28db9b87 420 int nargc, uid, gid;
c4ec2128 421 struct ucred *cred;
28db9b87 422{
ba7abd07 423 register struct proc *p = u.u_procp;
0c48b03e 424 size_t ts, ds, ids, uds, ss;
28db9b87
SL
425 int pagi;
426
c4ec2128
KM
427 if (ep->a_magic == ZMAGIC)
428 pagi = SPAGV;
28db9b87
SL
429 else
430 pagi = 0;
c4ec2128 431 if (vp->v_text && (vp->v_text->x_flag & XTRC)) {
ce08d752
MK
432 u.u_error = ETXTBSY;
433 goto bad;
434 }
c4ec2128 435 if (ep->a_text != 0 && (vp->v_flag & VTEXT) == 0 &&
c65056fe 436 vp->v_usecount != 1) {
28db9b87
SL
437 register struct file *fp;
438
439 for (fp = file; fp < fileNFILE; fp++) {
c4ec2128 440 if (fp->f_type == DTYPE_VNODE &&
28db9b87 441 fp->f_count > 0 &&
c4ec2128
KM
442 (struct vnode *)fp->f_data == vp &&
443 (fp->f_flag & FWRITE)) {
28db9b87
SL
444 u.u_error = ETXTBSY;
445 goto bad;
446 }
447 }
448 }
449
450 /*
451 * Compute text and data sizes and make sure not too large.
0c48b03e
KM
452 * NB - Check data and bss separately as they may overflow
453 * when summed together.
28db9b87 454 */
9fd50f35 455 ts = clrnd(btoc(ep->a_text));
0c48b03e
KM
456 ids = clrnd(btoc(ep->a_data));
457 uds = clrnd(btoc(ep->a_bss));
f3aaea26 458 ds = clrnd(btoc(ep->a_data + ep->a_bss));
28db9b87 459 ss = clrnd(SSIZE + btoc(nargc));
0c48b03e 460 if (chksize((unsigned)ts, (unsigned)ids, (unsigned)uds, (unsigned)ss))
28db9b87
SL
461 goto bad;
462
463 /*
464 * Make sure enough space to start process.
465 */
466 u.u_cdmap = zdmap;
467 u.u_csmap = zdmap;
468 if (swpexpand(ds, ss, &u.u_cdmap, &u.u_csmap) == NULL)
469 goto bad;
470
471 /*
c4ec2128 472 * At this point, we are committed to the new image!
28db9b87
SL
473 * Release virtual memory resources of old process, and
474 * initialize the virtual memory of the new process.
475 * If we resulted from vfork(), instead wakeup our
476 * parent who will set SVFDONE when he has taken back
477 * our resources.
478 */
ba7abd07 479 if ((p->p_flag & SVFORK) == 0)
28db9b87
SL
480 vrelvm();
481 else {
ba7abd07
MK
482 p->p_flag &= ~SVFORK;
483 p->p_flag |= SKEEP;
484 wakeup((caddr_t)p);
485 while ((p->p_flag & SVFDONE) == 0)
486 sleep((caddr_t)p, PZERO - 1);
487 p->p_flag &= ~(SVFDONE|SKEEP);
28db9b87 488 }
ba7abd07
MK
489 p->p_flag &= ~(SPAGV|SSEQL|SUANOM);
490 p->p_flag |= pagi | SEXEC;
28db9b87
SL
491 u.u_dmap = u.u_cdmap;
492 u.u_smap = u.u_csmap;
493 vgetvm(ts, ds, ss);
494
495 if (pagi == 0)
c4ec2128 496 u.u_error = vn_rdwr(UIO_READ, vp,
28db9b87 497 (char *)ctob(dptov(u.u_procp, 0)),
9fd50f35 498 (int)ep->a_data,
8011f5df 499 (off_t)(sizeof (struct exec) + ep->a_text),
c4ec2128
KM
500 UIO_USERSPACE, (IO_UNIT|IO_NODELOCKED), cred, (int *)0);
501 xalloc(vp, ep, pagi, cred);
fb1db32c
MK
502#if defined(tahoe)
503 /*
504 * Define new keys.
505 */
ba7abd07
MK
506 if (p->p_textp == 0) { /* use existing code key if shared */
507 ckeyrelease(p->p_ckey);
508 p->p_ckey = getcodekey();
fb1db32c 509 }
ba7abd07
MK
510 mtpr(CCK, p->p_ckey);
511 dkeyrelease(p->p_dkey);
512 p->p_dkey = getdatakey();
513 mtpr(DCK, p->p_dkey);
fb1db32c 514#endif
ba7abd07 515 if (pagi && p->p_textp)
18f30b25 516 vinifod(u.u_procp, (struct fpte *)dptopte(p, 0),
ba7abd07 517 PG_FTEXT, p->p_textp->x_vptr,
8011f5df 518 (long)(1 + ts/CLSIZE), (size_t)btoc(ep->a_data));
28db9b87 519
fb1db32c 520#if defined(vax) || defined(tahoe)
28db9b87 521 /* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */
28db9b87
SL
522 mtpr(TBIA, 0);
523#endif
524
28db9b87
SL
525 /*
526 * set SUID/SGID protections, if no tracing
527 */
ba7abd07
MK
528 if ((p->p_flag&STRC)==0) {
529 if (uid != u.u_cred->cr_uid || gid != u.u_cred->cr_gid)
c4ec2128 530 u.u_cred = crcopy(u.u_cred);
ba7abd07
MK
531 u.u_cred->cr_uid = uid;
532 u.u_cred->cr_gid = gid;
533 p->p_uid = uid;
28db9b87 534 } else
ba7abd07
MK
535 psignal(p, SIGTRAP);
536 p->p_svuid = p->p_uid;
537 p->p_svgid = u.u_cred->cr_gid;
28db9b87
SL
538 u.u_tsize = ts;
539 u.u_dsize = ds;
540 u.u_ssize = ss;
d4a03a57 541 u.u_prof.pr_scale = 0;
fb1db32c
MK
542#if defined(tahoe)
543 u.u_pcb.pcb_savacc.faddr = (float *)NULL;
544#endif
28db9b87
SL
545bad:
546 return;
547}