Commit | Line | Data |
---|---|---|
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 | */ | |
37 | struct execa { | |
38 | char *fname; | |
39 | char **argp; | |
40 | char **envp; | |
41 | }; | |
42 | ||
43 | execv() | |
44 | { | |
45 | ((struct execa *)u.u_ap)->envp = NULL; | |
46 | execve(); | |
47 | } | |
48 | ||
49 | execve() | |
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) { |
275 | badarg: | |
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 |
370 | bad: |
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 | 382 | getxfile(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 |
491 | bad: |
492 | return; | |
493 | } |