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