# 2.11BSD#431 - /usr/src/sys/sys/kern_exec.c

##### Functions

    execsigs          X
    execv             X
    execve            X
    getxfile          X

##### Macros

    SHSIZE            X

##### struct's

    execa             X

       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

- in line 347

execv defined in line 37; used 2 times

- in /usr/src/sys/sys/init_sysent.c line 20, 121

execve defined in line 43; used 3 times

- in line 40
- in /usr/src/sys/sys/init_sysent.c line 20, 169

getxfile defined in line 430; used 1 times

- in line 279

#### 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

- in line 58-60(2), 148, 173

Last modified: 1999-09-06 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1317 |