1 /* kern_exec.c 6.5 84/07/23 */ 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, 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.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 cc = 0; 190 uap = (struct execa *)u.u_ap; 191 bno = rmalloc(argmap, (long)ctod(clrnd((int)btoc(NCARGS)))); 192 if (bno == 0) { 193 swkill(u.u_procp, "exece"); 194 goto bad; 195 } 196 if (bno % CLSIZE) 197 panic("execa rmalloc"); 198 /* 199 * Copy arguments into file in argdev area. 200 */ 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 } 209 if (ap == NULL && uap->envp) { 210 uap->argp = NULL; 211 if ((ap = fuword((caddr_t)uap->envp)) != NULL) 212 uap->envp++, ne++; 213 } 214 if (ap == NULL) 215 break; 216 na++; 217 if (ap == -1) { 218 error = EFAULT; 219 break; 220 } 221 do { 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 } 232 if (bp) 233 bdwrite(bp); 234 cc = CLSIZE*NBPG; 235 bp = getblk(argdev, bno + ctod(nc/NBPG), cc); 236 cp = bp->b_un.b_addr; 237 } 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 } 254 } 255 if (bp) 256 bdwrite(bp); 257 bp = 0; 258 nc = (nc + NBPW-1) & ~(NBPW-1); 259 if (indir) { 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)); 263 } 264 getxfile(ip, &exdata.ex_exec, nc + (na+4)*NBPW, uid, gid); 265 if (u.u_error) { 266 badarg: 267 for (cc = 0; cc < nc; cc += CLSIZE*NBPG) { 268 bp = baddr(argdev, bno + ctod(cc/NBPG), CLSIZE*NBPG); 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 /* 280 * Copy back arglist. 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; 287 for (;;) { 288 ap += NBPW; 289 if (na == ne) { 290 (void) suword((caddr_t)ap, 0); 291 ap += NBPW; 292 } 293 if (--na < 0) 294 break; 295 (void) suword((caddr_t)ap, ucp); 296 do { 297 if (nc % (CLSIZE*NBPG) == 0) { 298 if (bp) 299 brelse(bp); 300 bp = bread(argdev, bno + ctod(nc / NBPG), 301 CLSIZE*NBPG); 302 bp->b_flags |= B_AGE; /* throw away */ 303 bp->b_flags &= ~B_DELWRI; /* cancel io */ 304 cp = bp->b_un.b_addr; 305 } 306 (void) subyte((caddr_t)ucp++, (cc = *cp++)); 307 nc++; 308 } while(cc&0377); 309 } 310 (void) suword((caddr_t)ap, 0); 311 setregs(exdata.ex_exec.a_entry); 312 /* 313 * Remember file name for accounting. 314 */ 315 u.u_acflag &= ~AFORK; 316 bcopy((caddr_t)ndp->ni_dent.d_name, (caddr_t)u.u_comm, 317 (unsigned)(ndp->ni_dent.d_namlen + 1)); 318 bad: 319 if (bp) 320 brelse(bp); 321 if (bno) 322 rmfree(argmap, (long)ctod(clrnd((int) btoc(NCARGS))), bno); 323 iput(ip); 324 } 325 326 /* 327 * Read in and set up memory for executed file. 328 */ 329 getxfile(ip, ep, nargc, uid, gid) 330 register struct inode *ip; 331 register struct exec *ep; 332 int nargc, uid, gid; 333 { 334 register size_t ts, ds, ss; 335 int pagi; 336 337 if (ep->a_magic == 0413) 338 pagi = SPAGI; 339 else 340 pagi = 0; 341 if (ep->a_text != 0 && (ip->i_flag&ITEXT) == 0 && 342 ip->i_count != 1) { 343 register struct file *fp; 344 345 for (fp = file; fp < fileNFILE; fp++) { 346 if (fp->f_type == DTYPE_INODE && 347 fp->f_count > 0 && 348 (struct inode *)fp->f_data == ip && 349 (fp->f_flag&FWRITE)) { 350 u.u_error = ETXTBSY; 351 goto bad; 352 } 353 } 354 } 355 356 /* 357 * Compute text and data sizes and make sure not too large. 358 */ 359 ts = clrnd(btoc(ep->a_text)); 360 ds = clrnd(btoc(ep->a_data + ep->a_bss)); 361 ss = clrnd(SSIZE + btoc(nargc)); 362 if (chksize((unsigned)ts, (unsigned)ds, (unsigned)ss)) 363 goto bad; 364 365 /* 366 * Make sure enough space to start process. 367 */ 368 u.u_cdmap = zdmap; 369 u.u_csmap = zdmap; 370 if (swpexpand(ds, ss, &u.u_cdmap, &u.u_csmap) == NULL) 371 goto bad; 372 373 /* 374 * At this point, committed to the new image! 375 * Release virtual memory resources of old process, and 376 * initialize the virtual memory of the new process. 377 * If we resulted from vfork(), instead wakeup our 378 * parent who will set SVFDONE when he has taken back 379 * our resources. 380 */ 381 if ((u.u_procp->p_flag & SVFORK) == 0) 382 vrelvm(); 383 else { 384 u.u_procp->p_flag &= ~SVFORK; 385 u.u_procp->p_flag |= SKEEP; 386 wakeup((caddr_t)u.u_procp); 387 while ((u.u_procp->p_flag & SVFDONE) == 0) 388 sleep((caddr_t)u.u_procp, PZERO - 1); 389 u.u_procp->p_flag &= ~(SVFDONE|SKEEP); 390 } 391 u.u_procp->p_flag &= ~(SPAGI|SSEQL|SUANOM|SOUSIG); 392 u.u_procp->p_flag |= pagi; 393 u.u_dmap = u.u_cdmap; 394 u.u_smap = u.u_csmap; 395 vgetvm(ts, ds, ss); 396 397 if (pagi == 0) 398 u.u_error = 399 rdwri(UIO_READ, ip, 400 (char *)ctob(dptov(u.u_procp, 0)), 401 (int)ep->a_data, 402 (int)(sizeof (struct exec) + ep->a_text), 403 0, (int *)0); 404 xalloc(ip, ep, pagi); 405 if (pagi && u.u_procp->p_textp) 406 vinifod((struct fpte *)dptopte(u.u_procp, 0), 407 PG_FTEXT, u.u_procp->p_textp->x_iptr, 408 (long)(1 + ts/CLSIZE), (int)btoc(ep->a_data)); 409 410 #ifdef vax 411 /* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */ 412 mtpr(TBIA, 0); 413 #endif 414 415 if (u.u_error) 416 swkill(u.u_procp, "i/o error mapping pages"); 417 /* 418 * set SUID/SGID protections, if no tracing 419 */ 420 if ((u.u_procp->p_flag&STRC)==0) { 421 u.u_uid = uid; 422 u.u_procp->p_uid = uid; 423 u.u_gid = gid; 424 } else 425 psignal(u.u_procp, SIGTRAP); 426 u.u_tsize = ts; 427 u.u_dsize = ds; 428 u.u_ssize = ss; 429 u.u_prof.pr_scale = 0; 430 bad: 431 return; 432 } 433 434 /* 435 * Clear registers on exec 436 */ 437 setregs(entry) 438 u_long entry; 439 { 440 register int i; 441 register struct proc *p = u.u_procp; 442 443 /* 444 * Reset caught signals. Held signals 445 * remain held through p_sigmask. 446 */ 447 while (p->p_sigcatch) { 448 (void) spl6(); 449 i = ffs(p->p_sigcatch); 450 p->p_sigcatch &= ~(1 << (i - 1)); 451 u.u_signal[i] = SIG_DFL; 452 (void) spl0(); 453 } 454 #ifdef notdef 455 /* should pass args to init on the stack */ 456 for (rp = &u.u_ar0[0]; rp < &u.u_ar0[16];) 457 *rp++ = 0; 458 #endif 459 u.u_ar0[PC] = entry + 2; 460 for (i=0; i<NOFILE; i++) { 461 if (u.u_pofile[i]&UF_EXCLOSE) { 462 closef(u.u_ofile[i]); 463 u.u_ofile[i] = NULL; 464 u.u_pofile[i] = 0; 465 } 466 u.u_pofile[i] &= ~UF_MAPPED; 467 } 468 } 469