1 /* kern_exec.c 6.12 85/05/27 */ 2 3 #include "../machine/reg.h" 4 #include "../machine/pte.h" 5 #include "../machine/psl.h" 6 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" 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, len, cc; 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, error; 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, magic number: 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, sizeof (exdata), 106 0, 1, &resid); 107 if (u.u_error) 108 goto bad; 109 #ifndef lint 110 if (resid > sizeof(exdata) - sizeof(exdata.ex_exec) && 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 cfarg[0] = '\0'; 159 if (*cp) { 160 *cp++ = '\0'; 161 while (*cp == ' ') 162 cp++; 163 if (*cp) 164 bcopy((caddr_t)cp, (caddr_t)cfarg, SHSIZE); 165 } 166 indir = 1; 167 iput(ip); 168 ndp->ni_nameiop = LOOKUP | FOLLOW; 169 ndp->ni_segflg = UIO_SYSSPACE; 170 ip = namei(ndp); 171 if (ip == NULL) 172 return; 173 bcopy((caddr_t)ndp->ni_dent.d_name, (caddr_t)cfname, 174 MAXCOMLEN); 175 cfname[MAXCOMLEN] = '\0'; 176 goto again; 177 } 178 179 /* 180 * Collect arguments on "file" in swap space. 181 */ 182 na = 0; 183 ne = 0; 184 nc = 0; 185 cc = 0; 186 uap = (struct execa *)u.u_ap; 187 bno = rmalloc(argmap, (long)ctod(clrnd((int)btoc(NCARGS)))); 188 if (bno == 0) { 189 swkill(u.u_procp, "exec: no swap space"); 190 goto bad; 191 } 192 if (bno % CLSIZE) 193 panic("execa rmalloc"); 194 /* 195 * Copy arguments into file in argdev area. 196 */ 197 if (uap->argp) for (;;) { 198 ap = NULL; 199 sharg = NULL; 200 if (indir && na == 0) { 201 sharg = cfname; 202 ap = (int)sharg; 203 uap->argp++; /* ignore argv[0] */ 204 } else if (indir && (na == 1 && cfarg[0])) { 205 sharg = cfarg; 206 ap = (int)sharg; 207 } else if (indir && (na == 1 || na == 2 && cfarg[0])) 208 ap = (int)uap->fname; 209 else if (uap->argp) { 210 ap = fuword((caddr_t)uap->argp); 211 uap->argp++; 212 } 213 if (ap == NULL && uap->envp) { 214 uap->argp = NULL; 215 if ((ap = fuword((caddr_t)uap->envp)) != NULL) 216 uap->envp++, ne++; 217 } 218 if (ap == NULL) 219 break; 220 na++; 221 if (ap == -1) { 222 error = EFAULT; 223 break; 224 } 225 do { 226 if (cc <= 0) { 227 /* 228 * We depend on NCARGS being a multiple of 229 * CLSIZE*NBPG. This way we need only check 230 * overflow before each buffer allocation. 231 */ 232 if (nc >= NCARGS-1) { 233 error = E2BIG; 234 break; 235 } 236 if (bp) 237 bdwrite(bp); 238 cc = CLSIZE*NBPG; 239 bp = getblk(argdev, bno + ctod(nc/NBPG), cc); 240 cp = bp->b_un.b_addr; 241 } 242 if (sharg) { 243 error = copystr(sharg, cp, cc, &len); 244 sharg += len; 245 } else { 246 error = copyinstr((caddr_t)ap, cp, cc, &len); 247 ap += len; 248 } 249 cp += len; 250 nc += len; 251 cc -= len; 252 } while (error == ENOENT); 253 if (error) { 254 u.u_error = error; 255 if (bp) 256 brelse(bp); 257 bp = 0; 258 goto badarg; 259 } 260 } 261 if (bp) 262 bdwrite(bp); 263 bp = 0; 264 nc = (nc + NBPW-1) & ~(NBPW-1); 265 getxfile(ip, &exdata.ex_exec, nc + (na+4)*NBPW, uid, gid); 266 if (u.u_error) { 267 badarg: 268 for (cc = 0; cc < nc; cc += CLSIZE*NBPG) { 269 bp = baddr(argdev, bno + ctod(cc/NBPG), CLSIZE*NBPG); 270 if (bp) { 271 bp->b_flags |= B_AGE; /* throw away */ 272 bp->b_flags &= ~B_DELWRI; /* cancel io */ 273 brelse(bp); 274 bp = 0; 275 } 276 } 277 goto bad; 278 } 279 iput(ip); 280 ip = NULL; 281 282 /* 283 * Copy back arglist. 284 */ 285 ucp = USRSTACK - nc - NBPW; 286 ap = ucp - na*NBPW - 3*NBPW; 287 u.u_ar0[SP] = ap; 288 (void) suword((caddr_t)ap, na-ne); 289 nc = 0; 290 cc = 0; 291 for (;;) { 292 ap += NBPW; 293 if (na == ne) { 294 (void) suword((caddr_t)ap, 0); 295 ap += NBPW; 296 } 297 if (--na < 0) 298 break; 299 (void) suword((caddr_t)ap, ucp); 300 do { 301 if (cc <= 0) { 302 if (bp) 303 brelse(bp); 304 cc = CLSIZE*NBPG; 305 bp = bread(argdev, bno + ctod(nc / NBPG), cc); 306 bp->b_flags |= B_AGE; /* throw away */ 307 bp->b_flags &= ~B_DELWRI; /* cancel io */ 308 cp = bp->b_un.b_addr; 309 } 310 error = copyoutstr(cp, (caddr_t)ucp, cc, &len); 311 ucp += len; 312 cp += len; 313 nc += len; 314 cc -= len; 315 } while (error == ENOENT); 316 if (error == EFAULT) 317 panic("exec: EFAULT"); 318 } 319 (void) suword((caddr_t)ap, 0); 320 321 /* 322 * Reset caught signals. Held signals 323 * remain held through p_sigmask. 324 */ 325 while (u.u_procp->p_sigcatch) { 326 nc = ffs(u.u_procp->p_sigcatch); 327 u.u_procp->p_sigcatch &= ~sigmask(nc); 328 u.u_signal[nc] = SIG_DFL; 329 } 330 /* 331 * Reset stack state to the user stack. 332 * Clear set of signals caught on the signal stack. 333 */ 334 u.u_onstack = 0; 335 u.u_sigsp = 0; 336 u.u_sigonstack = 0; 337 338 for (nc = u.u_lastfile; nc >= 0; --nc) { 339 if (u.u_pofile[nc] & UF_EXCLOSE) { 340 closef(u.u_ofile[nc]); 341 u.u_ofile[nc] = NULL; 342 u.u_pofile[nc] = 0; 343 } 344 u.u_pofile[nc] &= ~UF_MAPPED; 345 } 346 while (u.u_lastfile >= 0 && u.u_ofile[u.u_lastfile] == NULL) 347 u.u_lastfile--; 348 setregs(exdata.ex_exec.a_entry); 349 /* 350 * Remember file name for accounting. 351 */ 352 u.u_acflag &= ~AFORK; 353 if (indir) 354 bcopy((caddr_t)cfname, (caddr_t)u.u_comm, MAXCOMLEN); 355 else { 356 if (ndp->ni_dent.d_namlen > MAXCOMLEN) 357 ndp->ni_dent.d_namlen = MAXCOMLEN; 358 bcopy((caddr_t)ndp->ni_dent.d_name, (caddr_t)u.u_comm, 359 (unsigned)(ndp->ni_dent.d_namlen + 1)); 360 } 361 bad: 362 if (bp) 363 brelse(bp); 364 if (bno) 365 rmfree(argmap, (long)ctod(clrnd((int) btoc(NCARGS))), bno); 366 if (ip) 367 iput(ip); 368 } 369 370 /* 371 * Read in and set up memory for executed file. 372 */ 373 getxfile(ip, ep, nargc, uid, gid) 374 register struct inode *ip; 375 register struct exec *ep; 376 int nargc, uid, gid; 377 { 378 size_t ts, ds, ids, uds, ss; 379 int pagi; 380 381 if (ep->a_magic == 0413) 382 pagi = SPAGI; 383 else 384 pagi = 0; 385 if (ip->i_flag & IXMOD) { /* XXX */ 386 u.u_error = ETXTBSY; 387 goto bad; 388 } 389 if (ep->a_text != 0 && (ip->i_flag&ITEXT) == 0 && 390 ip->i_count != 1) { 391 register struct file *fp; 392 393 for (fp = file; fp < fileNFILE; fp++) { 394 if (fp->f_type == DTYPE_INODE && 395 fp->f_count > 0 && 396 (struct inode *)fp->f_data == ip && 397 (fp->f_flag&FWRITE)) { 398 u.u_error = ETXTBSY; 399 goto bad; 400 } 401 } 402 } 403 404 /* 405 * Compute text and data sizes and make sure not too large. 406 * NB - Check data and bss separately as they may overflow 407 * when summed together. 408 */ 409 ts = clrnd(btoc(ep->a_text)); 410 ids = clrnd(btoc(ep->a_data)); 411 uds = clrnd(btoc(ep->a_bss)); 412 ds = clrnd(btoc(ep->a_data + ep->a_bss)); 413 ss = clrnd(SSIZE + btoc(nargc)); 414 if (chksize((unsigned)ts, (unsigned)ids, (unsigned)uds, (unsigned)ss)) 415 goto bad; 416 417 /* 418 * Make sure enough space to start process. 419 */ 420 u.u_cdmap = zdmap; 421 u.u_csmap = zdmap; 422 if (swpexpand(ds, ss, &u.u_cdmap, &u.u_csmap) == NULL) 423 goto bad; 424 425 /* 426 * At this point, committed to the new image! 427 * Release virtual memory resources of old process, and 428 * initialize the virtual memory of the new process. 429 * If we resulted from vfork(), instead wakeup our 430 * parent who will set SVFDONE when he has taken back 431 * our resources. 432 */ 433 if ((u.u_procp->p_flag & SVFORK) == 0) 434 vrelvm(); 435 else { 436 u.u_procp->p_flag &= ~SVFORK; 437 u.u_procp->p_flag |= SKEEP; 438 wakeup((caddr_t)u.u_procp); 439 while ((u.u_procp->p_flag & SVFDONE) == 0) 440 sleep((caddr_t)u.u_procp, PZERO - 1); 441 u.u_procp->p_flag &= ~(SVFDONE|SKEEP); 442 } 443 u.u_procp->p_flag &= ~(SPAGI|SSEQL|SUANOM|SOUSIG); 444 u.u_procp->p_flag |= pagi; 445 u.u_dmap = u.u_cdmap; 446 u.u_smap = u.u_csmap; 447 vgetvm(ts, ds, ss); 448 449 if (pagi == 0) 450 u.u_error = 451 rdwri(UIO_READ, ip, 452 (char *)ctob(dptov(u.u_procp, 0)), 453 (int)ep->a_data, 454 (int)(sizeof (struct exec) + ep->a_text), 455 0, (int *)0); 456 xalloc(ip, ep, pagi); 457 if (pagi && u.u_procp->p_textp) 458 vinifod((struct fpte *)dptopte(u.u_procp, 0), 459 PG_FTEXT, u.u_procp->p_textp->x_iptr, 460 (long)(1 + ts/CLSIZE), (int)btoc(ep->a_data)); 461 462 #ifdef vax 463 /* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */ 464 mtpr(TBIA, 0); 465 #endif 466 467 if (u.u_error) 468 swkill(u.u_procp, "exec: I/O error mapping pages"); 469 /* 470 * set SUID/SGID protections, if no tracing 471 */ 472 if ((u.u_procp->p_flag&STRC)==0) { 473 u.u_uid = uid; 474 u.u_procp->p_uid = uid; 475 u.u_gid = gid; 476 } else 477 psignal(u.u_procp, SIGTRAP); 478 u.u_tsize = ts; 479 u.u_dsize = ds; 480 u.u_ssize = ss; 481 u.u_prof.pr_scale = 0; 482 bad: 483 return; 484 } 485