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