fix tests for bogus routers to reject addresses on shared,
[unix-history] / usr / src / sys / kern / kern_exec.c
CommitLineData
da7c5cc6 1/*
0880b18e 2 * Copyright (c) 1982, 1986 Regents of the University of California.
da7c5cc6
KM
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
0880b18e 6 * @(#)kern_exec.c 7.1 (Berkeley) %G%
da7c5cc6 7 */
28db9b87
SL
8
9#include "../machine/reg.h"
10#include "../machine/pte.h"
11#include "../machine/psl.h"
12
94368568
JB
13#include "param.h"
14#include "systm.h"
15#include "map.h"
16#include "dir.h"
17#include "user.h"
18#include "kernel.h"
19#include "proc.h"
20#include "buf.h"
21#include "inode.h"
22#include "seg.h"
23#include "vm.h"
24#include "text.h"
25#include "file.h"
26#include "uio.h"
27#include "acct.h"
28#include "exec.h"
28db9b87 29
e3d5bfde
SL
30#ifdef vax
31#include "../vax/mtpr.h"
32#endif
33
28db9b87
SL
34/*
35 * exec system call, with and without environments.
36 */
37struct execa {
38 char *fname;
39 char **argp;
40 char **envp;
41};
42
43execv()
44{
45 ((struct execa *)u.u_ap)->envp = NULL;
46 execve();
47}
48
49execve()
50{
51 register nc;
52 register char *cp;
53 register struct buf *bp;
54 register struct execa *uap;
8011f5df
MK
55 int na, ne, ucp, ap, cc;
56 unsigned len;
28db9b87
SL
57 int indir, uid, gid;
58 char *sharg;
59 struct inode *ip;
60 swblk_t bno;
61 char cfname[MAXCOMLEN + 1];
9fd50f35 62#define SHSIZE 32
28db9b87 63 char cfarg[SHSIZE];
9fd50f35
SL
64 union {
65 char ex_shell[SHSIZE]; /* #! and name of interpreter */
66 struct exec ex_exec;
67 } exdata;
715baff1 68 register struct nameidata *ndp = &u.u_nd;
f3aaea26 69 int resid, error;
28db9b87 70
715baff1
KM
71 ndp->ni_nameiop = LOOKUP | FOLLOW;
72 ndp->ni_segflg = UIO_USERSPACE;
73 ndp->ni_dirp = ((struct execa *)u.u_ap)->fname;
74 if ((ip = namei(ndp)) == NULL)
28db9b87
SL
75 return;
76 bno = 0;
77 bp = 0;
78 indir = 0;
79 uid = u.u_uid;
80 gid = u.u_gid;
81 if (ip->i_mode & ISUID)
82 uid = ip->i_uid;
83 if (ip->i_mode & ISGID)
84 gid = ip->i_gid;
85
86 again:
87 if (access(ip, IEXEC))
88 goto bad;
89 if ((u.u_procp->p_flag&STRC) && access(ip, IREAD))
90 goto bad;
91 if ((ip->i_mode & IFMT) != IFREG ||
92 (ip->i_mode & (IEXEC|(IEXEC>>3)|(IEXEC>>6))) == 0) {
93 u.u_error = EACCES;
94 goto bad;
95 }
96
97 /*
f3aaea26 98 * Read in first few bytes of file for segment sizes, magic number:
28db9b87
SL
99 * 407 = plain executable
100 * 410 = RO text
101 * 413 = demand paged RO text
102 * Also an ASCII line beginning with #! is
103 * the file name of a ``shell'' and arguments may be prepended
104 * to the argument list if given here.
105 *
106 * SHELL NAMES ARE LIMITED IN LENGTH.
107 *
108 * ONLY ONE ARGUMENT MAY BE PASSED TO THE SHELL FROM
109 * THE ASCII LINE.
110 */
9fd50f35 111 exdata.ex_shell[0] = '\0'; /* for zero length files */
f3aaea26 112 u.u_error = rdwri(UIO_READ, ip, (caddr_t)&exdata, sizeof (exdata),
8011f5df 113 (off_t)0, 1, &resid);
28db9b87
SL
114 if (u.u_error)
115 goto bad;
28db9b87 116#ifndef lint
ce66cb03 117 if (resid > sizeof(exdata) - sizeof(exdata.ex_exec) &&
9fd50f35 118 exdata.ex_shell[0] != '#') {
28db9b87
SL
119 u.u_error = ENOEXEC;
120 goto bad;
121 }
122#endif
aec7dd3b 123 switch ((int)exdata.ex_exec.a_magic) {
28db9b87
SL
124
125 case 0407:
9fd50f35
SL
126 exdata.ex_exec.a_data += exdata.ex_exec.a_text;
127 exdata.ex_exec.a_text = 0;
28db9b87
SL
128 break;
129
130 case 0413:
131 case 0410:
9fd50f35 132 if (exdata.ex_exec.a_text == 0) {
28db9b87
SL
133 u.u_error = ENOEXEC;
134 goto bad;
135 }
136 break;
137
138 default:
9fd50f35
SL
139 if (exdata.ex_shell[0] != '#' ||
140 exdata.ex_shell[1] != '!' ||
28db9b87
SL
141 indir) {
142 u.u_error = ENOEXEC;
143 goto bad;
144 }
9fd50f35
SL
145 cp = &exdata.ex_shell[2]; /* skip "#!" */
146 while (cp < &exdata.ex_shell[SHSIZE]) {
28db9b87
SL
147 if (*cp == '\t')
148 *cp = ' ';
149 else if (*cp == '\n') {
150 *cp = '\0';
151 break;
152 }
153 cp++;
154 }
155 if (*cp != '\0') {
156 u.u_error = ENOEXEC;
157 goto bad;
158 }
9fd50f35 159 cp = &exdata.ex_shell[2];
28db9b87
SL
160 while (*cp == ' ')
161 cp++;
715baff1 162 ndp->ni_dirp = cp;
28db9b87
SL
163 while (*cp && *cp != ' ')
164 cp++;
ce66cb03 165 cfarg[0] = '\0';
28db9b87
SL
166 if (*cp) {
167 *cp++ = '\0';
168 while (*cp == ' ')
169 cp++;
ce66cb03 170 if (*cp)
28db9b87 171 bcopy((caddr_t)cp, (caddr_t)cfarg, SHSIZE);
28db9b87 172 }
28db9b87
SL
173 indir = 1;
174 iput(ip);
715baff1
KM
175 ndp->ni_nameiop = LOOKUP | FOLLOW;
176 ndp->ni_segflg = UIO_SYSSPACE;
177 ip = namei(ndp);
28db9b87
SL
178 if (ip == NULL)
179 return;
ce66cb03
MK
180 bcopy((caddr_t)ndp->ni_dent.d_name, (caddr_t)cfname,
181 MAXCOMLEN);
182 cfname[MAXCOMLEN] = '\0';
28db9b87
SL
183 goto again;
184 }
185
186 /*
187 * Collect arguments on "file" in swap space.
188 */
189 na = 0;
190 ne = 0;
191 nc = 0;
f3aaea26 192 cc = 0;
28db9b87 193 uap = (struct execa *)u.u_ap;
9fd50f35
SL
194 bno = rmalloc(argmap, (long)ctod(clrnd((int)btoc(NCARGS))));
195 if (bno == 0) {
d03b3d84 196 swkill(u.u_procp, "exec: no swap space");
28db9b87
SL
197 goto bad;
198 }
199 if (bno % CLSIZE)
200 panic("execa rmalloc");
f3aaea26
SL
201 /*
202 * Copy arguments into file in argdev area.
203 */
28db9b87
SL
204 if (uap->argp) for (;;) {
205 ap = NULL;
ce66cb03
MK
206 sharg = NULL;
207 if (indir && na == 0) {
208 sharg = cfname;
209 ap = (int)sharg;
210 uap->argp++; /* ignore argv[0] */
211 } else if (indir && (na == 1 && cfarg[0])) {
212 sharg = cfarg;
213 ap = (int)sharg;
214 } else if (indir && (na == 1 || na == 2 && cfarg[0]))
28db9b87
SL
215 ap = (int)uap->fname;
216 else if (uap->argp) {
217 ap = fuword((caddr_t)uap->argp);
218 uap->argp++;
219 }
f3aaea26 220 if (ap == NULL && uap->envp) {
28db9b87 221 uap->argp = NULL;
f3aaea26
SL
222 if ((ap = fuword((caddr_t)uap->envp)) != NULL)
223 uap->envp++, ne++;
28db9b87
SL
224 }
225 if (ap == NULL)
226 break;
227 na++;
f3aaea26 228 if (ap == -1) {
1daa95c7 229 u.u_error = EFAULT;
f3aaea26
SL
230 break;
231 }
28db9b87 232 do {
f3aaea26
SL
233 if (cc <= 0) {
234 /*
235 * We depend on NCARGS being a multiple of
236 * CLSIZE*NBPG. This way we need only check
237 * overflow before each buffer allocation.
238 */
239 if (nc >= NCARGS-1) {
240 error = E2BIG;
241 break;
242 }
28db9b87
SL
243 if (bp)
244 bdwrite(bp);
f3aaea26
SL
245 cc = CLSIZE*NBPG;
246 bp = getblk(argdev, bno + ctod(nc/NBPG), cc);
28db9b87
SL
247 cp = bp->b_un.b_addr;
248 }
ce66cb03 249 if (sharg) {
8011f5df 250 error = copystr(sharg, cp, (unsigned)cc, &len);
ce66cb03
MK
251 sharg += len;
252 } else {
8011f5df
MK
253 error = copyinstr((caddr_t)ap, cp, (unsigned)cc,
254 &len);
ce66cb03
MK
255 ap += len;
256 }
f3aaea26
SL
257 cp += len;
258 nc += len;
259 cc -= len;
260 } while (error == ENOENT);
261 if (error) {
262 u.u_error = error;
263 if (bp)
264 brelse(bp);
265 bp = 0;
266 goto badarg;
267 }
28db9b87
SL
268 }
269 if (bp)
270 bdwrite(bp);
271 bp = 0;
272 nc = (nc + NBPW-1) & ~(NBPW-1);
9fd50f35 273 getxfile(ip, &exdata.ex_exec, nc + (na+4)*NBPW, uid, gid);
28db9b87
SL
274 if (u.u_error) {
275badarg:
f3aaea26
SL
276 for (cc = 0; cc < nc; cc += CLSIZE*NBPG) {
277 bp = baddr(argdev, bno + ctod(cc/NBPG), CLSIZE*NBPG);
28db9b87
SL
278 if (bp) {
279 bp->b_flags |= B_AGE; /* throw away */
280 bp->b_flags &= ~B_DELWRI; /* cancel io */
281 brelse(bp);
282 bp = 0;
283 }
284 }
285 goto bad;
286 }
ce66cb03
MK
287 iput(ip);
288 ip = NULL;
28db9b87
SL
289
290 /*
f3aaea26 291 * Copy back arglist.
28db9b87
SL
292 */
293 ucp = USRSTACK - nc - NBPW;
294 ap = ucp - na*NBPW - 3*NBPW;
295 u.u_ar0[SP] = ap;
296 (void) suword((caddr_t)ap, na-ne);
297 nc = 0;
72d4f41a 298 cc = 0;
28db9b87
SL
299 for (;;) {
300 ap += NBPW;
f3aaea26 301 if (na == ne) {
28db9b87
SL
302 (void) suword((caddr_t)ap, 0);
303 ap += NBPW;
304 }
305 if (--na < 0)
306 break;
307 (void) suword((caddr_t)ap, ucp);
308 do {
72d4f41a 309 if (cc <= 0) {
28db9b87
SL
310 if (bp)
311 brelse(bp);
72d4f41a
SL
312 cc = CLSIZE*NBPG;
313 bp = bread(argdev, bno + ctod(nc / NBPG), cc);
28db9b87
SL
314 bp->b_flags |= B_AGE; /* throw away */
315 bp->b_flags &= ~B_DELWRI; /* cancel io */
316 cp = bp->b_un.b_addr;
317 }
8011f5df
MK
318 error = copyoutstr(cp, (caddr_t)ucp, (unsigned)cc,
319 &len);
72d4f41a
SL
320 ucp += len;
321 cp += len;
322 nc += len;
323 cc -= len;
324 } while (error == ENOENT);
325 if (error == EFAULT)
326 panic("exec: EFAULT");
28db9b87
SL
327 }
328 (void) suword((caddr_t)ap, 0);
ce66cb03
MK
329
330 /*
331 * Reset caught signals. Held signals
332 * remain held through p_sigmask.
333 */
334 while (u.u_procp->p_sigcatch) {
8011f5df 335 nc = ffs((long)u.u_procp->p_sigcatch);
ce66cb03
MK
336 u.u_procp->p_sigcatch &= ~sigmask(nc);
337 u.u_signal[nc] = SIG_DFL;
338 }
339 /*
340 * Reset stack state to the user stack.
341 * Clear set of signals caught on the signal stack.
342 */
343 u.u_onstack = 0;
344 u.u_sigsp = 0;
345 u.u_sigonstack = 0;
346
347 for (nc = u.u_lastfile; nc >= 0; --nc) {
348 if (u.u_pofile[nc] & UF_EXCLOSE) {
349 closef(u.u_ofile[nc]);
350 u.u_ofile[nc] = NULL;
351 u.u_pofile[nc] = 0;
352 }
353 u.u_pofile[nc] &= ~UF_MAPPED;
354 }
355 while (u.u_lastfile >= 0 && u.u_ofile[u.u_lastfile] == NULL)
356 u.u_lastfile--;
9fd50f35 357 setregs(exdata.ex_exec.a_entry);
715baff1
KM
358 /*
359 * Remember file name for accounting.
360 */
361 u.u_acflag &= ~AFORK;
ce66cb03
MK
362 if (indir)
363 bcopy((caddr_t)cfname, (caddr_t)u.u_comm, MAXCOMLEN);
364 else {
365 if (ndp->ni_dent.d_namlen > MAXCOMLEN)
366 ndp->ni_dent.d_namlen = MAXCOMLEN;
367 bcopy((caddr_t)ndp->ni_dent.d_name, (caddr_t)u.u_comm,
368 (unsigned)(ndp->ni_dent.d_namlen + 1));
369 }
28db9b87
SL
370bad:
371 if (bp)
372 brelse(bp);
373 if (bno)
374 rmfree(argmap, (long)ctod(clrnd((int) btoc(NCARGS))), bno);
ce66cb03
MK
375 if (ip)
376 iput(ip);
28db9b87
SL
377}
378
379/*
380 * Read in and set up memory for executed file.
381 */
9fd50f35 382getxfile(ip, ep, nargc, uid, gid)
28db9b87 383 register struct inode *ip;
9fd50f35 384 register struct exec *ep;
28db9b87
SL
385 int nargc, uid, gid;
386{
0c48b03e 387 size_t ts, ds, ids, uds, ss;
28db9b87
SL
388 int pagi;
389
9fd50f35 390 if (ep->a_magic == 0413)
28db9b87
SL
391 pagi = SPAGI;
392 else
393 pagi = 0;
cdb14d96 394 if (ip->i_text && (ip->i_text->x_flag & XTRC)) {
ce08d752
MK
395 u.u_error = ETXTBSY;
396 goto bad;
397 }
9fd50f35
SL
398 if (ep->a_text != 0 && (ip->i_flag&ITEXT) == 0 &&
399 ip->i_count != 1) {
28db9b87
SL
400 register struct file *fp;
401
402 for (fp = file; fp < fileNFILE; fp++) {
403 if (fp->f_type == DTYPE_INODE &&
404 fp->f_count > 0 &&
405 (struct inode *)fp->f_data == ip &&
406 (fp->f_flag&FWRITE)) {
407 u.u_error = ETXTBSY;
408 goto bad;
409 }
410 }
411 }
412
413 /*
414 * Compute text and data sizes and make sure not too large.
0c48b03e
KM
415 * NB - Check data and bss separately as they may overflow
416 * when summed together.
28db9b87 417 */
9fd50f35 418 ts = clrnd(btoc(ep->a_text));
0c48b03e
KM
419 ids = clrnd(btoc(ep->a_data));
420 uds = clrnd(btoc(ep->a_bss));
f3aaea26 421 ds = clrnd(btoc(ep->a_data + ep->a_bss));
28db9b87 422 ss = clrnd(SSIZE + btoc(nargc));
0c48b03e 423 if (chksize((unsigned)ts, (unsigned)ids, (unsigned)uds, (unsigned)ss))
28db9b87
SL
424 goto bad;
425
426 /*
427 * Make sure enough space to start process.
428 */
429 u.u_cdmap = zdmap;
430 u.u_csmap = zdmap;
431 if (swpexpand(ds, ss, &u.u_cdmap, &u.u_csmap) == NULL)
432 goto bad;
433
434 /*
435 * At this point, committed to the new image!
436 * Release virtual memory resources of old process, and
437 * initialize the virtual memory of the new process.
438 * If we resulted from vfork(), instead wakeup our
439 * parent who will set SVFDONE when he has taken back
440 * our resources.
441 */
442 if ((u.u_procp->p_flag & SVFORK) == 0)
443 vrelvm();
444 else {
445 u.u_procp->p_flag &= ~SVFORK;
446 u.u_procp->p_flag |= SKEEP;
447 wakeup((caddr_t)u.u_procp);
448 while ((u.u_procp->p_flag & SVFDONE) == 0)
449 sleep((caddr_t)u.u_procp, PZERO - 1);
450 u.u_procp->p_flag &= ~(SVFDONE|SKEEP);
451 }
dd012d1e 452 u.u_procp->p_flag &= ~(SPAGI|SSEQL|SUANOM|SOUSIG);
28db9b87
SL
453 u.u_procp->p_flag |= pagi;
454 u.u_dmap = u.u_cdmap;
455 u.u_smap = u.u_csmap;
456 vgetvm(ts, ds, ss);
457
458 if (pagi == 0)
459 u.u_error =
460 rdwri(UIO_READ, ip,
461 (char *)ctob(dptov(u.u_procp, 0)),
9fd50f35 462 (int)ep->a_data,
8011f5df 463 (off_t)(sizeof (struct exec) + ep->a_text),
28db9b87 464 0, (int *)0);
9fd50f35 465 xalloc(ip, ep, pagi);
28db9b87
SL
466 if (pagi && u.u_procp->p_textp)
467 vinifod((struct fpte *)dptopte(u.u_procp, 0),
468 PG_FTEXT, u.u_procp->p_textp->x_iptr,
8011f5df 469 (long)(1 + ts/CLSIZE), (size_t)btoc(ep->a_data));
28db9b87
SL
470
471#ifdef vax
472 /* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */
28db9b87
SL
473 mtpr(TBIA, 0);
474#endif
475
476 if (u.u_error)
d03b3d84 477 swkill(u.u_procp, "exec: I/O error mapping pages");
28db9b87
SL
478 /*
479 * set SUID/SGID protections, if no tracing
480 */
481 if ((u.u_procp->p_flag&STRC)==0) {
482 u.u_uid = uid;
483 u.u_procp->p_uid = uid;
484 u.u_gid = gid;
485 } else
486 psignal(u.u_procp, SIGTRAP);
487 u.u_tsize = ts;
488 u.u_dsize = ds;
489 u.u_ssize = ss;
d4a03a57 490 u.u_prof.pr_scale = 0;
28db9b87
SL
491bad:
492 return;
493}