1: /*
   2:  * Copyright (c) 1986 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  *
   6:  *	@(#)kern_exec.c	1.8 (2.11BSD) 1999/9/6
   7:  */
   8: 
   9: #include "param.h"
  10: #include "../machine/reg.h"
  11: #include "../machine/seg.h"
  12: 
  13: #include "systm.h"
  14: #include "map.h"
  15: #include "user.h"
  16: #include "proc.h"
  17: #include "buf.h"
  18: #include "inode.h"
  19: #include "acct.h"
  20: #include "namei.h"
  21: #include "fs.h"
  22: #include "mount.h"
  23: #include "file.h"
  24: #include "text.h"
  25: #include "signalvar.h"
  26: extern  char    sigprop[];  /* XXX */
  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:     int nc;
  46:     register char *cp;
  47:     register struct buf *bp;
  48:     struct execa *uap = (struct execa *)u.u_ap;
  49:     int na, ne, ucp, ap;
  50:     register int cc;
  51:     unsigned len;
  52:     int indir, uid, gid;
  53:     char *sharg;
  54:     struct inode *ip;
  55:     memaddr bno;
  56:     char cfname[MAXCOMLEN + 1];
  57: #define SHSIZE  32
  58:     char cfarg[SHSIZE];
  59:     union {
  60:         char    ex_shell[SHSIZE];   /* #! and name of interpreter */
  61:         struct  exec ex_exec;
  62:     } exdata;
  63:     struct  nameidata nd;
  64:     register struct nameidata *ndp = &nd;
  65:     int resid, error;
  66: 
  67:     NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname);
  68:     if ((ip = namei(ndp)) == NULL)
  69:         return;
  70:     bno = 0;
  71:     bp = 0;
  72:     indir = 0;
  73:     uid = u.u_uid;
  74:     gid = u.u_groups[0];
  75:     if (ip->i_fs->fs_flags & MNT_NOEXEC) {
  76:         u.u_error = EACCES;
  77:         goto bad;
  78:     }
  79:     if ((ip->i_fs->fs_flags & MNT_NOSUID) == 0) {
  80:         if (ip->i_mode & ISUID)
  81:             uid = ip->i_uid;
  82:         if (ip->i_mode & ISGID)
  83:             gid = ip->i_gid;
  84:     }
  85:   again:
  86:     if (access(ip, IEXEC))
  87:         goto bad;
  88:     if ((u.u_procp->p_flag & P_TRACED) && access(ip, IREAD))
  89:         goto bad;
  90:     if ((ip->i_mode & IFMT) != IFREG ||
  91:         (ip->i_mode & (IEXEC|(IEXEC>>3)|(IEXEC>>6))) == 0) {
  92:         u.u_error = EACCES;
  93:         goto bad;
  94:     }
  95: 
  96:     /*
  97: 	 * Read in first few bytes of file for segment sizes, magic number:
  98: 	 *	407 = plain executable
  99: 	 *	410 = RO text
 100: 	 *	411 = separated I/D
 101: 	 *	405 = text overlay
 102: 	 *	430 = auto-overlay (nonseparate)
 103: 	 *	431 = auto-overlay (separate)
 104: 	 * Also an ASCII line beginning with #! is
 105: 	 * the file name of a ``shell'' and arguments may be prepended
 106: 	 * to the argument list if given here.
 107: 	 *
 108: 	 * SHELL NAMES ARE LIMITED IN LENGTH.
 109: 	 *
 110: 	 * ONLY ONE ARGUMENT MAY BE PASSED TO THE SHELL FROM
 111: 	 * THE ASCII LINE.
 112: 	 */
 113:     exdata.ex_shell[0] = '\0';  /* for zero length files */
 114:     u.u_error = rdwri(UIO_READ, ip, &exdata, sizeof(exdata), (off_t)0,
 115:                 UIO_SYSSPACE, IO_UNIT, &resid);
 116:     if (u.u_error)
 117:         goto bad;
 118:     if (resid > sizeof(exdata) - sizeof(exdata.ex_exec) &&
 119:         exdata.ex_shell[0] != '#') {
 120:         u.u_error = ENOEXEC;
 121:         goto bad;
 122:     }
 123: 
 124:     switch((int)exdata.ex_exec.a_magic) {
 125: 
 126:     case A_MAGIC1:
 127:     case A_MAGIC2:
 128:     case A_MAGIC3:
 129:     case A_MAGIC4:
 130:     case A_MAGIC5:
 131:     case A_MAGIC6:
 132:         break;
 133: 
 134:     default:
 135:         if (exdata.ex_shell[0] != '#' ||
 136:             exdata.ex_shell[1] != '!' ||
 137:             indir) {
 138:             u.u_error = ENOEXEC;
 139:             goto bad;
 140:         }
 141: /*
 142:  * If setuid/gid scripts were to be disallowed this is where it would
 143:  * have to be done.
 144:  *		u.u_uid = uid;
 145:  *		u.u_gid = u_groups[0];
 146: */
 147:         cp = &exdata.ex_shell[2];       /* skip "#!" */
 148:         while (cp < &exdata.ex_shell[SHSIZE]) {
 149:             if (*cp == '\t')
 150:                 *cp = ' ';
 151:             else if (*cp == '\n') {
 152:                 *cp = '\0';
 153:                 break;
 154:             }
 155:             cp++;
 156:         }
 157:         if (*cp != '\0') {
 158:             u.u_error = ENOEXEC;
 159:             goto bad;
 160:         }
 161:         cp = &exdata.ex_shell[2];
 162:         while (*cp == ' ')
 163:             cp++;
 164:         ndp->ni_dirp = cp;
 165:         while (*cp && *cp != ' ')
 166:             cp++;
 167:         cfarg[0] = '\0';
 168:         if (*cp) {
 169:             *cp++ = '\0';
 170:             while (*cp == ' ')
 171:                 cp++;
 172:             if (*cp)
 173:                 bcopy((caddr_t)cp, (caddr_t)cfarg, SHSIZE);
 174:         }
 175:         indir = 1;
 176:         iput(ip);
 177:         ndp->ni_nameiop = LOOKUP | FOLLOW;
 178:         ndp->ni_segflg = UIO_SYSSPACE;
 179:         ip = namei(ndp);
 180:         if (ip == NULL)
 181:             return;
 182:         bcopy((caddr_t)ndp->ni_dent.d_name, (caddr_t)cfname, MAXCOMLEN);
 183:         cfname[MAXCOMLEN] = '\0';
 184:         goto again;
 185:     }
 186: 
 187:     /*
 188: 	 * Collect arguments on "file" in swap space.
 189: 	 */
 190:     na = 0;
 191:     ne = 0;
 192:     nc = 0;
 193:     cc = 0;
 194:     bno = malloc(swapmap, ctod((int)btoc(NCARGS + MAXBSIZE)));
 195:     if (bno == 0) {
 196:         swkill(u.u_procp, "exec");
 197:         goto bad;
 198:     }
 199:     /*
 200: 	 * Copy arguments into file in argdev area.
 201: 	 */
 202:     if (uap->argp) for (;;) {
 203:         ap = NULL;
 204:         sharg = NULL;
 205:         if (indir && na == 0) {
 206:             sharg = cfname;
 207:             ap = (int)sharg;
 208:             uap->argp++;        /* ignore argv[0] */
 209:         } else if (indir && (na == 1 && cfarg[0])) {
 210:             sharg = cfarg;
 211:             ap = (int)sharg;
 212:         } else if (indir && (na == 1 || na == 2 && cfarg[0]))
 213:             ap = (int)uap->fname;
 214:         else if (uap->argp) {
 215:             ap = fuword((caddr_t)uap->argp);
 216:             uap->argp++;
 217:         }
 218:         if (ap == NULL && uap->envp) {
 219:             uap->argp = NULL;
 220:             if ((ap = fuword((caddr_t)uap->envp)) != NULL)
 221:                 uap->envp++, ne++;
 222:         }
 223:         if (ap == NULL)
 224:             break;
 225:         na++;
 226:         if (ap == -1) {
 227:             u.u_error = EFAULT;
 228:             break;
 229:         }
 230:         do {
 231:             if (cc <= 0) {
 232:                 /*
 233: 				 * We depend on NCARGS being a multiple of
 234: 				 * CLSIZE*NBPG.  This way we need only check
 235: 				 * overflow before each buffer allocation.
 236: 				 */
 237:                 if (nc >= NCARGS-1) {
 238:                     error = E2BIG;
 239:                     break;
 240:                 }
 241:                 if (bp) {
 242:                     mapout(bp);
 243:                     bdwrite(bp);
 244:                 }
 245:                 cc = CLSIZE*NBPG;
 246:                 bp = getblk(swapdev, dbtofsb(clrnd(bno)) + lblkno(nc));
 247:                 cp = mapin(bp);
 248:             }
 249:             if (sharg) {
 250:                 error = copystr(sharg, cp, (unsigned)cc, &len);
 251:                 sharg += len;
 252:             } else {
 253:                 error = copyinstr((caddr_t)ap, cp, (unsigned)cc,
 254:                     &len);
 255:                 ap += len;
 256:             }
 257:             cp += len;
 258:             nc += len;
 259:             cc -= len;
 260:         } while (error == ENOENT);
 261:         if (error) {
 262:             u.u_error = error;
 263:             if (bp) {
 264:                 mapout(bp);
 265:                 bp->b_flags |= B_AGE;
 266:                 bp->b_flags &= ~B_DELWRI;
 267:                 brelse(bp);
 268:             }
 269:             bp = 0;
 270:             goto badarg;
 271:         }
 272:     }
 273:     if (bp) {
 274:         mapout(bp);
 275:         bdwrite(bp);
 276:     }
 277:     bp = 0;
 278:     nc = (nc + NBPW-1) & ~(NBPW-1);
 279:     getxfile(ip, &exdata.ex_exec, nc + (na+4)*NBPW, uid, gid);
 280:     if (u.u_error) {
 281: badarg:
 282:         for (cc = 0;cc < nc; cc += CLSIZE * NBPG) {
 283:             daddr_t blkno;
 284: 
 285:             blkno = dbtofsb(clrnd(bno)) + lblkno(cc);
 286:             if (incore(swapdev,blkno)) {
 287:                 bp = bread(swapdev,blkno);
 288:                 bp->b_flags |= B_AGE;       /* throw away */
 289:                 bp->b_flags &= ~B_DELWRI;   /* cancel io */
 290:                 brelse(bp);
 291:                 bp = 0;
 292:             }
 293:         }
 294:         goto bad;
 295:     }
 296:     iput(ip);
 297:     ip = NULL;
 298: 
 299:     /*
 300: 	 * Copy back arglist.
 301: 	 */
 302:     ucp = -nc - NBPW;
 303:     ap = ucp - na*NBPW - 3*NBPW;
 304:     u.u_ar0[R6] = ap;
 305:     (void) suword((caddr_t)ap, na-ne);
 306:     nc = 0;
 307:     cc = 0;
 308:     for (;;) {
 309:         ap += NBPW;
 310:         if (na == ne) {
 311:             (void) suword((caddr_t)ap, 0);
 312:             ap += NBPW;
 313:         }
 314:         if (--na < 0)
 315:             break;
 316:         (void) suword((caddr_t)ap, ucp);
 317:         do {
 318:             if (cc <= 0) {
 319:                 if (bp) {
 320:                     mapout(bp);
 321:                     brelse(bp);
 322:                 }
 323:                 cc = CLSIZE*NBPG;
 324:                 bp = bread(swapdev, dbtofsb(clrnd(bno)) + lblkno(nc));
 325:                 bp->b_flags |= B_AGE;       /* throw away */
 326:                 bp->b_flags &= ~B_DELWRI;   /* cancel io */
 327:                 cp = mapin(bp);
 328:             }
 329:             error = copyoutstr(cp, (caddr_t)ucp, (unsigned)cc,
 330:                 &len);
 331:             ucp += len;
 332:             cp += len;
 333:             nc += len;
 334:             cc -= len;
 335:         } while (error == ENOENT);
 336:         if (error == EFAULT)
 337:             panic("exec: EFAULT");
 338:     }
 339:     (void) suword((caddr_t)ap, 0);
 340:     (void) suword((caddr_t)(-NBPW), 0);
 341:     if (bp) {
 342:         mapout(bp);
 343:         bp->b_flags |= B_AGE;
 344:         brelse(bp);
 345:         bp = NULL;
 346:     }
 347:     execsigs(u.u_procp);
 348:     for (cp = u.u_pofile, cc = 0; cc <= u.u_lastfile; cc++, cp++)
 349:         {
 350:         if  (*cp & UF_EXCLOSE)
 351:             {
 352:             (void)closef(u.u_ofile[cc]);
 353:             u.u_ofile[cc] = NULL;
 354:             *cp = 0;
 355:             }
 356:         }
 357:     while (u.u_lastfile >= 0 && u.u_ofile[u.u_lastfile] == NULL)
 358:         u.u_lastfile--;
 359: 
 360:     /*
 361: 	 * inline expansion of setregs(), found
 362: 	 * in ../pdp/machdep.c
 363: 	 *
 364: 	 * setregs(exdata.ex_exec.a_entry);
 365: 	 */
 366:     u.u_ar0[PC] = exdata.ex_exec.a_entry & ~01;
 367:     u.u_fps.u_fpsr = 0;
 368: 
 369:     /*
 370: 	 * Remember file name for accounting.
 371: 	 */
 372:     u.u_acflag &= ~AFORK;
 373:     if (indir)
 374:         bcopy((caddr_t)cfname, (caddr_t)u.u_comm, MAXCOMLEN);
 375:     else
 376:         bcopy((caddr_t)ndp->ni_dent.d_name, (caddr_t)u.u_comm, MAXCOMLEN);
 377: bad:
 378:     if (bp) {
 379:         mapout(bp);
 380:         bp->b_flags |= B_AGE;
 381:         brelse(bp);
 382:     }
 383:     if (bno)
 384:         mfree(swapmap, ctod((int)btoc(NCARGS + MAXBSIZE)), bno);
 385:     if (ip)
 386:         iput(ip);
 387: }
 388: 
 389: /*
 390:  * Reset signals for an exec of the specified process.  In 4.4 this function
 391:  * was in kern_sig.c but since in 2.11 kern_sig and kern_exec will likely be
 392:  * in different overlays placing this here potentially saves a kernel overlay
 393:  * switch.
 394:  */
 395: void
 396: execsigs(p)
 397:     register struct proc *p;
 398: {
 399:     register int nc;
 400:     unsigned long mask;
 401: 
 402:     /*
 403: 	 * Reset caught signals.  Held signals remain held
 404: 	 * through p_sigmask (unless they were caught,
 405: 	 * and are now ignored by default).
 406: 	 */
 407:     while (p->p_sigcatch) {
 408:         nc = ffs(p->p_sigcatch);
 409:         mask = sigmask(nc);
 410:         p->p_sigcatch &= ~mask;
 411:         if (sigprop[nc] & SA_IGNORE) {
 412:             if (nc != SIGCONT)
 413:                 p->p_sigignore |= mask;
 414:             p->p_sig &= ~mask;
 415:         }
 416:         u.u_signal[nc] = SIG_DFL;
 417:     }
 418:     /*
 419: 	 * Reset stack state to the user stack (disable the alternate stack).
 420: 	 */
 421:     u.u_sigstk.ss_flags = SA_DISABLE;
 422:     u.u_sigstk.ss_size = 0;
 423:     u.u_sigstk.ss_base = 0;
 424:     u.u_psflags = 0;
 425: }
 426: /*
 427:  * Read in and set up memory for executed file.
 428:  * u.u_error set on error
 429:  */
 430: getxfile(ip, ep, nargc, uid, gid)
 431:     struct inode *ip;
 432:     register struct exec *ep;
 433:     int nargc, uid, gid;
 434: {
 435:     struct u_ovd sovdata;
 436:     long lsize;
 437:     off_t   offset;
 438:     u_int ds, ts, ss;
 439:     u_int ovhead[NOVL + 1];
 440:     int sep, overlay, ovflag, ovmax, resid;
 441: 
 442:     overlay = sep = ovflag = 0;
 443:     switch(ep->a_magic) {
 444:         case A_MAGIC1:
 445:             lsize = (long)ep->a_data + ep->a_text;
 446:             ep->a_data = (u_int)lsize;
 447:             if (lsize != ep->a_data) {  /* check overflow */
 448:                 u.u_error = ENOMEM;
 449:                 return;
 450:             }
 451:             ep->a_text = 0;
 452:             break;
 453:         case A_MAGIC3:
 454:             sep++;
 455:             break;
 456:         case A_MAGIC4:
 457:             overlay++;
 458:             break;
 459:         case A_MAGIC5:
 460:             ovflag++;
 461:             break;
 462:         case A_MAGIC6:
 463:             sep++;
 464:             ovflag++;
 465:             break;
 466:     }
 467: 
 468:     if (ip->i_text && (ip->i_text->x_flag & XTRC)) {
 469:         u.u_error = ETXTBSY;
 470:         return;
 471:     }
 472:     if (ep->a_text != 0 && (ip->i_flag&ITEXT) == 0 &&
 473:         ip->i_count != 1) {
 474:         register struct file *fp;
 475: 
 476:         for (fp = file; fp < fileNFILE; fp++) {
 477:             if (fp->f_type == DTYPE_INODE &&
 478:                 fp->f_count > 0 &&
 479:                 (struct inode *)fp->f_data == ip &&
 480:                 (fp->f_flag&FWRITE)) {
 481:                 u.u_error = ETXTBSY;
 482:                 return;
 483:             }
 484:         }
 485:     }
 486: 
 487:     /*
 488: 	 * find text and data sizes try; them out for possible
 489: 	 * overflow of max sizes
 490: 	 */
 491:     ts = btoc(ep->a_text);
 492:     lsize = (long)ep->a_data + ep->a_bss;
 493:     if (lsize != (u_int)lsize) {
 494:         u.u_error = ENOMEM;
 495:         return;
 496:     }
 497:     ds = btoc(lsize);
 498:     ss = SSIZE + btoc(nargc);
 499: 
 500:     /*
 501: 	 * if auto overlay get second header
 502: 	 */
 503:     sovdata = u.u_ovdata;
 504:     u.u_ovdata.uo_ovbase = 0;
 505:     u.u_ovdata.uo_curov = 0;
 506:     if (ovflag) {
 507:         u.u_error = rdwri(UIO_READ, ip, ovhead, sizeof(ovhead),
 508:             (off_t)sizeof(struct exec), UIO_SYSSPACE, IO_UNIT, &resid);
 509:         if (resid != 0)
 510:             u.u_error = ENOEXEC;
 511:         if (u.u_error) {
 512:             u.u_ovdata = sovdata;
 513:             return;
 514:         }
 515:         /* set beginning of overlay segment */
 516:         u.u_ovdata.uo_ovbase = ctos(ts);
 517: 
 518:         /* 0th entry is max size of the overlays */
 519:         ovmax = btoc(ovhead[0]);
 520: 
 521:         /* set max number of segm. registers to be used */
 522:         u.u_ovdata.uo_nseg = ctos(ovmax);
 523: 
 524:         /* set base of data space */
 525:         u.u_ovdata.uo_dbase = stoc(u.u_ovdata.uo_ovbase +
 526:             u.u_ovdata.uo_nseg);
 527: 
 528:         /*
 529: 		 * Set up a table of offsets to each of the overlay
 530: 		 * segements. The ith overlay runs from ov_offst[i-1]
 531: 		 * to ov_offst[i].
 532: 		 */
 533:         u.u_ovdata.uo_ov_offst[0] = ts;
 534:         {
 535:             register int t, i;
 536: 
 537:             /* check if any overlay is larger than ovmax */
 538:             for (i = 1; i <= NOVL; i++) {
 539:                 if ((t = btoc(ovhead[i])) > ovmax) {
 540:                     u.u_error = ENOEXEC;
 541:                     u.u_ovdata = sovdata;
 542:                     return;
 543:                 }
 544:                 u.u_ovdata.uo_ov_offst[i] =
 545:                     t + u.u_ovdata.uo_ov_offst[i - 1];
 546:             }
 547:         }
 548:     }
 549:     if (overlay) {
 550:         if (u.u_sep == 0 && ctos(ts) != ctos(u.u_tsize) || nargc) {
 551:             u.u_error = ENOMEM;
 552:             return;
 553:         }
 554:         ds = u.u_dsize;
 555:         ss = u.u_ssize;
 556:         sep = u.u_sep;
 557:         xfree();
 558:         xalloc(ip,ep);
 559:         u.u_ar0[PC] = ep->a_entry & ~01;
 560:     } else {
 561:         if (estabur(ts, ds, ss, sep, RO)) {
 562:             u.u_ovdata = sovdata;
 563:             return;
 564:         }
 565: 
 566:         /*
 567: 		 * allocate and clear core at this point, committed
 568: 		 * to the new image
 569: 		 */
 570:         u.u_prof.pr_scale = 0;
 571:         if (u.u_procp->p_flag & SVFORK)
 572:             endvfork();
 573:         else
 574:             xfree();
 575:         expand(ds, S_DATA);
 576:         {
 577:             register u_int numc, startc;
 578: 
 579:             startc = btoc(ep->a_data);  /* clear BSS only */
 580:             if (startc != 0)
 581:                 startc--;
 582:             numc = ds - startc;
 583:             clear(u.u_procp->p_daddr + startc, numc);
 584:         }
 585:         expand(ss, S_STACK);
 586:         clear(u.u_procp->p_saddr, ss);
 587:         xalloc(ip, ep);
 588: 
 589:         /*
 590: 		 * read in data segment
 591: 		 */
 592:         estabur((u_int)0, ds, (u_int)0, 0, RO);
 593:         offset = sizeof(struct exec);
 594:         if (ovflag) {
 595:             offset += sizeof(ovhead);
 596:             offset += (((long)u.u_ovdata.uo_ov_offst[NOVL]) << 6);
 597:         }
 598:         else
 599:             offset += ep->a_text;
 600:         rdwri(UIO_READ, ip, (caddr_t) 0, ep->a_data, offset,
 601:             UIO_USERSPACE, IO_UNIT, (int *)0);
 602: 
 603:         /*
 604: 		 * set SUID/SGID protections, if no tracing
 605: 		 */
 606:         if ((u.u_procp->p_flag & P_TRACED)==0) {
 607:             u.u_uid = uid;
 608:             u.u_procp->p_uid = uid;
 609:             u.u_groups[0] = gid;
 610:         } else
 611:             psignal(u.u_procp, SIGTRAP);
 612:         u.u_svuid = u.u_uid;
 613:         u.u_svgid = u.u_groups[0];
 614:         u.u_acflag &= ~ASUGID;  /* start fresh setuid/gid priv use */
 615:     }
 616:     u.u_tsize = ts;
 617:     u.u_dsize = ds;
 618:     u.u_ssize = ss;
 619:     u.u_sep = sep;
 620:     estabur(ts, ds, ss, sep, RO);
 621: }

Defined functions

execsigs defined in line 395; used 1 times
execv defined in line 37; used 2 times
execve defined in line 43; used 3 times
getxfile defined in line 430; used 1 times

Defined struct's

execa defined in line 31; used 6 times
  • in line 39(2), 48(4)

Defined macros

SHSIZE defined in line 57; used 4 times
Last modified: 1999-09-06
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4553
Valid CSS Valid XHTML 1.0 Strict