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