1 /* kern_exec.c 6.4 84/07/21 */ 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/acct.h" 22 #include "../h/exec.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 #define SHSIZE 32 56 char cfarg[SHSIZE]; 57 union { 58 char ex_shell[SHSIZE]; /* #! and name of interpreter */ 59 struct exec ex_exec; 60 } exdata; 61 register struct nameidata *ndp = &u.u_nd; 62 int resid; 63 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) 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 /* 91 * Read in first few bytes of file for segment sizes, ux_mag: 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 */ 104 exdata.ex_shell[0] = '\0'; /* for zero length files */ 105 u.u_error = rdwri(UIO_READ, ip, (caddr_t)&exdata, 106 sizeof (struct exec), 0, 1, &resid); 107 if (u.u_error) 108 goto bad; 109 #ifndef lint 110 if (resid > sizeof (struct exec) - sizeof (exdata.ex_exec.a_magic) && 111 exdata.ex_shell[0] != '#') { 112 u.u_error = ENOEXEC; 113 goto bad; 114 } 115 #endif 116 switch (exdata.ex_exec.a_magic) { 117 118 case 0407: 119 exdata.ex_exec.a_data += exdata.ex_exec.a_text; 120 exdata.ex_exec.a_text = 0; 121 break; 122 123 case 0413: 124 case 0410: 125 if (exdata.ex_exec.a_text == 0) { 126 u.u_error = ENOEXEC; 127 goto bad; 128 } 129 break; 130 131 default: 132 if (exdata.ex_shell[0] != '#' || 133 exdata.ex_shell[1] != '!' || 134 indir) { 135 u.u_error = ENOEXEC; 136 goto bad; 137 } 138 cp = &exdata.ex_shell[2]; /* skip "#!" */ 139 while (cp < &exdata.ex_shell[SHSIZE]) { 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 } 152 cp = &exdata.ex_shell[2]; 153 while (*cp == ' ') 154 cp++; 155 ndp->ni_dirp = cp; 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 } 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)); 172 cfname[MAXCOMLEN] = 0; 173 indir = 1; 174 iput(ip); 175 ndp->ni_nameiop = LOOKUP | FOLLOW; 176 ndp->ni_segflg = UIO_SYSSPACE; 177 ip = namei(ndp); 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; 189 uap = (struct execa *)u.u_ap; 190 bno = rmalloc(argmap, (long)ctod(clrnd((int)btoc(NCARGS)))); 191 if (bno == 0) { 192 swkill(u.u_procp, "exece"); 193 goto bad; 194 } 195 if (bno % CLSIZE) 196 panic("execa rmalloc"); 197 if (uap->argp) for (;;) { 198 ap = NULL; 199 if (indir && (na == 1 || na == 2 && sharg)) 200 ap = (int)uap->fname; 201 else if (uap->argp) { 202 ap = fuword((caddr_t)uap->argp); 203 uap->argp++; 204 } 205 if (ap==NULL && uap->envp) { 206 uap->argp = NULL; 207 if ((ap = fuword((caddr_t)uap->envp)) == NULL) 208 break; 209 uap->envp++; 210 ne++; 211 } 212 if (ap == NULL) 213 break; 214 na++; 215 if (ap == -1) 216 u.u_error = EFAULT; 217 do { 218 if (nc >= NCARGS-1) 219 u.u_error = E2BIG; 220 if (indir && na == 2 && sharg != NULL) 221 c = *sharg++ & 0377; 222 else if ((c = fubyte((caddr_t)ap++)) < 0) 223 u.u_error = EFAULT; 224 if (u.u_error) { 225 if (bp) 226 brelse(bp); 227 bp = 0; 228 goto badarg; 229 } 230 if (nc % (CLSIZE*NBPG) == 0) { 231 if (bp) 232 bdwrite(bp); 233 bp = getblk(argdev, bno + ctod(nc / NBPG), 234 CLSIZE*NBPG); 235 cp = bp->b_un.b_addr; 236 } 237 nc++; 238 *cp++ = c; 239 } while (c > 0); 240 } 241 if (bp) 242 bdwrite(bp); 243 bp = 0; 244 nc = (nc + NBPW-1) & ~(NBPW-1); 245 if (indir) { 246 ndp->ni_dent.d_namlen = strlen(cfname); 247 bcopy((caddr_t)cfname, (caddr_t)ndp->ni_dent.d_name, 248 (unsigned)(ndp->ni_dent.d_namlen + 1)); 249 } 250 getxfile(ip, &exdata.ex_exec, nc + (na+4)*NBPW, uid, gid); 251 if (u.u_error) { 252 badarg: 253 for (c = 0; c < nc; c += CLSIZE*NBPG) { 254 bp = baddr(argdev, bno + ctod(c / NBPG), CLSIZE*NBPG); 255 if (bp) { 256 bp->b_flags |= B_AGE; /* throw away */ 257 bp->b_flags &= ~B_DELWRI; /* cancel io */ 258 brelse(bp); 259 bp = 0; 260 } 261 } 262 goto bad; 263 } 264 265 /* 266 * copy back arglist 267 */ 268 ucp = USRSTACK - nc - NBPW; 269 ap = ucp - na*NBPW - 3*NBPW; 270 u.u_ar0[SP] = ap; 271 (void) suword((caddr_t)ap, na-ne); 272 nc = 0; 273 for (;;) { 274 ap += NBPW; 275 if (na==ne) { 276 (void) suword((caddr_t)ap, 0); 277 ap += NBPW; 278 } 279 if (--na < 0) 280 break; 281 (void) suword((caddr_t)ap, ucp); 282 do { 283 if (nc % (CLSIZE*NBPG) == 0) { 284 if (bp) 285 brelse(bp); 286 bp = bread(argdev, bno + ctod(nc / NBPG), 287 CLSIZE*NBPG); 288 bp->b_flags |= B_AGE; /* throw away */ 289 bp->b_flags &= ~B_DELWRI; /* cancel io */ 290 cp = bp->b_un.b_addr; 291 } 292 (void) subyte((caddr_t)ucp++, (c = *cp++)); 293 nc++; 294 } while(c&0377); 295 } 296 (void) suword((caddr_t)ap, 0); 297 setregs(exdata.ex_exec.a_entry); 298 /* 299 * Remember file name for accounting. 300 */ 301 u.u_acflag &= ~AFORK; 302 bcopy((caddr_t)ndp->ni_dent.d_name, (caddr_t)u.u_comm, 303 (unsigned)(ndp->ni_dent.d_namlen + 1)); 304 bad: 305 if (bp) 306 brelse(bp); 307 if (bno) 308 rmfree(argmap, (long)ctod(clrnd((int) btoc(NCARGS))), bno); 309 iput(ip); 310 } 311 312 /* 313 * Read in and set up memory for executed file. 314 */ 315 getxfile(ip, ep, nargc, uid, gid) 316 register struct inode *ip; 317 register struct exec *ep; 318 int nargc, uid, gid; 319 { 320 register size_t ts, ds, ss; 321 int pagi; 322 323 if (ep->a_magic == 0413) 324 pagi = SPAGI; 325 else 326 pagi = 0; 327 if (ep->a_text != 0 && (ip->i_flag&ITEXT) == 0 && 328 ip->i_count != 1) { 329 register struct file *fp; 330 331 for (fp = file; fp < fileNFILE; fp++) { 332 if (fp->f_type == DTYPE_INODE && 333 fp->f_count > 0 && 334 (struct inode *)fp->f_data == ip && 335 (fp->f_flag&FWRITE)) { 336 u.u_error = ETXTBSY; 337 goto bad; 338 } 339 } 340 } 341 342 /* 343 * Compute text and data sizes and make sure not too large. 344 */ 345 ts = clrnd(btoc(ep->a_text)); 346 ds = clrnd(btoc((ep->a_data + ep->a_bss))); 347 ss = clrnd(SSIZE + btoc(nargc)); 348 if (chksize((unsigned)ts, (unsigned)ds, (unsigned)ss)) 349 goto bad; 350 351 /* 352 * Make sure enough space to start process. 353 */ 354 u.u_cdmap = zdmap; 355 u.u_csmap = zdmap; 356 if (swpexpand(ds, ss, &u.u_cdmap, &u.u_csmap) == NULL) 357 goto bad; 358 359 /* 360 * At this point, committed to the new image! 361 * Release virtual memory resources of old process, and 362 * initialize the virtual memory of the new process. 363 * If we resulted from vfork(), instead wakeup our 364 * parent who will set SVFDONE when he has taken back 365 * our resources. 366 */ 367 if ((u.u_procp->p_flag & SVFORK) == 0) 368 vrelvm(); 369 else { 370 u.u_procp->p_flag &= ~SVFORK; 371 u.u_procp->p_flag |= SKEEP; 372 wakeup((caddr_t)u.u_procp); 373 while ((u.u_procp->p_flag & SVFDONE) == 0) 374 sleep((caddr_t)u.u_procp, PZERO - 1); 375 u.u_procp->p_flag &= ~(SVFDONE|SKEEP); 376 } 377 u.u_procp->p_flag &= ~(SPAGI|SSEQL|SUANOM|SOUSIG); 378 u.u_procp->p_flag |= pagi; 379 u.u_dmap = u.u_cdmap; 380 u.u_smap = u.u_csmap; 381 vgetvm(ts, ds, ss); 382 383 if (pagi == 0) 384 u.u_error = 385 rdwri(UIO_READ, ip, 386 (char *)ctob(dptov(u.u_procp, 0)), 387 (int)ep->a_data, 388 (int)(sizeof (struct exec) + ep->a_text), 389 0, (int *)0); 390 xalloc(ip, ep, pagi); 391 if (pagi && u.u_procp->p_textp) 392 vinifod((struct fpte *)dptopte(u.u_procp, 0), 393 PG_FTEXT, u.u_procp->p_textp->x_iptr, 394 (long)(1 + ts/CLSIZE), (int)btoc(ep->a_data)); 395 396 #ifdef vax 397 /* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */ 398 mtpr(TBIA, 0); 399 #endif 400 401 if (u.u_error) 402 swkill(u.u_procp, "i/o error mapping pages"); 403 /* 404 * set SUID/SGID protections, if no tracing 405 */ 406 if ((u.u_procp->p_flag&STRC)==0) { 407 u.u_uid = uid; 408 u.u_procp->p_uid = uid; 409 u.u_gid = gid; 410 } else 411 psignal(u.u_procp, SIGTRAP); 412 u.u_tsize = ts; 413 u.u_dsize = ds; 414 u.u_ssize = ss; 415 u.u_prof.pr_scale = 0; 416 bad: 417 return; 418 } 419 420 /* 421 * Clear registers on exec 422 */ 423 setregs(entry) 424 int entry; 425 { 426 register int i; 427 register struct proc *p = u.u_procp; 428 429 /* 430 * Reset caught signals. Held signals 431 * remain held through p_sigmask. 432 */ 433 while (p->p_sigcatch) { 434 (void) spl6(); 435 i = ffs(p->p_sigcatch); 436 p->p_sigcatch &= ~(1 << (i - 1)); 437 u.u_signal[i] = SIG_DFL; 438 (void) spl0(); 439 } 440 #ifdef notdef 441 /* should pass args to init on the stack */ 442 for (rp = &u.u_ar0[0]; rp < &u.u_ar0[16];) 443 *rp++ = 0; 444 #endif 445 u.u_ar0[PC] = entry + 2; 446 for (i=0; i<NOFILE; i++) { 447 if (u.u_pofile[i]&UF_EXCLOSE) { 448 closef(u.u_ofile[i]); 449 u.u_ofile[i] = NULL; 450 u.u_pofile[i] = 0; 451 } 452 u.u_pofile[i] &= ~UF_MAPPED; 453 } 454 } 455