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