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